Commit e15b5ae93aa0897ebbc36cc371e028bf63c6e29e

Authored by gesilong
1 parent 9e3a17c5

commit:计划补录单联调

... ... @@ -33,6 +33,7 @@ export function procurementPlanCanChangeOrReplenishmentApi(params) {
33 33 })
34 34 }
35 35
  36 +
36 37 export function procurementPlanChangeCreateApi(data) {
37 38 return request({
38 39 url: '/procurement/plan/change/create',
... ... @@ -42,6 +43,15 @@ export function procurementPlanChangeCreateApi(data) {
42 43 })
43 44 }
44 45
  46 +export function procurementPlanReplenplenishApi(data) {
  47 + return request({
  48 + url: '/procurement/plan/replenish',
  49 + method: 'post',
  50 + data,
  51 + contentType: ContentTypeEnum.JSON
  52 + })
  53 +}
  54 +
45 55 export function procurementPlanChangeFindByIdApi(params) {
46 56 return request({
47 57 url: '/procurement/plan/change/findById',
... ... @@ -50,6 +60,14 @@ export function procurementPlanChangeFindByIdApi(params) {
50 60 })
51 61 }
52 62
  63 +// export function procurementPlanReplenishFindByIdApi(params) {
  64 +// return request({
  65 +// url: '/procurement/plan/replenish',
  66 +// method: 'get',
  67 +// params
  68 +// })
  69 +// }
  70 +
53 71 export function procurementPlanReplenishFindByIdApi(params) {
54 72 return request({
55 73 url: '/procurement/plan/replenish',
... ... @@ -67,6 +85,15 @@ export function procurementPlanChangeUpdateApi(data) {
67 85 })
68 86 }
69 87
  88 +export function procurementPlanReplenishUpdateApi(data) {
  89 + return request({
  90 + url: '/procurement/plan/replenish',
  91 + method: 'put',
  92 + data,
  93 + contentType: ContentTypeEnum.JSON
  94 + })
  95 +}
  96 +
70 97 export function procurementPlanSaveApi(data) {
71 98 return request({
72 99 url: '/procurement/plan',
... ...
... ... @@ -493,6 +493,30 @@
493 493 }
494 494 },
495 495 {
  496 + "path": "pages/supple-plan/add",
  497 + "style": {
  498 + "navigationBarTitleText": "新增计划补录单",
  499 + "navigationBarBackgroundColor": "#ffffff",
  500 + "navigationBarTextStyle": "black"
  501 + }
  502 + },
  503 + {
  504 + "path": "pages/supple-plan/modify",
  505 + "style": {
  506 + "navigationBarTitleText": "修改计划补录单",
  507 + "navigationBarBackgroundColor": "#ffffff",
  508 + "navigationBarTextStyle": "black"
  509 + }
  510 + },
  511 + {
  512 + "path": "pages/supple-plan/detail",
  513 + "style": {
  514 + "navigationBarTitleText": "计划补录单详情",
  515 + "navigationBarBackgroundColor": "#ffffff",
  516 + "navigationBarTextStyle": "black"
  517 + }
  518 + },
  519 + {
496 520 "path": "pages/order_list/index",
497 521 "style": {
498 522 "navigationBarTitleText": "订货单列表",
... ...
... ... @@ -137,7 +137,6 @@ export default {
137 137 { text: '终止', variant: 'danger', event: 'abort' },
138 138 { text: '审核', variant: 'primary', event: 'approve' },
139 139 { text: '审核详情', variant: 'outline', event: 'approveDetail' },
140   - { text: '打印', variant: 'outline', event: 'print' },
141 140 { text: '生成买断操作申请单', variant: 'outline', event: 'generate' },
142 141 { text: '废除买断操作申请单', variant: 'danger', event: 'cancel' },
143 142 { text: '查看买断操作申请单', variant: 'outline', event: 'look' },
... ...
... ... @@ -519,6 +519,24 @@ export default {
519 519 }
520 520 return r
521 521 })
  522 + this.notifyLineChange()
  523 + },
  524 + notifyLineChange() {
  525 + try {
  526 + var pr = this.$refs.productRel
  527 + if (pr) {
  528 + if (typeof pr.initItems === 'function') {
  529 + pr._initialized = false
  530 + pr.initItems()
  531 + var self = this
  532 + this.$nextTick(function () {
  533 + pr._initialized = true
  534 + })
  535 + }
  536 + }
  537 + } catch (e) {
  538 + console.warn('notifyLineChange error:', e)
  539 + }
522 540 },
523 541 async fillPriceByDetailPriceId() {
524 542 var d = this.detail || {}
... ... @@ -598,6 +616,8 @@ export default {
598 616 }
599 617 if (price != null) {
600 618 row.priceListPrices = self.toFixed(price, 2)
  619 + } else {
  620 + row.priceListPrices = ''
601 621 }
602 622 return row
603 623 })
... ...
... ... @@ -365,14 +365,13 @@ export default {
365 365 companySheetVisible: false,
366 366 priceSheetVisible: false,
367 367 companyDisplayFields: [
368   - { label: '公司简称', field: 'companyShortName' },
  368 + { label: '公司简称', field: 'shortName' },
369 369 { label: '公司名称', field: 'companyName' },
370   - { label: '编码', field: 'code' }
  370 + { label: '办事处', field: 'deptName' }
371 371 ],
372 372 priceTableDisplayFields: [
373   - { label: '价格表编号', field: 'priceTableCode' },
374   - { label: '名称', field: 'priceTableName' },
375   - { label: '日期', field: 'effectiveDate' }
  373 + { label: '价格表编号', field: 'code' },
  374 + { label: '创建人', field: 'createBy' },
376 375 ]
377 376 }
378 377 },
... ... @@ -642,6 +641,7 @@ export default {
642 641 var res = await priceTableDetailApi({ id: priceId })
643 642 var d = (res && res.data) ? res.data : {}
644 643 var priceLines = self.extractPriceLines(d)
  644 + console.log(priceLines,d,'6666')
645 645 self.applyPriceLinesToLines(priceLines)
646 646 } catch (e) {
647 647 return
... ... @@ -696,6 +696,8 @@ export default {
696 696 }
697 697 if (price != null) {
698 698 row.priceListPrices = self.toFixed(price, 2)
  699 + } else {
  700 + row.priceListPrices = ''
699 701 }
700 702 return row
701 703 })
... ... @@ -789,8 +791,19 @@ export default {
789 791 notifyLineChange() {
790 792 try {
791 793 var pr = this.$refs.productRel
792   - if (pr && typeof pr.emitChange === 'function') return
793   - } catch (e) {}
  794 + if (pr) {
  795 + if (typeof pr.initItems === 'function') {
  796 + pr._initialized = false
  797 + pr.initItems()
  798 + var self = this
  799 + this.$nextTick(function () {
  800 + pr._initialized = true
  801 + })
  802 + }
  803 + }
  804 + } catch (e) {
  805 + console.warn('notifyLineChange error:', e)
  806 + }
794 807 },
795 808 validateForm() {
796 809 if (!this.form.companyName || !this.form.companyId) {
... ...
... ... @@ -327,6 +327,7 @@ import SingleSelectSheet from '@/components/single-select/index.vue'
327 327 import { procurementPlanDetailApi, procurementPlanCanChangeOrReplenishmentApi, procurementPlanChangeCreateApi } from '@/api/procure-manage/procurementPlan.js'
328 328 import {
329 329 breedRelationshipQueryApi,
  330 + priceTableDetailApi,
330 331 workshopQueryApi
331 332 } from '@/api/devManage.js'
332 333 import { getDicByCodes } from '@/utils/dic.js'
... ... @@ -399,9 +400,10 @@ export default {
399 400 },
400 401 priceTableDisplay() {
401 402 var d = this.detail || {}
402   - var code = d.priceTableCode != null ? d.priceTableCode : (d.priceId != null ? d.priceId : '')
  403 + var code = d.priceTableCode != null ? String(d.priceTableCode).trim() : ''
  404 + if (!code) return ''
403 405 var name = d.priceTableName || ''
404   - return name ? (name + (code ? ' (' + code + ')' : '')) : code
  406 + return name ? (name + ' (' + code + ')') : code
405 407 }
406 408 },
407 409 onLoad() {
... ... @@ -540,6 +542,7 @@ export default {
540 542 this.lineList = Array.isArray(d.procurementPlanLineList) ? d.procurementPlanLineList.slice() : []
541 543 this.buildAttachmentList()
542 544 this.fillLineNames()
  545 + this.fetchPriceDetailAndApply(d.priceId)
543 546 } catch (e) {
544 547 uni.showToast({ title: '加载计划失败', icon: 'none' })
545 548 }
... ... @@ -598,6 +601,91 @@ export default {
598 601 return r
599 602 })
600 603 },
  604 + async fetchPriceDetailAndApply(priceId) {
  605 + if (!priceId) return
  606 + var self = this
  607 + try {
  608 + var res = await priceTableDetailApi({ id: priceId })
  609 + var d = (res && res.data) ? res.data : {}
  610 + if (d.code != null && this.detail) {
  611 + this.$set(this.detail, 'priceTableCode', String(d.code))
  612 + }
  613 + if (d.priceTableName != null && this.detail) {
  614 + this.$set(this.detail, 'priceTableName', d.priceTableName)
  615 + }
  616 + var priceLines = self.extractPriceLines(d)
  617 + self.applyPriceLinesToLines(priceLines)
  618 + } catch (e) {
  619 + return
  620 + }
  621 + },
  622 + extractPriceLines(priceDetail) {
  623 + if (!priceDetail || typeof priceDetail !== 'object') return []
  624 + var candidates = [
  625 + priceDetail.procurementPriceLineList,
  626 + priceDetail.priceSubTableList,
  627 + priceDetail.priceLineList,
  628 + priceDetail.priceList,
  629 + priceDetail.lineList,
  630 + priceDetail.datas,
  631 + priceDetail.records,
  632 + priceDetail.list
  633 + ]
  634 + for (var i = 0; i < candidates.length; i++) {
  635 + if (Array.isArray(candidates[i]) && candidates[i].length) return candidates[i]
  636 + }
  637 + for (var k in priceDetail) {
  638 + if (!Object.prototype.hasOwnProperty.call(priceDetail, k)) continue
  639 + if (Array.isArray(priceDetail[k])) {
  640 + var arr = priceDetail[k]
  641 + if (arr.length && arr[0] && typeof arr[0] === 'object' && (arr[0].price != null || arr[0].productId != null || arr[0].breedId != null || arr[0].varietyId != null)) {
  642 + return arr
  643 + }
  644 + }
  645 + }
  646 + return []
  647 + },
  648 + buildPriceMap(priceLines) {
  649 + var m = {}
  650 + if (!Array.isArray(priceLines)) return m
  651 + for (var i = 0; i < priceLines.length; i++) {
  652 + var line = priceLines[i] || {}
  653 + if (line.price == null) continue
  654 + var key = String(line.productId || line.breedId || line.varietyId || line.id || ('__idx_' + i))
  655 + m[key] = { price: Number(line.price), meta: line }
  656 + }
  657 + return m
  658 + },
  659 + applyPriceLinesToLines(priceLines) {
  660 + if (!Array.isArray(this.lineList)) return
  661 + var priceMap = this.buildPriceMap(priceLines)
  662 + var self = this
  663 + this.lineList = this.lineList.map(function (row) {
  664 + var pid = String(row.productId || row.breedId || row.varietyId || '')
  665 + var price = null
  666 + if (pid && priceMap[pid] != null) {
  667 + price = priceMap[pid].price
  668 + } else {
  669 + var pname = (row.productName || '').trim()
  670 + if (pname) {
  671 + for (var k in priceMap) {
  672 + if (!Object.prototype.hasOwnProperty.call(priceMap, k)) continue
  673 + var meta = priceMap[k] && priceMap[k].meta ? priceMap[k].meta : null
  674 + if (meta && ((meta.productName && meta.productName === pname) || (meta.breedName && meta.breedName === pname) || (meta.varietyName && meta.varietyName === pname))) {
  675 + price = priceMap[k].price
  676 + break
  677 + }
  678 + }
  679 + }
  680 + }
  681 + if (price != null) {
  682 + row.priceListPrices = self.toFixed(price, 2)
  683 + } else {
  684 + row.priceListPrices = ''
  685 + }
  686 + return row
  687 + })
  688 + },
601 689 onLineChange(list) {
602 690 this.lineList = Array.isArray(list) ? list.slice() : []
603 691 },
... ...
... ... @@ -103,7 +103,7 @@
103 103
104 104 <script>
105 105 import { procurementPlanChangeFindByIdApi, procurementPlanChangeSubmitApi, procurementPlanChangeCancelApi } from '@/api/procure-manage/procurementPlan.js'
106   -import { breedRelationshipQueryApi, workshopQueryApi } from '@/api/devManage.js'
  106 +import { breedRelationshipQueryApi, priceTableDetailApi, workshopQueryApi } from '@/api/devManage.js'
107 107 import { getDicByCodes } from '@/utils/dic.js'
108 108 import DetailButtons from '@/components/detail-buttons/index.vue'
109 109 export default {
... ... @@ -172,7 +172,7 @@ export default {
172 172 },
173 173 priceTableDisplay() {
174 174 var d = this.form || {}
175   - var code = d.priceTableCode != null ? d.priceTableCode : (d.priceId != null ? d.priceId : '')
  175 + var code = d.priceTableCode != null ? String(d.priceTableCode).trim() : ''
176 176 var name = d.priceTableName || ''
177 177 if (name || code) {
178 178 return (name ? name + (code ? ' (' + code + ')' : '') : String(code))
... ... @@ -338,6 +338,7 @@ export default {
338 338 var lines = d.lines || d.procurementPlanLineList || d.lineList || []
339 339 this.lineList = Array.isArray(lines) ? lines : []
340 340 this.buildAttachmentList()
  341 + this.fetchPriceDetailAndApply(d.priceId)
341 342 } catch (e) {
342 343 uni.showToast({ title: '加载详情失败', icon: 'none' })
343 344 }
... ... @@ -355,6 +356,89 @@ export default {
355 356 }
356 357 this.attachmentList = list
357 358 },
  359 + async fetchPriceDetailAndApply(priceId) {
  360 + if (!priceId) return
  361 + var self = this
  362 + try {
  363 + var res = await priceTableDetailApi({ id: priceId })
  364 + var d = (res && res.data) ? res.data : {}
  365 + if (d.code != null && this.form) {
  366 + this.$set(this.form, 'priceTableCode', String(d.code))
  367 + }
  368 + if (d.priceTableName != null && this.form) {
  369 + this.$set(this.form, 'priceTableName', d.priceTableName)
  370 + }
  371 + var priceLines = self.extractPriceLines(d)
  372 + self.applyPriceLinesToLines(priceLines)
  373 + } catch (e) {
  374 + return
  375 + }
  376 + },
  377 + extractPriceLines(priceDetail) {
  378 + if (!priceDetail || typeof priceDetail !== 'object') return []
  379 + var candidates = [
  380 + priceDetail.procurementPriceLineList,
  381 + priceDetail.priceSubTableList,
  382 + priceDetail.priceLineList,
  383 + priceDetail.priceList,
  384 + priceDetail.lineList,
  385 + priceDetail.datas,
  386 + priceDetail.records,
  387 + priceDetail.list
  388 + ]
  389 + for (var i = 0; i < candidates.length; i++) {
  390 + if (Array.isArray(candidates[i]) && candidates[i].length) return candidates[i]
  391 + }
  392 + for (var k in priceDetail) {
  393 + if (!Object.prototype.hasOwnProperty.call(priceDetail, k)) continue
  394 + if (Array.isArray(priceDetail[k])) {
  395 + var arr = priceDetail[k]
  396 + if (arr.length && arr[0] && typeof arr[0] === 'object' && (arr[0].price != null || arr[0].productId != null || arr[0].breedId != null || arr[0].varietyId != null)) {
  397 + return arr
  398 + }
  399 + }
  400 + }
  401 + return []
  402 + },
  403 + buildPriceMap(priceLines) {
  404 + var m = {}
  405 + if (!Array.isArray(priceLines)) return m
  406 + for (var i = 0; i < priceLines.length; i++) {
  407 + var line = priceLines[i] || {}
  408 + if (line.price == null) continue
  409 + var key = String(line.productId || line.breedId || line.varietyId || line.id || ('__idx_' + i))
  410 + m[key] = { price: Number(line.price), meta: line }
  411 + }
  412 + return m
  413 + },
  414 + applyPriceLinesToLines(priceLines) {
  415 + if (!Array.isArray(this.lineList)) return
  416 + var priceMap = this.buildPriceMap(priceLines)
  417 + var self = this
  418 + this.lineList = this.lineList.map(function (row) {
  419 + var pid = String(row.productId || row.breedId || row.varietyId || '')
  420 + var price = null
  421 + if (pid && priceMap[pid] != null) {
  422 + price = priceMap[pid].price
  423 + } else {
  424 + var pname = (row.productName || '').trim()
  425 + if (pname) {
  426 + for (var k in priceMap) {
  427 + if (!Object.prototype.hasOwnProperty.call(priceMap, k)) continue
  428 + var meta = priceMap[k] && priceMap[k].meta ? priceMap[k].meta : null
  429 + if (meta && ((meta.productName && meta.productName === pname) || (meta.breedName && meta.breedName === pname) || (meta.varietyName && meta.varietyName === pname))) {
  430 + price = priceMap[k].price
  431 + break
  432 + }
  433 + }
  434 + }
  435 + }
  436 + if (price != null) {
  437 + row.priceListPrices = Number(price).toFixed(2)
  438 + }
  439 + return row
  440 + })
  441 + },
358 442 getDictOptions(dictCode) {
359 443 var data = this.dictData[dictCode]
360 444 return (data && data.data) ? data.data : []
... ...
... ... @@ -322,6 +322,7 @@ import SingleSelectSheet from '@/components/single-select/index.vue'
322 322 import { procurementPlanChangeFindByIdApi, procurementPlanChangeUpdateApi } from '@/api/procure-manage/procurementPlan.js'
323 323 import {
324 324 breedRelationshipQueryApi,
  325 + priceTableDetailApi,
325 326 workshopQueryApi
326 327 } from '@/api/devManage.js'
327 328 import { getDicByCodes } from '@/utils/dic.js'
... ... @@ -387,9 +388,10 @@ export default {
387 388 },
388 389 priceTableDisplay() {
389 390 var d = this.detail || {}
390   - var code = d.priceTableCode != null ? d.priceTableCode : (d.priceId != null ? d.priceId : '')
  391 + var code = d.priceTableCode != null ? String(d.priceTableCode).trim() : ''
  392 + if (!code) return ''
391 393 var name = d.priceTableName || ''
392   - return name ? (name + (code ? ' (' + code + ')' : '')) : code
  394 + return name ? (name + ' (' + code + ')') : code
393 395 }
394 396 },
395 397 onLoad(query) {
... ... @@ -503,6 +505,7 @@ export default {
503 505 this.lineList = Array.isArray(lines) ? lines.slice() : []
504 506 this.buildAttachmentList()
505 507 this.fillLineNames()
  508 + this.fetchPriceDetailAndApply(d.priceId)
506 509 } catch (e) {
507 510 uni.showToast({ title: '加载详情失败', icon: 'none' })
508 511 }
... ... @@ -561,6 +564,91 @@ export default {
561 564 return r
562 565 })
563 566 },
  567 + async fetchPriceDetailAndApply(priceId) {
  568 + if (!priceId) return
  569 + var self = this
  570 + try {
  571 + var res = await priceTableDetailApi({ id: priceId })
  572 + var d = (res && res.data) ? res.data : {}
  573 + if (d.code != null && this.detail) {
  574 + this.$set(this.detail, 'priceTableCode', String(d.code))
  575 + }
  576 + if (d.priceTableName != null && this.detail) {
  577 + this.$set(this.detail, 'priceTableName', d.priceTableName)
  578 + }
  579 + var priceLines = self.extractPriceLines(d)
  580 + self.applyPriceLinesToLines(priceLines)
  581 + } catch (e) {
  582 + return
  583 + }
  584 + },
  585 + extractPriceLines(priceDetail) {
  586 + if (!priceDetail || typeof priceDetail !== 'object') return []
  587 + var candidates = [
  588 + priceDetail.procurementPriceLineList,
  589 + priceDetail.priceSubTableList,
  590 + priceDetail.priceLineList,
  591 + priceDetail.priceList,
  592 + priceDetail.lineList,
  593 + priceDetail.datas,
  594 + priceDetail.records,
  595 + priceDetail.list
  596 + ]
  597 + for (var i = 0; i < candidates.length; i++) {
  598 + if (Array.isArray(candidates[i]) && candidates[i].length) return candidates[i]
  599 + }
  600 + for (var k in priceDetail) {
  601 + if (!Object.prototype.hasOwnProperty.call(priceDetail, k)) continue
  602 + if (Array.isArray(priceDetail[k])) {
  603 + var arr = priceDetail[k]
  604 + if (arr.length && arr[0] && typeof arr[0] === 'object' && (arr[0].price != null || arr[0].productId != null || arr[0].breedId != null || arr[0].varietyId != null)) {
  605 + return arr
  606 + }
  607 + }
  608 + }
  609 + return []
  610 + },
  611 + buildPriceMap(priceLines) {
  612 + var m = {}
  613 + if (!Array.isArray(priceLines)) return m
  614 + for (var i = 0; i < priceLines.length; i++) {
  615 + var line = priceLines[i] || {}
  616 + if (line.price == null) continue
  617 + var key = String(line.productId || line.breedId || line.varietyId || line.id || ('__idx_' + i))
  618 + m[key] = { price: Number(line.price), meta: line }
  619 + }
  620 + return m
  621 + },
  622 + applyPriceLinesToLines(priceLines) {
  623 + if (!Array.isArray(this.lineList)) return
  624 + var priceMap = this.buildPriceMap(priceLines)
  625 + var self = this
  626 + this.lineList = this.lineList.map(function (row) {
  627 + var pid = String(row.productId || row.breedId || row.varietyId || '')
  628 + var price = null
  629 + if (pid && priceMap[pid] != null) {
  630 + price = priceMap[pid].price
  631 + } else {
  632 + var pname = (row.productName || '').trim()
  633 + if (pname) {
  634 + for (var k in priceMap) {
  635 + if (!Object.prototype.hasOwnProperty.call(priceMap, k)) continue
  636 + var meta = priceMap[k] && priceMap[k].meta ? priceMap[k].meta : null
  637 + if (meta && ((meta.productName && meta.productName === pname) || (meta.breedName && meta.breedName === pname) || (meta.varietyName && meta.varietyName === pname))) {
  638 + price = priceMap[k].price
  639 + break
  640 + }
  641 + }
  642 + }
  643 + }
  644 + if (price != null) {
  645 + row.priceListPrices = self.toFixed(price, 2)
  646 + } else {
  647 + row.priceListPrices = ''
  648 + }
  649 + return row
  650 + })
  651 + },
564 652 onLineChange(list) {
565 653 this.lineList = Array.isArray(list) ? list.slice() : []
566 654 },
... ...
... ... @@ -287,7 +287,7 @@ export default {
287 287 },
288 288 priceTableDisplay() {
289 289 var d = this.form || {}
290   - var code = d.priceTableCode != null ? d.priceTableCode : (d.priceId != null ? d.priceId : '')
  290 + var code = d.priceTableCode != null ? String(d.priceTableCode).trim() : ''
291 291 var name = d.priceTableName || ''
292 292 if (name || code) {
293 293 return (name ? name + (code ? ' (' + code + ')' : '') : String(code))
... ... @@ -409,6 +409,8 @@ export default {
409 409 this.refreshLinesFromShipping()
410 410 if (this.canEdit) {
411 411 this.loadLatestPriceTableAndApply()
  412 + } else {
  413 + this.fetchPriceDetailAndApply(d.priceId)
412 414 }
413 415 } catch (e) {
414 416 this.form = {}
... ... @@ -557,6 +559,12 @@ export default {
557 559 try {
558 560 var res = await priceTableDetailApi({ id: priceId })
559 561 var d = (res && res.data) ? res.data : {}
  562 + if (d.code != null && this.form) {
  563 + this.$set(this.form, 'priceTableCode', String(d.code))
  564 + }
  565 + if (d.priceTableName != null && this.form) {
  566 + this.$set(this.form, 'priceTableName', d.priceTableName)
  567 + }
560 568 var priceLines = self.extractPriceLines(d)
561 569 self.applyPriceLinesToLines(priceLines)
562 570 } catch (e) {
... ... @@ -612,6 +620,8 @@ export default {
612 620 }
613 621 if (price != null) {
614 622 row.priceListPrices = self.toFixed(price, 2)
  623 + } else {
  624 + row.priceListPrices = ''
615 625 }
616 626 return row
617 627 })
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view scroll-y class="scroll">
  4 + <uni-list>
  5 + <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'" clickable
  6 + @click="openPlanSheet" :rightText="form.code || '请选择计划编号'" showArrow>
  7 + <template v-slot:body>
  8 + <view class="item-title"><text class="required">*</text><text>计划数据</text></view>
  9 + </template>
  10 + </uni-list-item>
  11 +
  12 + <uni-list-item title="公司名称">
  13 + <template v-slot:footer>
  14 + <uni-easyinput v-model="companyNameDisplay" :inputBorder="false" disabled placeholder="-" />
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item>
  19 + <template v-slot:body>
  20 + <view class="item-title"><text class="required">*</text><text>供应商名称</text></view>
  21 + </template>
  22 + <template v-slot:footer>
  23 + <uni-easyinput v-model="detail.supplierName" :inputBorder="false" placeholder="请输入供应商名称" />
  24 + </template>
  25 + </uni-list-item>
  26 +
  27 + <uni-list-item title="采购处">
  28 + <template v-slot:footer>
  29 + <uni-easyinput v-model="purchaseDepartmentDisplay" :inputBorder="false" disabled placeholder="-" />
  30 + </template>
  31 + </uni-list-item>
  32 +
  33 + <uni-list-item title="区域">
  34 + <template v-slot:footer>
  35 + <uni-easyinput v-model="regionDisplay" :inputBorder="false" disabled placeholder="-" />
  36 + </template>
  37 + </uni-list-item>
  38 +
  39 + <uni-list-item title="日期">
  40 + <template v-slot:footer>
  41 + <uni-easyinput v-model="dateDisplay" :inputBorder="false" disabled placeholder="-" />
  42 + </template>
  43 + </uni-list-item>
  44 +
  45 + <uni-list-item>
  46 + <template v-slot:body>
  47 + <view class="item-title"><text class="required">*</text><text>报价时效</text></view>
  48 + </template>
  49 + <template v-slot:footer>
  50 + <uni-easyinput v-model="detail.validityPeriod" :inputBorder="false" placeholder="请输入报价时效" />
  51 + </template>
  52 + </uni-list-item>
  53 +
  54 + <uni-list-item>
  55 + <template v-slot:body>
  56 + <view class="item-title"><text class="required">*</text><text>报价人</text></view>
  57 + </template>
  58 + <template v-slot:footer>
  59 + <uni-easyinput v-model="detail.quoterName" :inputBorder="false" placeholder="请输入报价人" />
  60 + </template>
  61 + </uni-list-item>
  62 +
  63 + <uni-list-item class="select-item" :class="typeof detail.longTermOperation === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  64 + @click="toggleBool('longTermOperation')" :rightText="boolText(detail.longTermOperation) || '请选择'" showArrow>
  65 + <template v-slot:body>
  66 + <view class="item-title"><text class="required">*</text><text>是否长单操作</text></view>
  67 + </template>
  68 + </uni-list-item>
  69 +
  70 + <uni-list-item class="select-item" :class="typeof detail.terminalCustomer === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  71 + @click="toggleBool('terminalCustomer')" :rightText="boolText(detail.terminalCustomer) || '请选择'" showArrow>
  72 + <template v-slot:body>
  73 + <view class="item-title"><text class="required">*</text><text>是否终端客户</text></view>
  74 + </template>
  75 + </uni-list-item>
  76 +
  77 + <uni-list-item class="select-item" :class="typeof detail.priced === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  78 + @click="toggleBool('priced')" :rightText="boolText(detail.priced) || '请选择'" showArrow>
  79 + <template v-slot:body>
  80 + <view class="item-title"><text class="required">*</text><text>是否未点价</text></view>
  81 + </template>
  82 + </uni-list-item>
  83 +
  84 + <uni-list-item v-if="detail.priced === true">
  85 + <template v-slot:body>
  86 + <view class="item-title"><text class="required">*</text><text>点价截止日期</text></view>
  87 + </template>
  88 + <template v-slot:footer>
  89 + <uni-datetime-picker type="date" v-model="detail.pricingDeadline" return-type="string" />
  90 + </template>
  91 + </uni-list-item>
  92 +
  93 + <uni-list-item v-if="detail.priced === true" class="select-item" :class="typeof detail.temporaryPrice === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  94 + @click="toggleBool('temporaryPrice')" :rightText="boolText(detail.temporaryPrice) || '请选择'" showArrow>
  95 + <template v-slot:body>
  96 + <view class="item-title"><text class="required">*</text><text>是否暂定价</text></view>
  97 + </template>
  98 + </uni-list-item>
  99 +
  100 + <uni-list-item class="select-item" :class="typeof detail.otherExpenseSettlement === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  101 + @click="toggleBool('otherExpenseSettlement')" :rightText="boolText(detail.otherExpenseSettlement) || '请选择'" showArrow>
  102 + <template v-slot:body>
  103 + <view class="item-title"><text class="required">*</text><text>其他费用凭票到厂另行结算</text></view>
  104 + </template>
  105 + </uni-list-item>
  106 +
  107 + <uni-list-item class="select-item" :class="detail.deliveryMode ? 'is-filled' : 'is-empty'" clickable
  108 + @click="openDeliverySheet" :rightText="getDeliveryMethodLabel()" showArrow>
  109 + <template v-slot:body>
  110 + <view class="item-title"><text class="required">*</text><text>交提货方式</text></view>
  111 + </template>
  112 + </uni-list-item>
  113 +
  114 + <uni-list-item class="select-item" :class="typeof detail.commodityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  115 + @click="toggleBool('commodityBuyout')" :rightText="boolText(detail.commodityBuyout) || '请选择'" showArrow>
  116 + <template v-slot:body>
  117 + <view class="item-title"><text>是否通货买断</text></view>
  118 + </template>
  119 + </uni-list-item>
  120 +
  121 + <uni-list-item class="select-item" :class="typeof detail.qualityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  122 + @click="toggleBool('qualityBuyout')" :rightText="boolText(detail.qualityBuyout) || '请选择'" showArrow>
  123 + <template v-slot:body>
  124 + <view class="item-title"><text class="required">*</text><text>是否质量买断</text></view>
  125 + </template>
  126 + </uni-list-item>
  127 +
  128 + <uni-list-item class="select-item" :class="typeof detail.quantityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  129 + @click="toggleBool('quantityBuyout')" :rightText="boolText(detail.quantityBuyout) || '请选择'" showArrow>
  130 + <template v-slot:body>
  131 + <view class="item-title"><text>是否数量买断</text></view>
  132 + </template>
  133 + </uni-list-item>
  134 +
  135 + <uni-list-item class="select-item" :class="typeof detail.doorDelivery === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  136 + @click="toggleBool('doorDelivery')" :rightText="boolText(detail.doorDelivery) || '请选择'" showArrow>
  137 + <template v-slot:body>
  138 + <view class="item-title"><text class="required">*</text><text>是否送货上门</text></view>
  139 + </template>
  140 + </uni-list-item>
  141 +
  142 + <uni-list-item title="另付运费">
  143 + <template v-slot:footer>
  144 + <uni-easyinput v-model="shippingCostDisplay" :inputBorder="false" disabled placeholder="-" />
  145 + </template>
  146 + </uni-list-item>
  147 +
  148 + <uni-list-item>
  149 + <template v-slot:body>
  150 + <view class="item-title"><text class="required">*</text><text>装车费</text></view>
  151 + </template>
  152 + <template v-slot:footer>
  153 + <uni-easyinput
  154 + v-model="detail.loadingFee"
  155 + type="digit"
  156 + :inputBorder="false"
  157 + placeholder="请输入装车费"
  158 + @input="onNonNegativeInput('loadingFee')"
  159 + @blur="onNonNegativeBlur('loadingFee', 2)"
  160 + />
  161 + </template>
  162 + </uni-list-item>
  163 +
  164 + <uni-list-item title="开票品名">
  165 + <template v-slot:footer>
  166 + <uni-easyinput v-model="detail.invoiceProductName" :inputBorder="false" placeholder="请输入开票品名" />
  167 + </template>
  168 + </uni-list-item>
  169 +
  170 + <uni-list-item>
  171 + <template v-slot:body>
  172 + <view class="item-title"><text class="required">*</text><text>交货日期</text></view>
  173 + </template>
  174 + <template v-slot:footer>
  175 + <uni-datetime-picker type="date" v-model="detail.deliveryDate" return-type="string" />
  176 + </template>
  177 + </uni-list-item>
  178 + <uni-list-item>
  179 + <template v-slot:body>
  180 + <view class="item-title"><text class="required">*</text><text>结算方式</text></view>
  181 + </template>
  182 + <template v-slot:footer>
  183 + <uni-easyinput v-model="detail.settlementMethod" :inputBorder="false" placeholder="请输入结算方式" />
  184 + </template>
  185 + </uni-list-item>
  186 +
  187 + <uni-list-item>
  188 + <template v-slot:body>
  189 + <view class="item-title"><text class="required">*</text><text>结算比例(%)</text></view>
  190 + </template>
  191 + <template v-slot:footer>
  192 + <uni-easyinput
  193 + v-model="detail.settlementRatio"
  194 + type="digit"
  195 + :inputBorder="false"
  196 + placeholder="请输入结算比例"
  197 + @input="onNonNegativeInput('settlementRatio')"
  198 + @blur="onNonNegativeBlur('settlementRatio', 4)"
  199 + />
  200 + </template>
  201 + </uni-list-item>
  202 +
  203 + <uni-list-item title="价格表编号">
  204 + <template v-slot:footer>
  205 + <uni-easyinput v-model="priceTableDisplay" :inputBorder="false" disabled placeholder="-" />
  206 + </template>
  207 + </uni-list-item>
  208 +
  209 + <uni-list-item>
  210 + <template v-slot:body>
  211 + <view class="item-title"><text class="required">*</text><text>协调事由</text></view>
  212 + </template>
  213 + <template v-slot:footer>
  214 + <uni-easyinput v-model="detail.coordinationReason" :inputBorder="false" placeholder="请输入协调事由" />
  215 + </template>
  216 + </uni-list-item>
  217 +
  218 + <uni-list-item>
  219 + <template v-slot:body>
  220 + <view class="item-title"><text class="required">*</text><text>票类状况</text></view>
  221 + </template>
  222 + <template v-slot:footer>
  223 + <uni-easyinput v-model="detail.invoiceTypeStatus" :inputBorder="false" placeholder="请输入票类状况" />
  224 + </template>
  225 + </uni-list-item>
  226 +
  227 + <uni-list-item v-if="attachmentList.length" title="附件">
  228 + <template v-slot:footer>
  229 + <view class="attach-list">
  230 + <view v-for="(at, idx) in attachmentList" :key="idx" class="attach-item">
  231 + <text class="attach-name">{{ at.name }}</text>
  232 + <text class="attach-view" @click.stop="onPreviewAttachment(at)">查看</text>
  233 + </view>
  234 + </view>
  235 + </template>
  236 + </uni-list-item>
  237 +
  238 + <ProductRel
  239 + ref="productRel"
  240 + mode="edit"
  241 + :list="lineList"
  242 + :product-options="productOptions"
  243 + :workshop-options="workshopOptions"
  244 + :shipping-cost="detail.shippingCost"
  245 + :price-map="priceMap"
  246 + @change="onLineChange"
  247 + />
  248 + </uni-list>
  249 +
  250 + <view class="material-condition-section">
  251 + <view class="section-header">
  252 + <image class="opCollapse" src="/static/images/title.png" />
  253 + <text class="section-title">料质状况</text>
  254 + </view>
  255 + <view class="section-content">
  256 + <view class="form-row">
  257 + <text class="form-label">是否启用料质状况</text>
  258 + <text class="form-value toggle-link" @click="toggleBool('materialConditionEnabled')">{{ boolText(detail.materialConditionEnabled) || '请选择' }}</text>
  259 + </view>
  260 + <template v-if="detail.materialConditionEnabled">
  261 + <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group">
  262 + <text class="material-label">{{ mc.label }}</text>
  263 + <view class="tag-list">
  264 + <view
  265 + v-for="opt in getDictOptions(mc.dictCode)"
  266 + :key="opt.code"
  267 + class="tag-btn"
  268 + :class="{ active: isTagSelected(mc.field, opt.code) }"
  269 + @click="toggleTag(mc.field, opt.code)"
  270 + >
  271 + {{ opt.name }}
  272 + </view>
  273 + </view>
  274 + </view>
  275 + </template>
  276 + </view>
  277 + </view>
  278 +
  279 + <view class="remark-section">
  280 + <view class="section-header">
  281 + <image class="opCollapse" src="/static/images/title.png" />
  282 + <text class="section-title">备注</text>
  283 + </view>
  284 + <view class="section-content">
  285 + <uni-easyinput type="textarea" v-model="detail.remark" :inputBorder="false" placeholder="请输入备注" />
  286 + </view>
  287 + </view>
  288 + <view class="remark-section">
  289 + <view class="section-header">
  290 + <image class="opCollapse" src="/static/images/title.png" />
  291 + <text class="section-title"><text class="required">*</text>变更事由</text>
  292 + </view>
  293 + <view class="section-content">
  294 + <uni-easyinput type="textarea" v-model="detail.changeReason" :inputBorder="false" placeholder="请输入变更事由" />
  295 + </view>
  296 + </view>
  297 + </scroll-view>
  298 +
  299 + <view class="bottom-bar">
  300 + <button class="btn btn-outline" @click="onBack">取消</button>
  301 + <button class="btn btn-primary" @click="onSubmit">保存</button>
  302 + </view>
  303 +
  304 + <RelateSelectSheet
  305 + v-if="planSheetVisible"
  306 + :visible.sync="planSheetVisible"
  307 + title="选择计划"
  308 + :fetch-fn="fetchChangePlanList"
  309 + :display-fields="planDisplayFields"
  310 + :page-size="20"
  311 + :multiple="false"
  312 + row-key="id"
  313 + @confirm="onPlanConfirm"
  314 + />
  315 + <SingleSelectSheet
  316 + :visible.sync="deliverySheetVisible"
  317 + title="交提货方式"
  318 + :options="deliveryOptions"
  319 + v-model="deliverySheetValue"
  320 + @confirm="onDeliveryConfirm"
  321 + />
  322 + </view>
  323 +</template>
  324 +
  325 +<script>
  326 +import ProductRel from './productRel.vue'
  327 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  328 +import SingleSelectSheet from '@/components/single-select/index.vue'
  329 +import { procurementPlanDetailApi, procurementPlanCanChangeOrReplenishmentApi, procurementPlanReplenplenishApi } from '@/api/procure-manage/procurementPlan.js'
  330 +import {
  331 + breedRelationshipQueryApi,
  332 + priceTableDetailApi,
  333 + workshopQueryApi
  334 +} from '@/api/devManage.js'
  335 +import { getDicByCodes } from '@/utils/dic.js'
  336 +
  337 +export default {
  338 + name: 'SchedulePlanAdd',
  339 + components: { ProductRel, RelateSelectSheet, SingleSelectSheet },
  340 + data() {
  341 + return {
  342 + form: {
  343 + planId: '',
  344 + code: ''
  345 + },
  346 + detail: {},
  347 + attachmentList: [],
  348 + materialConditionConfigs: [
  349 + { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' },
  350 + { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' },
  351 + { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' },
  352 + { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' },
  353 + { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' },
  354 + { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' },
  355 + { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' },
  356 + { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' }
  357 + ],
  358 + dicOptions: {
  359 + DELIVERY_METHOD: []
  360 + },
  361 + dictData: {},
  362 + lineList: [],
  363 + productOptions: [],
  364 + workshopOptions: [],
  365 + priceMap: {},
  366 + planSheetVisible: false,
  367 + planDisplayFields: [
  368 + { label: '计划编号', field: 'code' },
  369 + { label: '公司简称', field: 'companyShortName' },
  370 + { label: '供应商名称', field: 'supplierName' },
  371 + { label: '数量', field: 'totalQuantity' },
  372 + { label: '采购处', field: 'purchaseDepartmentName' }
  373 + ],
  374 + deliverySheetVisible: false,
  375 + deliverySheetValue: '',
  376 + deliveryOptions: []
  377 + }
  378 + },
  379 + computed: {
  380 + companyNameDisplay() {
  381 + var d = this.detail || {}
  382 + return d.companyShortName != null ? d.companyShortName : (d.companyName != null ? d.companyName : '')
  383 + },
  384 + purchaseDepartmentDisplay() {
  385 + var d = this.detail || {}
  386 + return d.purchaseDepartmentName != null ? d.purchaseDepartmentName : (d.purchaseDepartment != null ? d.purchaseDepartment : '')
  387 + },
  388 + regionDisplay() {
  389 + var d = this.detail || {}
  390 + return d.regionName != null ? d.regionName : (d.region != null ? d.region : '')
  391 + },
  392 + dateDisplay() {
  393 + var d = this.detail || {}
  394 + var s = d.date == null ? '' : String(d.date).trim()
  395 + return s.length >= 10 ? s.slice(0, 10) : s
  396 + },
  397 + shippingCostDisplay() {
  398 + var v = (this.detail || {}).shippingCost
  399 + if (v == null || v === '') return ''
  400 + var n = Number(v)
  401 + if (isNaN(n)) return String(v)
  402 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  403 + },
  404 + priceTableDisplay() {
  405 + var d = this.detail || {}
  406 + var code = d.priceTableCode != null ? String(d.priceTableCode).trim() : ''
  407 + if (!code) return ''
  408 + var name = d.priceTableName || ''
  409 + return name ? (name + ' (' + code + ')') : code
  410 + }
  411 + },
  412 + onLoad() {
  413 + this.loadDictData()
  414 + this.loadRefData()
  415 + },
  416 + methods: {
  417 + safeText(v) {
  418 + var s = v == null ? '' : String(v)
  419 + return s.trim() ? s : '-'
  420 + },
  421 + boolText(v) {
  422 + if (typeof v !== 'boolean') return ''
  423 + return v ? '是' : '否'
  424 + },
  425 + toNumber(v) {
  426 + if (v == null || v === '') return 0
  427 + var n = Number(v)
  428 + return isNaN(n) ? 0 : n
  429 + },
  430 + toFixed(v, n) {
  431 + var num = Number(v)
  432 + if (isNaN(num)) return ''
  433 + return num.toFixed(n)
  434 + },
  435 + async loadDictData() {
  436 + var codes = [].concat(
  437 + this.materialConditionConfigs.map(function (mc) { return mc.dictCode }),
  438 + ['DELIVERY_METHOD']
  439 + )
  440 + try {
  441 + var results = await getDicByCodes(codes)
  442 + var d = results || {}
  443 + this.dictData = d
  444 + this.dicOptions.DELIVERY_METHOD = (d.DELIVERY_METHOD && d.DELIVERY_METHOD.data) || []
  445 + this.deliveryOptions = this.dicOptions.DELIVERY_METHOD.map(function (o) {
  446 + return { label: o.name || o.label || '', value: o.code != null ? o.code : o.value }
  447 + })
  448 + } catch (e) {
  449 + this.dictData = {}
  450 + }
  451 + },
  452 + async loadRefData() {
  453 + try {
  454 + var results = await Promise.all([
  455 + this.$pCall(breedRelationshipQueryApi, { pageIndex: 1, pageSize: 1000 }),
  456 + this.$pCall(workshopQueryApi, { pageIndex: 1, pageSize: 1000 })
  457 + ])
  458 + var r1 = (results[0] && results[0].data) ? results[0].data : {}
  459 + var r2 = (results[1] && results[1].data) ? results[1].data : {}
  460 + this.productOptions = (r1.datas && Array.isArray(r1.datas)) ? r1.datas : ((r1.list && Array.isArray(r1.list)) ? r1.list : ((r1.records && Array.isArray(r1.records)) ? r1.records : []))
  461 + this.workshopOptions = (r2.datas && Array.isArray(r2.datas)) ? r2.datas : ((r2.list && Array.isArray(r2.list)) ? r2.list : ((r2.records && Array.isArray(r2.records)) ? r2.records : []))
  462 + this.fillLineNames()
  463 + } catch (e) {
  464 + this.productOptions = []
  465 + this.workshopOptions = []
  466 + }
  467 + },
  468 + $pCall(fn, params) {
  469 + try { return Promise.resolve(fn(params)) } catch (e) { return Promise.reject(e) }
  470 + },
  471 + getDictOptions(dictCode) {
  472 + var data = this.dictData[dictCode]
  473 + return (data && data.data) ? data.data : []
  474 + },
  475 + getDeliveryMethodLabel() {
  476 + var opts = this.dicOptions.DELIVERY_METHOD || []
  477 + var v = String(this.detail.deliveryMode != null ? this.detail.deliveryMode : '')
  478 + if (!v) return '请选择'
  479 + for (var i = 0; i < opts.length; i++) {
  480 + var o = opts[i]
  481 + var code = o.code != null ? String(o.code) : (o.value != null ? String(o.value) : '')
  482 + if (code === v) return o.name || o.label || v
  483 + }
  484 + return v
  485 + },
  486 + openPlanSheet() {
  487 + this.planSheetVisible = true
  488 + },
  489 + fetchChangePlanList(args) {
  490 + var extra = (args && args.extra) ? args.extra : {}
  491 + var keyword = extra.keyword || extra.name || ''
  492 + var params = { pageIndex: args.pageIndex || 1, pageSize: args.pageSize || 20, queryType: 'REPLENISHMENT' }
  493 + if (keyword) params.keyword = keyword
  494 + return procurementPlanCanChangeOrReplenishmentApi(params).then(function (res) {
  495 + var d = (res && res.data) ? res.data : {}
  496 + var records = (d.datas && Array.isArray(d.datas)) ? d.datas : ((d.records && Array.isArray(d.records)) ? d.records : ((d.list && Array.isArray(d.list)) ? d.list : []))
  497 + var total = d.totalCount || d.count || (records ? records.length : 0)
  498 + var hasNext = !!d.hasNext
  499 + return { records: records, totalCount: total, hasNext: hasNext }
  500 + }).catch(function () {
  501 + return { records: [], totalCount: 0, hasNext: false }
  502 + })
  503 + },
  504 + onPlanConfirm(e) {
  505 + var items = (e && e.items) ? e.items : []
  506 + if (!items.length) return
  507 + var row = items[0] || {}
  508 + var id = row.id != null ? row.id : (row.planId != null ? row.planId : (row.procurementPlanId != null ? row.procurementPlanId : ''))
  509 + this.form.planId = id
  510 + this.form.code = row.code || ''
  511 + this.lineList = []
  512 + var pr = this.$refs.productRel
  513 + if (pr && typeof pr.clearItems === 'function') {
  514 + pr.clearItems()
  515 + }
  516 + if (id) {
  517 + this.loadSourceDetail(id)
  518 + }
  519 + },
  520 + async loadSourceDetail(id) {
  521 + if (!id) return
  522 + try {
  523 + var res = await procurementPlanDetailApi({ id: id })
  524 + var d = (res && res.data) ? res.data : {}
  525 + var boolFields = ['longTermOperation', 'terminalCustomer', 'priced', 'temporaryPrice', 'otherExpenseSettlement', 'commodityBuyout', 'qualityBuyout', 'quantityBuyout', 'doorDelivery', 'materialConditionEnabled']
  526 + boolFields.forEach(function (f) {
  527 + var v = d[f]
  528 + if (typeof v === 'string') {
  529 + d[f] = v === 'true' || v === '1'
  530 + } else if (typeof v === 'number') {
  531 + d[f] = v === 1
  532 + } else {
  533 + d[f] = !!v
  534 + }
  535 + })
  536 + this.materialConditionConfigs.forEach(function (mc) {
  537 + var v = d[mc.field]
  538 + if (typeof v === 'string' && v) {
  539 + d[mc.field] = v.split(',').filter(Boolean)
  540 + } else if (!Array.isArray(v)) {
  541 + d[mc.field] = []
  542 + }
  543 + })
  544 + d.pricingDeadline = this.trimDate(d.pricingDeadline)
  545 + d.deliveryDate = this.trimDate(d.deliveryDate)
  546 + this.detail = d
  547 + if (!this.form.code) {
  548 + this.form.code = d.code || ''
  549 + }
  550 + this.lineList = []
  551 + var pr = this.$refs.productRel
  552 + if (pr && typeof pr.clearItems === 'function') {
  553 + pr.clearItems()
  554 + }
  555 + this.buildAttachmentList()
  556 + this.fillLineNames()
  557 + this.fetchPriceDetailAndApply(d.priceId)
  558 + } catch (e) {
  559 + uni.showToast({ title: '加载计划失败', icon: 'none' })
  560 + }
  561 + },
  562 + trimDate(v) {
  563 + if (v == null || v === '') return ''
  564 + var s = String(v).trim()
  565 + return s.length >= 10 ? s.slice(0, 10) : s
  566 + },
  567 + buildAttachmentList() {
  568 + var ids = this.detail.attachmentFileIds
  569 + var names = this.detail.attachmentFileNames
  570 + var idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : [])
  571 + var nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : [])
  572 + var len = Math.max(idArr.length, nameArr.length)
  573 + var list = []
  574 + for (var i = 0; i < len; i++) {
  575 + list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) })
  576 + }
  577 + this.attachmentList = list
  578 + },
  579 + onPreviewAttachment(at) {
  580 + if (!at || !at.id) {
  581 + uni.showToast({ title: '无法查看', icon: 'none' })
  582 + return
  583 + }
  584 + uni.showToast({ title: '查看附件 ' + at.name, icon: 'none' })
  585 + },
  586 + fillLineNames() {
  587 + var list = Array.isArray(this.lineList) ? this.lineList : []
  588 + if (!list.length) return
  589 + var pOpts = Array.isArray(this.productOptions) ? this.productOptions : []
  590 + var wOpts = Array.isArray(this.workshopOptions) ? this.workshopOptions : []
  591 + this.lineList = list.map(function (row) {
  592 + var r = Object.assign({}, row)
  593 + var pid = r.productId != null ? String(r.productId) : ''
  594 + var wid = r.workshopId != null ? String(r.workshopId) : ''
  595 + if ((r.productName == null || String(r.productName).trim() === '') && pid) {
  596 + var p = pOpts.find(function (o) {
  597 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.value != null ? String(o.value) : ''))
  598 + return id === pid
  599 + })
  600 + if (p) {
  601 + r.productName = p.name != null ? p.name : (p.productName != null ? p.productName : (p.label != null ? p.label : ''))
  602 + }
  603 + }
  604 + if ((r.workshopName == null || String(r.workshopName).trim() === '') && wid) {
  605 + var w = wOpts.find(function (o) {
  606 + var id = o.id != null ? String(o.id) : (o.workshopId != null ? String(o.workshopId) : (o.value != null ? String(o.value) : ''))
  607 + return id === wid
  608 + })
  609 + if (w) {
  610 + r.workshopName = w.name != null ? w.name : (w.workshopName != null ? w.workshopName : (w.label != null ? w.label : ''))
  611 + }
  612 + }
  613 + return r
  614 + })
  615 + },
  616 + async fetchPriceDetailAndApply(priceId) {
  617 + if (!priceId) return
  618 + var self = this
  619 + try {
  620 + var res = await priceTableDetailApi({ id: priceId })
  621 + var d = (res && res.data) ? res.data : {}
  622 + if (d.code != null && this.detail) {
  623 + this.$set(this.detail, 'priceTableCode', String(d.code))
  624 + }
  625 + if (d.priceTableName != null && this.detail) {
  626 + this.$set(this.detail, 'priceTableName', d.priceTableName)
  627 + }
  628 + var priceLines = self.extractPriceLines(d)
  629 + self.applyPriceLinesToLines(priceLines)
  630 + } catch (e) {
  631 + return
  632 + }
  633 + },
  634 + extractPriceLines(priceDetail) {
  635 + if (!priceDetail || typeof priceDetail !== 'object') return []
  636 + var candidates = [
  637 + priceDetail.procurementPriceLineList,
  638 + priceDetail.priceSubTableList,
  639 + priceDetail.priceLineList,
  640 + priceDetail.priceList,
  641 + priceDetail.lineList,
  642 + priceDetail.datas,
  643 + priceDetail.records,
  644 + priceDetail.list
  645 + ]
  646 + for (var i = 0; i < candidates.length; i++) {
  647 + if (Array.isArray(candidates[i]) && candidates[i].length) return candidates[i]
  648 + }
  649 + for (var k in priceDetail) {
  650 + if (!Object.prototype.hasOwnProperty.call(priceDetail, k)) continue
  651 + if (Array.isArray(priceDetail[k])) {
  652 + var arr = priceDetail[k]
  653 + if (arr.length && arr[0] && typeof arr[0] === 'object' && (arr[0].price != null || arr[0].productId != null || arr[0].breedId != null || arr[0].varietyId != null)) {
  654 + return arr
  655 + }
  656 + }
  657 + }
  658 + return []
  659 + },
  660 + buildPriceMap(priceLines) {
  661 + var m = {}
  662 + if (!Array.isArray(priceLines)) return m
  663 + for (var i = 0; i < priceLines.length; i++) {
  664 + var line = priceLines[i] || {}
  665 + if (line.price == null) continue
  666 + var key = String(line.productId || line.breedId || line.varietyId || line.id || ('__idx_' + i))
  667 + m[key] = { price: Number(line.price), meta: line }
  668 + }
  669 + return m
  670 + },
  671 + applyPriceLinesToLines(priceLines) {
  672 + var priceMap = this.buildPriceMap(priceLines)
  673 + this.priceMap = priceMap || {}
  674 + if (!Array.isArray(this.lineList) || !this.lineList.length) {
  675 + var pr = this.$refs.productRel
  676 + if (pr && typeof pr.recalcAllItems === 'function') {
  677 + pr.recalcAllItems()
  678 + }
  679 + return
  680 + }
  681 + var self = this
  682 + this.lineList = this.lineList.map(function (row) {
  683 + var pid = String(row.productId || row.breedId || row.varietyId || '')
  684 + var price = null
  685 + if (pid && priceMap[pid] != null) {
  686 + price = priceMap[pid].price
  687 + } else {
  688 + var pname = (row.productName || '').trim()
  689 + if (pname) {
  690 + for (var k in priceMap) {
  691 + if (!Object.prototype.hasOwnProperty.call(priceMap, k)) continue
  692 + var meta = priceMap[k] && priceMap[k].meta ? priceMap[k].meta : null
  693 + if (meta && ((meta.productName && meta.productName === pname) || (meta.breedName && meta.breedName === pname) || (meta.varietyName && meta.varietyName === pname))) {
  694 + price = priceMap[k].price
  695 + break
  696 + }
  697 + }
  698 + }
  699 + }
  700 + if (price != null) {
  701 + row.priceListPrices = self.toFixed(price, 2)
  702 + } else {
  703 + row.priceListPrices = ''
  704 + }
  705 + return row
  706 + })
  707 + var pr = this.$refs.productRel
  708 + if (pr && typeof pr.recalcAllItems === 'function') {
  709 + pr.recalcAllItems()
  710 + }
  711 + },
  712 + onLineChange(list) {
  713 + var newList = Array.isArray(list) ? list.slice() : []
  714 + var oldList = Array.isArray(this.lineList) ? this.lineList : []
  715 + if (newList.length !== oldList.length) {
  716 + this.lineList = newList
  717 + return
  718 + }
  719 + var i = 0
  720 + for (i = 0; i < newList.length; i++) {
  721 + var n = newList[i] || {}
  722 + var o = oldList[i] || {}
  723 + if (n.productId !== o.productId || n.productName !== o.productName ||
  724 + n.materialType !== o.materialType || n.quantity !== o.quantity ||
  725 + n.actualPurchasePrice !== o.actualPurchasePrice || n.includingShippingPrice !== o.includingShippingPrice ||
  726 + n.priceListPrices !== o.priceListPrices || n.coordinationRange !== o.coordinationRange ||
  727 + n.estimatedLoss !== o.estimatedLoss || n.applicationAttrition !== o.applicationAttrition ||
  728 + n.paintDamageRatio !== o.paintDamageRatio || n.workshopId !== o.workshopId ||
  729 + n.workshopName !== o.workshopName || (n.itemId || '') !== (o.itemId || '')) {
  730 + this.lineList = newList
  731 + return
  732 + }
  733 + }
  734 + },
  735 + toggleBool(field) {
  736 + var cur = this.detail[field]
  737 + this.$set(this.detail, field, cur !== true)
  738 + },
  739 + onNonNegativeInput(field) {
  740 + var v = String(this.detail[field] != null ? this.detail[field] : '')
  741 + v = v.replace(/[^0-9.]/g, '')
  742 + v = v.replace(/(\..*)\./g, '$1')
  743 + this.$set(this.detail, field, v)
  744 + },
  745 + onNonNegativeBlur(field, digits) {
  746 + var raw = this.detail[field]
  747 + if (raw === '' || raw === null || raw === undefined) {
  748 + this.$set(this.detail, field, '')
  749 + return
  750 + }
  751 + var val = parseFloat(raw)
  752 + if (isNaN(val)) val = 0
  753 + var m = Math.pow(10, digits)
  754 + var rounded = Math.round(val * m) / m
  755 + this.$set(this.detail, field, rounded)
  756 + },
  757 + openDeliverySheet() {
  758 + var cur = this.detail.deliveryMode != null ? this.detail.deliveryMode : ''
  759 + var match = this.deliveryOptions.find(function (o) { return String(o.value) === String(cur) })
  760 + this.deliverySheetValue = match ? match.value : ''
  761 + this.deliverySheetVisible = true
  762 + },
  763 + onDeliveryConfirm(e) {
  764 + this.$set(this.detail, 'deliveryMode', e.value != null ? e.value : '')
  765 + },
  766 + isTagSelected(field, code) {
  767 + var selected = this.detail ? this.detail[field] : undefined
  768 + if (Array.isArray(selected)) return selected.indexOf(code) >= 0
  769 + if (typeof selected === 'string' && selected) {
  770 + return selected.split(',').indexOf(code) >= 0
  771 + }
  772 + return false
  773 + },
  774 + toggleTag(field, code) {
  775 + var selected = this.detail[field]
  776 + var arr = Array.isArray(selected) ? selected.slice() : []
  777 + var idx = arr.indexOf(code)
  778 + if (idx >= 0) {
  779 + arr.splice(idx, 1)
  780 + } else {
  781 + arr.push(code)
  782 + }
  783 + this.$set(this.detail, field, arr)
  784 + },
  785 + validateForm() {
  786 + if (!this.form.planId) {
  787 + uni.showToast({ title: '请选择计划', icon: 'none' })
  788 + return false
  789 + }
  790 + var d = this.detail || {}
  791 + var textChecks = [
  792 + { key: 'supplierName', title: '供应商名称' },
  793 + { key: 'validityPeriod', title: '报价时效' },
  794 + { key: 'quoterName', title: '报价人' },
  795 + { key: 'deliveryMode', title: '交提货方式' },
  796 + { key: 'loadingFee', title: '装车费' },
  797 + { key: 'invoiceProductName', title: '开票品名' },
  798 + { key: 'deliveryDate', title: '交货日期' },
  799 + { key: 'settlementMethod', title: '结算方式' },
  800 + { key: 'settlementRatio', title: '结算比例' },
  801 + { key: 'coordinationReason', title: '协调事由' },
  802 + { key: 'invoiceTypeStatus', title: '票类状况' },
  803 + { key: 'changeReason', title: '变更事由' }
  804 + ]
  805 + for (var i = 0; i < textChecks.length; i++) {
  806 + var tc = textChecks[i]
  807 + var tv = d[tc.key]
  808 + if (tv === '' || tv === null || tv === undefined) {
  809 + uni.showToast({ title: '请填写' + tc.title, icon: 'none' })
  810 + return false
  811 + }
  812 + }
  813 + var boolChecks = [
  814 + { key: 'longTermOperation', title: '是否长单操作' },
  815 + { key: 'terminalCustomer', title: '是否终端客户' },
  816 + { key: 'priced', title: '是否未点价' },
  817 + { key: 'otherExpenseSettlement', title: '其他费用凭票到厂另行结算' },
  818 + { key: 'commodityBuyout', title: '是否通货买断' },
  819 + { key: 'qualityBuyout', title: '是否质量买断' },
  820 + { key: 'quantityBuyout', title: '是否数量买断' },
  821 + { key: 'doorDelivery', title: '是否送货上门' }
  822 + ]
  823 + if (d.priced === true) {
  824 + boolChecks.push({ key: 'temporaryPrice', title: '是否暂定价' })
  825 + var pd = d.pricingDeadline
  826 + if (pd === '' || pd === null || pd === undefined) {
  827 + uni.showToast({ title: '请选择点价截止日期', icon: 'none' })
  828 + return false
  829 + }
  830 + }
  831 + for (var j = 0; j < boolChecks.length; j++) {
  832 + var bc = boolChecks[j]
  833 + if (typeof d[bc.key] !== 'boolean') {
  834 + uni.showToast({ title: '请选择' + bc.title, icon: 'none' })
  835 + return false
  836 + }
  837 + }
  838 + var pr = this.$refs.productRel
  839 + if (pr && typeof pr.validate === 'function') {
  840 + if (!pr.validate()) return false
  841 + }
  842 + return true
  843 + },
  844 + onBack() {
  845 + uni.navigateBack({ delta: 1 })
  846 + },
  847 + joinStr(arr) {
  848 + if (Array.isArray(arr)) return arr.filter(Boolean).join(',')
  849 + if (typeof arr === 'string') return arr
  850 + return ''
  851 + },
  852 + pickId(v) {
  853 + if (v == null || v === '') return ''
  854 + if (typeof v === 'string' || typeof v === 'number') return String(v)
  855 + if (typeof v === 'object') {
  856 + return String(v.id != null ? v.id : (v.value != null ? v.value : (v.code != null ? v.code : '')))
  857 + }
  858 + return String(v)
  859 + },
  860 + boolToStr(v) {
  861 + return v === true ? 'true' : 'false'
  862 + },
  863 + buildPayload() {
  864 + var self = this
  865 + var d = this.detail || {}
  866 + var lines = Array.isArray(this.lineList) ? this.lineList.slice() : []
  867 + var workshopId = d.workshopId != null ? d.workshopId : ''
  868 + var lineList = lines.map(function (row, i) {
  869 + var r = row || {}
  870 + var itemId = r.itemId != null ? r.itemId : (r.id != null ? String(r.id) : (r._key != null ? r._key : ('line-' + Date.now() + '-' + i)))
  871 + if (!workshopId && r.workshopId != null) workshopId = r.workshopId
  872 + return {
  873 + productId: self.pickId(r.productId),
  874 + materialType: r.materialType != null ? String(r.materialType) : '',
  875 + quantity: r.quantity != null ? String(r.quantity) : '',
  876 + actualPurchasePrice: r.actualPurchasePrice != null ? String(r.actualPurchasePrice) : '',
  877 + includingShippingPrice: r.includingShippingPrice != null ? String(r.includingShippingPrice) : '',
  878 + priceListPrices: r.priceListPrices != null ? String(r.priceListPrices) : '',
  879 + coordinationRange: r.coordinationRange != null ? String(r.coordinationRange) : '',
  880 + estimatedLoss: r.estimatedLoss != null ? String(r.estimatedLoss) : '',
  881 + applicationAttrition: r.applicationAttrition != null ? String(r.applicationAttrition) : '',
  882 + paintDamageRatio: r.paintDamageRatio != null ? String(r.paintDamageRatio) : '',
  883 + workshopId: self.pickId(r.workshopId),
  884 + itemId: itemId
  885 + }
  886 + })
  887 + var body = {
  888 + procurementPlanId: this.form.planId || d.id || '',
  889 + changeReason: d.changeReason != null ? String(d.changeReason) : '',
  890 + code: d.code != null ? String(d.code) : '',
  891 + companyShortId: this.pickId(d.companyShortId || d.companyId),
  892 + supplierId: this.pickId(d.supplierId),
  893 + purchaseDepartment: this.pickId(d.purchaseDepartment),
  894 + region: this.pickId(d.region),
  895 + date: d.date != null ? String(d.date).slice(0, 10) : '',
  896 + validityPeriod: d.validityPeriod != null ? String(d.validityPeriod) : '',
  897 + quoterId: this.pickId(d.quoterId),
  898 + workshopId: this.pickId(workshopId),
  899 + quoterName: d.quoterName != null ? String(d.quoterName) : '',
  900 + longTermOperation: this.boolToStr(d.longTermOperation),
  901 + terminalCustomer: this.boolToStr(d.terminalCustomer),
  902 + priced: this.boolToStr(d.priced),
  903 + pricingDeadline: d.pricingDeadline != null ? String(d.pricingDeadline) : '',
  904 + temporaryPrice: this.boolToStr(d.temporaryPrice),
  905 + otherExpenseSettlement: this.boolToStr(d.otherExpenseSettlement),
  906 + deliveryMode: d.deliveryMode != null ? String(d.deliveryMode) : '',
  907 + commodityBuyout: this.boolToStr(d.commodityBuyout),
  908 + qualityBuyout: this.boolToStr(d.qualityBuyout),
  909 + quantityBuyout: this.boolToStr(d.quantityBuyout),
  910 + doorDelivery: this.boolToStr(d.doorDelivery),
  911 + shippingCost: d.shippingCost != null ? String(d.shippingCost) : '',
  912 + loadingFee: d.loadingFee != null ? String(d.loadingFee) : '',
  913 + invoiceProductName: d.invoiceProductName != null ? String(d.invoiceProductName) : '',
  914 + deliveryDate: d.deliveryDate != null ? String(d.deliveryDate) : '',
  915 + settlementMethod: d.settlementMethod != null ? String(d.settlementMethod) : '',
  916 + settlementRatio: d.settlementRatio != null ? String(d.settlementRatio) : '',
  917 + priceId: this.pickId(d.priceId),
  918 + coordinationReason: d.coordinationReason != null ? String(d.coordinationReason) : '',
  919 + invoiceTypeStatus: d.invoiceTypeStatus != null ? String(d.invoiceTypeStatus) : '',
  920 + totalQuantity: d.totalQuantity != null ? String(d.totalQuantity) : '',
  921 + remark: d.remark != null ? String(d.remark) : '',
  922 + materialConditionEnabled: this.boolToStr(d.materialConditionEnabled),
  923 + lines: lineList
  924 + }
  925 + this.materialConditionConfigs.forEach(function (mc) {
  926 + body[mc.field] = self.joinStr(d[mc.field])
  927 + })
  928 + return body
  929 + },
  930 + async onSubmit() {
  931 + if (!this.validateForm()) return
  932 + var payload = this.buildPayload()
  933 + try {
  934 + await procurementPlanReplenplenishApi(payload)
  935 + uni.showToast({ title: '保存成功', icon: 'none' })
  936 + try {
  937 + uni.setStorageSync('SCHEDULE_PLAN_LIST_NEED_REFRESH', '1')
  938 + } catch (e) {}
  939 + var self = this
  940 + setTimeout(function () {
  941 + uni.navigateTo({ url: '/pages/schedule-plan/index' })
  942 + }, 400)
  943 + } catch (e) {
  944 + uni.showToast({ title: (e && (e.msg || e.message)) ? (e.msg || e.message) : '保存失败', icon: 'none' })
  945 + }
  946 + }
  947 + }
  948 +}
  949 +</script>
  950 +
  951 +<style lang="scss" scoped>
  952 +.page {
  953 + display: flex;
  954 + flex-direction: column;
  955 + height: 100%;
  956 +}
  957 +.scroll {
  958 + flex: 1;
  959 + padding: 12rpx 0 392rpx !important;
  960 +}
  961 +.bottom-bar {
  962 + z-index: 2;
  963 + position: fixed;
  964 + left: 0;
  965 + right: 0;
  966 + bottom: 0;
  967 + padding: 32rpx;
  968 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  969 + background: #fff;
  970 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  971 + display: flex;
  972 + gap: 24rpx;
  973 + .btn {
  974 + flex: 1;
  975 + height: 80rpx;
  976 + line-height: 80rpx;
  977 + border-radius: 12rpx;
  978 + font-size: 32rpx;
  979 + }
  980 + .btn-outline {
  981 + background: #fff;
  982 + color: $theme-primary;
  983 + border: 2rpx solid $theme-primary;
  984 + }
  985 + .btn-primary {
  986 + background: $theme-primary;
  987 + color: #fff;
  988 + border: 2rpx solid $theme-primary;
  989 + }
  990 +}
  991 +
  992 +::v-deep .uni-list {
  993 + .uni-easyinput {
  994 + display: flex;
  995 + .uni-input-input {
  996 + color: rgba(0, 0, 0, 0.9);
  997 + }
  998 + }
  999 + .uni-input-placeholder { z-index: 1; }
  1000 + .uni-input-input { background-color: #ffffff; }
  1001 + background: transparent;
  1002 + &-item {
  1003 + &__extra-text { font-size: 32rpx; }
  1004 + &__content-title {
  1005 + font-size: 32rpx;
  1006 + color: rgba(0, 0, 0, 0.9);
  1007 + }
  1008 + &__container {
  1009 + padding: 32rpx;
  1010 + .uni-easyinput {
  1011 + &__placeholder-class {
  1012 + font-size: 32rpx;
  1013 + color: rgba(0, 0, 0, 0.4);
  1014 + }
  1015 + &__content {
  1016 + border: none;
  1017 + background-color: #ffffff !important;
  1018 + &-input {
  1019 + padding-left: 0 !important;
  1020 + height: 48rpx;
  1021 + line-height: 48rpx;
  1022 + font-size: 32rpx;
  1023 + }
  1024 + .content-clear-icon {
  1025 + font-size: 44rpx !important;
  1026 + }
  1027 + }
  1028 + }
  1029 + .item-title,
  1030 + .uni-list-item__content {
  1031 + flex: none;
  1032 + min-height: 48rpx;
  1033 + line-height: 48rpx;
  1034 + font-size: 32rpx;
  1035 + position: relative;
  1036 + width: 240rpx;
  1037 + margin-right: 32rpx;
  1038 + color: rgba(0, 0, 0, 0.9);
  1039 + .required {
  1040 + color: red;
  1041 + position: absolute;
  1042 + top: 50%;
  1043 + transform: translateY(-50%);
  1044 + left: -16rpx;
  1045 + }
  1046 + }
  1047 + }
  1048 + &.select-item {
  1049 + &.is-empty {
  1050 + .uni-list-item__extra-text {
  1051 + color: rgba(0, 0, 0, 0.4) !important;
  1052 + }
  1053 + }
  1054 + &.is-filled {
  1055 + .uni-list-item__extra-text {
  1056 + color: rgba(0, 0, 0, 0.9) !important;
  1057 + }
  1058 + }
  1059 + .serial-number-row {
  1060 + display: flex;
  1061 + align-items: center;
  1062 + }
  1063 + }
  1064 + }
  1065 +}
  1066 +
  1067 +.readonly-text {
  1068 + color: rgba(0, 0, 0, 0.9);
  1069 + font-size: 32rpx;
  1070 + line-height: 48rpx;
  1071 + text-align: right;
  1072 + white-space: pre-wrap;
  1073 + word-break: break-all;
  1074 +}
  1075 +.value-code {
  1076 + width: 260rpx;
  1077 + text-align: left;
  1078 +}
  1079 +
  1080 +.attach-list {
  1081 + flex: 1;
  1082 + display: flex;
  1083 + flex-direction: column;
  1084 + align-items: flex-end;
  1085 + gap: 8rpx;
  1086 +}
  1087 +.attach-item {
  1088 + display: flex;
  1089 + align-items: center;
  1090 + gap: 16rpx;
  1091 + .attach-name { font-size: 26rpx; color: rgba(0,0,0,0.9); }
  1092 + .attach-view { font-size: 26rpx; color: $theme-primary; }
  1093 +}
  1094 +
  1095 +.material-condition-section,
  1096 +.remark-section {
  1097 + margin-top: 20rpx;
  1098 + background: #fff;
  1099 +}
  1100 +.section-header {
  1101 + display: flex;
  1102 + align-items: center;
  1103 + padding: 24rpx 32rpx;
  1104 + border-bottom: 1rpx solid #f0f0f0;
  1105 +}
  1106 +.section-title {
  1107 + position: relative;
  1108 + font-size: 32rpx;
  1109 + color: rgba(0, 0, 0, 0.9);
  1110 + font-weight: 600;
  1111 + .required {
  1112 + color: red;
  1113 + position: absolute;
  1114 + top: 50%;
  1115 + transform: translateY(-50%);
  1116 + left: -16rpx;
  1117 + }
  1118 +}
  1119 +.opCollapse {
  1120 + width: 32rpx;
  1121 + height: 28rpx;
  1122 + margin-right: 16rpx;
  1123 + margin-top: 8rpx;
  1124 +}
  1125 +.section-content {
  1126 + padding: 32rpx;
  1127 +}
  1128 +.form-row {
  1129 + display: flex;
  1130 + align-items: center;
  1131 + justify-content: space-between;
  1132 + margin-bottom: 24rpx;
  1133 +}
  1134 +.form-row:last-child { margin-bottom: 0; }
  1135 +.form-label {
  1136 + font-size: 32rpx;
  1137 + color: rgba(0, 0, 0, 0.9);
  1138 +}
  1139 +.form-value {
  1140 + font-size: 32rpx;
  1141 + color: rgba(0, 0, 0, 0.9);
  1142 +}
  1143 +.toggle-link {
  1144 + color: $theme-primary;
  1145 +}
  1146 +.material-group {
  1147 + margin-top: 32rpx;
  1148 +}
  1149 +.material-label {
  1150 + display: block;
  1151 + font-size: 30rpx;
  1152 + color: rgba(0, 0, 0, 0.9);
  1153 + margin-bottom: 20rpx;
  1154 +}
  1155 +.tag-list {
  1156 + display: flex;
  1157 + flex-wrap: wrap;
  1158 + gap: 16rpx;
  1159 +}
  1160 +.tag-btn {
  1161 + padding: 12rpx 24rpx;
  1162 + border: 1rpx solid #ddd;
  1163 + border-radius: 8rpx;
  1164 + font-size: 28rpx;
  1165 + color: #666;
  1166 + background: #fff;
  1167 +}
  1168 +.tag-btn.active {
  1169 + background: $theme-primary;
  1170 + border-color: $theme-primary;
  1171 + color: #fff;
  1172 +}
  1173 +
  1174 +::v-deep .uni-easyinput {
  1175 + width: 100%;
  1176 + &__content {
  1177 + background: #f8f8f8 !important;
  1178 + border-radius: 8rpx;
  1179 + &-input { font-size: 30rpx; }
  1180 + }
  1181 +}
  1182 +</style>
... ...
... ... @@ -160,7 +160,7 @@ export default {
160 160 },
161 161 methods: {
162 162 onAdd() {
163   - uni.navigateTo({ url: '/pages/schedule-plan/add' })
  163 + uni.navigateTo({ url: '/pages/supple-plan/add' })
164 164 },
165 165 async loadDicData() {
166 166 try {
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view scroll-y class="scroll">
  4 + <uni-list>
  5 + <uni-list-item class="select-item" :class="form.planCode ? 'is-filled' : 'is-empty'">
  6 + <template v-slot:body>
  7 + <view class="item-title"><text class="required">*</text><text>计划数据</text></view>
  8 + </template>
  9 + <template v-slot:footer>
  10 + <text class="readonly-text">{{ form.planCode || '-' }}</text>
  11 + </template>
  12 + </uni-list-item>
  13 +
  14 + <uni-list-item title="公司名称">
  15 + <template v-slot:footer>
  16 + <uni-easyinput v-model="companyNameDisplay" :inputBorder="false" disabled placeholder="-" />
  17 + </template>
  18 + </uni-list-item>
  19 +
  20 + <uni-list-item>
  21 + <template v-slot:body>
  22 + <view class="item-title"><text class="required">*</text><text>供应商名称</text></view>
  23 + </template>
  24 + <template v-slot:footer>
  25 + <uni-easyinput v-model="detail.supplierName" :inputBorder="false" placeholder="请输入供应商名称" />
  26 + </template>
  27 + </uni-list-item>
  28 +
  29 + <uni-list-item title="采购处">
  30 + <template v-slot:footer>
  31 + <uni-easyinput v-model="purchaseDepartmentDisplay" :inputBorder="false" disabled placeholder="-" />
  32 + </template>
  33 + </uni-list-item>
  34 +
  35 + <uni-list-item title="区域">
  36 + <template v-slot:footer>
  37 + <uni-easyinput v-model="regionDisplay" :inputBorder="false" disabled placeholder="-" />
  38 + </template>
  39 + </uni-list-item>
  40 +
  41 + <uni-list-item title="日期">
  42 + <template v-slot:footer>
  43 + <uni-easyinput v-model="dateDisplay" :inputBorder="false" disabled placeholder="-" />
  44 + </template>
  45 + </uni-list-item>
  46 +
  47 + <uni-list-item>
  48 + <template v-slot:body>
  49 + <view class="item-title"><text class="required">*</text><text>报价时效</text></view>
  50 + </template>
  51 + <template v-slot:footer>
  52 + <uni-easyinput v-model="detail.validityPeriod" :inputBorder="false" placeholder="请输入报价时效" />
  53 + </template>
  54 + </uni-list-item>
  55 +
  56 + <uni-list-item>
  57 + <template v-slot:body>
  58 + <view class="item-title"><text class="required">*</text><text>报价人</text></view>
  59 + </template>
  60 + <template v-slot:footer>
  61 + <uni-easyinput v-model="detail.quoterName" :inputBorder="false" placeholder="请输入报价人" />
  62 + </template>
  63 + </uni-list-item>
  64 +
  65 + <uni-list-item class="select-item" :class="typeof detail.longTermOperation === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  66 + @click="toggleBool('longTermOperation')" :rightText="boolText(detail.longTermOperation) || '请选择'" showArrow>
  67 + <template v-slot:body>
  68 + <view class="item-title"><text class="required">*</text><text>是否长单操作</text></view>
  69 + </template>
  70 + </uni-list-item>
  71 +
  72 + <uni-list-item class="select-item" :class="typeof detail.terminalCustomer === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  73 + @click="toggleBool('terminalCustomer')" :rightText="boolText(detail.terminalCustomer) || '请选择'" showArrow>
  74 + <template v-slot:body>
  75 + <view class="item-title"><text class="required">*</text><text>是否终端客户</text></view>
  76 + </template>
  77 + </uni-list-item>
  78 +
  79 + <uni-list-item class="select-item" :class="typeof detail.priced === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  80 + @click="toggleBool('priced')" :rightText="boolText(detail.priced) || '请选择'" showArrow>
  81 + <template v-slot:body>
  82 + <view class="item-title"><text class="required">*</text><text>是否未点价</text></view>
  83 + </template>
  84 + </uni-list-item>
  85 +
  86 + <uni-list-item v-if="detail.priced === true">
  87 + <template v-slot:body>
  88 + <view class="item-title"><text class="required">*</text><text>点价截止日期</text></view>
  89 + </template>
  90 + <template v-slot:footer>
  91 + <uni-datetime-picker type="date" v-model="detail.pricingDeadline" return-type="string" />
  92 + </template>
  93 + </uni-list-item>
  94 +
  95 + <uni-list-item v-if="detail.priced === true" class="select-item" :class="typeof detail.temporaryPrice === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  96 + @click="toggleBool('temporaryPrice')" :rightText="boolText(detail.temporaryPrice) || '请选择'" showArrow>
  97 + <template v-slot:body>
  98 + <view class="item-title"><text class="required">*</text><text>是否暂定价</text></view>
  99 + </template>
  100 + </uni-list-item>
  101 +
  102 + <uni-list-item class="select-item" :class="typeof detail.otherExpenseSettlement === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  103 + @click="toggleBool('otherExpenseSettlement')" :rightText="boolText(detail.otherExpenseSettlement) || '请选择'" showArrow>
  104 + <template v-slot:body>
  105 + <view class="item-title"><text class="required">*</text><text>其他费用凭票到厂另行结算</text></view>
  106 + </template>
  107 + </uni-list-item>
  108 +
  109 + <uni-list-item class="select-item" :class="detail.deliveryMode ? 'is-filled' : 'is-empty'" clickable
  110 + @click="openDeliverySheet" :rightText="getDeliveryMethodLabel()" showArrow>
  111 + <template v-slot:body>
  112 + <view class="item-title"><text class="required">*</text><text>交提货方式</text></view>
  113 + </template>
  114 + </uni-list-item>
  115 +
  116 + <uni-list-item class="select-item" :class="typeof detail.commodityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  117 + @click="toggleBool('commodityBuyout')" :rightText="boolText(detail.commodityBuyout) || '请选择'" showArrow>
  118 + <template v-slot:body>
  119 + <view class="item-title"><text class="required">*</text><text>是否通货买断</text></view>
  120 + </template>
  121 + </uni-list-item>
  122 +
  123 + <uni-list-item class="select-item" :class="typeof detail.qualityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  124 + @click="toggleBool('qualityBuyout')" :rightText="boolText(detail.qualityBuyout) || '请选择'" showArrow>
  125 + <template v-slot:body>
  126 + <view class="item-title"><text class="required">*</text><text>是否质量买断</text></view>
  127 + </template>
  128 + </uni-list-item>
  129 +
  130 + <uni-list-item class="select-item" :class="typeof detail.quantityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  131 + @click="toggleBool('quantityBuyout')" :rightText="boolText(detail.quantityBuyout) || '请选择'" showArrow>
  132 + <template v-slot:body>
  133 + <view class="item-title"><text class="required">*</text><text>是否数量买断</text></view>
  134 + </template>
  135 + </uni-list-item>
  136 +
  137 + <uni-list-item class="select-item" :class="typeof detail.doorDelivery === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  138 + @click="toggleBool('doorDelivery')" :rightText="boolText(detail.doorDelivery) || '请选择'" showArrow>
  139 + <template v-slot:body>
  140 + <view class="item-title"><text class="required">*</text><text>是否送货上门</text></view>
  141 + </template>
  142 + </uni-list-item>
  143 +
  144 + <uni-list-item title="另付运费">
  145 + <template v-slot:footer>
  146 + <uni-easyinput v-model="shippingCostDisplay" :inputBorder="false" disabled placeholder="-" />
  147 + </template>
  148 + </uni-list-item>
  149 +
  150 + <uni-list-item>
  151 + <template v-slot:body>
  152 + <view class="item-title"><text class="required">*</text><text>装车费</text></view>
  153 + </template>
  154 + <template v-slot:footer>
  155 + <uni-easyinput
  156 + v-model="detail.loadingFee"
  157 + type="digit"
  158 + :inputBorder="false"
  159 + placeholder="请输入装车费"
  160 + @input="onNonNegativeInput('loadingFee')"
  161 + @blur="onNonNegativeBlur('loadingFee', 2)"
  162 + />
  163 + </template>
  164 + </uni-list-item>
  165 +
  166 + <uni-list-item>
  167 + <template v-slot:body>
  168 + <view class="item-title"><text class="required">*</text><text>开票品名</text></view>
  169 + </template>
  170 + <template v-slot:footer>
  171 + <uni-easyinput v-model="detail.invoiceProductName" :inputBorder="false" placeholder="请输入开票品名" />
  172 + </template>
  173 + </uni-list-item>
  174 +
  175 + <uni-list-item>
  176 + <template v-slot:body>
  177 + <view class="item-title"><text class="required">*</text><text>交货日期</text></view>
  178 + </template>
  179 + <template v-slot:footer>
  180 + <uni-datetime-picker type="date" v-model="detail.deliveryDate" return-type="string" />
  181 + </template>
  182 + </uni-list-item>
  183 +
  184 + <uni-list-item>
  185 + <template v-slot:body>
  186 + <view class="item-title"><text class="required">*</text><text>结算方式</text></view>
  187 + </template>
  188 + <template v-slot:footer>
  189 + <uni-easyinput v-model="detail.settlementMethod" :inputBorder="false" placeholder="请输入结算方式" />
  190 + </template>
  191 + </uni-list-item>
  192 +
  193 + <uni-list-item>
  194 + <template v-slot:body>
  195 + <view class="item-title"><text class="required">*</text><text>结算比例(%)</text></view>
  196 + </template>
  197 + <template v-slot:footer>
  198 + <uni-easyinput
  199 + v-model="detail.settlementRatio"
  200 + type="digit"
  201 + :inputBorder="false"
  202 + placeholder="请输入结算比例"
  203 + @input="onNonNegativeInput('settlementRatio')"
  204 + @blur="onNonNegativeBlur('settlementRatio', 4)"
  205 + />
  206 + </template>
  207 + </uni-list-item>
  208 +
  209 + <uni-list-item title="价格表编号">
  210 + <template v-slot:footer>
  211 + <uni-easyinput v-model="priceTableDisplay" :inputBorder="false" disabled placeholder="-" />
  212 + </template>
  213 + </uni-list-item>
  214 +
  215 + <uni-list-item>
  216 + <template v-slot:body>
  217 + <view class="item-title"><text class="required">*</text><text>协调事由</text></view>
  218 + </template>
  219 + <template v-slot:footer>
  220 + <uni-easyinput v-model="detail.coordinationReason" :inputBorder="false" placeholder="请输入协调事由" />
  221 + </template>
  222 + </uni-list-item>
  223 +
  224 + <uni-list-item>
  225 + <template v-slot:body>
  226 + <view class="item-title"><text class="required">*</text><text>票类状况</text></view>
  227 + </template>
  228 + <template v-slot:footer>
  229 + <uni-easyinput v-model="detail.invoiceTypeStatus" :inputBorder="false" placeholder="请输入票类状况" />
  230 + </template>
  231 + </uni-list-item>
  232 +
  233 + <uni-list-item v-if="attachmentList.length" title="附件">
  234 + <template v-slot:footer>
  235 + <view class="attach-list">
  236 + <view v-for="(at, idx) in attachmentList" :key="idx" class="attach-item">
  237 + <text class="attach-name">{{ at.name }}</text>
  238 + <text class="attach-view" @click.stop="onPreviewAttachment(at)">查看</text>
  239 + </view>
  240 + </view>
  241 + </template>
  242 + </uni-list-item>
  243 +
  244 + <ProductRel
  245 + ref="productRel"
  246 + mode="edit"
  247 + :list="lineList"
  248 + :product-options="productOptions"
  249 + :workshop-options="workshopOptions"
  250 + :shipping-cost="detail.shippingCost"
  251 + :price-map="priceMap"
  252 + @change="onLineChange"
  253 + />
  254 + </uni-list>
  255 +
  256 + <view class="material-condition-section">
  257 + <view class="section-header">
  258 + <image class="opCollapse" src="/static/images/title.png" />
  259 + <text class="section-title">料质状况</text>
  260 + </view>
  261 + <view class="section-content">
  262 + <view class="form-row">
  263 + <text class="form-label">是否启用料质状况</text>
  264 + <text class="form-value toggle-link" @click="toggleBool('materialConditionEnabled')">{{ boolText(detail.materialConditionEnabled) || '请选择' }}</text>
  265 + </view>
  266 + <template v-if="detail.materialConditionEnabled">
  267 + <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group">
  268 + <text class="material-label">{{ mc.label }}</text>
  269 + <view class="tag-list">
  270 + <view
  271 + v-for="opt in getDictOptions(mc.dictCode)"
  272 + :key="opt.code"
  273 + class="tag-btn"
  274 + :class="{ active: isTagSelected(mc.field, opt.code) }"
  275 + @click="toggleTag(mc.field, opt.code)"
  276 + >
  277 + {{ opt.name }}
  278 + </view>
  279 + </view>
  280 + </view>
  281 + </template>
  282 + </view>
  283 + </view>
  284 +
  285 + <view class="remark-section">
  286 + <view class="section-header">
  287 + <image class="opCollapse" src="/static/images/title.png" />
  288 + <text class="section-title">备注</text>
  289 + </view>
  290 + <view class="section-content">
  291 + <uni-easyinput type="textarea" v-model="detail.remark" :inputBorder="false" placeholder="请输入备注" />
  292 + </view>
  293 + </view>
  294 +
  295 + <view class="remark-section">
  296 + <view class="section-header">
  297 + <image class="opCollapse" src="/static/images/title.png" />
  298 + <text class="section-title"><text class="required">*</text>变更事由</text>
  299 + </view>
  300 + <view class="section-content">
  301 + <uni-easyinput type="textarea" v-model="detail.changeReason" :inputBorder="false" placeholder="请输入变更事由" />
  302 + </view>
  303 + </view>
  304 + </scroll-view>
  305 +
  306 + <view class="bottom-bar">
  307 + <button class="btn btn-outline" @click="onBack">取消</button>
  308 + <button class="btn btn-primary" @click="onSubmit">保存</button>
  309 + </view>
  310 +
  311 + <SingleSelectSheet
  312 + :visible.sync="deliverySheetVisible"
  313 + title="交提货方式"
  314 + :options="deliveryOptions"
  315 + v-model="deliverySheetValue"
  316 + @confirm="onDeliveryConfirm"
  317 + />
  318 + </view>
  319 +</template>
  320 +
  321 +<script>
  322 +import ProductRel from './productRel.vue'
  323 +import SingleSelectSheet from '@/components/single-select/index.vue'
  324 +import { procurementPlanReplenishFindByIdApi, procurementPlanReplenishUpdateApi } from '@/api/procure-manage/procurementPlan.js'
  325 +import {
  326 + breedRelationshipQueryApi,
  327 + priceTableDetailApi,
  328 + workshopQueryApi
  329 +} from '@/api/devManage.js'
  330 +import { getDicByCodes } from '@/utils/dic.js'
  331 +
  332 +export default {
  333 + name: 'SchedulePlanModify',
  334 + components: { ProductRel, SingleSelectSheet },
  335 + data() {
  336 + return {
  337 + id: '',
  338 + form: {
  339 + planId: '',
  340 + planCode: ''
  341 + },
  342 + detail: {},
  343 + attachmentList: [],
  344 + materialConditionConfigs: [
  345 + { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' },
  346 + { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' },
  347 + { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' },
  348 + { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' },
  349 + { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' },
  350 + { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' },
  351 + { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' },
  352 + { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' }
  353 + ],
  354 + dicOptions: {
  355 + DELIVERY_METHOD: []
  356 + },
  357 + dictData: {},
  358 + lineList: [],
  359 + productOptions: [],
  360 + workshopOptions: [],
  361 + priceMap: {},
  362 + deliverySheetVisible: false,
  363 + deliverySheetValue: '',
  364 + deliveryOptions: []
  365 + }
  366 + },
  367 + computed: {
  368 + companyNameDisplay() {
  369 + var d = this.detail || {}
  370 + return d.companyShortName != null ? d.companyShortName : (d.companyName != null ? d.companyName : '')
  371 + },
  372 + purchaseDepartmentDisplay() {
  373 + var d = this.detail || {}
  374 + return d.purchaseDepartmentName != null ? d.purchaseDepartmentName : (d.purchaseDepartment != null ? d.purchaseDepartment : '')
  375 + },
  376 + regionDisplay() {
  377 + var d = this.detail || {}
  378 + return d.regionName != null ? d.regionName : (d.region != null ? d.region : '')
  379 + },
  380 + dateDisplay() {
  381 + var d = this.detail || {}
  382 + var s = d.date == null ? '' : String(d.date).trim()
  383 + return s.length >= 10 ? s.slice(0, 10) : s
  384 + },
  385 + shippingCostDisplay() {
  386 + var v = (this.detail || {}).shippingCost
  387 + if (v == null || v === '') return ''
  388 + var n = Number(v)
  389 + if (isNaN(n)) return String(v)
  390 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  391 + },
  392 + priceTableDisplay() {
  393 + var d = this.detail || {}
  394 + var code = d.priceTableCode != null ? String(d.priceTableCode).trim() : ''
  395 + if (!code) return ''
  396 + var name = d.priceTableName || ''
  397 + return name ? (name + ' (' + code + ')') : code
  398 + }
  399 + },
  400 + onLoad(query) {
  401 + this.id = (query && query.id) || ''
  402 + this.loadDictData()
  403 + this.loadRefData()
  404 + if (this.id) {
  405 + this.loadDetailById(this.id)
  406 + }
  407 + },
  408 + methods: {
  409 + safeText(v) {
  410 + var s = v == null ? '' : String(v)
  411 + return s.trim() ? s : '-'
  412 + },
  413 + boolText(v) {
  414 + if (typeof v !== 'boolean') return ''
  415 + return v ? '是' : '否'
  416 + },
  417 + toNumber(v) {
  418 + if (v == null || v === '') return 0
  419 + var n = Number(v)
  420 + return isNaN(n) ? 0 : n
  421 + },
  422 + toFixed(v, n) {
  423 + var num = Number(v)
  424 + if (isNaN(num)) return ''
  425 + return num.toFixed(n)
  426 + },
  427 + async loadDictData() {
  428 + var codes = [].concat(
  429 + this.materialConditionConfigs.map(function (mc) { return mc.dictCode }),
  430 + ['DELIVERY_METHOD']
  431 + )
  432 + try {
  433 + var results = await getDicByCodes(codes)
  434 + var d = results || {}
  435 + this.dictData = d
  436 + this.dicOptions.DELIVERY_METHOD = (d.DELIVERY_METHOD && d.DELIVERY_METHOD.data) || []
  437 + this.deliveryOptions = this.dicOptions.DELIVERY_METHOD.map(function (o) {
  438 + return { label: o.name || o.label || '', value: o.code != null ? o.code : o.value }
  439 + })
  440 + } catch (e) {
  441 + this.dictData = {}
  442 + }
  443 + },
  444 + async loadRefData() {
  445 + try {
  446 + var results = await Promise.all([
  447 + this.$pCall(breedRelationshipQueryApi, { pageIndex: 1, pageSize: 1000 }),
  448 + this.$pCall(workshopQueryApi, { pageIndex: 1, pageSize: 1000 })
  449 + ])
  450 + var r1 = (results[0] && results[0].data) ? results[0].data : {}
  451 + var r2 = (results[1] && results[1].data) ? results[1].data : {}
  452 + this.productOptions = (r1.datas && Array.isArray(r1.datas)) ? r1.datas : ((r1.list && Array.isArray(r1.list)) ? r1.list : ((r1.records && Array.isArray(r1.records)) ? r1.records : []))
  453 + this.workshopOptions = (r2.datas && Array.isArray(r2.datas)) ? r2.datas : ((r2.list && Array.isArray(r2.list)) ? r2.list : ((r2.records && Array.isArray(r2.records)) ? r2.records : []))
  454 + this.fillLineNames()
  455 + } catch (e) {
  456 + this.productOptions = []
  457 + this.workshopOptions = []
  458 + }
  459 + },
  460 + $pCall(fn, params) {
  461 + try { return Promise.resolve(fn(params)) } catch (e) { return Promise.reject(e) }
  462 + },
  463 + getDictOptions(dictCode) {
  464 + var data = this.dictData[dictCode]
  465 + return (data && data.data) ? data.data : []
  466 + },
  467 + getDeliveryMethodLabel() {
  468 + var opts = this.dicOptions.DELIVERY_METHOD || []
  469 + var v = String(this.detail.deliveryMode != null ? this.detail.deliveryMode : '')
  470 + if (!v) return '请选择'
  471 + for (var i = 0; i < opts.length; i++) {
  472 + var o = opts[i]
  473 + var code = o.code != null ? String(o.code) : (o.value != null ? String(o.value) : '')
  474 + if (code === v) return o.name || o.label || v
  475 + }
  476 + return v
  477 + },
  478 + async loadDetailById(id) {
  479 + if (!id) return
  480 + try {
  481 + var res = await procurementPlanReplenishFindByIdApi({ id: id })
  482 + var d = (res && res.data) ? res.data : {}
  483 + var boolFields = ['longTermOperation', 'terminalCustomer', 'priced', 'temporaryPrice', 'otherExpenseSettlement', 'commodityBuyout', 'qualityBuyout', 'quantityBuyout', 'doorDelivery', 'materialConditionEnabled']
  484 + boolFields.forEach(function (f) {
  485 + var v = d[f]
  486 + if (typeof v === 'string') {
  487 + d[f] = v === 'true' || v === '1'
  488 + } else if (typeof v === 'number') {
  489 + d[f] = v === 1
  490 + } else {
  491 + d[f] = !!v
  492 + }
  493 + })
  494 + this.materialConditionConfigs.forEach(function (mc) {
  495 + var v = d[mc.field]
  496 + if (typeof v === 'string' && v) {
  497 + d[mc.field] = v.split(',').filter(Boolean)
  498 + } else if (!Array.isArray(v)) {
  499 + d[mc.field] = []
  500 + }
  501 + })
  502 + d.pricingDeadline = this.trimDate(d.pricingDeadline)
  503 + d.deliveryDate = this.trimDate(d.deliveryDate)
  504 + this.detail = d
  505 + this.form.planId = d.procurementPlanId != null ? d.procurementPlanId : (d.planId != null ? d.planId : (d.id || ''))
  506 + this.form.planCode = d.procurementPlanCode != null ? d.procurementPlanCode : (d.planCode != null ? d.planCode : d.code)
  507 + var lines = d.lines || d.procurementPlanLineList || d.lineList || []
  508 + this.lineList = Array.isArray(lines) ? lines.slice() : []
  509 + this.buildAttachmentList()
  510 + this.fillLineNames()
  511 + this.fetchPriceDetailAndApply(d.priceId)
  512 + } catch (e) {
  513 + uni.showToast({ title: '加载详情失败', icon: 'none' })
  514 + }
  515 + },
  516 + trimDate(v) {
  517 + if (v == null || v === '') return ''
  518 + var s = String(v).trim()
  519 + return s.length >= 10 ? s.slice(0, 10) : s
  520 + },
  521 + buildAttachmentList() {
  522 + var ids = this.detail.attachmentFileIds
  523 + var names = this.detail.attachmentFileNames
  524 + var idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : [])
  525 + var nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : [])
  526 + var len = Math.max(idArr.length, nameArr.length)
  527 + var list = []
  528 + for (var i = 0; i < len; i++) {
  529 + list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) })
  530 + }
  531 + this.attachmentList = list
  532 + },
  533 + onPreviewAttachment(at) {
  534 + if (!at || !at.id) {
  535 + uni.showToast({ title: '无法查看', icon: 'none' })
  536 + return
  537 + }
  538 + uni.showToast({ title: '查看附件 ' + at.name, icon: 'none' })
  539 + },
  540 + fillLineNames() {
  541 + var list = Array.isArray(this.lineList) ? this.lineList : []
  542 + if (!list.length) return
  543 + var pOpts = Array.isArray(this.productOptions) ? this.productOptions : []
  544 + var wOpts = Array.isArray(this.workshopOptions) ? this.workshopOptions : []
  545 + this.lineList = list.map(function (row) {
  546 + var r = Object.assign({}, row)
  547 + var pid = r.productId != null ? String(r.productId) : ''
  548 + var wid = r.workshopId != null ? String(r.workshopId) : ''
  549 + if ((r.productName == null || String(r.productName).trim() === '') && pid) {
  550 + var p = pOpts.find(function (o) {
  551 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.value != null ? String(o.value) : ''))
  552 + return id === pid
  553 + })
  554 + if (p) {
  555 + r.productName = p.name != null ? p.name : (p.productName != null ? p.productName : (p.label != null ? p.label : ''))
  556 + }
  557 + }
  558 + if ((r.workshopName == null || String(r.workshopName).trim() === '') && wid) {
  559 + var w = wOpts.find(function (o) {
  560 + var id = o.id != null ? String(o.id) : (o.workshopId != null ? String(o.workshopId) : (o.value != null ? String(o.value) : ''))
  561 + return id === wid
  562 + })
  563 + if (w) {
  564 + r.workshopName = w.name != null ? w.name : (w.workshopName != null ? w.workshopName : (w.label != null ? w.label : ''))
  565 + }
  566 + }
  567 + return r
  568 + })
  569 + },
  570 + async fetchPriceDetailAndApply(priceId) {
  571 + if (!priceId) return
  572 + var self = this
  573 + try {
  574 + var res = await priceTableDetailApi({ id: priceId })
  575 + var d = (res && res.data) ? res.data : {}
  576 + if (d.code != null && this.detail) {
  577 + this.$set(this.detail, 'priceTableCode', String(d.code))
  578 + }
  579 + if (d.priceTableName != null && this.detail) {
  580 + this.$set(this.detail, 'priceTableName', d.priceTableName)
  581 + }
  582 + var priceLines = self.extractPriceLines(d)
  583 + self.applyPriceLinesToLines(priceLines)
  584 + } catch (e) {
  585 + return
  586 + }
  587 + },
  588 + extractPriceLines(priceDetail) {
  589 + if (!priceDetail || typeof priceDetail !== 'object') return []
  590 + var candidates = [
  591 + priceDetail.procurementPriceLineList,
  592 + priceDetail.priceSubTableList,
  593 + priceDetail.priceLineList,
  594 + priceDetail.priceList,
  595 + priceDetail.lineList,
  596 + priceDetail.datas,
  597 + priceDetail.records,
  598 + priceDetail.list
  599 + ]
  600 + for (var i = 0; i < candidates.length; i++) {
  601 + if (Array.isArray(candidates[i]) && candidates[i].length) return candidates[i]
  602 + }
  603 + for (var k in priceDetail) {
  604 + if (!Object.prototype.hasOwnProperty.call(priceDetail, k)) continue
  605 + if (Array.isArray(priceDetail[k])) {
  606 + var arr = priceDetail[k]
  607 + if (arr.length && arr[0] && typeof arr[0] === 'object' && (arr[0].price != null || arr[0].productId != null || arr[0].breedId != null || arr[0].varietyId != null)) {
  608 + return arr
  609 + }
  610 + }
  611 + }
  612 + return []
  613 + },
  614 + buildPriceMap(priceLines) {
  615 + var m = {}
  616 + if (!Array.isArray(priceLines)) return m
  617 + for (var i = 0; i < priceLines.length; i++) {
  618 + var line = priceLines[i] || {}
  619 + if (line.price == null) continue
  620 + var key = String(line.productId || line.breedId || line.varietyId || line.id || ('__idx_' + i))
  621 + m[key] = { price: Number(line.price), meta: line }
  622 + }
  623 + return m
  624 + },
  625 + applyPriceLinesToLines(priceLines) {
  626 + var priceMap = this.buildPriceMap(priceLines)
  627 + this.priceMap = priceMap || {}
  628 + if (!Array.isArray(this.lineList)) return
  629 + var self = this
  630 + this.lineList = this.lineList.map(function (row) {
  631 + var pid = String(row.productId || row.breedId || row.varietyId || '')
  632 + var price = null
  633 + if (pid && priceMap[pid] != null) {
  634 + price = priceMap[pid].price
  635 + } else {
  636 + var pname = (row.productName || '').trim()
  637 + if (pname) {
  638 + for (var k in priceMap) {
  639 + if (!Object.prototype.hasOwnProperty.call(priceMap, k)) continue
  640 + var meta = priceMap[k] && priceMap[k].meta ? priceMap[k].meta : null
  641 + if (meta && ((meta.productName && meta.productName === pname) || (meta.breedName && meta.breedName === pname) || (meta.varietyName && meta.varietyName === pname))) {
  642 + price = priceMap[k].price
  643 + break
  644 + }
  645 + }
  646 + }
  647 + }
  648 + if (price != null) {
  649 + row.priceListPrices = self.toFixed(price, 2)
  650 + } else {
  651 + row.priceListPrices = ''
  652 + }
  653 + return row
  654 + })
  655 + var pr = this.$refs.productRel
  656 + if (pr && typeof pr.recalcAllItems === 'function') {
  657 + pr.recalcAllItems()
  658 + }
  659 + },
  660 + onLineChange(list) {
  661 + var newList = Array.isArray(list) ? list.slice() : []
  662 + var oldList = Array.isArray(this.lineList) ? this.lineList : []
  663 + if (newList.length !== oldList.length) {
  664 + this.lineList = newList
  665 + return
  666 + }
  667 + var i = 0
  668 + for (i = 0; i < newList.length; i++) {
  669 + var n = newList[i] || {}
  670 + var o = oldList[i] || {}
  671 + if (n.productId !== o.productId || n.productName !== o.productName ||
  672 + n.materialType !== o.materialType || n.quantity !== o.quantity ||
  673 + n.actualPurchasePrice !== o.actualPurchasePrice || n.includingShippingPrice !== o.includingShippingPrice ||
  674 + n.priceListPrices !== o.priceListPrices || n.coordinationRange !== o.coordinationRange ||
  675 + n.estimatedLoss !== o.estimatedLoss || n.applicationAttrition !== o.applicationAttrition ||
  676 + n.paintDamageRatio !== o.paintDamageRatio || n.workshopId !== o.workshopId ||
  677 + n.workshopName !== o.workshopName || (n.itemId || '') !== (o.itemId || '')) {
  678 + this.lineList = newList
  679 + return
  680 + }
  681 + }
  682 + },
  683 + toggleBool(field) {
  684 + var cur = this.detail[field]
  685 + this.$set(this.detail, field, cur !== true)
  686 + },
  687 + onNonNegativeInput(field) {
  688 + var v = String(this.detail[field] != null ? this.detail[field] : '')
  689 + v = v.replace(/[^0-9.]/g, '')
  690 + v = v.replace(/(\..*)\./g, '$1')
  691 + this.$set(this.detail, field, v)
  692 + },
  693 + onNonNegativeBlur(field, digits) {
  694 + var raw = this.detail[field]
  695 + if (raw === '' || raw === null || raw === undefined) {
  696 + this.$set(this.detail, field, '')
  697 + return
  698 + }
  699 + var val = parseFloat(raw)
  700 + if (isNaN(val)) val = 0
  701 + var m = Math.pow(10, digits)
  702 + var rounded = Math.round(val * m) / m
  703 + this.$set(this.detail, field, rounded)
  704 + },
  705 + openDeliverySheet() {
  706 + var cur = this.detail.deliveryMode != null ? this.detail.deliveryMode : ''
  707 + var match = this.deliveryOptions.find(function (o) { return String(o.value) === String(cur) })
  708 + this.deliverySheetValue = match ? match.value : ''
  709 + this.deliverySheetVisible = true
  710 + },
  711 + onDeliveryConfirm(e) {
  712 + this.$set(this.detail, 'deliveryMode', e.value != null ? e.value : '')
  713 + },
  714 + isTagSelected(field, code) {
  715 + var selected = this.detail ? this.detail[field] : undefined
  716 + if (Array.isArray(selected)) return selected.indexOf(code) >= 0
  717 + if (typeof selected === 'string' && selected) {
  718 + return selected.split(',').indexOf(code) >= 0
  719 + }
  720 + return false
  721 + },
  722 + toggleTag(field, code) {
  723 + var selected = this.detail[field]
  724 + var arr = Array.isArray(selected) ? selected.slice() : []
  725 + var idx = arr.indexOf(code)
  726 + if (idx >= 0) {
  727 + arr.splice(idx, 1)
  728 + } else {
  729 + arr.push(code)
  730 + }
  731 + this.$set(this.detail, field, arr)
  732 + },
  733 + validateForm() {
  734 + if (!this.form.planId) {
  735 + uni.showToast({ title: '请选择计划', icon: 'none' })
  736 + return false
  737 + }
  738 + var d = this.detail || {}
  739 + var textChecks = [
  740 + { key: 'supplierName', title: '供应商名称' },
  741 + { key: 'validityPeriod', title: '报价时效' },
  742 + { key: 'quoterName', title: '报价人' },
  743 + { key: 'deliveryMode', title: '交提货方式' },
  744 + { key: 'loadingFee', title: '装车费' },
  745 + { key: 'invoiceProductName', title: '开票品名' },
  746 + { key: 'deliveryDate', title: '交货日期' },
  747 + { key: 'settlementMethod', title: '结算方式' },
  748 + { key: 'settlementRatio', title: '结算比例' },
  749 + { key: 'coordinationReason', title: '协调事由' },
  750 + { key: 'invoiceTypeStatus', title: '票类状况' },
  751 + { key: 'changeReason', title: '变更事由' }
  752 + ]
  753 + for (var i = 0; i < textChecks.length; i++) {
  754 + var tc = textChecks[i]
  755 + var tv = d[tc.key]
  756 + if (tv === '' || tv === null || tv === undefined) {
  757 + uni.showToast({ title: '请填写' + tc.title, icon: 'none' })
  758 + return false
  759 + }
  760 + }
  761 + var boolChecks = [
  762 + { key: 'longTermOperation', title: '是否长单操作' },
  763 + { key: 'terminalCustomer', title: '是否终端客户' },
  764 + { key: 'priced', title: '是否未点价' },
  765 + { key: 'otherExpenseSettlement', title: '其他费用凭票到厂另行结算' },
  766 + { key: 'commodityBuyout', title: '是否通货买断' },
  767 + { key: 'qualityBuyout', title: '是否质量买断' },
  768 + { key: 'quantityBuyout', title: '是否数量买断' },
  769 + { key: 'doorDelivery', title: '是否送货上门' }
  770 + ]
  771 + if (d.priced === true) {
  772 + boolChecks.push({ key: 'temporaryPrice', title: '是否暂定价' })
  773 + var pd = d.pricingDeadline
  774 + if (pd === '' || pd === null || pd === undefined) {
  775 + uni.showToast({ title: '请选择点价截止日期', icon: 'none' })
  776 + return false
  777 + }
  778 + }
  779 + for (var j = 0; j < boolChecks.length; j++) {
  780 + var bc = boolChecks[j]
  781 + if (typeof d[bc.key] !== 'boolean') {
  782 + uni.showToast({ title: '请选择' + bc.title, icon: 'none' })
  783 + return false
  784 + }
  785 + }
  786 + var pr = this.$refs.productRel
  787 + if (pr && typeof pr.validate === 'function') {
  788 + if (!pr.validate()) return false
  789 + }
  790 + return true
  791 + },
  792 + onBack() {
  793 + uni.navigateBack({ delta: 1 })
  794 + },
  795 + joinStr(arr) {
  796 + if (Array.isArray(arr)) return arr.filter(Boolean).join(',')
  797 + if (typeof arr === 'string') return arr
  798 + return ''
  799 + },
  800 + pickId(v) {
  801 + if (v == null || v === '') return ''
  802 + if (typeof v === 'string' || typeof v === 'number') return String(v)
  803 + if (typeof v === 'object') {
  804 + return String(v.id != null ? v.id : (v.value != null ? v.value : (v.code != null ? v.code : '')))
  805 + }
  806 + return String(v)
  807 + },
  808 + boolToStr(v) {
  809 + return v === true ? 'true' : 'false'
  810 + },
  811 + buildPayload() {
  812 + var self = this
  813 + var d = this.detail || {}
  814 + var lines = Array.isArray(this.lineList) ? this.lineList.slice() : []
  815 + var workshopId = d.workshopId != null ? d.workshopId : ''
  816 + var lineList = lines.map(function (row, i) {
  817 + var r = row || {}
  818 + var itemId = r.itemId != null ? r.itemId : (r.id != null ? String(r.id) : (r._key != null ? r._key : ('line-' + Date.now() + '-' + i)))
  819 + if (!workshopId && r.workshopId != null) workshopId = r.workshopId
  820 + return {
  821 + productId: self.pickId(r.productId),
  822 + materialType: r.materialType != null ? String(r.materialType) : '',
  823 + quantity: r.quantity != null ? String(r.quantity) : '',
  824 + actualPurchasePrice: r.actualPurchasePrice != null ? String(r.actualPurchasePrice) : '',
  825 + includingShippingPrice: r.includingShippingPrice != null ? String(r.includingShippingPrice) : '',
  826 + priceListPrices: r.priceListPrices != null ? String(r.priceListPrices) : '',
  827 + coordinationRange: r.coordinationRange != null ? String(r.coordinationRange) : '',
  828 + estimatedLoss: r.estimatedLoss != null ? String(r.estimatedLoss) : '',
  829 + applicationAttrition: r.applicationAttrition != null ? String(r.applicationAttrition) : '',
  830 + paintDamageRatio: r.paintDamageRatio != null ? String(r.paintDamageRatio) : '',
  831 + workshopId: self.pickId(r.workshopId),
  832 + itemId: itemId
  833 + }
  834 + })
  835 + var body = {
  836 + id: this.id || d.id || '',
  837 + procurementPlanId: this.form.planId || d.id || '',
  838 + changeReason: d.changeReason != null ? String(d.changeReason) : '',
  839 + code: d.code != null ? String(d.code) : '',
  840 + companyShortId: this.pickId(d.companyShortId || d.companyId),
  841 + supplierId: this.pickId(d.supplierId),
  842 + purchaseDepartment: this.pickId(d.purchaseDepartment),
  843 + region: this.pickId(d.region),
  844 + date: d.date != null ? String(d.date).slice(0, 10) : '',
  845 + validityPeriod: d.validityPeriod != null ? String(d.validityPeriod) : '',
  846 + quoterId: this.pickId(d.quoterId),
  847 + workshopId: this.pickId(workshopId),
  848 + quoterName: d.quoterName != null ? String(d.quoterName) : '',
  849 + longTermOperation: this.boolToStr(d.longTermOperation),
  850 + terminalCustomer: this.boolToStr(d.terminalCustomer),
  851 + priced: this.boolToStr(d.priced),
  852 + pricingDeadline: d.pricingDeadline != null ? String(d.pricingDeadline) : '',
  853 + temporaryPrice: this.boolToStr(d.temporaryPrice),
  854 + otherExpenseSettlement: this.boolToStr(d.otherExpenseSettlement),
  855 + deliveryMode: d.deliveryMode != null ? String(d.deliveryMode) : '',
  856 + commodityBuyout: this.boolToStr(d.commodityBuyout),
  857 + qualityBuyout: this.boolToStr(d.qualityBuyout),
  858 + quantityBuyout: this.boolToStr(d.quantityBuyout),
  859 + doorDelivery: this.boolToStr(d.doorDelivery),
  860 + shippingCost: d.shippingCost != null ? String(d.shippingCost) : '',
  861 + loadingFee: d.loadingFee != null ? String(d.loadingFee) : '',
  862 + invoiceProductName: d.invoiceProductName != null ? String(d.invoiceProductName) : '',
  863 + deliveryDate: d.deliveryDate != null ? String(d.deliveryDate) : '',
  864 + settlementMethod: d.settlementMethod != null ? String(d.settlementMethod) : '',
  865 + settlementRatio: d.settlementRatio != null ? String(d.settlementRatio) : '',
  866 + priceId: this.pickId(d.priceId),
  867 + coordinationReason: d.coordinationReason != null ? String(d.coordinationReason) : '',
  868 + invoiceTypeStatus: d.invoiceTypeStatus != null ? String(d.invoiceTypeStatus) : '',
  869 + totalQuantity: d.totalQuantity != null ? String(d.totalQuantity) : '',
  870 + remark: d.remark != null ? String(d.remark) : '',
  871 + materialConditionEnabled: this.boolToStr(d.materialConditionEnabled),
  872 + lines: lineList
  873 + }
  874 + this.materialConditionConfigs.forEach(function (mc) {
  875 + body[mc.field] = self.joinStr(d[mc.field])
  876 + })
  877 + return body
  878 + },
  879 + async onSubmit() {
  880 + if (!this.validateForm()) return
  881 + var payload = this.buildPayload()
  882 + try {
  883 + await procurementPlanReplenishUpdateApi(payload)
  884 + uni.showToast({ title: '保存成功', icon: 'none' })
  885 + try {
  886 + uni.setStorageSync('SCHEDULE_PLAN_LIST_NEED_REFRESH', '1')
  887 + } catch (e) {}
  888 + var self = this
  889 + setTimeout(function () {
  890 + uni.navigateTo({ url: '/pages/schedule-plan/index' })
  891 + }, 400)
  892 + } catch (e) {
  893 + uni.showToast({ title: (e && (e.msg || e.message)) ? (e.msg || e.message) : '保存失败', icon: 'none' })
  894 + }
  895 + }
  896 + }
  897 +}
  898 +</script>
  899 +
  900 +<style lang="scss" scoped>
  901 +.page {
  902 + display: flex;
  903 + flex-direction: column;
  904 + height: 100%;
  905 +}
  906 +.scroll {
  907 + flex: 1;
  908 + padding: 12rpx 0 392rpx !important;
  909 +}
  910 +.bottom-bar {
  911 + z-index: 2;
  912 + position: fixed;
  913 + left: 0;
  914 + right: 0;
  915 + bottom: 0;
  916 + padding: 32rpx;
  917 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  918 + background: #fff;
  919 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  920 + display: flex;
  921 + gap: 24rpx;
  922 + .btn {
  923 + flex: 1;
  924 + height: 80rpx;
  925 + line-height: 80rpx;
  926 + border-radius: 12rpx;
  927 + font-size: 32rpx;
  928 + }
  929 + .btn-outline {
  930 + background: #fff;
  931 + color: $theme-primary;
  932 + border: 2rpx solid $theme-primary;
  933 + }
  934 + .btn-primary {
  935 + background: $theme-primary;
  936 + color: #fff;
  937 + border: 2rpx solid $theme-primary;
  938 + }
  939 +}
  940 +
  941 +::v-deep .uni-list {
  942 + .uni-easyinput {
  943 + display: flex;
  944 + .uni-input-input {
  945 + color: rgba(0, 0, 0, 0.9);
  946 + }
  947 + }
  948 + .uni-input-placeholder { z-index: 1; }
  949 + .uni-input-input { background-color: #ffffff; }
  950 + background: transparent;
  951 + &-item {
  952 + &__extra-text { font-size: 32rpx; }
  953 + &__content-title {
  954 + font-size: 32rpx;
  955 + color: rgba(0, 0, 0, 0.9);
  956 + }
  957 + &__container {
  958 + padding: 32rpx;
  959 + .uni-easyinput {
  960 + &__placeholder-class {
  961 + font-size: 32rpx;
  962 + color: rgba(0, 0, 0, 0.4);
  963 + }
  964 + &__content {
  965 + border: none;
  966 + background-color: #ffffff !important;
  967 + &-input {
  968 + padding-left: 0 !important;
  969 + height: 48rpx;
  970 + line-height: 48rpx;
  971 + font-size: 32rpx;
  972 + }
  973 + .content-clear-icon {
  974 + font-size: 44rpx !important;
  975 + }
  976 + }
  977 + }
  978 + .item-title,
  979 + .uni-list-item__content {
  980 + flex: none;
  981 + min-height: 48rpx;
  982 + line-height: 48rpx;
  983 + font-size: 32rpx;
  984 + position: relative;
  985 + width: 240rpx;
  986 + margin-right: 32rpx;
  987 + color: rgba(0, 0, 0, 0.9);
  988 + .required {
  989 + color: red;
  990 + position: absolute;
  991 + top: 50%;
  992 + transform: translateY(-50%);
  993 + left: -16rpx;
  994 + }
  995 + }
  996 + }
  997 + &.select-item {
  998 + &.is-empty {
  999 + .uni-list-item__extra-text {
  1000 + color: rgba(0, 0, 0, 0.4) !important;
  1001 + }
  1002 + }
  1003 + &.is-filled {
  1004 + .uni-list-item__extra-text {
  1005 + color: rgba(0, 0, 0, 0.9) !important;
  1006 + }
  1007 + }
  1008 + .serial-number-row {
  1009 + display: flex;
  1010 + align-items: center;
  1011 + }
  1012 + }
  1013 + }
  1014 +}
  1015 +
  1016 +.readonly-text {
  1017 + color: rgba(0, 0, 0, 0.9);
  1018 + font-size: 32rpx;
  1019 + line-height: 48rpx;
  1020 + text-align: right;
  1021 + white-space: pre-wrap;
  1022 + word-break: break-all;
  1023 +}
  1024 +.value-code {
  1025 + width: 260rpx;
  1026 + text-align: left;
  1027 +}
  1028 +
  1029 +.attach-list {
  1030 + flex: 1;
  1031 + display: flex;
  1032 + flex-direction: column;
  1033 + align-items: flex-end;
  1034 + gap: 8rpx;
  1035 +}
  1036 +.attach-item {
  1037 + display: flex;
  1038 + align-items: center;
  1039 + gap: 16rpx;
  1040 + .attach-name { font-size: 26rpx; color: rgba(0,0,0,0.9); }
  1041 + .attach-view { font-size: 26rpx; color: $theme-primary; }
  1042 +}
  1043 +
  1044 +.material-condition-section,
  1045 +.remark-section {
  1046 + margin-top: 20rpx;
  1047 + background: #fff;
  1048 +}
  1049 +.section-header {
  1050 + display: flex;
  1051 + align-items: center;
  1052 + padding: 24rpx 32rpx;
  1053 + border-bottom: 1rpx solid #f0f0f0;
  1054 +}
  1055 +.section-title {
  1056 + position: relative;
  1057 + font-size: 32rpx;
  1058 + color: rgba(0, 0, 0, 0.9);
  1059 + font-weight: 600;
  1060 + .required {
  1061 + color: red;
  1062 + position: absolute;
  1063 + top: 50%;
  1064 + transform: translateY(-50%);
  1065 + left: -16rpx;
  1066 + }
  1067 +}
  1068 +.opCollapse {
  1069 + width: 32rpx;
  1070 + height: 28rpx;
  1071 + margin-right: 16rpx;
  1072 + margin-top: 8rpx;
  1073 +}
  1074 +.section-content {
  1075 + padding: 32rpx;
  1076 +}
  1077 +.form-row {
  1078 + display: flex;
  1079 + align-items: center;
  1080 + justify-content: space-between;
  1081 + margin-bottom: 24rpx;
  1082 +}
  1083 +.form-row:last-child { margin-bottom: 0; }
  1084 +.form-label {
  1085 + font-size: 32rpx;
  1086 + color: rgba(0, 0, 0, 0.9);
  1087 +}
  1088 +.form-value {
  1089 + font-size: 32rpx;
  1090 + color: rgba(0, 0, 0, 0.9);
  1091 +}
  1092 +.toggle-link {
  1093 + color: $theme-primary;
  1094 +}
  1095 +.material-group {
  1096 + margin-top: 32rpx;
  1097 +}
  1098 +.material-label {
  1099 + display: block;
  1100 + font-size: 30rpx;
  1101 + color: rgba(0, 0, 0, 0.9);
  1102 + margin-bottom: 20rpx;
  1103 +}
  1104 +.tag-list {
  1105 + display: flex;
  1106 + flex-wrap: wrap;
  1107 + gap: 16rpx;
  1108 +}
  1109 +.tag-btn {
  1110 + padding: 12rpx 24rpx;
  1111 + border: 1rpx solid #ddd;
  1112 + border-radius: 8rpx;
  1113 + font-size: 28rpx;
  1114 + color: #666;
  1115 + background: #fff;
  1116 +}
  1117 +.tag-btn.active {
  1118 + background: $theme-primary;
  1119 + border-color: $theme-primary;
  1120 + color: #fff;
  1121 +}
  1122 +
  1123 +::v-deep .uni-easyinput {
  1124 + width: 100%;
  1125 + &__content {
  1126 + background: #f8f8f8 !important;
  1127 + border-radius: 8rpx;
  1128 + &-input { font-size: 30rpx; }
  1129 + }
  1130 +}
  1131 +</style>
... ...
  1 +<template>
  2 + <view class="product-rel">
  3 + <view class="header">
  4 + <image class="opCollapse" src="/static/images/title.png" />
  5 + <text class="title">明细信息</text>
  6 + <view class="ops">
  7 + <image v-if="mode === 'add' || mode === 'edit'" class="opAdd" @click="onAdd" src="/static/images/plus.png" />
  8 + </view>
  9 + </view>
  10 +
  11 + <view class="add-list">
  12 + <view v-for="(item, idx) in items" :key="item._key || idx" class="block">
  13 + <uni-list v-show="!item.collapsed">
  14 + <uni-list-item
  15 + class="select-item"
  16 + :class="item.productName ? 'is-filled' : 'is-empty'"
  17 + clickable
  18 + @click="openSelectSheet('product', idx)"
  19 + :rightText="item.productName || '请选择品种'"
  20 + showArrow
  21 + >
  22 + <template v-slot:body>
  23 + <view class="item-title">
  24 + <text class="required">*</text><text>品种</text>
  25 + </view>
  26 + </template>
  27 + </uni-list-item>
  28 +
  29 + <uni-list-item>
  30 + <template v-slot:body>
  31 + <view class="item-title"><text>料型</text></view>
  32 + </template>
  33 + <template v-slot:footer>
  34 + <uni-easyinput v-model="item.materialType" :inputBorder="false" placeholder="请输入料型" />
  35 + </template>
  36 + </uni-list-item>
  37 +
  38 + <uni-list-item>
  39 + <template v-slot:body>
  40 + <view class="item-title">
  41 + <text class="required">*</text><text>数量(吨)</text>
  42 + </view>
  43 + </template>
  44 + <template v-slot:footer>
  45 + <uni-easyinput
  46 + v-model="item.quantity"
  47 + type="digit"
  48 + :inputBorder="false"
  49 + placeholder="请输入数量"
  50 + @input="onNonNegativeInput(idx, 'quantity')"
  51 + @blur="onNonNegativeBlur(idx, 'quantity', 1)"
  52 + @change="recalcAll(idx)"
  53 + />
  54 + </template>
  55 + </uni-list-item>
  56 +
  57 + <uni-list-item>
  58 + <template v-slot:body>
  59 + <view class="item-title">
  60 + <text class="required">*</text><text>实际采购价</text>
  61 + </view>
  62 + </template>
  63 + <template v-slot:footer>
  64 + <uni-easyinput
  65 + v-model="item.actualPurchasePrice"
  66 + type="digit"
  67 + :inputBorder="false"
  68 + placeholder="请输入实际采购价"
  69 + @input="onNonNegativeInput(idx, 'actualPurchasePrice')"
  70 + @blur="onNonNegativeBlur(idx, 'actualPurchasePrice', 2)"
  71 + @change="recalcAll(idx)"
  72 + />
  73 + </template>
  74 + </uni-list-item>
  75 +
  76 + <uni-list-item title="含运到厂价">
  77 + <template v-slot:footer>
  78 + <text class="lock-value">{{ formatTextNumber(item.includingShippingPrice) }}</text>
  79 + </template>
  80 + </uni-list-item>
  81 +
  82 + <uni-list-item title="价格表价格">
  83 + <template v-slot:footer>
  84 + <text class="lock-value">{{ formatTextNumber(item.priceListPrices) }}</text>
  85 + </template>
  86 + </uni-list-item>
  87 +
  88 + <uni-list-item title="买断料预计损耗">
  89 + <template v-slot:footer>
  90 + <text class="lock-value">{{ formatTextNumber(item.estimatedLoss) }}</text>
  91 + </template>
  92 + </uni-list-item>
  93 +
  94 + <uni-list-item>
  95 + <template v-slot:body>
  96 + <view class="item-title"><text>申请损耗(%)</text></view>
  97 + </template>
  98 + <template v-slot:footer>
  99 + <uni-easyinput
  100 + v-model="item.applicationAttrition"
  101 + type="digit"
  102 + :inputBorder="false"
  103 + placeholder="请输入申请损耗"
  104 + @input="onNonNegativeInput(idx, 'applicationAttrition')"
  105 + @blur="onNonNegativeBlur(idx, 'applicationAttrition', 2)"
  106 + @change="recalcAll(idx)"
  107 + />
  108 + </template>
  109 + </uni-list-item>
  110 +
  111 + <uni-list-item>
  112 + <template v-slot:body>
  113 + <view class="item-title"><text>漆损率(%)</text></view>
  114 + </template>
  115 + <template v-slot:footer>
  116 + <uni-easyinput
  117 + v-model="item.paintDamageRatio"
  118 + type="digit"
  119 + :inputBorder="false"
  120 + placeholder="请输入漆损率"
  121 + @input="onNonNegativeInput(idx, 'paintDamageRatio')"
  122 + @blur="onNonNegativeBlur(idx, 'paintDamageRatio', 2)"
  123 + />
  124 + </template>
  125 + </uni-list-item>
  126 +
  127 + <uni-list-item title="协调幅度">
  128 + <template v-slot:footer>
  129 + <text class="lock-value">{{ formatTextNumber(item.coordinationRange) }}</text>
  130 + </template>
  131 + </uni-list-item>
  132 +
  133 + <uni-list-item
  134 + class="select-item"
  135 + :class="item.workshopName ? 'is-filled' : 'is-empty'"
  136 + clickable
  137 + @click="openSelectSheet('workshop', idx)"
  138 + :rightText="item.workshopName || '请选择分厂'"
  139 + showArrow
  140 + >
  141 + <template v-slot:body>
  142 + <view class="item-title"><text>分厂</text></view>
  143 + </template>
  144 + </uni-list-item>
  145 + </uni-list>
  146 +
  147 + <uni-list v-show="item.collapsed">
  148 + <uni-list-item
  149 + class="select-item"
  150 + :class="item.productName ? 'is-filled' : 'is-empty'"
  151 + clickable
  152 + @click="openSelectSheet('product', idx)"
  153 + :rightText="item.productName || '请选择品种'"
  154 + showArrow
  155 + >
  156 + <template v-slot:body>
  157 + <view class="item-title">
  158 + <text class="required">*</text><text>品种</text>
  159 + </view>
  160 + </template>
  161 + </uni-list-item>
  162 + </uni-list>
  163 +
  164 + <view class="block-ops">
  165 + <div class="del" @click="onRemove(idx)">
  166 + <image src="/static/images/delete.png" class="icon" />
  167 + 删除
  168 + </div>
  169 + <div class="toggle" @click="toggleItem(idx)">
  170 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" class="icon" />
  171 + {{ item.collapsed ? '展开' : '收起' }}
  172 + </div>
  173 + </view>
  174 + </view>
  175 + </view>
  176 +
  177 + <SingleSelectSheet
  178 + :visible.sync="sheet.visible"
  179 + :title="sheet.title"
  180 + :options="sheet.options"
  181 + v-model="sheet.value"
  182 + @confirm="onSheetConfirm"
  183 + />
  184 + </view>
  185 +</template>
  186 +
  187 +<script>
  188 +import SingleSelectSheet from '@/components/single-select/index.vue'
  189 +
  190 +export default {
  191 + name: 'SchedulePlanProductRel',
  192 + components: { SingleSelectSheet },
  193 + props: {
  194 + mode: { type: String, default: 'edit' },
  195 + list: { type: Array, default: function () { return [] } },
  196 + max: { type: Number, default: 50 },
  197 + productOptions: { type: Array, default: function () { return [] } },
  198 + workshopOptions: { type: Array, default: function () { return [] } },
  199 + shippingCost: { type: [String, Number], default: '' },
  200 + priceMap: { type: Object, default: function () { return {} } }
  201 + },
  202 + data() {
  203 + return {
  204 + items: [],
  205 + sheet: { visible: false, title: '请选择', options: [], value: '', idx: -1, type: '' },
  206 + _initialized: false,
  207 + _emitSuppressed: false,
  208 + _lastEmitSignature: ''
  209 + }
  210 + },
  211 + computed: {
  212 + productOptsComputed() {
  213 + var list = Array.isArray(this.productOptions) ? this.productOptions : []
  214 + return list.map(function (o) {
  215 + return {
  216 + label: o.label != null ? o.label : (o.name != null ? o.name : (o.productName || '')),
  217 + value: o.value != null ? o.value : (o.id != null ? o.id : o.productId)
  218 + }
  219 + })
  220 + },
  221 + workshopOptsComputed() {
  222 + var list = Array.isArray(this.workshopOptions) ? this.workshopOptions : []
  223 + return list.map(function (o) {
  224 + return {
  225 + label: o.label != null ? o.label : (o.name != null ? o.name : (o.workshopName || '')),
  226 + value: o.value != null ? o.value : (o.id != null ? o.id : o.workshopId)
  227 + }
  228 + })
  229 + },
  230 + shippingCostNum() {
  231 + var v = this.shippingCost
  232 + if (v == null || v === '') return 0
  233 + var n = Number(v)
  234 + return isNaN(n) ? 0 : n
  235 + }
  236 + },
  237 + watch: {
  238 + items: {
  239 + handler() {
  240 + this.emitChange()
  241 + },
  242 + deep: true
  243 + },
  244 + list: {
  245 + handler(newList) {
  246 + if (this._emitSuppressed) return
  247 + if (this.isListSameAsItems(newList)) return
  248 + this._emitSuppressed = true
  249 + this._initialized = false
  250 + this.initItems()
  251 + var self = this
  252 + this.$nextTick(function () {
  253 + self._initialized = true
  254 + self.recalcAllItems()
  255 + self.$nextTick(function () {
  256 + self._emitSuppressed = false
  257 + })
  258 + })
  259 + },
  260 + immediate: false
  261 + }
  262 + },
  263 + created() {
  264 + this._emitSuppressed = true
  265 + this.initItems()
  266 + var self = this
  267 + this.$nextTick(function () {
  268 + self._initialized = true
  269 + self.recalcAllItems()
  270 + self.$nextTick(function () {
  271 + self._emitSuppressed = false
  272 + })
  273 + })
  274 + },
  275 + methods: {
  276 + initItems() {
  277 + var src = Array.isArray(this.list) && this.list.length > 0 ? this.list : []
  278 + if (!src.length) {
  279 + if (this.mode === 'add' || this.mode === 'edit') {
  280 + this.items = [Object.assign({}, this.defaultItem(), { _key: this.newKey(), collapsed: false })]
  281 + } else {
  282 + this.items = []
  283 + }
  284 + return
  285 + }
  286 + var existing = this.items || []
  287 + var existingMap = {}
  288 + existing.forEach(function (it) {
  289 + if (it.itemId) existingMap[it.itemId] = it
  290 + })
  291 + var self = this
  292 + this.items = src.map(function (x, i) {
  293 + var key = x && x.itemId ? x.itemId : (x && x._key ? x._key : self.newKey())
  294 + var old = existingMap[key]
  295 + var collapsed = old ? old.collapsed : (typeof x.collapsed === 'boolean' ? x.collapsed : false)
  296 + return Object.assign({}, self.defaultItem(), x, {
  297 + _key: key,
  298 + itemId: x && x.itemId ? x.itemId : key,
  299 + collapsed: collapsed
  300 + })
  301 + })
  302 + },
  303 + newKey() {
  304 + return Date.now() + '-' + Math.random().toString(16).slice(2)
  305 + },
  306 + defaultItem() {
  307 + return {
  308 + productId: '',
  309 + productName: '',
  310 + materialType: '',
  311 + quantity: '',
  312 + actualPurchasePrice: '',
  313 + includingShippingPrice: '',
  314 + priceListPrices: '',
  315 + coordinationRange: '',
  316 + estimatedLoss: '',
  317 + applicationAttrition: '',
  318 + paintDamageRatio: '',
  319 + workshopId: '',
  320 + workshopName: '',
  321 + fixedLossRate: ''
  322 + }
  323 + },
  324 + onNonNegativeInput(idx, field) {
  325 + var it = this.items[idx]
  326 + if (!it) return
  327 + var v = String(it[field] != null ? it[field] : '')
  328 + v = v.replace(/[^0-9.]/g, '')
  329 + v = v.replace(/(\..*)\./g, '$1')
  330 + it[field] = v
  331 + this.$set(this.items, idx, it)
  332 + },
  333 + onNonNegativeBlur(idx, field, digits) {
  334 + var it = this.items[idx]
  335 + if (!it) return
  336 + var raw = it[field]
  337 + if (raw === '' || raw === null || raw === undefined) {
  338 + this.$set(this.items, idx, it)
  339 + return
  340 + }
  341 + var val = parseFloat(raw)
  342 + if (isNaN(val)) val = 0
  343 + var m = Math.pow(10, digits)
  344 + var rounded = Math.round(val * m) / m
  345 + it[field] = rounded
  346 + this.$set(this.items, idx, it)
  347 + },
  348 + getProductOption(productId) {
  349 + var pid = productId != null ? String(productId) : ''
  350 + if (!pid) return null
  351 + var pOpts = Array.isArray(this.productOptions) ? this.productOptions : []
  352 + for (var i = 0; i < pOpts.length; i++) {
  353 + var o = pOpts[i]
  354 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.value != null ? String(o.value) : ''))
  355 + if (id === pid) return o
  356 + }
  357 + return null
  358 + },
  359 + getPriceFromMap(productId, productName) {
  360 + var pid = productId != null ? String(productId) : ''
  361 + var pname = (productName || '').trim()
  362 + var map = this.priceMap || {}
  363 + if (pid && map[pid] != null) {
  364 + var v = map[pid]
  365 + if (typeof v === 'object' && v != null) {
  366 + return v.price != null ? Number(v.price) : null
  367 + }
  368 + return Number(v)
  369 + }
  370 + if (pname) {
  371 + for (var k in map) {
  372 + if (!Object.prototype.hasOwnProperty.call(map, k)) continue
  373 + var meta = map[k]
  374 + if (meta && typeof meta === 'object' && meta.meta) {
  375 + var mm = meta.meta
  376 + if ((mm.productName && mm.productName === pname) || (mm.breedName && mm.breedName === pname) || (mm.varietyName && mm.varietyName === pname)) {
  377 + return meta.price != null ? Number(meta.price) : null
  378 + }
  379 + }
  380 + }
  381 + }
  382 + return null
  383 + },
  384 + recalcAll(idx) {
  385 + var it = this.items[idx]
  386 + if (!it) return
  387 + var self = this
  388 +
  389 + var actualPriceRaw = it.actualPurchasePrice
  390 + var actualPrice = parseFloat(actualPriceRaw)
  391 + var actualPriceIsNumber = actualPriceRaw !== '' && actualPriceRaw != null && !isNaN(actualPrice)
  392 +
  393 + if (actualPriceIsNumber) {
  394 + it.includingShippingPrice = this.round2(actualPrice + this.shippingCostNum)
  395 + } else {
  396 + it.includingShippingPrice = ''
  397 + }
  398 +
  399 + var pid = it.productId
  400 + var pname = (it.productName || '').trim()
  401 + if (pid || pname) {
  402 + var priceFromMap = this.getPriceFromMap(pid, pname)
  403 + if (priceFromMap != null && !isNaN(priceFromMap)) {
  404 + it.priceListPrices = this.round2(priceFromMap)
  405 + }
  406 + } else {
  407 + it.priceListPrices = ''
  408 + }
  409 +
  410 + var estimatedLoss = ''
  411 + if (actualPriceIsNumber) {
  412 + var app = it.applicationAttrition
  413 + var appNum = parseFloat(app)
  414 + var appHasVal = app !== '' && app != null && !isNaN(appNum)
  415 + if (appHasVal) {
  416 + estimatedLoss = this.round2(actualPrice * appNum / 100)
  417 + } else {
  418 + var pOpt = this.getProductOption(it.productId)
  419 + var fixedRate = null
  420 + if (pOpt) {
  421 + fixedRate = pOpt.fixedLossRate != null ? pOpt.fixedLossRate : (pOpt.lossRate != null ? pOpt.lossRate : (pOpt.attritionRate != null ? pOpt.attritionRate : null))
  422 + }
  423 + var fixedNum = parseFloat(fixedRate)
  424 + if (!isNaN(fixedNum)) {
  425 + estimatedLoss = this.round2(actualPrice * fixedNum / 100)
  426 + }
  427 + }
  428 + }
  429 + it.estimatedLoss = estimatedLoss
  430 +
  431 + var incShip = parseFloat(it.includingShippingPrice)
  432 + var estLoss = parseFloat(it.estimatedLoss)
  433 + var priceList = parseFloat(it.priceListPrices)
  434 + var hasAll = !isNaN(incShip) && !isNaN(estLoss) && !isNaN(priceList)
  435 + if (hasAll) {
  436 + it.coordinationRange = this.round2(incShip + estLoss - priceList)
  437 + } else {
  438 + it.coordinationRange = ''
  439 + }
  440 +
  441 + this.$set(this.items, idx, it)
  442 + },
  443 + recalcAllItems() {
  444 + var len = (this.items || []).length
  445 + for (var i = 0; i < len; i++) {
  446 + this.recalcAll(i)
  447 + }
  448 + },
  449 + round2(v) {
  450 + var n = Number(v)
  451 + if (isNaN(n)) return ''
  452 + return Math.round(n * 100) / 100
  453 + },
  454 + onAdd() {
  455 + if (this.items.length >= this.max) {
  456 + uni.showToast({ title: '最多' + this.max + '条明细', icon: 'none' })
  457 + return
  458 + }
  459 + this.items.push(Object.assign({}, this.defaultItem(), { _key: this.newKey(), collapsed: false }))
  460 + },
  461 + onRemove(idx) {
  462 + this.items.splice(idx, 1)
  463 + if ((this.mode === 'add' || this.mode === 'edit') && this.items.length === 0) {
  464 + this.items.push(Object.assign({}, this.defaultItem(), { _key: this.newKey(), collapsed: false }))
  465 + }
  466 + },
  467 + toggleItem(idx) {
  468 + var it = this.items[idx]
  469 + if (!it) return
  470 + this.$set(it, 'collapsed', !it.collapsed)
  471 + },
  472 + openSelectSheet(type, idx) {
  473 + if (type === 'product') {
  474 + var pOpts = this.productOptsComputed
  475 + var curP = this.items[idx] && this.items[idx].productId
  476 + var mP = pOpts.find(function (o) { return String(o.value) === String(curP) })
  477 + this.sheet = { visible: true, title: '请选择品种', options: pOpts, value: mP ? mP.value : '', idx: idx, type: type }
  478 + } else if (type === 'workshop') {
  479 + var wOpts = this.workshopOptsComputed
  480 + var curW = this.items[idx] && this.items[idx].workshopId
  481 + var mW = wOpts.find(function (o) { return String(o.value) === String(curW) })
  482 + this.sheet = { visible: true, title: '请选择分厂', options: wOpts, value: mW ? mW.value : '', idx: idx, type: type }
  483 + }
  484 + },
  485 + onSheetConfirm(_ref) {
  486 + var value = _ref.value
  487 + var label = _ref.label
  488 + var idx = this.sheet.idx
  489 + var type = this.sheet.type
  490 + if (idx < 0 || !this.items[idx]) return
  491 + var it = this.items[idx]
  492 + if (type === 'product') {
  493 + this.$set(it, 'productId', value)
  494 + this.$set(it, 'productName', label)
  495 + var pOpt = this.getProductOption(value)
  496 + if (pOpt) {
  497 + var rate = pOpt.fixedLossRate != null ? pOpt.fixedLossRate : (pOpt.lossRate != null ? pOpt.lossRate : (pOpt.attritionRate != null ? pOpt.attritionRate : ''))
  498 + this.$set(it, 'fixedLossRate', rate != null ? rate : '')
  499 + }
  500 + this.recalcAll(idx)
  501 + } else if (type === 'workshop') {
  502 + this.$set(it, 'workshopId', value)
  503 + this.$set(it, 'workshopName', label)
  504 + }
  505 + },
  506 + fillLineNames() {
  507 + if (!Array.isArray(this.items) || !this.items.length) return
  508 + var pOpts = Array.isArray(this.productOptions) ? this.productOptions : []
  509 + var wOpts = Array.isArray(this.workshopOptions) ? this.workshopOptions : []
  510 + var self = this
  511 + this.items = this.items.map(function (row) {
  512 + var r = Object.assign({}, row)
  513 + var pid = r.productId != null ? String(r.productId) : ''
  514 + var wid = r.workshopId != null ? String(r.workshopId) : ''
  515 + if ((r.productName == null || String(r.productName).trim() === '') && pid) {
  516 + var p = pOpts.find(function (o) {
  517 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.value != null ? String(o.value) : ''))
  518 + return id === pid
  519 + })
  520 + if (p) {
  521 + r.productName = p.name != null ? p.name : (p.productName != null ? p.productName : (p.label != null ? p.label : ''))
  522 + }
  523 + }
  524 + if ((r.workshopName == null || String(r.workshopName).trim() === '') && wid) {
  525 + var w = wOpts.find(function (o) {
  526 + var id = o.id != null ? String(o.id) : (o.workshopId != null ? String(o.workshopId) : (o.value != null ? String(o.value) : ''))
  527 + return id === wid
  528 + })
  529 + if (w) {
  530 + r.workshopName = w.name != null ? w.name : (w.workshopName != null ? w.workshopName : (w.label != null ? w.label : ''))
  531 + }
  532 + }
  533 + return r
  534 + })
  535 + this.$nextTick(function () {
  536 + self.recalcAllItems()
  537 + self.emitChange()
  538 + })
  539 + },
  540 + emitChange() {
  541 + if (!this._initialized) return
  542 + if (this._emitSuppressed) return
  543 + var self = this
  544 + var list = (this.items || []).map(function (it) {
  545 + var c = Object.assign({}, it)
  546 + var key = c._key
  547 + delete c._key
  548 + delete c.collapsed
  549 + delete c._selected
  550 + delete c.fixedLossRate
  551 + if (!c.itemId) c.itemId = key
  552 + return c
  553 + })
  554 + var sig = list.length + '|' + list.map(function (r) {
  555 + return [r.itemId, r.productId, r.productName, r.materialType, r.quantity, r.actualPurchasePrice, r.includingShippingPrice, r.priceListPrices, r.coordinationRange, r.estimatedLoss, r.applicationAttrition, r.paintDamageRatio, r.workshopId, r.workshopName].join('~')
  556 + }).join('||')
  557 + if (sig === this._lastEmitSignature) return
  558 + this._lastEmitSignature = sig
  559 + this.$emit('change', list)
  560 + },
  561 + isListSameAsItems(newList) {
  562 + var a = Array.isArray(newList) ? newList : []
  563 + var b = (this.items || []).map(function (it) {
  564 + var c = Object.assign({}, it)
  565 + var key = c._key
  566 + delete c._key
  567 + delete c.collapsed
  568 + delete c._selected
  569 + delete c.fixedLossRate
  570 + if (!c.itemId) c.itemId = key
  571 + return c
  572 + })
  573 + if (a.length !== b.length) return false
  574 + for (var i = 0; i < a.length; i++) {
  575 + var x = a[i] || {}
  576 + var y = b[i] || {}
  577 + if ((x.itemId || '') !== (y.itemId || '')) return false
  578 + if (x.productId !== y.productId) return false
  579 + if (x.productName !== y.productName) return false
  580 + if (x.materialType !== y.materialType) return false
  581 + if (x.quantity !== y.quantity) return false
  582 + if (x.actualPurchasePrice !== y.actualPurchasePrice) return false
  583 + if (x.includingShippingPrice !== y.includingShippingPrice) return false
  584 + if (x.priceListPrices !== y.priceListPrices) return false
  585 + if (x.coordinationRange !== y.coordinationRange) return false
  586 + if (x.estimatedLoss !== y.estimatedLoss) return false
  587 + if (x.applicationAttrition !== y.applicationAttrition) return false
  588 + if (x.paintDamageRatio !== y.paintDamageRatio) return false
  589 + if (x.workshopId !== y.workshopId) return false
  590 + if (x.workshopName !== y.workshopName) return false
  591 + }
  592 + return true
  593 + },
  594 + safeText(v) {
  595 + var s = v == null ? '' : String(v)
  596 + return s.trim() ? s : '-'
  597 + },
  598 + formatTextNumber(v) {
  599 + if (v == null || v === '') return '-'
  600 + var n = Number(v)
  601 + if (isNaN(n)) return String(v)
  602 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  603 + },
  604 + validate() {
  605 + var items = this.items || []
  606 + if (!items.length) {
  607 + uni.showToast({ title: '请添加明细', icon: 'none' })
  608 + return false
  609 + }
  610 + for (var i = 0; i < items.length; i++) {
  611 + var it = items[i]
  612 + if (!it.productId && !it.productName) {
  613 + uni.showToast({ title: '请填写第' + (i + 1) + '条明细的品种', icon: 'none' })
  614 + return false
  615 + }
  616 + if (it.quantity === '' || it.quantity === null || it.quantity === undefined) {
  617 + uni.showToast({ title: '请填写第' + (i + 1) + '条明细的数量', icon: 'none' })
  618 + return false
  619 + }
  620 + if (it.actualPurchasePrice === '' || it.actualPurchasePrice === null || it.actualPurchasePrice === undefined) {
  621 + uni.showToast({ title: '请填写第' + (i + 1) + '条明细的实际采购价', icon: 'none' })
  622 + return false
  623 + }
  624 + }
  625 + return true
  626 + },
  627 + clearItems() {
  628 + this._emitSuppressed = true
  629 + this._initialized = false
  630 + this.items = [Object.assign({}, this.defaultItem(), { _key: this.newKey(), collapsed: false })]
  631 + var self = this
  632 + this.$nextTick(function () {
  633 + self._initialized = true
  634 + self.recalcAllItems()
  635 + self.$nextTick(function () {
  636 + self._emitSuppressed = false
  637 + })
  638 + })
  639 + }
  640 + }
  641 +}
  642 +</script>
  643 +
  644 +<style lang="scss" scoped>
  645 +.product-rel {
  646 + margin-top: 20rpx;
  647 + background: #fff;
  648 +}
  649 +.header {
  650 + display: flex;
  651 + align-items: center;
  652 + padding: 24rpx 32rpx;
  653 + border-bottom: 1rpx solid #f0f0f0;
  654 +}
  655 +.title {
  656 + font-size: 32rpx;
  657 + color: rgba(0, 0, 0, 0.9);
  658 + font-weight: 600;
  659 +}
  660 +.ops {
  661 + margin-left: auto;
  662 +}
  663 +.opAdd {
  664 + color: rgba(0, 0, 0, 0.6);
  665 + width: 40rpx;
  666 + height: 40rpx;
  667 +}
  668 +.opCollapse {
  669 + color: rgba(0, 0, 0, 0.6);
  670 + width: 32rpx;
  671 + height: 28rpx;
  672 + margin-right: 16rpx;
  673 + margin-top: 8rpx;
  674 +}
  675 +.block {
  676 + background: #fff;
  677 + margin-bottom: 20rpx;
  678 +}
  679 +::v-deep .uni-list-item__content {
  680 + display: flex;
  681 + justify-content: center;
  682 +}
  683 +::v-deep .uni-list {
  684 + .uni-easyinput {
  685 + display: flex;
  686 + .uni-input-input {
  687 + color: rgba(0, 0, 0, 0.9);
  688 + }
  689 + }
  690 + .uni-input-placeholder { z-index: 1; }
  691 + .uni-input-input { background-color: #ffffff; }
  692 + background: transparent;
  693 + &-item {
  694 + &__container { padding: 32rpx; }
  695 + &__content-title {
  696 + font-size: 28rpx;
  697 + color: rgba(0, 0, 0, 0.9);
  698 + }
  699 + &__extra-text { font-size: 32rpx; }
  700 + .uni-easyinput {
  701 + width: 100%;
  702 + &__placeholder-class {
  703 + font-size: 32rpx;
  704 + color: rgba(0, 0, 0, 0.4);
  705 + }
  706 + &__content {
  707 + border: none;
  708 + background-color: #ffffff !important;
  709 + display: flex;
  710 + &-input {
  711 + padding-left: 0 !important;
  712 + height: 48rpx;
  713 + line-height: 48rpx;
  714 + font-size: 32rpx;
  715 + }
  716 + }
  717 + }
  718 + &.select-item {
  719 + &.is-empty {
  720 + .uni-list-item__extra-text { color: rgba(0, 0, 0, 0.4) !important; }
  721 + }
  722 + &.is-filled {
  723 + .uni-list-item__extra-text { color: rgba(0, 0, 0, 0.9) !important; }
  724 + }
  725 + }
  726 + }
  727 +}
  728 +
  729 +::v-deep .uni-easyinput {
  730 + width: 100%;
  731 + &__content {
  732 + background: #f8f8f8 !important;
  733 + border-radius: 8rpx;
  734 + &-input { font-size: 30rpx; }
  735 + }
  736 +}
  737 +.block-ops {
  738 + display: flex;
  739 + padding: 20rpx 32rpx 20rpx;
  740 + justify-content: space-around;
  741 +}
  742 +.del {
  743 + color: #D54941;
  744 + font-size: 28rpx;
  745 + display: flex;
  746 + align-items: center;
  747 + image { width: 40rpx; height: 40rpx; }
  748 +}
  749 +.toggle {
  750 + color: $theme-primary;
  751 + font-size: 28rpx;
  752 + display: flex;
  753 + align-items: center;
  754 + image { width: 40rpx; height: 40rpx; }
  755 +}
  756 +.item-title {
  757 + position: relative;
  758 + width: 210rpx;
  759 + margin-right: 32rpx;
  760 + color: rgba(0, 0, 0, 0.9);
  761 + font-size: 32rpx;
  762 + min-height: 48rpx;
  763 + line-height: 48rpx;
  764 + .required {
  765 + color: red;
  766 + position: absolute;
  767 + top: 50%;
  768 + transform: translateY(-50%);
  769 + left: -16rpx;
  770 + }
  771 +}
  772 +.lock-value {
  773 + flex: 1;
  774 + text-align: right;
  775 + font-size: 32rpx;
  776 + color: rgba(0, 0, 0, 0.85);
  777 + padding: 8rpx 0;
  778 +}
  779 +</style>
... ...