Commit e3311a55e43512298281df5c210fc0c67316842b

Authored by gesilong
1 parent 767e0550

commit:计划单联调开发

  1 +import request from '@/utils/request'
  2 +
  3 +export function buyoutApplyDetailByPlanIdApi(planId) {
  4 + return request({
  5 + url: '/procurement/buyout/apply/detailByPlanId',
  6 + method: 'get',
  7 + params: { planId: planId }
  8 + })
  9 +}
  10 +
  11 +export function buyoutApplyCreateApi(data) {
  12 + return request({
  13 + url: '/procurement/buyout/apply/create',
  14 + method: 'post',
  15 + data: data,
  16 + contentType: 'application/json'
  17 + })
  18 +}
  19 +
  20 +export function buyoutApplyAbolishApi(planId) {
  21 + return request({
  22 + url: '/procurement/buyout/apply/abolish',
  23 + method: 'post',
  24 + params: { planId: planId }
  25 + })
  26 +}
... ...
... ... @@ -413,6 +413,62 @@
413 413 }
414 414 },
415 415 {
  416 + "path": "pages/domestic-plan/index",
  417 + "style": {
  418 + "navigationBarTitleText": "内贸计划单",
  419 + "navigationBarBackgroundColor": "#ffffff",
  420 + "navigationBarTextStyle": "black"
  421 + }
  422 + },
  423 + {
  424 + "path": "pages/domestic-plan/detail",
  425 + "style": {
  426 + "navigationBarTitleText": "内贸计划单详情",
  427 + "navigationBarBackgroundColor": "#ffffff",
  428 + "navigationBarTextStyle": "black"
  429 + }
  430 + },
  431 + {
  432 + "path": "pages/domestic-plan/supplement",
  433 + "style": {
  434 + "navigationBarTitleText": "内贸计划单补充",
  435 + "navigationBarBackgroundColor": "#ffffff",
  436 + "navigationBarTextStyle": "black"
  437 + }
  438 + },
  439 + {
  440 + "path": "pages/domestic-plan/selectWorkshop",
  441 + "style": {
  442 + "navigationBarTitleText": "选择分厂",
  443 + "navigationBarBackgroundColor": "#ffffff",
  444 + "navigationBarTextStyle": "black"
  445 + }
  446 + },
  447 + {
  448 + "path": "pages/domestic-plan/viewBuyoutApply",
  449 + "style": {
  450 + "navigationBarTitleText": "查看买断操作申请单",
  451 + "navigationBarBackgroundColor": "#ffffff",
  452 + "navigationBarTextStyle": "black"
  453 + }
  454 + },
  455 + // {
  456 + // "path": "pages/schedule-plan/index",
  457 + // "style": {
  458 + // "navigationBarTitleText": "计划变更单",
  459 + // "navigationBarBackgroundColor": "#ffffff",
  460 + // "navigationBarTextStyle": "black"
  461 + // }
  462 + // },
  463 + // {
  464 + // "path": "pages/supple-plan/index",
  465 + // "style": {
  466 + // "navigationBarTitleText": "计划补录单",
  467 + // "navigationBarBackgroundColor": "#ffffff",
  468 + // "navigationBarTextStyle": "black"
  469 + // }
  470 + // },
  471 + {
416 472 "path": "pages/order_list/index",
417 473 "style": {
418 474 "navigationBarTitleText": "订货单列表",
... ...
... ... @@ -82,6 +82,7 @@
82 82 import DetailButtons from '@/components/detail-buttons/index.vue'
83 83 import ProductRel from './productRel.vue'
84 84 import { procurementPlanDetailApi, procurementPlanGenerateContractApi, procurementPlanSubmitAuditApi, procurementPlanSubmitApi, procurementPlanStopApi } from '@/api/procure-manage/procurementPlan.js'
  85 +import { buyoutApplyCreateApi, buyoutApplyAbolishApi } from '@/api/procure-manage/buyout.js'
85 86 import { getDicByCodes, getDicName } from '@/utils/dic.js'
86 87 import { getInfo } from '@/api/login.js'
87 88 import { priceTableQueryApi, breedRelationshipQueryApi, workshopQueryApi } from '@/api/devManage.js'
... ... @@ -140,7 +141,7 @@ export default {
140 141 { text: '生成买断操作申请单', variant: 'outline', event: 'generate' },
141 142 { text: '废除买断操作申请单', variant: 'danger', event: 'cancel' },
142 143 { text: '查看买断操作申请单', variant: 'outline', event: 'look' },
143   - { text: '上传附件', variant: 'primary', event: 'upload' }
  144 + // { text: '上传附件', variant: 'primary', event: 'upload' }
144 145 ]
145 146 }
146 147 },
... ... @@ -197,7 +198,7 @@ export default {
197 198 generate: this.hasPerm('plan-manage:domestic-plan:generate'),
198 199 cancel: this.hasPerm('plan-manage:domestic-plan:cancel'),
199 200 look: this.hasPerm('plan-manage:domestic-plan:look'),
200   - upload: this.hasPerm('plan-manage:domestic-plan:upload')
  201 + // upload: this.hasPerm('plan-manage:domestic-plan:upload')
201 202 }
202 203 var visibleMap = {
203 204 supplement: inStatus([SC.TO_SUPPLEMENT]) && perms.supplement,
... ... @@ -209,10 +210,10 @@ export default {
209 210 approve: (inStatus([SC.AUDIT, SC.REFUSE]) && aStatus === 'AUDIT' && !!f.showExamine) && perms.approve,
210 211 approveDetail: !!f.showExamineDetail && (inStatus([SC.AUDIT, SC.COMPLETED, SC.REFUSE])) && perms.approveDetail,
211 212 print: inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED, SC.ABORTED, SC.REFUSE]) && perms.print,
212   - generateBuyoutApply: !!f.showGenerateBuyoutApply && inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED]) && perms.generateBuyoutApply,
213   - abolishBuyoutApply: !!f.showAbolishBuyoutApply && inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED]) && perms.abolishBuyoutApply,
214   - viewBuyoutApply: inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED, SC.REFUSE]) && perms.viewBuyoutApply,
215   - uploadAttachment: inStatus([SC.COMPLETED]) && !!this.planRoleFlags.isPlanner && perms.uploadAttachment
  213 + generate: !!f.showGenerateBuyoutApply && inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED]) && perms.generateBuyoutApply,
  214 + cancel: !!f.showAbolishBuyoutApply && inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED]) && perms.abolishBuyoutApply,
  215 + look: inStatus([SC.TO_SUBMIT_REVIEW, SC.AUDIT, SC.COMPLETED, SC.REFUSE]) && perms.viewBuyoutApply,
  216 + // uploadAttachment: inStatus([SC.COMPLETED]) && !!this.planRoleFlags.isPlanner && perms.uploadAttachment
216 217 }
217 218 var out = []
218 219 for (var i = 0; i < this.buttonTemplates.length; i++) {
... ... @@ -416,7 +417,7 @@ export default {
416 417 if (e === 'print') return this.onPrint()
417 418 if (e === 'generateBuyoutApply') return this.onGenerateBuyoutApply()
418 419 if (e === 'abolishBuyoutApply') return this.onAbolishBuyoutApply()
419   - if (e === 'viewBuyoutApply') return this.onViewBuyoutApply()
  420 + if (e === 'look') return this.onViewBuyoutApply()
420 421 if (e === 'uploadAttachment') return this.onUploadAttachment()
421 422 },
422 423 onView() {
... ... @@ -501,7 +502,12 @@ export default {
501 502 })
502 503 },
503 504 onSelectWorkshop() {
504   - uni.showToast({ title: '选择分厂(待对接)', icon: 'none' })
  505 + var id = this.id || (this.form && this.form.id) || ''
  506 + if (!id) {
  507 + uni.showToast({ title: '缺少单据id', icon: 'none' })
  508 + return
  509 + }
  510 + uni.navigateTo({ url: '/pages/domestic-plan/selectWorkshop?id=' + id })
505 511 },
506 512 onSubmitSplit() {
507 513 this.runWithConfirm({
... ... @@ -537,13 +543,36 @@ export default {
537 543 uni.showToast({ title: '打印(待对接)', icon: 'none' })
538 544 },
539 545 onGenerateBuyoutApply() {
540   - uni.showToast({ title: '生成买断操作申请单(待对接)', icon: 'none' })
  546 + var self = this
  547 + var id = this.id || (this.form && this.form.id) || ''
  548 + this.runWithConfirm({
  549 + title: '生成买断操作申请单',
  550 + content: '确定生成买断操作申请单吗?',
  551 + loading: '生成中',
  552 + successText: '生成成功',
  553 + failText: '生成买断操作申请单失败',
  554 + run: function () { return buyoutApplyCreateApi({ procurementPlanId: id }) }
  555 + })
541 556 },
542 557 onAbolishBuyoutApply() {
543   - uni.showToast({ title: '废除买断操作申请单(待对接)', icon: 'none' })
  558 + var self = this
  559 + var id = this.id || (this.form && this.form.id) || ''
  560 + this.runWithConfirm({
  561 + title: '废除买断操作申请单',
  562 + content: '确定废除买断操作申请单吗?',
  563 + loading: '废除中',
  564 + successText: '废除成功',
  565 + failText: '废除买断操作申请单失败',
  566 + run: function () { return buyoutApplyAbolishApi(id) }
  567 + })
544 568 },
545 569 onViewBuyoutApply() {
546   - uni.showToast({ title: '查看买断操作申请单(待对接)', icon: 'none' })
  570 + var id = this.id || (this.form && this.form.id) || ''
  571 + if (!id) {
  572 + uni.showToast({ title: '缺少单据id', icon: 'none' })
  573 + return
  574 + }
  575 + uni.navigateTo({ url: '/pages/domestic-plan/viewBuyoutApply?planId=' + id })
547 576 },
548 577 onUploadAttachment() {
549 578 uni.showToast({ title: '上传附件(待对接)', icon: 'none' })
... ...
... ... @@ -4,7 +4,7 @@
4 4 <image class="opCollapse" src="/static/images/title.png" />
5 5 <text class="title">明细信息</text>
6 6 <view class="ops">
7   - <image v-if="mode === 'add' || mode === 'edit'" class="opAdd" @click="onAdd" src="/static/images/plus.png" />
  7 + <image v-if="(mode === 'add' || mode === 'edit') && !isSupplement && !isSelectWorkshop" class="opAdd" @click="onAdd" src="/static/images/plus.png" />
8 8 <view v-if="mode === 'view'" class="op1" @click="toggleViewCollapse">
9 9 <image class="opAdd" :src="collapsedView ? '/static/images/down.png' : '/static/images/up.png'" />
10 10 <text class="op">{{ collapsedView ? '展开' : '收起' }}</text>
... ... @@ -18,61 +18,82 @@
18 18 <uni-list-item
19 19 class="select-item"
20 20 :class="item.productName ? 'is-filled' : 'is-empty'"
21   - clickable
22   - @click="openSelectSheet('product', idx)"
23   - :rightText="item.productName || '请选择品种'"
24   - showArrow
  21 + :clickable="!isSelectWorkshop && !isSupplement"
  22 + @click="!isSelectWorkshop && !isSupplement ? openSelectSheet('product', idx) : undefined"
  23 + :rightText="item.productName || (isSelectWorkshop || isSupplement ? '-' : '请选择品种')"
  24 + :showArrow="!isSelectWorkshop && !isSupplement"
25 25 >
26 26 <template v-slot:body>
27   - <view class="item-title"><text class="required">*</text><text>品种</text></view>
  27 + <view class="item-title" :class="{ 'no-required': isSelectWorkshop || isSupplement }">
  28 + <text v-if="!isSelectWorkshop && !isSupplement" class="required">*</text><text>品种</text>
  29 + </view>
28 30 </template>
29 31 </uni-list-item>
30 32 <uni-list-item title="料型">
31 33 <template v-slot:footer>
32   - <uni-easyinput v-model="item.materialType" :inputBorder="false" placeholder="请输入料型" />
  34 + <uni-easyinput v-if="!isSelectWorkshop && !isSupplement" v-model="item.materialType" :inputBorder="false" placeholder="请输入料型" />
  35 + <text v-else class="lock-value">{{ safeText(item.materialType) }}</text>
33 36 </template>
34 37 </uni-list-item>
35 38 <uni-list-item title="数量(吨)">
36 39 <template v-slot:footer>
37   - <uni-easyinput
38   - v-model="item.quantity"
39   - type="digit"
40   - :inputBorder="false"
41   - placeholder="请输入数量"
42   - @input="onNonNegativeInput(idx, 'quantity')"
43   - @blur="onNonNegativeBlur(idx, 'quantity', 4)"
44   - />
  40 + <template v-if="!isSelectWorkshop && !isSupplement">
  41 + <uni-easyinput
  42 + v-model="item.quantity"
  43 + type="digit"
  44 + :inputBorder="false"
  45 + placeholder="请输入数量"
  46 + @input="onNonNegativeInput(idx, 'quantity')"
  47 + @blur="onNonNegativeBlur(idx, 'quantity', 4)"
  48 + />
  49 + </template>
  50 + <text v-else class="lock-value">{{ formatTextNumber(item.quantity) }}</text>
45 51 </template>
46 52 </uni-list-item>
47 53 <uni-list-item title="实际采购价">
48 54 <template v-slot:footer>
49   - <uni-easyinput
50   - v-model="item.actualPurchasePrice"
51   - type="digit"
52   - :inputBorder="false"
53   - placeholder="请输入实际采购价"
54   - @input="onNonNegativeInput(idx, 'actualPurchasePrice')"
55   - @blur="onNonNegativeBlur(idx, 'actualPurchasePrice', 2)"
56   - />
  55 + <template v-if="!isSelectWorkshop && !isSupplement">
  56 + <uni-easyinput
  57 + v-model="item.actualPurchasePrice"
  58 + type="digit"
  59 + :inputBorder="false"
  60 + placeholder="请输入实际采购价"
  61 + @input="onNonNegativeInput(idx, 'actualPurchasePrice')"
  62 + @blur="onNonNegativeBlur(idx, 'actualPurchasePrice', 2)"
  63 + />
  64 + </template>
  65 + <text v-else class="lock-value">{{ formatTextNumber(item.actualPurchasePrice) }}</text>
57 66 </template>
58 67 </uni-list-item>
59 68 <uni-list-item title="含运到厂价">
60 69 <template v-slot:footer>
61   - <uni-easyinput
62   - v-if="!isSupplement"
63   - v-model="item.includingShippingPrice"
64   - type="digit"
65   - :inputBorder="false"
66   - placeholder="请输入含运到厂价"
67   - @input="onNonNegativeInput(idx, 'includingShippingPrice')"
68   - @blur="onNonNegativeBlur(idx, 'includingShippingPrice', 2)"
69   - />
  70 + <!-- <template v-if="isSupplement">
  71 + <uni-easyinput
  72 + v-model="item.includingShippingPrice"
  73 + type="digit"
  74 + :inputBorder="false"
  75 + placeholder="请输入含运到厂价"
  76 + @input="onNonNegativeInput(idx, 'includingShippingPrice')"
  77 + @blur="onNonNegativeBlur(idx, 'includingShippingPrice', 2)"
  78 + />
  79 + </template> -->
  80 + <template v-if="!isSelectWorkshop || isSupplement">
  81 + <uni-easyinput
  82 + v-model="item.includingShippingPrice"
  83 + type="digit"
  84 + :inputBorder="false"
  85 + placeholder="请输入含运到厂价"
  86 + @input="onNonNegativeInput(idx, 'includingShippingPrice')"
  87 + @blur="onNonNegativeBlur(idx, 'includingShippingPrice', 2)"
  88 + />
  89 + </template>
70 90 <text v-else class="lock-value">{{ formatTextNumber(item.includingShippingPrice) }}</text>
71 91 </template>
72 92 </uni-list-item>
73 93 <uni-list-item title="价格表价格">
74 94 <template v-slot:footer>
75 95 <uni-easyinput
  96 + v-if="!isSelectWorkshop"
76 97 v-model="item.priceListPrices"
77 98 type="digit"
78 99 :inputBorder="false"
... ... @@ -80,56 +101,76 @@
80 101 @input="onNonNegativeInput(idx, 'priceListPrices')"
81 102 @blur="onNonNegativeBlur(idx, 'priceListPrices', 2)"
82 103 />
  104 + <text v-else class="lock-value">{{ formatTextNumber(item.priceListPrices) }}</text>
83 105 </template>
84 106 </uni-list-item>
85 107 <uni-list-item title="协调幅度">
86 108 <template v-slot:footer>
87   - <uni-easyinput
88   - v-if="!isSupplement"
89   - v-model="item.coordinationRange"
90   - type="digit"
91   - :inputBorder="false"
92   - placeholder="请输入协调幅度"
93   - @input="onSignedInput(idx, 'coordinationRange')"
94   - @blur="onNonNegativeBlur(idx, 'coordinationRange', 2)"
95   - />
  109 + <template v-if="isSupplement">
  110 + <uni-easyinput
  111 + v-model="item.coordinationRange"
  112 + type="digit"
  113 + :inputBorder="false"
  114 + placeholder="请输入协调幅度"
  115 + @input="onSignedInput(idx, 'coordinationRange')"
  116 + @blur="onNonNegativeBlur(idx, 'coordinationRange', 2)"
  117 + />
  118 + </template>
  119 + <template v-else-if="!isSelectWorkshop">
  120 + <uni-easyinput
  121 + v-model="item.coordinationRange"
  122 + type="digit"
  123 + :inputBorder="false"
  124 + placeholder="请输入协调幅度"
  125 + @input="onSignedInput(idx, 'coordinationRange')"
  126 + @blur="onNonNegativeBlur(idx, 'coordinationRange', 2)"
  127 + />
  128 + </template>
96 129 <text v-else class="lock-value">{{ formatTextNumber(item.coordinationRange) }}</text>
97 130 </template>
98 131 </uni-list-item>
99 132 <uni-list-item title="买断料预计损耗">
100 133 <template v-slot:footer>
101   - <uni-easyinput
102   - v-model="item.estimatedLoss"
103   - type="digit"
104   - :inputBorder="false"
105   - placeholder="请输入预计损耗"
106   - @input="onNonNegativeInput(idx, 'estimatedLoss')"
107   - @blur="onNonNegativeBlur(idx, 'estimatedLoss', 2)"
108   - />
  134 + <template v-if="!isSelectWorkshop && !isSupplement">
  135 + <uni-easyinput
  136 + v-model="item.estimatedLoss"
  137 + type="digit"
  138 + :inputBorder="false"
  139 + placeholder="请输入预计损耗"
  140 + @input="onNonNegativeInput(idx, 'estimatedLoss')"
  141 + @blur="onNonNegativeBlur(idx, 'estimatedLoss', 2)"
  142 + />
  143 + </template>
  144 + <text v-else class="lock-value">{{ formatTextNumber(item.estimatedLoss) }}</text>
109 145 </template>
110 146 </uni-list-item>
111 147 <uni-list-item title="申请损耗(%)">
112 148 <template v-slot:footer>
113   - <uni-easyinput
114   - v-model="item.applicationAttrition"
115   - type="digit"
116   - :inputBorder="false"
117   - placeholder="请输入申请损耗"
118   - @input="onNonNegativeInput(idx, 'applicationAttrition')"
119   - @blur="onNonNegativeBlur(idx, 'applicationAttrition', 2)"
120   - />
  149 + <template v-if="!isSelectWorkshop && !isSupplement">
  150 + <uni-easyinput
  151 + v-model="item.applicationAttrition"
  152 + type="digit"
  153 + :inputBorder="false"
  154 + placeholder="请输入申请损耗"
  155 + @input="onNonNegativeInput(idx, 'applicationAttrition')"
  156 + @blur="onNonNegativeBlur(idx, 'applicationAttrition', 2)"
  157 + />
  158 + </template>
  159 + <text v-else class="lock-value">{{ formatTextNumber(item.applicationAttrition) }}</text>
121 160 </template>
122 161 </uni-list-item>
123 162 <uni-list-item
124 163 class="select-item"
125 164 :class="item.workshopName ? 'is-filled' : 'is-empty'"
126   - clickable
127   - @click="openSelectSheet('workshop', idx)"
128   - :rightText="item.workshopName || '请选择分厂'"
129   - showArrow
  165 + :clickable="!isSupplement"
  166 + @click="!isSupplement ? openSelectSheet('workshop', idx) : undefined"
  167 + :rightText="item.workshopName || (isSupplement ? '-' : '请选择分厂')"
  168 + :showArrow="!isSupplement"
130 169 >
131 170 <template v-slot:body>
132   - <view class="item-title"><text class="required">*</text><text>选择分厂</text></view>
  171 + <view class="item-title" :class="{ 'no-required': isSupplement }">
  172 + <text v-if="!isSupplement" class="required">*</text><text>选择分厂</text>
  173 + </view>
133 174 </template>
134 175 </uni-list-item>
135 176 </uni-list>
... ... @@ -137,18 +178,20 @@
137 178 <uni-list-item
138 179 class="select-item"
139 180 :class="item.productName ? 'is-filled' : 'is-empty'"
140   - clickable
141   - @click="openSelectSheet('product', idx)"
142   - :rightText="item.productName || '请选择品种'"
143   - showArrow
  181 + :clickable="!isSelectWorkshop && !isSupplement"
  182 + @click="!isSelectWorkshop && !isSupplement ? openSelectSheet('product', idx) : undefined"
  183 + :rightText="item.productName || (isSelectWorkshop || isSupplement ? '-' : '请选择品种')"
  184 + :showArrow="!isSelectWorkshop && !isSupplement"
144 185 >
145 186 <template v-slot:body>
146   - <view class="item-title"><text class="required">*</text><text>品种</text></view>
  187 + <view class="item-title" :class="{ 'no-required': isSelectWorkshop || isSupplement }">
  188 + <text v-if="!isSelectWorkshop && !isSupplement" class="required">*</text><text>品种</text>
  189 + </view>
147 190 </template>
148 191 </uni-list-item>
149 192 </uni-list>
150   - <view class="block-ops">
151   - <div class="del" @click="onRemove(idx)">
  193 + <view class="block-ops" :class="{ 'readonly-ops': isSelectWorkshop || isSupplement }">
  194 + <div v-if="!isSelectWorkshop && !isSupplement" class="del" @click="onRemove(idx)">
152 195 <image src="/static/images/delete.png" class="icon" />
153 196 删除
154 197 </div>
... ... @@ -210,6 +253,7 @@ export default {
210 253 },
211 254 computed: {
212 255 isSupplement() { return this.scene === 'supplement' },
  256 + isSelectWorkshop() { return this.scene === 'selectWorkshop' },
213 257 productOptsComputed() {
214 258 var list = Array.isArray(this.productOptions) ? this.productOptions : []
215 259 return list.map(function (o) {
... ... @@ -412,11 +456,11 @@ export default {
412 456 var list = this.items || []
413 457 for (var i = 0; i < list.length; i++) {
414 458 var it = list[i]
415   - if (!it.productId) {
  459 + if (!this.isSupplement && !this.isSelectWorkshop && !it.productId) {
416 460 uni.showToast({ title: '第' + (i + 1) + '条明细:请选择品种', icon: 'none' })
417 461 return false
418 462 }
419   - if (!it.workshopId) {
  463 + if (!this.isSupplement && !it.workshopId) {
420 464 uni.showToast({ title: '第' + (i + 1) + '条明细:请选择分厂', icon: 'none' })
421 465 return false
422 466 }
... ... @@ -533,6 +577,9 @@ export default {
533 577 display: flex;
534 578 padding: 20rpx 32rpx 20rpx;
535 579 justify-content: space-around;
  580 + &.readonly-ops {
  581 + justify-content: flex-end;
  582 + }
536 583 }
537 584 .del {
538 585 color: #D54941;
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view scroll-y class="scroll">
  4 + <uni-list>
  5 + <uni-list-item class="select-item" :class="detail.code ? 'is-filled' : 'is-empty'">
  6 + <template v-slot:body>
  7 + <view class="item-title"><text>编号</text></view>
  8 + </template>
  9 + <template v-slot:footer>
  10 + <view class="serial-number-row">
  11 + <text class="readonly-text value-code">{{ safeText(detail.code) }}</text>
  12 + </view>
  13 + </template>
  14 + </uni-list-item>
  15 +
  16 + <uni-list-item title="公司名称">
  17 + <template v-slot:footer>
  18 + <uni-easyinput v-model="companyNameDisplay" :inputBorder="false" disabled placeholder="-" />
  19 + </template>
  20 + </uni-list-item>
  21 +
  22 + <uni-list-item title="供应商名称">
  23 + <template v-slot:footer>
  24 + <uni-easyinput v-model="detail.supplierName" :inputBorder="false" disabled placeholder="-" />
  25 + </template>
  26 + </uni-list-item>
  27 +
  28 + <uni-list-item title="采购处">
  29 + <template v-slot:footer>
  30 + <uni-easyinput v-model="purchaseDepartmentDisplay" :inputBorder="false" disabled placeholder="-" />
  31 + </template>
  32 + </uni-list-item>
  33 +
  34 + <uni-list-item title="区域">
  35 + <template v-slot:footer>
  36 + <uni-easyinput v-model="regionDisplay" :inputBorder="false" disabled placeholder="-" />
  37 + </template>
  38 + </uni-list-item>
  39 +
  40 + <uni-list-item title="日期">
  41 + <template v-slot:footer>
  42 + <uni-easyinput v-model="dateDisplay" :inputBorder="false" disabled placeholder="-" />
  43 + </template>
  44 + </uni-list-item>
  45 +
  46 + <uni-list-item title="报价时效">
  47 + <template v-slot:footer>
  48 + <uni-easyinput v-model="detail.validityPeriod" :inputBorder="false" disabled placeholder="-" />
  49 + </template>
  50 + </uni-list-item>
  51 +
  52 + <uni-list-item title="报价人">
  53 + <template v-slot:footer>
  54 + <uni-easyinput v-model="detail.quoterName" :inputBorder="false" disabled placeholder="-" />
  55 + </template>
  56 + </uni-list-item>
  57 +
  58 + <uni-list-item class="select-item" :class="typeof detail.longTermOperation === 'boolean' ? 'is-filled' : 'is-empty'">
  59 + <template v-slot:body>
  60 + <view class="item-title"><text>是否长单操作</text></view>
  61 + </template>
  62 + <template v-slot:footer>
  63 + <text class="readonly-text">{{ boolText(detail.longTermOperation) }}</text>
  64 + </template>
  65 + </uni-list-item>
  66 +
  67 + <uni-list-item class="select-item" :class="typeof detail.terminalCustomer === 'boolean' ? 'is-filled' : 'is-empty'">
  68 + <template v-slot:body>
  69 + <view class="item-title"><text>是否终端客户</text></view>
  70 + </template>
  71 + <template v-slot:footer>
  72 + <text class="readonly-text">{{ boolText(detail.terminalCustomer) }}</text>
  73 + </template>
  74 + </uni-list-item>
  75 +
  76 + <uni-list-item class="select-item" :class="typeof detail.priced === 'boolean' ? 'is-filled' : 'is-empty'">
  77 + <template v-slot:body>
  78 + <view class="item-title"><text>是否未点价</text></view>
  79 + </template>
  80 + <template v-slot:footer>
  81 + <text class="readonly-text">{{ boolText(detail.priced) }}</text>
  82 + </template>
  83 + </uni-list-item>
  84 +
  85 + <uni-list-item v-if="detail.priced === true" title="点价截止日期">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="pricingDeadlineDisplay" :inputBorder="false" disabled placeholder="-" />
  88 + </template>
  89 + </uni-list-item>
  90 +
  91 + <uni-list-item v-if="detail.priced === true" class="select-item" :class="typeof detail.temporaryPrice === 'boolean' ? 'is-filled' : 'is-empty'">
  92 + <template v-slot:body>
  93 + <view class="item-title"><text>是否暂定价</text></view>
  94 + </template>
  95 + <template v-slot:footer>
  96 + <text class="readonly-text">{{ boolText(detail.temporaryPrice) }}</text>
  97 + </template>
  98 + </uni-list-item>
  99 +
  100 + <uni-list-item class="select-item" :class="typeof detail.otherExpenseSettlement === 'boolean' ? 'is-filled' : 'is-empty'">
  101 + <template v-slot:body>
  102 + <view class="item-title"><text>其他费用凭票到厂另行结算</text></view>
  103 + </template>
  104 + <template v-slot:footer>
  105 + <text class="readonly-text">{{ boolText(detail.otherExpenseSettlement) }}</text>
  106 + </template>
  107 + </uni-list-item>
  108 +
  109 + <uni-list-item class="select-item" :class="detail.deliveryMode ? 'is-filled' : 'is-empty'">
  110 + <template v-slot:body>
  111 + <view class="item-title"><text>交提货方式</text></view>
  112 + </template>
  113 + <template v-slot:footer>
  114 + <text class="readonly-text">{{ getDeliveryMethodLabel() }}</text>
  115 + </template>
  116 + </uni-list-item>
  117 +
  118 + <uni-list-item class="select-item" :class="typeof detail.commodityBuyout === 'boolean' ? 'is-filled' : 'is-empty'">
  119 + <template v-slot:body>
  120 + <view class="item-title"><text>是否通货买断</text></view>
  121 + </template>
  122 + <template v-slot:footer>
  123 + <text class="readonly-text">{{ boolText(detail.commodityBuyout) }}</text>
  124 + </template>
  125 + </uni-list-item>
  126 +
  127 + <uni-list-item class="select-item" :class="typeof detail.qualityBuyout === 'boolean' ? 'is-filled' : 'is-empty'">
  128 + <template v-slot:body>
  129 + <view class="item-title"><text>是否质量买断</text></view>
  130 + </template>
  131 + <template v-slot:footer>
  132 + <text class="readonly-text">{{ boolText(detail.qualityBuyout) }}</text>
  133 + </template>
  134 + </uni-list-item>
  135 +
  136 + <uni-list-item class="select-item" :class="typeof detail.quantityBuyout === 'boolean' ? 'is-filled' : 'is-empty'">
  137 + <template v-slot:body>
  138 + <view class="item-title"><text>是否数量买断</text></view>
  139 + </template>
  140 + <template v-slot:footer>
  141 + <text class="readonly-text">{{ boolText(detail.quantityBuyout) }}</text>
  142 + </template>
  143 + </uni-list-item>
  144 +
  145 + <uni-list-item class="select-item" :class="typeof detail.doorDelivery === 'boolean' ? 'is-filled' : 'is-empty'">
  146 + <template v-slot:body>
  147 + <view class="item-title"><text>是否送货上门</text></view>
  148 + </template>
  149 + <template v-slot:footer>
  150 + <text class="readonly-text">{{ boolText(detail.doorDelivery) }}</text>
  151 + </template>
  152 + </uni-list-item>
  153 +
  154 + <uni-list-item title="另付运费">
  155 + <template v-slot:footer>
  156 + <uni-easyinput v-model="shippingCostDisplay" :inputBorder="false" disabled placeholder="-" />
  157 + </template>
  158 + </uni-list-item>
  159 +
  160 + <uni-list-item title="装车费">
  161 + <template v-slot:footer>
  162 + <uni-easyinput v-model="loadingFeeDisplay" :inputBorder="false" disabled placeholder="-" />
  163 + </template>
  164 + </uni-list-item>
  165 +
  166 + <uni-list-item title="开票品名">
  167 + <template v-slot:footer>
  168 + <uni-easyinput v-model="detail.invoiceProductName" :inputBorder="false" disabled placeholder="-" />
  169 + </template>
  170 + </uni-list-item>
  171 +
  172 + <uni-list-item title="交货日期">
  173 + <template v-slot:footer>
  174 + <uni-easyinput v-model="deliveryDateDisplay" :inputBorder="false" disabled placeholder="-" />
  175 + </template>
  176 + </uni-list-item>
  177 +
  178 + <uni-list-item title="结算方式">
  179 + <template v-slot:footer>
  180 + <uni-easyinput v-model="detail.settlementMethod" :inputBorder="false" disabled placeholder="-" />
  181 + </template>
  182 + </uni-list-item>
  183 +
  184 + <uni-list-item title="结算比例(%)">
  185 + <template v-slot:footer>
  186 + <uni-easyinput v-model="settlementRatioDisplay" :inputBorder="false" disabled placeholder="-" />
  187 + </template>
  188 + </uni-list-item>
  189 +
  190 + <uni-list-item title="价格表编号">
  191 + <template v-slot:footer>
  192 + <uni-easyinput v-model="priceTableDisplay" :inputBorder="false" disabled placeholder="-" />
  193 + </template>
  194 + </uni-list-item>
  195 +
  196 + <uni-list-item title="协调事由">
  197 + <template v-slot:footer>
  198 + <uni-easyinput v-model="detail.coordinationReason" :inputBorder="false" disabled placeholder="-" />
  199 + </template>
  200 + </uni-list-item>
  201 +
  202 + <uni-list-item title="票类状况">
  203 + <template v-slot:footer>
  204 + <uni-easyinput v-model="detail.invoiceTypeStatus" :inputBorder="false" disabled placeholder="-" />
  205 + </template>
  206 + </uni-list-item>
  207 +
  208 + <uni-list-item v-if="attachmentList.length" title="附件">
  209 + <template v-slot:footer>
  210 + <view class="attach-list">
  211 + <view v-for="(at, idx) in attachmentList" :key="idx" class="attach-item">
  212 + <text class="attach-name">{{ at.name }}</text>
  213 + <text class="attach-view" @click.stop="onPreviewAttachment(at)">查看</text>
  214 + </view>
  215 + </view>
  216 + </template>
  217 + </uni-list-item>
  218 +
  219 + <ProductRel
  220 + ref="productRel"
  221 + mode="edit"
  222 + :scene="workshopScene"
  223 + :list="lineList"
  224 + :product-options="productOptions"
  225 + :workshop-options="workshopOptions"
  226 + @change="onLineChange"
  227 + />
  228 + </uni-list>
  229 +
  230 + <view class="material-condition-section">
  231 + <view class="section-header">
  232 + <image class="opCollapse" src="/static/images/title.png" />
  233 + <text class="section-title">料质状况</text>
  234 + </view>
  235 + <view class="section-content">
  236 + <view class="form-row">
  237 + <text class="form-label">是否启用料质状况</text>
  238 + <text class="form-value">{{ boolText(detail.materialConditionEnabled) }}</text>
  239 + </view>
  240 + <template v-if="detail.materialConditionEnabled">
  241 + <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group">
  242 + <text class="material-label">{{ mc.label }}</text>
  243 + <view class="tag-list">
  244 + <view
  245 + v-for="opt in getDictOptions(mc.dictCode)"
  246 + :key="opt.code"
  247 + class="tag-btn"
  248 + :class="{ active: isTagSelected(mc.field, opt.code) }"
  249 + >
  250 + {{ opt.name }}
  251 + </view>
  252 + </view>
  253 + </view>
  254 + </template>
  255 + </view>
  256 + </view>
  257 +
  258 + <view class="remark-section">
  259 + <view class="section-header">
  260 + <image class="opCollapse" src="/static/images/title.png" />
  261 + <text class="section-title">备注</text>
  262 + </view>
  263 + <view class="section-content">
  264 + <text class="remark-text">{{ safeText(detail.remark) }}</text>
  265 + </view>
  266 + </view>
  267 +
  268 + <view class="footer-tip">提示:仅「选择分厂」字段可编辑,其余字段自动带出且不可编辑</view>
  269 + </scroll-view>
  270 +
  271 + <view class="bottom-bar">
  272 + <button class="btn btn-outline" @click="onBack">取消</button>
  273 + <button class="btn btn-primary" @click="onSubmit">保存</button>
  274 + </view>
  275 + </view>
  276 +</template>
  277 +
  278 +<script>
  279 +import ProductRel from './productRel.vue'
  280 +import { procurementPlanDetailApi, procurementPlanUpdateApi } from '@/api/procure-manage/procurementPlan.js'
  281 +import { breedRelationshipQueryApi, workshopQueryApi, priceTableQueryApi, priceTableDetailApi } from '@/api/devManage.js'
  282 +import { getDicByCodes } from '@/utils/dic.js'
  283 +
  284 +export default {
  285 + name: 'DomesticPlanSelectWorkshop',
  286 + components: { ProductRel },
  287 + data() {
  288 + return {
  289 + workshopScene: 'selectWorkshop',
  290 + id: '',
  291 + detail: {},
  292 + attachmentList: [],
  293 + materialConditionConfigs: [
  294 + { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' },
  295 + { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' },
  296 + { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' },
  297 + { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' },
  298 + { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' },
  299 + { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' },
  300 + { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' },
  301 + { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' }
  302 + ],
  303 + dictData: {},
  304 + lineList: [],
  305 + productOptions: [],
  306 + workshopOptions: []
  307 + }
  308 + },
  309 + computed: {
  310 + companyNameDisplay() {
  311 + var d = this.detail || {}
  312 + return d.companyShortName != null ? d.companyShortName : (d.companyName != null ? d.companyName : '')
  313 + },
  314 + purchaseDepartmentDisplay() {
  315 + var d = this.detail || {}
  316 + return d.purchaseDepartmentName != null ? d.purchaseDepartmentName : (d.purchaseDepartment != null ? d.purchaseDepartment : '')
  317 + },
  318 + regionDisplay() {
  319 + var d = this.detail || {}
  320 + return d.regionName != null ? d.regionName : (d.region != null ? d.region : '')
  321 + },
  322 + dateDisplay() {
  323 + var d = this.detail || {}
  324 + var s = d.date == null ? '' : String(d.date).trim()
  325 + if (!s) return ''
  326 + return s.length >= 10 ? s.slice(0, 10) : s
  327 + },
  328 + pricingDeadlineDisplay() {
  329 + var d = this.detail || {}
  330 + var s = d.pricingDeadline == null ? '' : String(d.pricingDeadline).trim()
  331 + if (!s) return ''
  332 + return s.length >= 10 ? s.slice(0, 10) : s
  333 + },
  334 + deliveryDateDisplay() {
  335 + var d = this.detail || {}
  336 + var s = d.deliveryDate == null ? '' : String(d.deliveryDate).trim()
  337 + if (!s) return ''
  338 + return s.length >= 10 ? s.slice(0, 10) : s
  339 + },
  340 + loadingFeeDisplay() {
  341 + var v = (this.detail || {}).loadingFee
  342 + if (v == null || v === '') return ''
  343 + var n = Number(v)
  344 + if (isNaN(n)) return String(v)
  345 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  346 + },
  347 + shippingCostDisplay() {
  348 + var v = (this.detail || {}).shippingCost
  349 + if (v == null || v === '') return ''
  350 + var n = Number(v)
  351 + if (isNaN(n)) return String(v)
  352 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 2 })
  353 + },
  354 + settlementRatioDisplay() {
  355 + var v = (this.detail || {}).settlementRatio
  356 + if (v == null || v === '') return ''
  357 + var n = Number(v)
  358 + if (isNaN(n)) return String(v)
  359 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  360 + },
  361 + priceTableDisplay() {
  362 + var d = this.detail || {}
  363 + var c = d.priceTableCode != null ? d.priceTableCode : (d.priceTableId != null ? d.priceTableId : '')
  364 + var n = d.priceTableName != null ? d.priceTableName : ''
  365 + if (!c && !n) return ''
  366 + return n ? (n + (c ? ' (' + c + ')' : '')) : c
  367 + }
  368 + },
  369 + onLoad(query) {
  370 + this.id = (query && query.id) ? query.id : ''
  371 + this.loadDictData()
  372 + this.loadRefData()
  373 + if (this.id) {
  374 + this.loadSourceDetail()
  375 + }
  376 + },
  377 + methods: {
  378 + toNumber(v) {
  379 + if (v == null || v === '') return 0
  380 + var n = Number(v)
  381 + return isNaN(n) ? 0 : n
  382 + },
  383 + toFixed(v, n) {
  384 + var num = Number(v)
  385 + if (isNaN(num)) return ''
  386 + return num.toFixed(n)
  387 + },
  388 + safeText(v) {
  389 + var s = v == null ? '' : String(v)
  390 + return s.trim() ? s : '-'
  391 + },
  392 + boolText(v) {
  393 + if (typeof v !== 'boolean') return '-'
  394 + return v ? '是' : '否'
  395 + },
  396 + async loadDictData() {
  397 + var codes = this.materialConditionConfigs.map(function (mc) { return mc.dictCode }).concat(['DELIVERY_METHOD'])
  398 + try {
  399 + var results = await getDicByCodes(codes)
  400 + this.dictData = results || {}
  401 + } catch (e) {
  402 + this.dictData = {}
  403 + }
  404 + },
  405 + getDictOptions(dictCode) {
  406 + var data = this.dictData[dictCode]
  407 + return (data && data.data) ? data.data : []
  408 + },
  409 + isTagSelected(field, code) {
  410 + var selected = this.detail ? this.detail[field] : undefined
  411 + if (Array.isArray(selected)) return selected.indexOf(code) >= 0
  412 + if (typeof selected === 'string' && selected) {
  413 + return selected.split(',').indexOf(code) >= 0
  414 + }
  415 + return false
  416 + },
  417 + getDeliveryMethodLabel() {
  418 + var opts = this.getDictOptions('DELIVERY_METHOD') || []
  419 + var v = String(this.detail.deliveryMode != null ? this.detail.deliveryMode : '')
  420 + if (!v) return '-'
  421 + for (var i = 0; i < opts.length; i++) {
  422 + var o = opts[i]
  423 + var code = o.code != null ? String(o.code) : (o.value != null ? String(o.value) : '')
  424 + if (code === v) return o.name || o.label || '-'
  425 + }
  426 + return v
  427 + },
  428 + buildAttachmentList() {
  429 + var ids = this.detail.attachmentFileIds
  430 + var names = this.detail.attachmentFileNames
  431 + var idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : [])
  432 + var nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : [])
  433 + var len = Math.max(idArr.length, nameArr.length)
  434 + var list = []
  435 + for (var i = 0; i < len; i++) {
  436 + list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) })
  437 + }
  438 + this.attachmentList = list
  439 + },
  440 + onPreviewAttachment(at) {
  441 + if (!at || !at.id) {
  442 + uni.showToast({ title: '无法查看', icon: 'none' })
  443 + return
  444 + }
  445 + uni.showToast({ title: '查看附件 ' + at.name, icon: 'none' })
  446 + },
  447 + async loadSourceDetail() {
  448 + if (!this.id) return
  449 + try {
  450 + var res = await procurementPlanDetailApi({ id: this.id })
  451 + var d = (res && res.data) ? res.data : {}
  452 + var self = this
  453 + this.materialConditionConfigs.forEach(function (mc) {
  454 + var v = d[mc.field]
  455 + if (typeof v === 'string' && v) {
  456 + d[mc.field] = v.split(',').filter(Boolean)
  457 + } else if (!Array.isArray(v)) {
  458 + d[mc.field] = []
  459 + }
  460 + })
  461 + this.detail = d
  462 + this.lineList = Array.isArray(d.procurementPlanLineList) ? d.procurementPlanLineList.slice() : []
  463 + this.buildAttachmentList()
  464 + this.fillLineNames()
  465 + await this.fillPriceByDetailPriceId()
  466 + } catch (e) {
  467 + uni.showToast({ title: '加载详情失败', icon: 'none' })
  468 + }
  469 + },
  470 + async loadRefData() {
  471 + try {
  472 + var results = await Promise.all([
  473 + this.$pCall(breedRelationshipQueryApi, { pageIndex: 1, pageSize: 1000 }),
  474 + this.$pCall(workshopQueryApi, { pageIndex: 1, pageSize: 1000 })
  475 + ])
  476 + var r1 = (results[0] && results[0].data) ? results[0].data : {}
  477 + var r2 = (results[1] && results[1].data) ? results[1].data : {}
  478 + 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 : []))
  479 + 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 : []))
  480 + this.fillLineNames()
  481 + } catch (e) {
  482 + this.productOptions = []
  483 + this.workshopOptions = []
  484 + }
  485 + },
  486 + $pCall(fn, params) {
  487 + try { return Promise.resolve(fn(params)) } catch (e) { return Promise.reject(e) }
  488 + },
  489 + onLineChange(list) {
  490 + this.lineList = Array.isArray(list) ? list.slice() : []
  491 + this.fillLineNames()
  492 + },
  493 + fillLineNames() {
  494 + if (!Array.isArray(this.lineList) || !this.lineList.length) return
  495 + var pOpts = Array.isArray(this.productOptions) ? this.productOptions : []
  496 + var wOpts = Array.isArray(this.workshopOptions) ? this.workshopOptions : []
  497 + var self = this
  498 + this.lineList = this.lineList.map(function (row) {
  499 + var r = Object.assign({}, row)
  500 + var pid = r.productId != null ? String(r.productId) : ''
  501 + var wid = r.workshopId != null ? String(r.workshopId) : ''
  502 + if ((r.productName == null || String(r.productName).trim() === '') && pid) {
  503 + var p = pOpts.find(function (o) {
  504 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.value != null ? String(o.value) : ''))
  505 + return id === pid
  506 + })
  507 + if (p) {
  508 + r.productName = p.name != null ? p.name : (p.productName != null ? p.productName : (p.label != null ? p.label : ''))
  509 + }
  510 + }
  511 + if ((r.workshopName == null || String(r.workshopName).trim() === '') && wid) {
  512 + var w = wOpts.find(function (o) {
  513 + var id = o.id != null ? String(o.id) : (o.workshopId != null ? String(o.workshopId) : (o.value != null ? String(o.value) : ''))
  514 + return id === wid
  515 + })
  516 + if (w) {
  517 + r.workshopName = w.name != null ? w.name : (w.workshopName != null ? w.workshopName : (w.label != null ? w.label : ''))
  518 + }
  519 + }
  520 + return r
  521 + })
  522 + },
  523 + async fillPriceByDetailPriceId() {
  524 + var d = this.detail || {}
  525 + var priceId = d.priceId != null ? d.priceId : (d.priceTableId != null ? d.priceTableId : '')
  526 + if (!priceId) return
  527 + await this.fetchPriceDetailAndApply(priceId)
  528 + },
  529 + async fetchPriceDetailAndApply(priceId) {
  530 + if (!priceId) return
  531 + var self = this
  532 + try {
  533 + var res = await priceTableDetailApi({ id: priceId })
  534 + var d = (res && res.data) ? res.data : {}
  535 + var priceLines = self.extractPriceLines(d)
  536 + self.applyPriceLinesToLines(priceLines)
  537 + } catch (e) {
  538 + return
  539 + }
  540 + },
  541 + extractPriceLines(priceDetail) {
  542 + if (!priceDetail || typeof priceDetail !== 'object') return []
  543 + var candidates = [
  544 + priceDetail.procurementPriceLineList,
  545 + priceDetail.priceLineList,
  546 + priceDetail.priceList,
  547 + priceDetail.lineList,
  548 + priceDetail.datas,
  549 + priceDetail.records,
  550 + priceDetail.list
  551 + ]
  552 + for (var i = 0; i < candidates.length; i++) {
  553 + if (Array.isArray(candidates[i]) && candidates[i].length) return candidates[i]
  554 + }
  555 + for (var k in priceDetail) {
  556 + if (!Object.prototype.hasOwnProperty.call(priceDetail, k)) continue
  557 + if (Array.isArray(priceDetail[k])) {
  558 + var arr = priceDetail[k]
  559 + 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)) {
  560 + return arr
  561 + }
  562 + }
  563 + }
  564 + return []
  565 + },
  566 + buildPriceMap(priceLines) {
  567 + var m = {}
  568 + if (!Array.isArray(priceLines)) return m
  569 + for (var i = 0; i < priceLines.length; i++) {
  570 + var line = priceLines[i] || {}
  571 + if (line.price == null) continue
  572 + var key = String(line.productId || line.breedId || line.varietyId || line.id || ('__idx_' + i))
  573 + m[key] = { price: Number(line.price), meta: line }
  574 + }
  575 + return m
  576 + },
  577 + applyPriceLinesToLines(priceLines) {
  578 + if (!Array.isArray(this.lineList)) return
  579 + var priceMap = this.buildPriceMap(priceLines)
  580 + var self = this
  581 + this.lineList = this.lineList.map(function (row) {
  582 + var pid = String(row.productId || row.breedId || row.varietyId || '')
  583 + var price = null
  584 + if (pid && priceMap[pid] != null) {
  585 + price = priceMap[pid].price
  586 + } else {
  587 + var pname = (row.productName || '').trim()
  588 + if (pname) {
  589 + for (var k in priceMap) {
  590 + if (!Object.prototype.hasOwnProperty.call(priceMap, k)) continue
  591 + var meta = priceMap[k] && priceMap[k].meta ? priceMap[k].meta : null
  592 + if (meta && ((meta.productName && meta.productName === pname) || (meta.breedName && meta.breedName === pname) || (meta.varietyName && meta.varietyName === pname))) {
  593 + price = priceMap[k].price
  594 + break
  595 + }
  596 + }
  597 + }
  598 + }
  599 + if (price != null) {
  600 + row.priceListPrices = self.toFixed(price, 2)
  601 + }
  602 + return row
  603 + })
  604 + this.fillLineNames()
  605 + },
  606 + joinStr(arr) {
  607 + if (Array.isArray(arr)) return arr.filter(Boolean).join(',')
  608 + if (typeof arr === 'string') return arr
  609 + return ''
  610 + },
  611 + toBool(v, fallback) {
  612 + if (typeof v === 'boolean') return v
  613 + if (v === 'true' || v === '1' || v === 1) return true
  614 + if (v === 'false' || v === '0' || v === 0) return false
  615 + return typeof fallback === 'boolean' ? fallback : false
  616 + },
  617 + pickId(v) {
  618 + if (v == null || v === '') return ''
  619 + if (typeof v === 'string' || typeof v === 'number') return String(v)
  620 + if (typeof v === 'object') {
  621 + return String(v.id != null ? v.id : (v.value != null ? v.value : (v.code != null ? v.code : '')))
  622 + }
  623 + return String(v)
  624 + },
  625 + buildPayload() {
  626 + var self = this
  627 + var d = this.detail || {}
  628 + var lines = Array.isArray(this.lineList) ? this.lineList.slice() : []
  629 + var lineList = lines.map(function (row, i) {
  630 + var r = row || {}
  631 + var itemId = r.itemId || (r._key != null ? r._key : (r.id ? String(r.id) : ('line-' + Date.now() + '-' + i)))
  632 + return {
  633 + id: r.id != null ? r.id : '',
  634 + itemId: itemId,
  635 + procurementPlanId: (r.procurementPlanId != null ? r.procurementPlanId : (self.id || d.id || '')),
  636 + productId: self.pickId(r.productId),
  637 + materialType: r.materialType != null ? String(r.materialType) : '',
  638 + quantity: self.toNumber(r.quantity),
  639 + actualPurchasePrice: self.toNumber(r.actualPurchasePrice),
  640 + includingShippingPrice: self.toNumber(r.includingShippingPrice),
  641 + priceListPrices: self.toNumber(r.priceListPrices),
  642 + coordinationRange: self.toNumber(r.coordinationRange),
  643 + estimatedLoss: self.toNumber(r.estimatedLoss),
  644 + applicationAttrition: self.toNumber(r.applicationAttrition),
  645 + workshopId: self.pickId(r.workshopId)
  646 + }
  647 + })
  648 + var mcFields = this.materialConditionConfigs.map(function (mc) { return mc.field })
  649 + var materialPayload = {}
  650 + mcFields.forEach(function (f) {
  651 + materialPayload[f] = self.joinStr(d[f])
  652 + })
  653 + var body = {
  654 + id: this.id || d.id || '',
  655 + code: d.code != null ? String(d.code) : '',
  656 + companyShortId: this.pickId(d.companyShortId || d.companyId),
  657 + supplierId: this.pickId(d.supplierId),
  658 + purchaseDepartment: this.pickId(d.purchaseDepartmentId || d.purchaseDepartment),
  659 + region: this.pickId(d.regionId || d.region),
  660 + date: d.date != null ? String(d.date) : '',
  661 + validityPeriod: d.validityPeriod != null ? String(d.validityPeriod) : '',
  662 + quoterId: this.pickId(d.quoterId),
  663 + quoterName: d.quoterName != null ? String(d.quoterName) : '',
  664 + longTermOperation: this.toBool(d.longTermOperation, false),
  665 + terminalCustomer: this.toBool(d.terminalCustomer, false),
  666 + priced: this.toBool(d.priced, false),
  667 + pricingDeadline: d.pricingDeadline != null ? String(d.pricingDeadline) : '',
  668 + temporaryPrice: this.toBool(d.temporaryPrice, false),
  669 + otherExpenseSettlement: this.toBool(d.otherExpenseSettlement, false),
  670 + deliveryMode: d.deliveryMode != null ? String(d.deliveryMode) : '',
  671 + commodityBuyout: this.toBool(d.commodityBuyout, false),
  672 + qualityBuyout: this.toBool(d.qualityBuyout, false),
  673 + quantityBuyout: this.toBool(d.quantityBuyout, false),
  674 + doorDelivery: this.toBool(d.doorDelivery, false),
  675 + shippingCost: this.toNumber(d.shippingCost),
  676 + loadingFee: this.toNumber(d.loadingFee),
  677 + invoiceProductName: d.invoiceProductName != null ? String(d.invoiceProductName) : '',
  678 + deliveryDate: d.deliveryDate != null ? String(d.deliveryDate) : '',
  679 + settlementMethod: d.settlementMethod != null ? String(d.settlementMethod) : '',
  680 + settlementRatio: this.toNumber(d.settlementRatio),
  681 + priceId: this.pickId(d.priceId || d.priceTableId),
  682 + coordinationReason: d.coordinationReason != null ? String(d.coordinationReason) : '',
  683 + invoiceTypeStatus: d.invoiceTypeStatus != null ? String(d.invoiceTypeStatus) : '',
  684 + remark: d.remark != null ? String(d.remark) : '',
  685 + materialConditionEnabled: this.toBool(d.materialConditionEnabled, false),
  686 + approvalStatus: d.approvalStatus != null ? String(d.approvalStatus) : '',
  687 + processStatus: d.processStatus != null ? String(d.processStatus) : '',
  688 + processNode: d.processNode != null ? String(d.processNode) : '',
  689 + procurementPlanLineList: lineList
  690 + }
  691 + Object.keys(materialPayload).forEach(function (k) {
  692 + body[k] = materialPayload[k]
  693 + })
  694 + return body
  695 + },
  696 + onBack() {
  697 + uni.navigateBack({ delta: 1 })
  698 + },
  699 + validateForm() {
  700 + var pr = this.$refs.productRel
  701 + if (pr && typeof pr.validate === 'function') {
  702 + var ok = pr.validate()
  703 + if (!ok) return false
  704 + }
  705 + return true
  706 + },
  707 + async onSubmit() {
  708 + if (!this.validateForm()) return
  709 + var payload = this.buildPayload()
  710 + try {
  711 + await procurementPlanUpdateApi(payload)
  712 + uni.showToast({ title: '保存成功', icon: 'none' })
  713 + try {
  714 + uni.setStorageSync('DOMESTIC_PLAN_LIST_NEED_REFRESH', '1')
  715 + uni.setStorageSync('SUPPLE_PLAN_LIST_NEED_REFRESH', '1')
  716 + } catch (e) {}
  717 + var self = this
  718 + setTimeout(function () {
  719 + uni.navigateBack({ delta: 1 })
  720 + }, 400)
  721 + } catch (e) {
  722 + uni.showToast({ title: (e && (e.msg || e.message)) ? (e.msg || e.message) : '保存失败', icon: 'none' })
  723 + }
  724 + }
  725 + }
  726 +}
  727 +</script>
  728 +
  729 +<style lang="scss" scoped>
  730 +.page {
  731 + display: flex;
  732 + flex-direction: column;
  733 + height: 100%;
  734 +}
  735 +.scroll {
  736 + flex: 1;
  737 + padding: 12rpx 0 392rpx !important;
  738 +}
  739 +.bottom-bar {
  740 + z-index: 2;
  741 + position: fixed;
  742 + left: 0;
  743 + right: 0;
  744 + bottom: 0;
  745 + padding: 32rpx;
  746 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  747 + background: #fff;
  748 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  749 + display: flex;
  750 + gap: 24rpx;
  751 + .btn {
  752 + flex: 1;
  753 + height: 80rpx;
  754 + line-height: 80rpx;
  755 + border-radius: 12rpx;
  756 + font-size: 32rpx;
  757 + }
  758 + .btn-outline {
  759 + background: #fff;
  760 + color: $theme-primary;
  761 + border: 2rpx solid $theme-primary;
  762 + }
  763 + .btn-primary {
  764 + background: $theme-primary;
  765 + color: #fff;
  766 + border: 2rpx solid $theme-primary;
  767 + }
  768 +}
  769 +
  770 +::v-deep .uni-list {
  771 + .uni-easyinput {
  772 + display: flex;
  773 + .uni-input-input {
  774 + color: rgba(0, 0, 0, 0.9);
  775 + }
  776 + }
  777 + .uni-input-placeholder { z-index: 1; }
  778 + .uni-input-input { background-color: #ffffff; }
  779 + background: transparent;
  780 + &-item {
  781 + &__extra-text { font-size: 32rpx; }
  782 + &__content-title {
  783 + font-size: 32rpx;
  784 + color: rgba(0, 0, 0, 0.9);
  785 + }
  786 + &__container {
  787 + padding: 32rpx;
  788 + .uni-easyinput {
  789 + &__placeholder-class {
  790 + font-size: 32rpx;
  791 + color: rgba(0, 0, 0, 0.4);
  792 + }
  793 + &__content {
  794 + border: none;
  795 + background-color: #ffffff !important;
  796 + &-input {
  797 + padding-left: 0 !important;
  798 + height: 48rpx;
  799 + line-height: 48rpx;
  800 + font-size: 32rpx;
  801 + }
  802 + .content-clear-icon {
  803 + font-size: 44rpx !important;
  804 + }
  805 + }
  806 + }
  807 + .item-title,
  808 + .uni-list-item__content {
  809 + flex: none;
  810 + min-height: 48rpx;
  811 + line-height: 48rpx;
  812 + font-size: 32rpx;
  813 + position: relative;
  814 + width: 240rpx;
  815 + margin-right: 32rpx;
  816 + color: rgba(0, 0, 0, 0.9);
  817 + .required {
  818 + color: red;
  819 + position: absolute;
  820 + top: 50%;
  821 + transform: translateY(-50%);
  822 + left: -16rpx;
  823 + }
  824 + }
  825 + }
  826 + &.select-item {
  827 + &.is-empty {
  828 + .uni-list-item__extra-text {
  829 + color: rgba(0, 0, 0, 0.4) !important;
  830 + }
  831 + }
  832 + &.is-filled {
  833 + .uni-list-item__extra-text {
  834 + color: rgba(0, 0, 0, 0.9) !important;
  835 + }
  836 + }
  837 + .serial-number-row {
  838 + display: flex;
  839 + align-items: center;
  840 + }
  841 + }
  842 + }
  843 +}
  844 +
  845 +.readonly-text {
  846 + color: rgba(0, 0, 0, 0.9);
  847 + font-size: 32rpx;
  848 + line-height: 48rpx;
  849 + text-align: right;
  850 + white-space: pre-wrap;
  851 + word-break: break-all;
  852 +}
  853 +.value-code {
  854 + width: 260rpx;
  855 + text-align: left;
  856 +}
  857 +
  858 +.attach-list {
  859 + flex: 1;
  860 + display: flex;
  861 + flex-direction: column;
  862 + align-items: flex-end;
  863 + gap: 8rpx;
  864 +}
  865 +.attach-item {
  866 + display: flex;
  867 + align-items: center;
  868 + gap: 16rpx;
  869 + .attach-name { font-size: 26rpx; color: rgba(0,0,0,0.9); }
  870 + .attach-view { font-size: 26rpx; color: $theme-primary; }
  871 +}
  872 +
  873 +.material-condition-section,
  874 +.remark-section {
  875 + margin-top: 20rpx;
  876 + background: #fff;
  877 +}
  878 +.section-header {
  879 + display: flex;
  880 + align-items: center;
  881 + padding: 24rpx 32rpx;
  882 + border-bottom: 1rpx solid #f0f0f0;
  883 +}
  884 +.section-title {
  885 + font-size: 32rpx;
  886 + color: rgba(0, 0, 0, 0.9);
  887 + font-weight: 600;
  888 +}
  889 +.opCollapse {
  890 + width: 32rpx;
  891 + height: 28rpx;
  892 + margin-right: 16rpx;
  893 + margin-top: 8rpx;
  894 +}
  895 +.section-content {
  896 + padding: 32rpx;
  897 +}
  898 +.form-row {
  899 + display: flex;
  900 + align-items: center;
  901 + justify-content: space-between;
  902 + margin-bottom: 24rpx;
  903 +}
  904 +.form-row:last-child { margin-bottom: 0; }
  905 +.form-label {
  906 + font-size: 32rpx;
  907 + color: rgba(0, 0, 0, 0.9);
  908 +}
  909 +.form-value {
  910 + font-size: 32rpx;
  911 + color: rgba(0, 0, 0, 0.9);
  912 +}
  913 +.material-group {
  914 + margin-top: 32rpx;
  915 +}
  916 +.material-label {
  917 + display: block;
  918 + font-size: 30rpx;
  919 + color: rgba(0, 0, 0, 0.9);
  920 + margin-bottom: 20rpx;
  921 +}
  922 +.tag-list {
  923 + display: flex;
  924 + flex-wrap: wrap;
  925 + gap: 16rpx;
  926 +}
  927 +.tag-btn {
  928 + padding: 12rpx 24rpx;
  929 + border: 1rpx solid #ddd;
  930 + border-radius: 8rpx;
  931 + font-size: 28rpx;
  932 + color: #666;
  933 + background: #fff;
  934 +}
  935 +.tag-btn.active {
  936 + background: $theme-primary;
  937 + border-color: $theme-primary;
  938 + color: #fff;
  939 +}
  940 +.remark-text {
  941 + font-size: 30rpx;
  942 + color: rgba(0,0,0,0.9);
  943 + line-height: 1.6;
  944 + white-space: pre-wrap;
  945 +}
  946 +.footer-tip {
  947 + padding: 24rpx 32rpx;
  948 + color: rgba(0,0,0,0.45);
  949 + font-size: 24rpx;
  950 +}
  951 +
  952 +::v-deep .uni-easyinput {
  953 + width: 100%;
  954 + &__content {
  955 + background: #f8f8f8 !important;
  956 + border-radius: 8rpx;
  957 + &-input { font-size: 30rpx; }
  958 + }
  959 +}
  960 +</style>
... ...
... ... @@ -535,6 +535,7 @@ export default {
535 535 }
536 536 this.lineList = Array.isArray(d.procurementPlanLineList) ? d.procurementPlanLineList.slice() : []
537 537 this.buildAttachmentList()
  538 + this.fillLineNames()
538 539 this.refreshLinesFromShipping()
539 540 this.loadLatestPriceTableAndApply()
540 541 } catch (e) {
... ... @@ -551,6 +552,7 @@ export default {
551 552 var r2 = (results[1] && results[1].data) ? results[1].data : {}
552 553 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 : []))
553 554 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 : []))
  555 + this.fillLineNames()
554 556 } catch (e) {
555 557 this.productOptions = []
556 558 this.workshopOptions = []
... ... @@ -751,8 +753,39 @@ export default {
751 753 },
752 754 onLineChange(list) {
753 755 this.lineList = Array.isArray(list) ? list.slice() : []
  756 + this.fillLineNames()
754 757 this.refreshLinesFromShipping()
755 758 },
  759 + fillLineNames() {
  760 + if (!Array.isArray(this.lineList) || !this.lineList.length) return
  761 + var pOpts = Array.isArray(this.productOptions) ? this.productOptions : []
  762 + var wOpts = Array.isArray(this.workshopOptions) ? this.workshopOptions : []
  763 + var self = this
  764 + this.lineList = this.lineList.map(function (row) {
  765 + var r = Object.assign({}, row)
  766 + var pid = r.productId != null ? String(r.productId) : ''
  767 + var wid = r.workshopId != null ? String(r.workshopId) : ''
  768 + if ((r.productName == null || String(r.productName).trim() === '') && pid) {
  769 + var p = pOpts.find(function (o) {
  770 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.value != null ? String(o.value) : ''))
  771 + return id === pid
  772 + })
  773 + if (p) {
  774 + r.productName = p.name != null ? p.name : (p.productName != null ? p.productName : (p.label != null ? p.label : ''))
  775 + }
  776 + }
  777 + if ((r.workshopName == null || String(r.workshopName).trim() === '') && wid) {
  778 + var w = wOpts.find(function (o) {
  779 + var id = o.id != null ? String(o.id) : (o.workshopId != null ? String(o.workshopId) : (o.value != null ? String(o.value) : ''))
  780 + return id === wid
  781 + })
  782 + if (w) {
  783 + r.workshopName = w.name != null ? w.name : (w.workshopName != null ? w.workshopName : (w.label != null ? w.label : ''))
  784 + }
  785 + }
  786 + return r
  787 + })
  788 + },
756 789 notifyLineChange() {
757 790 try {
758 791 var pr = this.$refs.productRel
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view scroll-y class="scroll">
  4 + <uni-list>
  5 + <uni-list-item class="select-item is-filled">
  6 + <template v-slot:body>
  7 + <view class="item-title"><text>编号</text></view>
  8 + </template>
  9 + <template v-slot:footer>
  10 + <view class="serial-number-row">
  11 + <text class="readonly-text value-code">{{ safeText(main.code) }}</text>
  12 + </view>
  13 + </template>
  14 + </uni-list-item>
  15 +
  16 + <uni-list-item title="供应商名称">
  17 + <template v-slot:footer>
  18 + <uni-easyinput v-model="main.supplierName" :inputBorder="false" disabled placeholder="-" />
  19 + </template>
  20 + </uni-list-item>
  21 +
  22 + <uni-list-item title="采购处">
  23 + <template v-slot:footer>
  24 + <uni-easyinput v-model="purchaseDepartmentDisplay" :inputBorder="false" disabled placeholder="-" />
  25 + </template>
  26 + </uni-list-item>
  27 +
  28 + <uni-list-item title="区域">
  29 + <template v-slot:footer>
  30 + <uni-easyinput v-model="regionDisplay" :inputBorder="false" disabled placeholder="-" />
  31 + </template>
  32 + </uni-list-item>
  33 +
  34 + <uni-list-item title="日期">
  35 + <template v-slot:footer>
  36 + <uni-easyinput v-model="dateDisplay" :inputBorder="false" disabled placeholder="-" />
  37 + </template>
  38 + </uni-list-item>
  39 +
  40 + <uni-list-item title="运费(另付运费)">
  41 + <template v-slot:footer>
  42 + <uni-easyinput v-model="shippingCostDisplay" :inputBorder="false" disabled placeholder="-" />
  43 + </template>
  44 + </uni-list-item>
  45 +
  46 + <uni-list-item title="外观描述">
  47 + <template v-slot:footer>
  48 + <uni-easyinput v-model="main.appearanceDesc" :inputBorder="false" disabled placeholder="-" />
  49 + </template>
  50 + </uni-list-item>
  51 +
  52 + <uni-list-item title="料质状况">
  53 + <template v-slot:footer>
  54 + <uni-easyinput v-model="main.materialQualityDesc" :inputBorder="false" disabled placeholder="-" />
  55 + </template>
  56 + </uni-list-item>
  57 +
  58 + <uni-list-item title="废杂物情况">
  59 + <template v-slot:footer>
  60 + <uni-easyinput v-model="main.impurityDesc" :inputBorder="false" disabled placeholder="-" />
  61 + </template>
  62 + </uni-list-item>
  63 +
  64 + <uni-list-item title="油水杂情况">
  65 + <template v-slot:footer>
  66 + <uni-easyinput v-model="main.oilWaterDesc" :inputBorder="false" disabled placeholder="-" />
  67 + </template>
  68 + </uni-list-item>
  69 +
  70 + <uni-list-item title="装车费情况">
  71 + <template v-slot:footer>
  72 + <uni-easyinput v-model="loadingFeeDisplay" :inputBorder="false" disabled placeholder="-" />
  73 + </template>
  74 + </uni-list-item>
  75 +
  76 + <uni-list-item title="买断原因">
  77 + <template v-slot:footer>
  78 + <uni-easyinput v-model="main.buyoutReason" :inputBorder="false" disabled placeholder="-" />
  79 + </template>
  80 + </uni-list-item>
  81 +
  82 + <uni-list-item title="漆损率(%)">
  83 + <template v-slot:footer>
  84 + <uni-easyinput v-model="paintLossRatioDisplay" :inputBorder="false" disabled placeholder="-" />
  85 + </template>
  86 + </uni-list-item>
  87 +
  88 + <uni-list-item title="带漆说明">
  89 + <template v-slot:footer>
  90 + <text class="readonly-text small">{{ paintSummaryText || '-' }}</text>
  91 + </template>
  92 + </uni-list-item>
  93 + </uni-list>
  94 +
  95 + <view class="line-section">
  96 + <view class="section-header">
  97 + <image class="opCollapse" src="/static/images/title.png" />
  98 + <text class="section-title">买断明细</text>
  99 + </view>
  100 + <view v-if="!lineList.length" class="empty-tip">暂无明细</view>
  101 + <view v-else class="line-list">
  102 + <view v-for="(item, idx) in lineList" :key="item._key || ('line-' + idx)" class="line-card">
  103 + <view class="line-title">第 {{ idx + 1 }} 条明细</view>
  104 + <uni-list>
  105 + <uni-list-item title="买断品种">
  106 + <template v-slot:footer>
  107 + <text class="readonly-text">{{ safeText(item.productName) }}</text>
  108 + </template>
  109 + </uni-list-item>
  110 + <uni-list-item title="料型">
  111 + <template v-slot:footer>
  112 + <text class="readonly-text">{{ safeText(item.materialType) }}</text>
  113 + </template>
  114 + </uni-list-item>
  115 + <uni-list-item title="买断数量(吨)">
  116 + <template v-slot:footer>
  117 + <text class="readonly-text">{{ formatNumberText(item.quantity, 4) }}</text>
  118 + </template>
  119 + </uni-list-item>
  120 + <uni-list-item title="买断价格">
  121 + <template v-slot:footer>
  122 + <text class="readonly-text">{{ formatNumberText(item.buyoutPrice, 2) }}</text>
  123 + </template>
  124 + </uni-list-item>
  125 + <uni-list-item title="预计吨损耗">
  126 + <template v-slot:footer>
  127 + <text class="readonly-text">{{ formatNumberText(item.estimatedLoss, 2) }}</text>
  128 + </template>
  129 + </uni-list-item>
  130 + <uni-list-item title="漆损率(%)">
  131 + <template v-slot:footer>
  132 + <text class="readonly-text">{{ formatNumberText(item.paintLossRatio, 4) }}</text>
  133 + </template>
  134 + </uni-list-item>
  135 + <uni-list-item title="是否带漆">
  136 + <template v-slot:footer>
  137 + <text class="readonly-text">{{ item.withPaint ? '是(按漆损率计算)' : '否' }}</text>
  138 + </template>
  139 + </uni-list-item>
  140 + <uni-list-item title="除损耗后纯铜价格">
  141 + <template v-slot:footer>
  142 + <text class="readonly-text value-code price-code">{{ formatNumberText(item.pureCopperPrice, 2) }}</text>
  143 + </template>
  144 + </uni-list-item>
  145 + </uni-list>
  146 + </view>
  147 + </view>
  148 + </view>
  149 + </scroll-view>
  150 + </view>
  151 +</template>
  152 +
  153 +<script>
  154 +import { buyoutApplyDetailByPlanIdApi } from '@/api/procure-manage/buyout.js'
  155 +import { procurementPlanDetailApi } from '@/api/procure-manage/procurementPlan.js'
  156 +import { breedRelationshipQueryApi } from '@/api/devManage.js'
  157 +
  158 +export default {
  159 + name: 'DomesticPlanViewBuyoutApply',
  160 + data() {
  161 + return {
  162 + planId: '',
  163 + planData: {},
  164 + buyoutData: null,
  165 + breedOptions: [],
  166 + main: {
  167 + code: '',
  168 + supplierName: '',
  169 + purchaseDepartment: '',
  170 + purchaseDepartmentId: '',
  171 + region: '',
  172 + regionId: '',
  173 + date: '',
  174 + shippingCost: '',
  175 + appearanceDesc: '',
  176 + materialQualityDesc: '',
  177 + impurityDesc: '',
  178 + oilWaterDesc: '',
  179 + loadingFee: '',
  180 + buyoutReason: '',
  181 + paintLossRatio: ''
  182 + },
  183 + lineList: []
  184 + }
  185 + },
  186 + computed: {
  187 + purchaseDepartmentDisplay() {
  188 + var m = this.main || {}
  189 + var p = this.planData || {}
  190 + var v1 = m.purchaseDepartment != null ? String(m.purchaseDepartment) : ''
  191 + var v2 = p.purchaseDepartmentName != null ? String(p.purchaseDepartmentName) : (p.purchaseDepartment != null ? String(p.purchaseDepartment) : '')
  192 + return v1 ? v1 : v2
  193 + },
  194 + regionDisplay() {
  195 + var m = this.main || {}
  196 + var p = this.planData || {}
  197 + var v1 = m.region != null ? String(m.region) : ''
  198 + var v2 = p.regionName != null ? String(p.regionName) : (p.region != null ? String(p.region) : '')
  199 + return v1 ? v1 : v2
  200 + },
  201 + dateDisplay() {
  202 + var s = String(this.main.date || (this.planData.date || '')).trim()
  203 + if (!s) return ''
  204 + return s.length >= 10 ? s.slice(0, 10) : s
  205 + },
  206 + shippingCostDisplay() {
  207 + var v = this.toNumber(this.main.shippingCost != null ? this.main.shippingCost : this.planData.shippingCost)
  208 + return v === 0 ? '0.00' : v.toFixed(2)
  209 + },
  210 + loadingFeeDisplay() {
  211 + var v = this.toNumber(this.main.loadingFee != null ? this.main.loadingFee : this.planData.loadingFee)
  212 + return v === 0 ? '0.00' : v.toFixed(2)
  213 + },
  214 + paintLossRatioDisplay() {
  215 + var v = this.toNumber(this.main.paintLossRatio)
  216 + if (v === 0) return '0.0000'
  217 + return v ? v.toFixed(4) : ''
  218 + },
  219 + paintSummaryText() {
  220 + var list = Array.isArray(this.lineList) ? this.lineList : []
  221 + var withPaintList = list.filter(function (r) { return r.withPaint })
  222 + if (!withPaintList.length) return '本单明细未发现带漆的买断品种'
  223 + var totalQty = 0
  224 + var totalPureQty = 0
  225 + for (var i = 0; i < withPaintList.length; i++) {
  226 + var r = withPaintList[i]
  227 + var qty = this.toNumber(r.quantity)
  228 + var ratio = this.toNumber(r.paintLossRatio) / 100
  229 + if (ratio < 0) ratio = 0
  230 + if (ratio >= 1) ratio = 0.9999
  231 + totalQty += qty
  232 + totalPureQty += qty * (1 - ratio)
  233 + }
  234 + var avg = totalQty > 0 ? (totalPureQty / totalQty * 100) : 0
  235 + return '带漆品种数量合计 ' + this.formatNumber(totalQty, 4) + ' 吨,按品种漆损率计算的纯料折合比例约 ' + this.formatNumber(avg, 2) + '%(=∑ 数量*(1-漆损率) / 带漆总数量)'
  236 + }
  237 + },
  238 + onLoad(query) {
  239 + this.planId = (query && (query.planId || query.id)) ? (query.planId || query.id) : ''
  240 + this.loadAll()
  241 + },
  242 + methods: {
  243 + toNumber(v) {
  244 + if (v == null || v === '') return 0
  245 + var n = Number(v)
  246 + return isNaN(n) ? 0 : n
  247 + },
  248 + formatNumber(v, fraction) {
  249 + var n = this.toNumber(v)
  250 + if (fraction != null) return n.toFixed(fraction)
  251 + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  252 + },
  253 + formatNumberText(v, fraction) {
  254 + if (v == null || v === '') return '-'
  255 + var n = Number(v)
  256 + if (isNaN(n)) return String(v)
  257 + return fraction != null ? n.toFixed(fraction) : n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
  258 + },
  259 + safeText(v) {
  260 + var s = v == null ? '' : String(v)
  261 + return s.trim() ? s : '-'
  262 + },
  263 + async loadAll() {
  264 + var self = this
  265 + try {
  266 + await this.loadBreedOptions()
  267 + await this.loadPlanAndApply()
  268 + } catch (e) {
  269 + uni.showToast({ title: '加载失败', icon: 'none' })
  270 + }
  271 + },
  272 + async loadBreedOptions() {
  273 + try {
  274 + var res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 2000 })
  275 + var d = (res && res.data) ? res.data : {}
  276 + this.breedOptions = (d.datas && Array.isArray(d.datas)) ? d.datas : ((d.list && Array.isArray(d.list)) ? d.list : ((d.records && Array.isArray(d.records)) ? d.records : []))
  277 + } catch (e) {
  278 + this.breedOptions = []
  279 + }
  280 + },
  281 + findBreedOption(productId) {
  282 + if (!productId) return null
  283 + var pid = String(productId)
  284 + var list = Array.isArray(this.breedOptions) ? this.breedOptions : []
  285 + for (var i = 0; i < list.length; i++) {
  286 + var o = list[i] || {}
  287 + var id = o.id != null ? String(o.id) : (o.productId != null ? String(o.productId) : (o.breedId != null ? String(o.breedId) : (o.value != null ? String(o.value) : '')))
  288 + if (id === pid) return o
  289 + }
  290 + return null
  291 + },
  292 + getPaintLossRatioFromBreed(productId, fallbackRatio) {
  293 + var opt = this.findBreedOption(productId)
  294 + if (opt) {
  295 + var keys = ['paintLossRatio', 'paintLossRate', 'lossRatio', 'lacquerLossRatio']
  296 + for (var i = 0; i < keys.length; i++) {
  297 + if (opt[keys[i]] != null && opt[keys[i]] !== '') {
  298 + var n = Number(opt[keys[i]])
  299 + if (!isNaN(n)) return n
  300 + }
  301 + }
  302 + }
  303 + if (fallbackRatio != null && fallbackRatio !== '') {
  304 + var f = Number(fallbackRatio)
  305 + if (!isNaN(f)) return f
  306 + }
  307 + return 0
  308 + },
  309 + isWithPaintByBreed(productId, productName, breedPaintLossRatio) {
  310 + if (breedPaintLossRatio > 0) return true
  311 + var name = String(productName || '')
  312 + var tags = ['带漆', '漆', '漆包', '油漆', '喷漆', '覆漆']
  313 + for (var i = 0; i < tags.length; i++) {
  314 + if (name.indexOf(tags[i]) >= 0) return true
  315 + }
  316 + return false
  317 + },
  318 + async loadPlanAndApply() {
  319 + var self = this
  320 + var planRes = null
  321 + var plan = {}
  322 + if (this.planId) {
  323 + try { planRes = await procurementPlanDetailApi({ id: this.planId }) } catch (e) { planRes = null }
  324 + plan = (planRes && planRes.data) ? planRes.data : {}
  325 + this.planData = plan || {}
  326 + }
  327 + var buyout = null
  328 + if (this.planId) {
  329 + try {
  330 + var bRes = await buyoutApplyDetailByPlanIdApi(this.planId)
  331 + if (bRes && (bRes.data != null || (bRes.code && bRes.code === 200))) {
  332 + buyout = bRes.data ? bRes.data : {}
  333 + if (buyout && (buyout.id || buyout.code || (Array.isArray(buyout.procurementBuyoutApplyLineList) && buyout.procurementBuyoutApplyLineList.length))) {
  334 + this.buyoutData = buyout
  335 + }
  336 + }
  337 + } catch (e) {
  338 + buyout = null
  339 + }
  340 + }
  341 + this.buildMain(plan, buyout)
  342 + this.buildLineList(plan, buyout)
  343 + },
  344 + buildMain(plan, buyout) {
  345 + var b = buyout || {}
  346 + var p = plan || {}
  347 + var code = b.code || p.code || ''
  348 + var supplierName = b.supplierName != null ? b.supplierName : (p.supplierName != null ? p.supplierName : '')
  349 + var pd = b.purchaseDepartment != null ? b.purchaseDepartment : (p.purchaseDepartmentName != null ? p.purchaseDepartmentName : p.purchaseDepartment)
  350 + var pdId = b.purchaseDepartmentId != null ? b.purchaseDepartmentId : (p.purchaseDepartmentId != null ? p.purchaseDepartmentId : p.purchaseDepartment)
  351 + var region = b.region != null ? b.region : (p.regionName != null ? p.regionName : p.region)
  352 + var regionId = b.regionId != null ? b.regionId : (p.regionId != null ? p.regionId : p.region)
  353 + var date = b.date != null ? b.date : p.date
  354 + var shippingCost = b.shippingCost != null ? b.shippingCost : (p.shippingCost != null ? p.shippingCost : '')
  355 + var appearanceDesc = b.appearanceDesc != null ? b.appearanceDesc : '厂家生产过程中报废的一手料'
  356 + var materialQualityDesc = b.materialQualityDesc != null ? b.materialQualityDesc : '料质清爽'
  357 + var impurityDesc = b.impurityDesc != null ? b.impurityDesc : '含少量杂质'
  358 + var oilWaterDesc = b.oilWaterDesc != null ? b.oilWaterDesc : ''
  359 + var loadingFee = b.loadingFee != null ? b.loadingFee : (p.loadingFee != null ? p.loadingFee : '')
  360 + var buyoutReason = b.buyoutReason != null ? b.buyoutReason : ''
  361 + var paintLossRatio = b.paintLossRatio != null ? b.paintLossRatio : (p.paintLossRatio != null ? p.paintLossRatio : '')
  362 + this.main = {
  363 + code: code,
  364 + supplierName: supplierName,
  365 + purchaseDepartment: pd,
  366 + purchaseDepartmentId: pdId,
  367 + region: region,
  368 + regionId: regionId,
  369 + date: date,
  370 + shippingCost: shippingCost,
  371 + appearanceDesc: appearanceDesc,
  372 + materialQualityDesc: materialQualityDesc,
  373 + impurityDesc: impurityDesc,
  374 + oilWaterDesc: oilWaterDesc,
  375 + loadingFee: loadingFee,
  376 + buyoutReason: buyoutReason,
  377 + paintLossRatio: paintLossRatio
  378 + }
  379 + },
  380 + buildLineList(plan, buyout) {
  381 + var self = this
  382 + var lines = []
  383 + var bLines = (buyout && buyout.procurementBuyoutApplyLineList && Array.isArray(buyout.procurementBuyoutApplyLineList)) ? buyout.procurementBuyoutApplyLineList : null
  384 + var pLines = (plan && plan.procurementPlanLineList && Array.isArray(plan.procurementPlanLineList)) ? plan.procurementPlanLineList.slice() : []
  385 + if (bLines && bLines.length) {
  386 + lines = bLines
  387 + } else {
  388 + lines = pLines
  389 + }
  390 + var shippingCost = this.toNumber(this.main.shippingCost != null ? this.main.shippingCost : this.planData.shippingCost)
  391 + var loadingFee = this.toNumber(this.main.loadingFee != null ? this.main.loadingFee : this.planData.loadingFee)
  392 + var defaultPaintLossRatio = this.toNumber(this.main.paintLossRatio != null ? this.main.paintLossRatio : this.planData.paintLossRatio)
  393 + this.lineList = lines.map(function (r, i) {
  394 + var row = r || {}
  395 + var productId = row.productId
  396 + var breedPaintLossRatio = self.getPaintLossRatioFromBreed(productId, defaultPaintLossRatio)
  397 + var withPaint = self.isWithPaintByBreed(productId, row.productName, breedPaintLossRatio)
  398 + var ratio = withPaint ? breedPaintLossRatio : 0
  399 + var ratioFrac = ratio / 100
  400 + if (ratioFrac < 0) ratioFrac = 0
  401 + if (ratioFrac >= 1) ratioFrac = 0.9999
  402 + var actualPurchase = row.actualPurchasePrice != null ? row.actualPurchasePrice : (row.buyoutPrice != null ? row.buyoutPrice : 0)
  403 + var buyoutPrice = row.buyoutPrice != null ? row.buyoutPrice : actualPurchase
  404 + var estimatedLoss = row.estimatedLoss != null ? row.estimatedLoss : 0
  405 + var divisor = 1 - ratioFrac
  406 + var base = divisor > 0 ? (self.toNumber(actualPurchase) / divisor) : self.toNumber(actualPurchase)
  407 + var pureCopperPrice = base + shippingCost + self.toNumber(estimatedLoss) + loadingFee
  408 + return {
  409 + _key: row._key || row.id || ('row-' + i + '-' + Date.now()),
  410 + productId: productId,
  411 + productName: row.productName || '',
  412 + materialType: row.materialType || '',
  413 + quantity: row.quantity != null ? row.quantity : 0,
  414 + buyoutPrice: buyoutPrice,
  415 + estimatedLoss: estimatedLoss,
  416 + paintLossRatio: ratio,
  417 + withPaint: !!withPaint,
  418 + pureCopperPrice: pureCopperPrice
  419 + }
  420 + })
  421 + if (!this.main.paintLossRatio && defaultPaintLossRatio > 0) {
  422 + this.main.paintLossRatio = defaultPaintLossRatio
  423 + }
  424 + }
  425 + }
  426 +}
  427 +</script>
  428 +
  429 +<style lang="scss" scoped>
  430 +.page { display: flex; flex-direction: column; height: 100%; background: #f7f7f7; }
  431 +.scroll { flex: 1; padding: 12rpx 0 40rpx; }
  432 +
  433 +.line-section { margin-top: 20rpx; background: #fff; }
  434 +.section-header { display: flex; align-items: center; padding: 24rpx 32rpx; border-bottom: 1rpx solid #f0f0f0; }
  435 +.section-title { font-size: 32rpx; color: rgba(0,0,0,0.9); font-weight: 600; }
  436 +.opCollapse { width: 32rpx; height: 28rpx; margin-right: 16rpx; margin-top: 8rpx; }
  437 +.empty-tip { padding: 80rpx 32rpx; text-align: center; color: rgba(0,0,0,0.4); font-size: 28rpx; }
  438 +.line-list { padding: 0 0 20rpx; }
  439 +.line-card { margin: 24rpx 24rpx 0; background: #fff; border-radius: 16rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05); overflow: hidden; }
  440 +.line-title { padding: 20rpx 32rpx; font-size: 30rpx; color: rgba(0,0,0,0.9); border-bottom: 1rpx solid #f2f2f2; font-weight: 600; }
  441 +.value-code.price-code { font-weight: 700; color: $theme-primary; font-size: 32rpx; }
  442 +
  443 +::v-deep .uni-list {
  444 + .uni-easyinput {
  445 + display: flex;
  446 + .uni-input-input { color: rgba(0,0,0,0.9); }
  447 + }
  448 + .uni-input-placeholder { z-index: 1; }
  449 + .uni-input-input { background-color: #ffffff; }
  450 + background: transparent;
  451 + &-item {
  452 + &__container {
  453 + padding: 32rpx;
  454 + .uni-easyinput {
  455 + &__content {
  456 + border: none;
  457 + background-color: #ffffff !important;
  458 + &-input {
  459 + padding-left: 0 !important;
  460 + height: 48rpx;
  461 + line-height: 48rpx;
  462 + font-size: 32rpx;
  463 + }
  464 + }
  465 + }
  466 + .item-title,
  467 + .uni-list-item__content {
  468 + flex: none;
  469 + min-height: 48rpx;
  470 + line-height: 48rpx;
  471 + font-size: 32rpx;
  472 + width: 280rpx;
  473 + margin-right: 32rpx;
  474 + color: rgba(0,0,0,0.9);
  475 + }
  476 + }
  477 + &.select-item {
  478 + &.is-empty .uni-list-item__extra-text { color: rgba(0,0,0,0.4) !important; }
  479 + &.is-filled .uni-list-item__extra-text { color: rgba(0,0,0,0.9) !important; }
  480 + }
  481 + }
  482 +}
  483 +.readonly-text {
  484 + color: rgba(0,0,0,0.9);
  485 + font-size: 32rpx;
  486 + line-height: 48rpx;
  487 + text-align: right;
  488 + white-space: pre-wrap;
  489 + word-break: break-all;
  490 + &.small { font-size: 26rpx; line-height: 1.6; text-align: right; }
  491 +}
  492 +.value-code { width: 260rpx; text-align: left; }
  493 +.serial-number-row { display: flex; align-items: center; }
  494 +
  495 +::v-deep .uni-easyinput {
  496 + width: 100%;
  497 + &__content {
  498 + background: #f8f8f8 !important;
  499 + border-radius: 8rpx;
  500 + &-input { font-size: 30rpx; }
  501 + }
  502 +}
  503 +</style>
... ...