Commit 362b7ef1b311bff35ed365fa54ef1a9713ee178f

Authored by gesilong
2 parents c50564e6 d8ca7459

Merge branch 'cjerp-contract-1.0' into test_cjerp

... ... @@ -207,6 +207,16 @@ export function priceLock(data) {
207 207 region
208 208 })
209 209 }
  210 +//拆分数量
  211 +export function splitQuantityLock(data) {
  212 + return request({
  213 + url: `${baseUrl}/contractDistributorStandard/split`,
  214 + method: 'post',
  215 + data,
  216 + contentType: ContentTypeEnum.JSON,
  217 + region
  218 + })
  219 +}
210 220
211 221 // 删除合同
212 222 export function deleteContractApi(id) {
... ...
... ... @@ -31,7 +31,7 @@
31 31 }}</text></view>
32 32 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode ||
33 33 '-'}}</text></view>
34   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel || '-'
  34 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination || '-'
35 35 }}</text></view>
36 36 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
37 37 detail.includesPackagingFeeName || '-' }}</text></view>
... ... @@ -114,8 +114,7 @@ export default {
114 114 packagingRequirements: '',
115 115 paymentTerms: '',
116 116 transportMode: '',
117   - destinationId: '',
118   - destinationLabel: '',
  117 + foreignDestination: '',
119 118 specialInstructions: '',
120 119 remarks: '',
121 120 pieceWeightHead: '',
... ... @@ -154,8 +153,7 @@ export default {
154 153 ...this.detail,
155 154 ...data,
156 155 includesPackagingFeeName, includesTransportFeeName,
157   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
158   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  156 + foreignDestination: (data.foreignDestination || ''),
159 157 }
160 158 const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
161 159 this.productList = lines
... ...
... ... @@ -31,7 +31,7 @@
31 31 }}</text></view>
32 32 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode ||
33 33 '-'}}</text></view>
34   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel || '-'
  34 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination || '-'
35 35 }}</text></view>
36 36 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
37 37 detail.includesPackagingFeeName || '-' }}</text></view>
... ... @@ -114,8 +114,7 @@ export default {
114 114 packagingRequirements: '',
115 115 paymentTerms: '',
116 116 transportMode: '',
117   - destinationId: '',
118   - destinationLabel: '',
  117 + foreignDestination: '',
119 118 specialInstructions: '',
120 119 remarks: '',
121 120 pieceWeightHead: '',
... ... @@ -154,8 +153,7 @@ export default {
154 153 ...this.detail,
155 154 ...data,
156 155 includesPackagingFeeName, includesTransportFeeName,
157   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
158   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  156 + foreignDestination: (data.foreignDestination || ''),
159 157 }
160 158 const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
161 159 this.productList = lines
... ...
... ... @@ -412,6 +412,14 @@
412 412 }
413 413 },
414 414 {
  415 + "path": "pages/contract_stock/uploadStandard",
  416 + "style": {
  417 + "navigationBarTitleText": "上传合同附件",
  418 + "navigationBarBackgroundColor": "#ffffff",
  419 + "navigationBarTextStyle": "black"
  420 + }
  421 + },
  422 + {
415 423 "path": "pages/contract_stock/lock",
416 424 "style": {
417 425 "navigationBarTitleText": "锁价",
... ... @@ -420,6 +428,14 @@
420 428 }
421 429 },
422 430 {
  431 + "path": "pages/contract_stock/split",
  432 + "style": {
  433 + "navigationBarTitleText": "拆分",
  434 + "navigationBarBackgroundColor": "#ffffff",
  435 + "navigationBarTextStyle": "black"
  436 + }
  437 + },
  438 + {
423 439 "path": "pages/contract_unplan/index",
424 440 "style": {
425 441 "navigationBarTitleText": "经销未锁规合同",
... ... @@ -452,6 +468,14 @@
452 468 }
453 469 },
454 470 {
  471 + "path": "pages/contract_unplan/uploadStandard",
  472 + "style": {
  473 + "navigationBarTitleText": "上传合同附件",
  474 + "navigationBarBackgroundColor": "#ffffff",
  475 + "navigationBarTextStyle": "black"
  476 + }
  477 + },
  478 + {
455 479 "path": "pages/contract_unplan/lock",
456 480 "style": {
457 481 "navigationBarTitleText": "锁规",
... ... @@ -580,6 +604,14 @@
580 604 }
581 605 },
582 606 {
  607 + "path": "pages/contract_foreign_stock/uploadStandard",
  608 + "style": {
  609 + "navigationBarTitleText": "上传合同附件",
  610 + "navigationBarBackgroundColor": "#ffffff",
  611 + "navigationBarTextStyle": "black"
  612 + }
  613 + },
  614 + {
583 615 "path": "pages/contract_foreign_stock/lock",
584 616 "style": {
585 617 "navigationBarTitleText": "锁价",
... ... @@ -588,6 +620,14 @@
588 620 }
589 621 },
590 622 {
  623 + "path": "pages/contract_foreign_stock/split",
  624 + "style": {
  625 + "navigationBarTitleText": "拆分",
  626 + "navigationBarBackgroundColor": "#ffffff",
  627 + "navigationBarTextStyle": "black"
  628 + }
  629 + },
  630 + {
591 631 "path": "pages/contract_foreign_unplan/index",
592 632 "style": {
593 633 "navigationBarTitleText": "外贸未锁规合同",
... ... @@ -620,6 +660,14 @@
620 660 }
621 661 },
622 662 {
  663 + "path": "pages/contract_foreign_unplan/uploadStandard",
  664 + "style": {
  665 + "navigationBarTitleText": "上传合同附件",
  666 + "navigationBarBackgroundColor": "#ffffff",
  667 + "navigationBarTextStyle": "black"
  668 + }
  669 + },
  670 + {
623 671 "path": "pages/contract_foreign_unplan/lock",
624 672 "style": {
625 673 "navigationBarTitleText": "锁规",
... ...
... ... @@ -88,11 +88,9 @@
88 88 </template>
89 89 </uni-list-item>
90 90
91   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
92   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
93   - <template v-slot:body>
94   - <view class="item-title"><text>目的地</text></view>
95   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  91 + <uni-list-item title="目的地">
  92 + <template v-slot:footer>
  93 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
96 94 </template>
97 95 </uni-list-item>
98 96 <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
... ... @@ -229,7 +227,6 @@
229 227 import SingleSelectSheet from '@/components/single-select/index.vue'
230 228 import RelateSelectSheet from '@/components/relate-select/index.vue'
231 229 import ProductRel from './productRel.vue'
232   -import CitySelector from '@/components/city-selector/index.vue'
233 230 import { getRetailCodeApi, createContractApi, getCustomerRemarks, getCustomerSpecificQualityRequirements, getDeptApi, getContractApi } from '@/api/contract'
234 231 import { getDicByCodes } from '@/utils/dic'
235 232 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -239,7 +236,7 @@ import { getArea } from '@/api/credit_manage.js'
239 236
240 237 export default {
241 238 name: 'AddContractForeignStd',
242   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  239 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
243 240 data() {
244 241 return {
245 242 copyId: '',
... ... @@ -268,8 +265,7 @@ export default {
268 265 includesTransportFeeName: '否',
269 266 unit: '美元、公斤、美元/公斤',
270 267 totalAmountCapital: '',
271   - destinationId: [],
272   - destinationLabel: '',
  268 + foreignDestination: '',
273 269 workshopIdName: '',
274 270 workshopId: '',
275 271 remarks: '',
... ... @@ -315,11 +311,6 @@ export default {
315 311 this.loadRegionOptions()
316 312 if (!this.copyId) this.form.orderDate = this.formatDate(new Date())
317 313 if (this.copyId) this.loadCopyDetail(this.copyId)
318   - this.$nextTick(() => {
319   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
320   - this.initDestinationLabel()
321   - }
322   - })
323 314 },
324 315 watch: {
325 316 'form.buyer': {
... ... @@ -404,8 +395,7 @@ export default {
404 395 packagingRequirements: m.packagingRequirements || '',
405 396 paymentTerms: m.paymentTerms || '',
406 397 transportMode: m.transportMode || '',
407   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
408   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  398 + foreignDestination: (m.foreignDestination || ''),
409 399 specialInstructions: m.specialInstructions || '',
410 400 remarks: m.remarks || '',
411 401 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -551,20 +541,6 @@ export default {
551 541 const val = m[field]
552 542 return val ? String(val) : map[field]
553 543 },
554   - openCitySelector() {
555   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
556   - },
557   - async initDestinationLabel() {
558   - const comp = this.$refs.citySelectorRef
559   - if (comp && typeof comp.getLabel === 'function') {
560   - const label = await comp.getLabel()
561   - this.form.destinationLabel = label || ''
562   - }
563   - },
564   - onCityChange(payload) {
565   - const label = payload && payload.label != null ? payload.label : ''
566   - this.form.destinationLabel = label
567   - },
568 544 async openSheet(field) {
569 545 const setSheet = (title, options) => {
570 546 const current = this.form[field]
... ... @@ -664,13 +640,9 @@ export default {
664 640 return out
665 641 }
666 642 const lines = (this.productLineList || []).map(it => clean(it))
667   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
668   - // 区id
669   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
670 643 const payload = clean({
671   - ...formForSubmit,
  644 + ...this.form,
672 645 operateType: isCopy ? 'COPY' : 'ADD',
673   - destination,
674 646 type: 'INTL_STD_CONTRACT',
675 647 totalQuantity: this.totalQuantity,
676 648 // totalAmountExcludingTax: this.totalAmountExcludingTax,
... ...
... ... @@ -38,7 +38,7 @@
38 38 '-' }}</text></view>
39 39 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode || '-'
40 40 }}</text></view>
41   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel ||
  41 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination ||
42 42 '-'
43 43 }}</text></view>
44 44 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
... ... @@ -167,8 +167,7 @@ export default {
167 167 packagingRequirements: '',
168 168 paymentTerms: '',
169 169 transportMode: '',
170   - destinationId: '',
171   - destinationLabel: '',
  170 + foreignDestination: '',
172 171 specialInstructions: '',
173 172 remarks: '',
174 173 pieceWeightHead: '',
... ... @@ -386,7 +385,7 @@ export default {
386 385 const e = btn.event || ''
387 386 if (e === 'edit') return this.onEdit(btn && btn.params)
388 387 if (e === 'delete') return this.onDelete(btn && btn.params)
389   - if (e === 'upload') return this.uploadContract(this.detail.id || '')
  388 + if (e === 'upload') return this.uploadContract(this.detail.id || '', 'standard')
390 389 if (e === 'uploadSeal') return this.uploadContract(this.detail.id || '', 'seal')
391 390 if (e === 'audit') return this.onAudit(btn && btn.params)
392 391 if (e === 'auditDetail') return this.onAuditDetail(btn && btn.params)
... ... @@ -435,8 +434,7 @@ export default {
435 434 regionName: data.regionName || '',
436 435 deptName: data.deptName || '',
437 436 includesPackagingFeeName, includesTransportFeeName,
438   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
439   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  437 + foreignDestination: (data.foreignDestination || ''),
440 438 }
441 439 this.detail = await fillStandardApprovedName(this.detail)
442 440 const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
... ...
... ... @@ -90,11 +90,9 @@
90 90 <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
91 91 </template>
92 92 </uni-list-item>
93   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
94   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
95   - <template v-slot:body>
96   - <view class="item-title"><text>目的地</text></view>
97   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  93 + <uni-list-item title="目的地">
  94 + <template v-slot:footer>
  95 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
98 96 </template>
99 97 </uni-list-item>
100 98
... ... @@ -214,7 +212,6 @@
214 212 import SingleSelectSheet from '@/components/single-select/index.vue'
215 213 import RelateSelectSheet from '@/components/relate-select/index.vue'
216 214 import ProductRel from './productRel.vue'
217   -import CitySelector from '@/components/city-selector/index.vue'
218 215 import { getContractApi, updateContractApi } from '@/api/contract'
219 216 import { getDicByCodes } from '@/utils/dic'
220 217 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -222,7 +219,7 @@ import { workshopQueryApi } from '@/api/devManage'
222 219 import { getArea } from '@/api/credit_manage.js'
223 220 export default {
224 221 name: 'ModifyContractForeignStd',
225   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  222 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
226 223 data() {
227 224 return {
228 225 id: '',
... ... @@ -259,8 +256,7 @@ export default {
259 256 packagingRequirements: '',
260 257 paymentTerms: '',
261 258 transportMode: '',
262   - destinationId: [],
263   - destinationLabel: '',
  259 + foreignDestination: '',
264 260 specialInstructions: '',
265 261 remarks: '',
266 262 pieceWeightHead: '',
... ... @@ -293,11 +289,6 @@ export default {
293 289 this.loadExtraOptions()
294 290 this.loadRegionOptions()
295 291 this.loadDetail()
296   - this.$nextTick(() => {
297   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
298   - this.initDestinationLabel()
299   - }
300   - })
301 292 },
302 293 methods: {
303 294 async loadRegionOptions() {
... ... @@ -344,8 +335,7 @@ export default {
344 335 packagingRequirements: m.packagingRequirements || '',
345 336 paymentTerms: m.paymentTerms || '',
346 337 transportMode: m.transportMode || '',
347   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
348   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  338 + foreignDestination: (m.foreignDestination || ''),
349 339 specialInstructions: m.specialInstructions || '',
350 340 remarks: m.remarks || '',
351 341 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -366,20 +356,6 @@ export default {
366 356 this.onProductsChange(lines)
367 357 } catch (e) { }
368 358 },
369   - async initDestinationLabel() {
370   - const comp = this.$refs.citySelectorRef
371   - if (comp && typeof comp.getLabel === 'function') {
372   - const label = await comp.getLabel()
373   - this.form.destinationLabel = label || ''
374   - }
375   - },
376   - openCitySelector() {
377   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
378   - },
379   - onCityChange(payload) {
380   - const label = payload && payload.label != null ? payload.label : ''
381   - this.form.destinationLabel = label
382   - },
383 359 onProductsChange(products) {
384 360 const list = Array.isArray(products) ? products : []
385 361 this.newProductLineList = list
... ... @@ -528,7 +504,6 @@ export default {
528 504 return true
529 505 },
530 506 async onSubmit() {
531   - console.log('onSubmit__payload', payload)
532 507 if (!this.validateRequired()) return
533 508 const confirmRes = await new Promise(resolve => {
534 509 uni.showModal({ title: '提示', content: '确定保存当前外贸标准合同吗?', confirmText: '确定', cancelText: '取消', success: resolve })
... ... @@ -546,25 +521,22 @@ export default {
546 521 return out
547 522 }
548 523 const lines = (this.newProductLineList || []).map(it => clean(it))
549   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
550   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
551   - const payload = clean({
552   - ...formForSubmit,
553   - id: this.form.id,
554   - destination,
555   - type: 'INTL_STD_CONTRACT',
556   - totalQuantity: this.totalQuantity,
557   - // totalAmountExcludingTax: this.totalAmountExcludingTax,
558   - totalAmountIncludingTax: this.totalAmountIncludingTax,
559   - contractDistributorLineList: lines
560   - })
561   - try {
562   - await updateContractApi(payload)
563   - uni.showToast({ title: '保存成功', icon: 'none' })
564   - setTimeout(() => { uni.redirectTo({ url: '/pages/contract_foreign_std/index' }) }, 400)
565   - } catch (e) {
566   - uni.showToast({ title: e.msg ||'提交失败', icon: 'none' })
567   - }
  524 + const payload = clean({
  525 + ...this.form,
  526 + id: this.form.id,
  527 + type: 'INTL_STD_CONTRACT',
  528 + totalQuantity: this.totalQuantity,
  529 + // totalAmountExcludingTax: this.totalAmountExcludingTax,
  530 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  531 + contractDistributorLineList: lines
  532 + })
  533 + try {
  534 + await updateContractApi(payload)
  535 + uni.showToast({ title: '保存成功', icon: 'none' })
  536 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_foreign_std/index' }) }, 400)
  537 + } catch (e) {
  538 + uni.showToast({ title: e.msg ||'提交失败', icon: 'none' })
  539 + }
568 540 }
569 541 }
570 542 }
... ... @@ -809,4 +781,4 @@ export default {
809 781 }
810 782 }
811 783
812   -</style>
\ No newline at end of file
  784 +</style>
... ...
... ... @@ -89,12 +89,9 @@
89 89 <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
90 90 </template>
91 91 </uni-list-item>
92   - <uni-list-item class="select-item"
93   - :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
94   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
95   - <template v-slot:body>
96   - <view class="item-title"><text>目的地</text></view>
97   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  92 + <uni-list-item title="目的地">
  93 + <template v-slot:footer>
  94 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
98 95 </template>
99 96 </uni-list-item>
100 97
... ... @@ -219,7 +216,6 @@
219 216 import SingleSelectSheet from '@/components/single-select/index.vue'
220 217 import RelateSelectSheet from '@/components/relate-select/index.vue'
221 218 import ProductRel from './productRel.vue'
222   -import CitySelector from '@/components/city-selector/index.vue'
223 219 import FileUpload from '@/components/file-upload/index.vue'
224 220 import { getContractApi, uploadStandardContract } from '@/api/contract'
225 221 import { getDicByCodes } from '@/utils/dic'
... ... @@ -229,7 +225,7 @@ import { getArea } from '@/api/credit_manage.js'
229 225
230 226 export default {
231 227 name: 'UploadStandardContractForeignStd',
232   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  228 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, FileUpload },
233 229 data() {
234 230 return {
235 231 id: '',
... ... @@ -269,8 +265,7 @@ export default {
269 265 packagingRequirements: '',
270 266 paymentTerms: '',
271 267 transportMode: '',
272   - destinationId: [],
273   - destinationLabel: '',
  268 + foreignDestination: '',
274 269 specialInstructions: '',
275 270 remarks: '',
276 271 pieceWeightHead: '',
... ... @@ -311,11 +306,6 @@ export default {
311 306 this.loadExtraOptions()
312 307 this.loadRegionOptions()
313 308 this.loadDetail()
314   - this.$nextTick(() => {
315   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
316   - this.initDestinationLabel()
317   - }
318   - })
319 309 },
320 310 methods: {
321 311 async loadRegionOptions() {
... ... @@ -362,8 +352,7 @@ export default {
362 352 packagingRequirements: m.packagingRequirements || '',
363 353 paymentTerms: m.paymentTerms || '',
364 354 transportMode: m.transportMode || '',
365   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
366   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  355 + foreignDestination: (m.foreignDestination || ''),
367 356 specialInstructions: m.specialInstructions || '',
368 357 remarks: m.remarks || '',
369 358 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -387,20 +376,6 @@ export default {
387 376 this.onProductsChange(lines)
388 377 } catch (e) { }
389 378 },
390   - async initDestinationLabel() {
391   - const comp = this.$refs.citySelectorRef
392   - if (comp && typeof comp.getLabel === 'function') {
393   - const label = await comp.getLabel()
394   - this.form.destinationLabel = label || ''
395   - }
396   - },
397   - openCitySelector() {
398   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
399   - },
400   - onCityChange(payload) {
401   - const label = payload && payload.label != null ? payload.label : ''
402   - this.form.destinationLabel = label
403   - },
404 379 onProductsChange(products) {
405 380 const list = Array.isArray(products) ? products : []
406 381 this.newProductLineList = list
... ... @@ -602,12 +577,9 @@ export default {
602 577 return out
603 578 }
604 579 const lines = (this.newProductLineList || []).map(it => clean(it))
605   - const { destinationLabel, destinationId, ...formForSubmit } = this.form
606   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : ''
607 580 const payload = clean({
608   - ...formForSubmit,
  581 + ...this.form,
609 582 id: this.form.id,
610   - destination,
611 583 type: 'INTL_STD_CONTRACT',
612 584 totalQuantity: this.totalQuantity,
613 585 totalAmountIncludingTax: this.totalAmountIncludingTax,
... ...
... ... @@ -91,11 +91,9 @@
91 91 </template>
92 92 </uni-list-item>
93 93
94   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
95   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
96   - <template v-slot:body>
97   - <view class="item-title"><text>目的地</text></view>
98   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  94 + <uni-list-item title="目的地">
  95 + <template v-slot:footer>
  96 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
99 97 </template>
100 98 </uni-list-item>
101 99 <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
... ... @@ -232,7 +230,6 @@
232 230 import SingleSelectSheet from '@/components/single-select/index.vue'
233 231 import RelateSelectSheet from '@/components/relate-select/index.vue'
234 232 import ProductRel from './productRel.vue'
235   -import CitySelector from '@/components/city-selector/index.vue'
236 233 import { getRetailCodeApi, createContractApi, getCustomerSpecificQualityRequirements, getCustomerRemarks, getDeptApi, getContractApi } from '@/api/contract'
237 234 import { getDicByCodes } from '@/utils/dic'
238 235 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -241,7 +238,7 @@ import { getArea } from '@/api/credit_manage.js'
241 238
242 239 export default {
243 240 name: 'AddContractForeignStock',
244   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  241 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
245 242 data() {
246 243 return {
247 244 copyId: '',
... ... @@ -268,8 +265,7 @@ export default {
268 265 includesTransportFeeName: '否',
269 266 unit: '美元、公斤、美元/公斤',
270 267 totalAmountCapital: '',
271   - destinationId: [],
272   - destinationLabel: '',
  268 + foreignDestination: '',
273 269 workshopIdName: '',
274 270 workshopId: '',
275 271 deptName: '',
... ... @@ -317,11 +313,6 @@ export default {
317 313 this.loadRegionOptions()
318 314 if (!this.copyId) this.form.orderDate = this.formatDate(new Date())
319 315 if (this.copyId) this.loadCopyDetail(this.copyId)
320   - this.$nextTick(() => {
321   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
322   - this.initDestinationLabel()
323   - }
324   - })
325 316 },
326 317 watch: {
327 318 'form.buyer': {
... ... @@ -406,8 +397,7 @@ export default {
406 397 packagingRequirements: m.packagingRequirements || '',
407 398 paymentTerms: m.paymentTerms || '',
408 399 transportMode: m.transportMode || '',
409   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
410   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  400 + foreignDestination: (m.foreignDestination || ''),
411 401 specialInstructions: m.specialInstructions || '',
412 402 remarks: m.remarks || '',
413 403 packaging: m.packaging || '',
... ... @@ -554,20 +544,6 @@ export default {
554 544 const val = m[field]
555 545 return val ? String(val) : map[field]
556 546 },
557   - openCitySelector() {
558   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
559   - },
560   - async initDestinationLabel() {
561   - const comp = this.$refs.citySelectorRef
562   - if (comp && typeof comp.getLabel === 'function') {
563   - const label = await comp.getLabel()
564   - this.form.destinationLabel = label || ''
565   - }
566   - },
567   - onCityChange(payload) {
568   - const label = payload && payload.label != null ? payload.label : ''
569   - this.form.destinationLabel = label
570   - },
571 547 async openSheet(field) {
572 548 const setSheet = (title, options) => {
573 549 const current = this.form[field]
... ... @@ -667,13 +643,9 @@ export default {
667 643 return out
668 644 }
669 645 const lines = (this.productLineList || []).map(it => clean(it))
670   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
671   - // 区id
672   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
673 646 const payload = clean({
674   - ...formForSubmit,
  647 + ...this.form,
675 648 operateType: isCopy ? 'COPY' : 'ADD',
676   - destination,
677 649 type: 'INTL_INVENTORY_AGMT',
678 650 totalQuantity: this.totalQuantity,
679 651 // totalAmountExcludingTax: this.totalAmountExcludingTax,
... ...
... ... @@ -50,7 +50,7 @@
50 50 '-' }}</text></view>
51 51 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode || '-'
52 52 }}</text></view>
53   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel ||
  53 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination ||
54 54 '-'
55 55 }}</text></view>
56 56 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
... ... @@ -188,8 +188,7 @@ export default {
188 188 packagingRequirements: '',
189 189 paymentTerms: '',
190 190 transportMode: '',
191   - destinationId: '',
192   - destinationLabel: '',
  191 + foreignDestination: '',
193 192 specialInstructions: '',
194 193 remarks: '',
195 194 pieceWeightHead: '',
... ... @@ -292,6 +291,12 @@ export default {
292 291 variant: 'outline',
293 292 event: 'print'
294 293 },
  294 + {
  295 + text: '拆分',
  296 + visible: true,
  297 + variant: 'outline',
  298 + event: 'split'
  299 + },
295 300 ],
296 301 }
297 302 },
... ... @@ -303,6 +308,7 @@ export default {
303 308 const a = this.detail.standardApproved || false
304 309 const e = this.detail.showExamine || false
305 310 const f = this.detail.standardShowExamine || false
  311 + const g = this.detail.canSplit || false
306 312 return [
307 313 { ...this.buttons[0], visible: (s === 'DRAFT' && this.$auth.hasPermi('contract-manage:foreign-trade-inventory-contract:modify')) }, //编辑
308 314 { ...this.buttons[1], visible: (s === 'DRAFT' && this.$auth.hasPermi('contract-manage:foreign-trade-inventory-contract:delete')) }, //删除
... ... @@ -319,6 +325,7 @@ export default {
319 325 { ...this.buttons[8], visible: (s === 'STANDARD' && f && a === 'AUDIT' && this.$auth.hasPermi('contract-manage:foreign-trade-inventory-contract:standard-approve')) },
320 326 { ...this.buttons[13], visible: (s !== 'DELETED' && this.$auth.hasPermi('contract-manage:foreign-trade-inventory-contract:copy')) },
321 327 { ...this.buttons[14], visible: true },
  328 + { ...this.buttons[15], visible: g },
322 329 ]
323 330 }
324 331 },
... ... @@ -373,6 +380,13 @@ export default {
373 380 uploadContract(id, type = 'formal') {
374 381 if (!id) return
375 382 this.uploadId = id
  383 + if ((type === 'uploadParent' || type === 'upload' )&& this.detail?.canEdit) {
  384 + const query = `?id=${encodeURIComponent(id)}`
  385 + uni.navigateTo({
  386 + url: '/pages/contract_foreign_stock/uploadStandard' + query
  387 + })
  388 + return
  389 + }
376 390 this.uploadType = type
377 391 this.$refs.uploadPopup.open()
378 392 },
... ... @@ -456,8 +470,8 @@ export default {
456 470 if (e === 'edit') return this.onEdit(btn && btn.params)
457 471 if (e === 'delete') return this.onDelete(btn && btn.params)
458 472 if (e === 'lock') return this.onLock()
459   - if (e === 'upload') return this.uploadContract(this.detail.id || '')
460   - if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '')
  473 + if (e === 'upload') return this.uploadContract(this.detail.id || '','upload')
  474 + if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '', 'uploadParent')
461 475 if (e === 'uploadStandard') return this.uploadContract(this.detail.id || '', 'standard')
462 476 if (e === 'audit1') return this.onAudit(this.detail.id || '', 'FORMAL_CONTRACT')
463 477 if (e === 'audit2') return this.onAudit(this.detail.parentId || '', 'FORMAL_CONTRACT')
... ... @@ -468,6 +482,12 @@ export default {
468 482 if (e === 'uploadSeal') return this.uploadContract(this.detail.id || '', 'seal')
469 483 if (e === 'copy') return this.onCopy(btn && btn.params)
470 484 if (e === 'print') return this.onPrint(this.detail.id || '')
  485 + if (e === 'split') return this.onSplit(this.detail.id || '')
  486 + },
  487 + onSplit(id) {
  488 + uni.navigateTo({
  489 + url: '/pages/contract_foreign_stock/split?id=' + id
  490 + })
471 491 },
472 492 onPrint(id) {
473 493 printFile(id)
... ... @@ -516,8 +536,7 @@ export default {
516 536 regionName: data.regionName || '',
517 537 deptName: data.deptName || '',
518 538 includesPackagingFeeName, includesTransportFeeName,
519   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
520   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  539 + foreignDestination: (data.foreignDestination || ''),
521 540 }
522 541 this.detail = await fillStandardApprovedName(this.detail)
523 542 this.detail = await fillFormalApprovedName(this.detail)
... ...
... ... @@ -94,11 +94,9 @@
94 94 <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
95 95 </template>
96 96 </uni-list-item>
97   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
98   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
99   - <template v-slot:body>
100   - <view class="item-title"><text>目的地</text></view>
101   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  97 + <uni-list-item title="目的地">
  98 + <template v-slot:footer>
  99 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
102 100 </template>
103 101 </uni-list-item>
104 102
... ... @@ -218,7 +216,6 @@
218 216 import SingleSelectSheet from '@/components/single-select/index.vue'
219 217 import RelateSelectSheet from '@/components/relate-select/index.vue'
220 218 import ProductRel from './productRel.vue'
221   -import CitySelector from '@/components/city-selector/index.vue'
222 219 import { getContractApi, updateContractApi } from '@/api/contract'
223 220 import { getDicByCodes } from '@/utils/dic'
224 221 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -227,7 +224,7 @@ import { getArea } from '@/api/credit_manage.js'
227 224
228 225 export default {
229 226 name: 'ModifyContractForeignStock',
230   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  227 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
231 228 data() {
232 229 return {
233 230 id: '',
... ... @@ -264,8 +261,7 @@ export default {
264 261 packagingRequirements: '',
265 262 paymentTerms: '',
266 263 transportMode: '',
267   - destinationId: [],
268   - destinationLabel: '',
  264 + foreignDestination: '',
269 265 specialInstructions: '',
270 266 remarks: '',
271 267 pieceWeightHead: '',
... ... @@ -298,11 +294,6 @@ export default {
298 294 this.loadExtraOptions()
299 295 this.loadRegionOptions()
300 296 this.loadDetail()
301   - this.$nextTick(() => {
302   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
303   - this.initDestinationLabel()
304   - }
305   - })
306 297 },
307 298 methods: {
308 299 async loadRegionOptions() {
... ... @@ -349,8 +340,7 @@ export default {
349 340 packagingRequirements: m.packagingRequirements || '',
350 341 paymentTerms: m.paymentTerms || '',
351 342 transportMode: m.transportMode || '',
352   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
353   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  343 + foreignDestination: (m.foreignDestination || ''),
354 344 specialInstructions: m.specialInstructions || '',
355 345 remarks: m.remarks || '',
356 346 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -371,20 +361,6 @@ export default {
371 361 this.onProductsChange(lines)
372 362 } catch (e) { }
373 363 },
374   - async initDestinationLabel() {
375   - const comp = this.$refs.citySelectorRef
376   - if (comp && typeof comp.getLabel === 'function') {
377   - const label = await comp.getLabel()
378   - this.form.destinationLabel = label || ''
379   - }
380   - },
381   - openCitySelector() {
382   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
383   - },
384   - onCityChange(payload) {
385   - const label = payload && payload.label != null ? payload.label : ''
386   - this.form.destinationLabel = label
387   - },
388 364 onProductsChange(products) {
389 365 const list = Array.isArray(products) ? products : []
390 366 this.newProductLineList = list
... ... @@ -531,7 +507,6 @@ export default {
531 507 return true
532 508 },
533 509 async onSubmit() {
534   - console.log('onSubmit__payload', payload)
535 510 if (!this.validateRequired()) return
536 511 const confirmRes = await new Promise(resolve => {
537 512 uni.showModal({ title: '提示', content: '确定保存当前外贸库存合同吗?', confirmText: '确定', cancelText: '取消', success: resolve })
... ... @@ -549,12 +524,9 @@ export default {
549 524 return out
550 525 }
551 526 const lines = (this.newProductLineList || []).map(it => clean(it))
552   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
553   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
554 527 const payload = clean({
555   - ...formForSubmit,
  528 + ...this.form,
556 529 id: this.form.id,
557   - destination,
558 530 type: 'INTL_INVENTORY_AGMT',
559 531 totalQuantity: this.totalQuantity,
560 532 // totalAmountExcludingTax: this.totalAmountExcludingTax,
... ... @@ -812,4 +784,4 @@ export default {
812 784 }
813 785 }
814 786
815   -</style>
\ No newline at end of file
  787 +</style>
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="lock-page">
  5 + <view class="block" v-for="(item, idx) in items" :key="idx">
  6 + <view class="block-header">
  7 + <uni-data-checkbox multiple mode="default" :localdata="[{ text: '拆分', value: 'LOCKED' }]"
  8 + :modelValue="item.locked ? ['LOCKED'] : []" :disabled="true"
  9 + @change="onLockChange(idx, $event)" />
  10 + <view class="ops" @click="toggleItem(idx)">
  11 + <image class="opIcon"
  12 + :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" />
  13 + <text class="opText">{{ item.collapsed ? '收起' : '展开' }}</text>
  14 + </view>
  15 + </view>
  16 +
  17 + <uni-list v-show="item.collapsed">
  18 + <uni-list-item title="产品名称">
  19 + <template v-slot:footer>
  20 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false"
  21 + disabled />
  22 + </template>
  23 + </uni-list-item>
  24 + <uni-list-item title="行业">
  25 + <template v-slot:footer>
  26 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false"
  27 + disabled />
  28 + </template>
  29 + </uni-list-item>
  30 + <uni-list-item title="牌号">
  31 + <template v-slot:footer>
  32 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  33 + </template>
  34 + </uni-list-item>
  35 + <uni-list-item title="品质">
  36 + <template v-slot:footer>
  37 + <uni-easyinput v-model="item.quality" placeholder="请输入品质" :clearable="false" disabled />
  38 + </template>
  39 + </uni-list-item>
  40 + <uni-list-item title="规格(mm)">
  41 + <template v-slot:footer>
  42 + <view class="value value-spec">
  43 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  44 + <view v-if="item.thickness" class="value-spec_box">
  45 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{
  46 + item.thicknessTolPos > 0 ? '+' + item.thicknessTolPos : item.thicknessTolPos
  47 + }}
  48 + </view>
  49 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{
  50 + item.thicknessTolNeg > 0 ? '+' + item.thicknessTolNeg : item.thicknessTolNeg
  51 + }}
  52 + </view>
  53 + </view>
  54 + <view v-if="item.width" class="value-spec_val p12">*</view>
  55 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  56 + <view v-if="item.width" class="value-spec_box">
  57 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ?
  58 + '+' + item.widthTolPos : item.widthTolPos }}
  59 + </view>
  60 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ?
  61 + '+' + item.widthTolNeg : item.widthTolNeg }}
  62 + </view>
  63 + </view>
  64 + <view v-if="item.length" class="value-spec_val p12">*</view>
  65 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  66 + <view v-if="item.length" class="value-spec_box">
  67 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0
  68 + ? '+' + item.lengthTolPos : item.lengthTolPos }}
  69 + </view>
  70 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0
  71 + ? '+' + item.lengthTolNeg : item.lengthTolNeg }}
  72 + </view>
  73 + </view>
  74 + </view>
  75 + </template>
  76 + </uni-list-item>
  77 + <uni-list-item title="物料编码">
  78 + <template v-slot:footer>
  79 + <uni-easyinput v-model="item.materialCode" placeholder="请输入物料编码" :clearable="false" disabled />
  80 + </template>
  81 + </uni-list-item>
  82 + <uni-list-item title="状态">
  83 + <template v-slot:footer>
  84 + <uni-easyinput v-model="item.status" placeholder="请输入状态" :clearable="false" disabled />
  85 + </template>
  86 + </uni-list-item>
  87 + <uni-list-item title="数量">
  88 + <template v-slot:footer>
  89 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" disabled
  90 + placeholder="不可编辑" />
  91 + </template>
  92 + </uni-list-item>
  93 + <uni-list-item title="本次锁价数量">
  94 + <template v-slot:footer>
  95 + <uni-easyinput v-model="item.currentQuantity" type="number" :inputBorder="false" placeholder="请输入本次锁价数量" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'currentQuantity', 3)" />
  96 + </template>
  97 + </uni-list-item>
  98 + <uni-list-item title="单价">
  99 + <template v-slot:footer>
  100 + <uni-easyinput v-model="item.unitPrice" type="digit" :inputBorder="false" disabled
  101 + placeholder="不可编辑" @input="onImmediateChange(idx)"
  102 + @blur="onNumberBlur(idx, 'unitPrice', 0)" />
  103 + </template>
  104 + </uni-list-item>
  105 + <!-- <uni-list-item title="不含税金额">
  106 + <template v-slot:footer>
  107 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false"
  108 + disabled placeholder="" />
  109 + </template>
  110 + </uni-list-item> -->
  111 + <uni-list-item title="总金额">
  112 + <template v-slot:footer>
  113 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled
  114 + placeholder="" />
  115 + </template>
  116 + </uni-list-item>
  117 + <uni-list-item title="发货日期">
  118 + <template v-slot:footer>
  119 + <uni-easyinput v-model="item.deliveryDate" :inputBorder="false" disabled />
  120 + </template>
  121 + </uni-list-item>
  122 + </uni-list>
  123 +
  124 + <uni-list v-show="!item.collapsed">
  125 + <uni-list-item title="产品名称">
  126 + <template v-slot:footer>
  127 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false"
  128 + disabled />
  129 + </template>
  130 + </uni-list-item>
  131 + <uni-list-item title="行业">
  132 + <template v-slot:footer>
  133 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false"
  134 + disabled />
  135 + </template>
  136 + </uni-list-item>
  137 + <uni-list-item title="牌号">
  138 + <template v-slot:footer>
  139 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  140 + </template>
  141 + </uni-list-item>
  142 +
  143 + </uni-list>
  144 + </view>
  145 + <view class="footer">
  146 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  147 + </view>
  148 + </view>
  149 + </scroll-view>
  150 +
  151 +
  152 + </view>
  153 +</template>
  154 +
  155 +<script>
  156 +import { getContractApi, splitQuantityLock } from '@/api/contract'
  157 +
  158 +export default {
  159 + name: 'ContractUnplanLock',
  160 + data() {
  161 + return {
  162 + id: '',
  163 + items: [],
  164 + planQty: 30,
  165 + }
  166 + },
  167 + onLoad(options) {
  168 + const id = options && options.id ? options.id : ''
  169 + this.id = id
  170 + this.loadDetail()
  171 + },
  172 + methods: {
  173 + onLockChange(idx, e) {
  174 + const it = this.items[idx]
  175 + if (!it) return
  176 + const arr = e && e.detail && e.detail.value ? e.detail.value : []
  177 + it.locked = Array.isArray(arr) && arr.length > 0
  178 + this.$set(this.items, idx, it)
  179 + },
  180 + async loadDetail() {
  181 + if (!this.id) return
  182 + try {
  183 + const res = await getContractApi(this.id)
  184 + const data = res && res.data ? res.data : {}
  185 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  186 + const init = lines.map(v => ({
  187 + locked: true,
  188 + collapsed: true,
  189 + raw: v,
  190 + productName: v.rawProductName || v.productName || '',
  191 + industry: v.industry || '',
  192 + brand: v.rawProductGrade || v.brand || '',
  193 + quality: v.quality || '',
  194 + thickness: v.thickness || '',
  195 + thicknessTolPos: v.thicknessTolPos || '',
  196 + thicknessTolNeg: v.thicknessTolNeg || '',
  197 + width: v.width || '',
  198 + widthTolPos: v.widthTolPos || '',
  199 + widthTolNeg: v.widthTolNeg || '',
  200 + length: v.length || '',
  201 + lengthTolPos: v.lengthTolPos || '',
  202 + lengthTolNeg: v.lengthTolNeg || '',
  203 + materialCode: v.materialCode || '',
  204 + status: v.status || '',
  205 + currentQuantity: v.currentQuantity === 0 ? 0 : (v.currentQuantity || ''),
  206 + quantity: v.productQuantity || v.quantity || '',
  207 + unitPrice: v.unitPrice || '',
  208 + // amountExcludingTax: v.amountExcludingTax || 0,
  209 + totalAmount: v.totalAmount || 0,
  210 + deliveryDate: v.deliveryDate || '',
  211 + specDisplay: ''
  212 + }))
  213 + this.items = init.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  214 + this.recalculateAll()
  215 + } catch (e) {
  216 + this.items = []
  217 + }
  218 + },
  219 + toggleItem(idx) {
  220 + const it = this.items[idx]
  221 + if (!it) return
  222 + it.collapsed = !it.collapsed
  223 + this.$set(this.items, idx, it)
  224 + },
  225 + onImmediateChange(idx) {
  226 + this.$nextTick(() => this.recalculate(idx))
  227 + },
  228 + onNumberBlur(idx, field, digits) {
  229 + const it = this.items[idx]
  230 + if (!it) return
  231 + const raw = it[field]
  232 + if (raw === '' || raw === null || raw === undefined) {
  233 + this.$set(this.items, idx, it)
  234 + this.recalculate(idx)
  235 + return
  236 + }
  237 + const num = this.toNumber(raw)
  238 + const rounded = this.round(num, digits)
  239 + it[field] = rounded
  240 + this.$set(this.items, idx, it)
  241 + this.recalculate(idx)
  242 + },
  243 + recalculate(idx) {
  244 + const TAX_RATE = 0.13
  245 + const it = this.items[idx]
  246 + if (!it) return
  247 + const qty = this.toNumber(it.quantity)
  248 + const price = this.toNumber(it.unitPrice)
  249 + const total = this.round(qty * price, 2)
  250 + // const excl = this.round(total / (1 + TAX_RATE), 2)
  251 + // it.amountExcludingTax = excl
  252 + it.totalAmount = total
  253 + this.$set(this.items, idx, it)
  254 + },
  255 + recalculateAll() {
  256 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
  257 + },
  258 + toNumber(val) {
  259 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  260 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  261 + return isNaN(n) ? 0 : n
  262 + },
  263 + round(val, digits = 2) {
  264 + const n = Number(val)
  265 + if (isNaN(n)) return 0
  266 + const m = Math.pow(10, digits)
  267 + return Math.round(n * m) / m
  268 + },
  269 + specOf(item) {
  270 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/ ')
  271 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/ ')
  272 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/ ')
  273 + return [t, w, l].filter(Boolean).join(' × ')
  274 + },
  275 + formatCurrency(val) {
  276 + if (val == null || val === '') return ''
  277 + const num = Number(val)
  278 + const pre = isNaN(num) ? '' : '¥'
  279 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  280 + return `${pre}${fixed}`
  281 + },
  282 + onReset() {
  283 + this.items = this.items.map((it, i) => ({
  284 + ...it,
  285 + quantity: '',
  286 + currentQuantity: '',
  287 + unitPrice: '',
  288 + // amountExcludingTax: 0
  289 + }))
  290 + },
  291 + async onSubmit() {
  292 + const selected = this.items.filter(it => it.locked).map(it => {
  293 + const raw = { ...(it.raw || {}) }
  294 + const qty = this.toNumber(it.quantity)
  295 + const price = this.toNumber(it.unitPrice)
  296 + const curQtyRaw = it.currentQuantity
  297 + const total = this.toNumber(it.totalAmount)
  298 + // const excl = this.toNumber(it.amountExcludingTax)
  299 + if (Object.prototype.hasOwnProperty.call(raw, 'productQuantity')) raw.productQuantity = qty
  300 + else raw.quantity = qty
  301 + raw.currentQuantity = (curQtyRaw === '' || curQtyRaw === null || curQtyRaw === undefined) ? null : this.toNumber(curQtyRaw)
  302 + raw.unitPrice = price
  303 + raw.totalAmount = total
  304 + // raw.amountExcludingTax = excl
  305 + return raw
  306 + })
  307 + if (!selected.length) {
  308 + uni.showToast({ title: '未选择任何拆分项', icon: 'none' })
  309 + return
  310 + }
  311 + const invalidQty = selected.find(r => {
  312 + const q = this.toNumber(r.currentQuantity)
  313 + return !(q > 0)
  314 + })
  315 + if (invalidQty) {
  316 + uni.showToast({ title: '请填写本次拆分数量', icon: 'none' })
  317 + return
  318 + }
  319 + this.selectedItems = selected
  320 + const payload = {
  321 + id: this.id,
  322 + contractDistributorLineList: selected
  323 + }
  324 +
  325 + uni.showModal({
  326 + title: '确认提交',
  327 + content: '确定提交拆分吗?',
  328 + success: (res) => {
  329 + if (res.confirm) {
  330 + splitQuantityLock(payload).then(() => {
  331 + uni.showToast({ title: '拆分已提交', icon: 'success' })
  332 + setTimeout(() => {
  333 + uni.navigateTo({ url: '/pages/contract_foreign_stock/index' })
  334 + }, 500)
  335 + }).catch((err) => {
  336 + uni.showToast({ title: err.msg || '提交失败', icon: 'none' })
  337 + })
  338 + }
  339 + }
  340 + })
  341 + }
  342 + }
  343 +}
  344 +</script>
  345 +
  346 +<style lang="scss" scoped>
  347 +.page {
  348 + display: flex;
  349 + flex-direction: column;
  350 + height: 100%;
  351 +}
  352 +
  353 +.scroll {
  354 + flex: 1;
  355 + padding: 12rpx 0 392rpx !important;
  356 +}
  357 +
  358 +.header {
  359 + background-color: #fff;
  360 + display: flex;
  361 + align-items: center;
  362 + padding: 24rpx 32rpx;
  363 + border-bottom: 1rpx solid #f0f0f0;
  364 +}
  365 +
  366 +.title {
  367 + font-size: 32rpx;
  368 + color: rgba(0, 0, 0, 0.9);
  369 + font-weight: 600;
  370 +}
  371 +
  372 +.opCollapse {
  373 + width: 24rpx;
  374 + height: 24rpx;
  375 + margin-right: 16rpx;
  376 + margin-top: 8rpx;
  377 +}
  378 +
  379 +.block {
  380 + background: #fff;
  381 + margin-top: 20rpx;
  382 +}
  383 +
  384 +.block-header {
  385 + display: flex;
  386 + align-items: center;
  387 + padding: 24rpx 32rpx;
  388 + border-bottom: 1rpx solid #f0f0f0;
  389 +}
  390 +
  391 +.block-header ::v-deep .uni-data-checklist .checkbox__inner {
  392 + width: 36rpx;
  393 + height: 36rpx;
  394 +}
  395 +
  396 +.block-header ::v-deep .uni-data-checklist .checklist-text {
  397 + font-size: 28rpx;
  398 + margin-left: 12rpx;
  399 +}
  400 +
  401 +.block-title {
  402 + margin-left: 12rpx;
  403 + font-size: 28rpx;
  404 + color: rgba(0, 0, 0, 0.9);
  405 +}
  406 +
  407 +.ops {
  408 + margin-left: auto;
  409 + display: flex;
  410 + align-items: center;
  411 + color: $theme-primary;
  412 + font-size: 28rpx;
  413 +}
  414 +
  415 +.opIcon {
  416 + width: 40rpx;
  417 + height: 40rpx;
  418 +}
  419 +
  420 +.opText {
  421 + margin-left: 8rpx;
  422 + color: $theme-primary;
  423 +}
  424 +
  425 +::v-deep .uni-list {
  426 + .uni-easyinput {
  427 + display: flex;
  428 +
  429 + .uni-input-input {
  430 + color: rgba(0, 0, 0, 0.9);
  431 + }
  432 + }
  433 +
  434 + .uni-input-placeholder {
  435 + z-index: 1;
  436 + }
  437 +
  438 + .uni-input-input {
  439 + background-color: #ffffff;
  440 + }
  441 +
  442 + background: transparent;
  443 +
  444 + &-item {
  445 + &__extra-text {
  446 + font-size: 32rpx;
  447 + }
  448 +
  449 + &__content-title {
  450 + font-size: 32rpx;
  451 + color: rgba(0, 0, 0, 0.9);
  452 + }
  453 +
  454 + &__container {
  455 + padding: 32rpx;
  456 +
  457 + .uni-easyinput {
  458 + &__placeholder-class {
  459 + font-size: 32rpx;
  460 + color: rgba(0, 0, 0, 0.4);
  461 + }
  462 +
  463 + &__content {
  464 + border: none;
  465 + background-color: #ffffff !important;
  466 +
  467 + &-input {
  468 + padding-left: 0 !important;
  469 + height: 48rpx;
  470 + line-height: 48rpx;
  471 + font-size: 32rpx;
  472 + }
  473 +
  474 + .content-clear-icon {
  475 + font-size: 44rpx !important;
  476 + }
  477 + }
  478 + }
  479 +
  480 + .item-title,
  481 + .uni-list-item__content {
  482 + flex: none;
  483 + min-height: 48rpx;
  484 + line-height: 48rpx;
  485 + font-size: 32rpx;
  486 + position: relative;
  487 + width: 210rpx;
  488 + margin-right: 32rpx;
  489 + color: rgba(0, 0, 0, 0.9);
  490 +
  491 + .required {
  492 + color: red;
  493 + position: absolute;
  494 + top: 50%;
  495 + transform: translateY(-50%);
  496 + left: -16rpx;
  497 + }
  498 + }
  499 + }
  500 +
  501 + &.select-item {
  502 + &.is-empty {
  503 + .uni-list-item__extra-text {
  504 + color: rgba(0, 0, 0, 0.4) !important;
  505 + }
  506 + }
  507 +
  508 + &.is-filled {
  509 + .uni-list-item__extra-text {
  510 + color: rgba(0, 0, 0, 0.9) !important;
  511 + }
  512 + }
  513 + }
  514 +
  515 + &.mgb10 {
  516 + margin-bottom: 20rpx;
  517 + }
  518 + }
  519 +}
  520 +
  521 +// ::v-deep .uni-list-item__container {
  522 +// padding: 32rpx;
  523 +// }
  524 +
  525 +::v-deep .is-disabled {
  526 + background-color: transparent !important;
  527 +}
  528 +
  529 +// ::v-deep .uni-list-item__content-title {
  530 +// font-size: 28rpx;
  531 +// color: rgba(0, 0, 0, 0.9);
  532 +// }
  533 +
  534 +// ::v-deep .uni-list-item__extra-text {
  535 +// font-size: 32rpx;
  536 +// }
  537 +
  538 +::v-deep .uni-easyinput {
  539 + width: 100%;
  540 +}
  541 +
  542 +::v-deep .uni-easyinput__placeholder-class {
  543 + font-size: 32rpx;
  544 + color: rgba(0, 0, 0, 0.4);
  545 +}
  546 +
  547 +::v-deep .uni-easyinput__content {
  548 + border: none;
  549 + display: flex;
  550 +}
  551 +
  552 +::v-deep .uni-easyinput__content-input {
  553 + padding-left: 0 !important;
  554 + height: 48rpx;
  555 + line-height: 48rpx;
  556 + font-size: 32rpx;
  557 + color: rgba(0, 0, 0, 0.9);
  558 +}
  559 +
  560 +.amount-item .item-title {
  561 + display: flex;
  562 + align-items: center;
  563 +}
  564 +
  565 +.amount-row {
  566 + display: flex;
  567 + align-items: center;
  568 +}
  569 +
  570 +.amount-row .unit {
  571 + margin-left: 12rpx;
  572 + color: rgba(0, 0, 0, 0.6);
  573 +}
  574 +
  575 +.summary {
  576 + margin-top: 20rpx;
  577 + background: #fff;
  578 + padding-bottom: 12rpx;
  579 +}
  580 +
  581 +.title-header {
  582 + display: flex;
  583 + align-items: center;
  584 + padding: 20rpx 32rpx;
  585 +}
  586 +
  587 +.title-header_icon {
  588 + width: 24rpx;
  589 + height: 24rpx;
  590 + margin-right: 16rpx;
  591 +}
  592 +
  593 +.sum-card {
  594 + background: #f3f3f3;
  595 + border-radius: 16rpx;
  596 + padding: 24rpx;
  597 + margin: 0 32rpx 20rpx;
  598 +}
  599 +
  600 +.row {
  601 + display: flex;
  602 + margin-bottom: 16rpx;
  603 +}
  604 +
  605 +.row .label {
  606 + width: 140rpx;
  607 + color: rgba(0, 0, 0, 0.6);
  608 + font-size: 28rpx;
  609 +}
  610 +
  611 +.row .value {
  612 + flex: 1;
  613 + text-align: right;
  614 + color: rgba(0, 0, 0, 0.9);
  615 + font-size: 28rpx;
  616 +}
  617 +
  618 +.row .amount {
  619 + color: #D54941;
  620 +}
  621 +
  622 +.total {
  623 + .total-text {
  624 + font-weight: 600;
  625 + font-size: 32rpx;
  626 + color: rgba(0, 0, 0, 0.9);
  627 + padding-bottom: 28rpx;
  628 + border-bottom: 2rpx solid #E7E7E7;
  629 + }
  630 +
  631 + .total-item {
  632 + display: flex;
  633 + align-items: center;
  634 +
  635 + .total-item-text {
  636 + font-weight: 400;
  637 + font-size: 28rpx;
  638 + color: rgba(0, 0, 0, 0.6);
  639 + line-height: 32rpx;
  640 + width: 240rpx;
  641 + padding: 12rpx 0;
  642 + }
  643 +
  644 + .total-item-price {
  645 + font-weight: 600;
  646 + font-size: 32rpx;
  647 + color: rgba(0, 0, 0, 0.9);
  648 + line-height: 32rpx;
  649 + }
  650 +
  651 + .text-red {
  652 + color: #D54941;
  653 + }
  654 + }
  655 +
  656 +}
  657 +
  658 +.footer {
  659 + z-index: 2;
  660 + position: fixed;
  661 + left: 0;
  662 + right: 0;
  663 + bottom: 0;
  664 + padding: 32rpx;
  665 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  666 + background: #fff;
  667 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  668 +
  669 + .btn {
  670 + height: 80rpx;
  671 + line-height: 80rpx;
  672 + border-radius: 12rpx;
  673 + font-size: 32rpx;
  674 + }
  675 +
  676 + .submit {
  677 + background: $theme-primary;
  678 + color: #fff;
  679 + }
  680 +}
  681 +
  682 +.btn {
  683 + height: 80rpx;
  684 + line-height: 80rpx;
  685 + border-radius: 12rpx;
  686 + font-size: 32rpx;
  687 + flex: 1;
  688 +}
  689 +
  690 +.submit {
  691 + background: $theme-primary;
  692 + color: #fff;
  693 +}
  694 +
  695 +.value-spec {
  696 + height: 48rpx;
  697 + display: flex;
  698 + align-items: center;
  699 + color: #000000;
  700 +
  701 + // justify-content: end;
  702 + &_box {
  703 + position: relative;
  704 + width: 60rpx;
  705 + height: 48rpx;
  706 +
  707 + &_1 {
  708 + font-size: 16rpx;
  709 + position: absolute;
  710 + top: -10rpx;
  711 + left: 0;
  712 + }
  713 +
  714 + &_2 {
  715 + font-size: 16rpx;
  716 + position: absolute;
  717 + bottom: -10rpx;
  718 + left: 0;
  719 + }
  720 + }
  721 +
  722 + &_val {
  723 + font-size: 28rpx;
  724 +
  725 + &.p12 {
  726 + padding-right: 12rpx;
  727 + }
  728 + }
  729 +}
  730 +
  731 +.row-spec {
  732 + height: 60rpx;
  733 + align-items: center;
  734 +}
  735 +</style>
\ No newline at end of file
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput v-model="form.code" :inputBorder="false" disabled />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.supplier ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openSheet('supplier')" :rightText="displayLabel('supplierName')" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>供方</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.buyer ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openRelate('buyer')" :rightText="form.buyerName || '请选择需方'" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>需方</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item class="select-item" :class="form.stockUpCompanyId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openRelate('stockUpCompanyId')" :rightText="form.stockUpCompanyName || '请选择备货单位'" showArrow>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>备货单位/人(生产标准)</text></view>
  29 + </template>
  30 + </uni-list-item>
  31 +
  32 + <uni-list-item class="select-item" :class="form.workshopId ? 'is-filled' : 'is-empty'" clickable
  33 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" showArrow>
  34 + <template v-slot:body>
  35 + <view class="item-title"><text class="required">*</text><text>生产厂</text></view>
  36 + </template>
  37 + </uni-list-item>
  38 + <uni-list-item class="select-item" :class="form.deptName ? 'is-filled' : 'is-empty'">
  39 + <template v-slot:body>
  40 + <view class="item-title"><text class="required">*</text><text>办事处</text></view>
  41 + </template>
  42 + <template v-slot:footer>
  43 + <view class="serial-number-row">
  44 + <uni-easyinput v-model="form.deptName" :inputBorder="false" disabled />
  45 + </view>
  46 + </template>
  47 + </uni-list-item>
  48 + <uni-list-item class="select-item" :class="form.region ? 'is-filled' : 'is-empty'" clickable
  49 + @click="openSheet('region')" :rightText="displayLabel('regionName')" showArrow>
  50 + <template v-slot:body>
  51 + <view class="item-title"><text class="required">*</text><text>区域</text></view>
  52 + </template>
  53 + </uni-list-item>
  54 +
  55 + <uni-list-item title="订货日期">
  56 + <template v-slot:footer>
  57 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  58 + </template>
  59 + </uni-list-item>
  60 +
  61 + <uni-list-item title="单位">
  62 + <template v-slot:footer>
  63 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  64 + </template>
  65 + </uni-list-item>
  66 +
  67 + <ProductRel ref="productRel" mode="add" :deliveryDate="form.orderDate" :deliveryDateBase="form.deliveryDate"
  68 + :list="productLineList" @change="onProductsChange" :options="productList" />
  69 +
  70 + <uni-list-item title="合计金额(大写)">
  71 + <template v-slot:footer>
  72 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false" disabled />
  73 + </template>
  74 + </uni-list-item>
  75 + <uni-list-item title="交付定金、数额、时间">
  76 + <template v-slot:footer>
  77 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  78 + </template>
  79 + </uni-list-item>
  80 + <uni-list-item title="包装要求">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求" :inputBorder="false" />
  83 + </template>
  84 + </uni-list-item>
  85 + <uni-list-item title="付款方式、付款期限">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  88 + </template>
  89 + </uni-list-item>
  90 + <uni-list-item title="运输方式">
  91 + <template v-slot:footer>
  92 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  93 + </template>
  94 + </uni-list-item>
  95 + <uni-list-item title="目的地">
  96 + <template v-slot:footer>
  97 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
  98 + </template>
  99 + </uni-list-item>
  100 +
  101 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
  102 + @click="openSheet('includesPackagingFee')" :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  103 + <template v-slot:body>
  104 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  105 + </template>
  106 + </uni-list-item>
  107 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'" clickable
  108 + @click="openSheet('includesTransportFee')" :rightText="form.includesTransportFeeName || '请选择'" showArrow>
  109 + <template v-slot:body>
  110 + <view class="item-title"><text>单价中是否已包含运费</text></view>
  111 + </template>
  112 + </uni-list-item>
  113 + <uni-list-item title="需方指定收货人">
  114 + <template v-slot:footer>
  115 + <uni-easyinput v-model="form.designatedConsignee" placeholder="请输入需方指定收货人" :inputBorder="false" />
  116 + </template>
  117 + </uni-list-item>
  118 + <uni-list-item class="select-item" :class="form.specialTermsName ? 'is-filled' : 'is-empty'" clickable
  119 + @click="openSheet('specialTerms')" :rightText="form.specialTermsName || '请选择'" showArrow>
  120 + <template v-slot:body>
  121 + <view class="item-title"><text class="required">*</text><text>特别条款要求</text></view>
  122 + </template>
  123 + </uni-list-item>
  124 + <uni-list-item class="select-item" :class="form.executionStandardName ? 'is-filled' : 'is-empty'" clickable
  125 + @click="openSheet('executionStandard')" :rightText="form.executionStandardName || '请选择'" showArrow>
  126 + <template v-slot:body>
  127 + <view class="item-title"><text>执行标准</text></view>
  128 + </template>
  129 + </uni-list-item>
  130 + <uni-list-item v-if="form.executionStandard === 'OTHER'" title="其他">
  131 + <template v-slot:footer>
  132 + <uni-easyinput v-model="form.executionStandardRemarks" placeholder="请输入其他标准备注" :inputBorder="false" />
  133 + </template>
  134 + </uni-list-item>
  135 + <uni-list-item title="特别说明" style="margin-top: 20rpx;">
  136 + <template v-slot:footer>
  137 + <uni-easyinput v-model="form.specialInstructions" placeholder="请输入特别说明" :inputBorder="false" />
  138 + </template>
  139 + </uni-list-item>
  140 + <uni-list-item title="备注">
  141 + <template v-slot:footer>
  142 + <uni-easyinput v-model="form.remarks" placeholder="请输入备注" :inputBorder="false" maxlength="2000" />
  143 + </template>
  144 + </uni-list-item>
  145 +
  146 + <view class="quality">
  147 + <image class="opCollapse" src="/static/images/title.png" />
  148 + <text class="title">具体质量要求</text>
  149 + </view>
  150 + <uni-list-item title="件重条头">
  151 + <template v-slot:footer>
  152 + <uni-easyinput v-model="form.pieceWeightHead" placeholder="请输入" :inputBorder="false" />
  153 + </template>
  154 + </uni-list-item>
  155 + <uni-list-item title="表面">
  156 + <template v-slot:footer>
  157 + <uni-easyinput v-model="form.surface" placeholder="请输入" :inputBorder="false" />
  158 + </template>
  159 + </uni-list-item>
  160 + <uni-list-item title="公差">
  161 + <template v-slot:footer>
  162 + <uni-easyinput v-model="form.tolerance" placeholder="请输入" :inputBorder="false" />
  163 + </template>
  164 + </uni-list-item>
  165 + <uni-list-item title="性能">
  166 + <template v-slot:footer>
  167 + <uni-easyinput v-model="form.performance" placeholder="请输入" :inputBorder="false" />
  168 + </template>
  169 + </uni-list-item>
  170 + <uni-list-item title="成分">
  171 + <template v-slot:footer>
  172 + <uni-easyinput v-model="form.component" placeholder="请输入" :inputBorder="false" />
  173 + </template>
  174 + </uni-list-item>
  175 + <uni-list-item title="包装">
  176 + <template v-slot:footer>
  177 + <uni-easyinput v-model="form.packaging" placeholder="请输入" :inputBorder="false" />
  178 + </template>
  179 + </uni-list-item>
  180 +
  181 + <uni-list-item :title="uploadType === 'seal' ? '双方盖章合同附件' : (uploadType === 'formal' ? '正式合同附件' : '标准合同附件')" style="margin-top: 20rpx;">
  182 + <template v-slot:footer>
  183 + <FileUpload v-model="fileInfo" />
  184 + </template>
  185 + </uni-list-item>
  186 + <uni-list-item v-if="uploadType !== 'seal'" class="select-item" :class="standardStandardizedName ? 'is-filled' : 'is-empty'" clickable
  187 + @click="openSheet('standardStandardized')" :rightText="standardStandardizedName || '请选择'" showArrow>
  188 + <template v-slot:body>
  189 + <view class="item-title"><text class="required">*</text><text>合同是否规范</text></view>
  190 + </template>
  191 + </uni-list-item>
  192 +
  193 + <view class="footer">
  194 + <div class="total">
  195 + <div class="total-text">合计</div>
  196 + <div class="total-item" style="padding: 20rpx 0;">
  197 + <div class="total-item-text">数量</div>
  198 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  199 + </div>
  200 + </div>
  201 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  202 + </view>
  203 + </uni-list>
  204 + </scroll-view>
  205 +
  206 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  207 + @confirm="onSheetConfirm" />
  208 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  209 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  210 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  211 + </view>
  212 +</template>
  213 +
  214 +<script>
  215 +import SingleSelectSheet from '@/components/single-select/index.vue'
  216 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  217 +import ProductRel from './productRel.vue'
  218 +import FileUpload from '@/components/file-upload/index.vue'
  219 +import { getContractApi, uploadFormalContract, uploadStandardContract, uploadSignedContractFile } from '@/api/contract'
  220 +import { getDicByCodes } from '@/utils/dic'
  221 +import { formatCurrencyToChinese } from '@/utils/common'
  222 +import { workshopQueryApi } from '@/api/devManage'
  223 +import { getArea } from '@/api/credit_manage.js'
  224 +
  225 +export default {
  226 + name: 'UploadContractForeignStock',
  227 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, FileUpload },
  228 + data() {
  229 + return {
  230 + id: '',
  231 + uploadType: 'formal',
  232 + fileInfo: { id: '', name: '' },
  233 + standardStandardized: '',
  234 + standardStandardizedName: '',
  235 + form: {
  236 + id: '',
  237 + code: '',
  238 + supplier: '',
  239 + supplierName: '',
  240 + buyer: '',
  241 + buyerName: '',
  242 + stockUpCompanyId: '',
  243 + stockUpCompanyName: '',
  244 + workshopId: '',
  245 + workshopName: '',
  246 + region: '',
  247 + regionName: '',
  248 + deptName: '',
  249 + deptId: '',
  250 + orderDate: '',
  251 + deliveryDate: '',
  252 + designatedConsignee: '',
  253 + specialTerms: '',
  254 + specialTermsName: '',
  255 + executionStandard: '',
  256 + executionStandardName: '',
  257 + executionStandardRemarks: '',
  258 + includesPackagingFee: false,
  259 + includesPackagingFeeName: '否',
  260 + includesTransportFee: false,
  261 + includesTransportFeeName: '否',
  262 + unit: '美元、公斤、美元/公斤',
  263 + totalAmountCapital: '',
  264 + depositInfo: '',
  265 + packagingRequirements: '',
  266 + paymentTerms: '',
  267 + transportMode: '',
  268 + foreignDestination: '',
  269 + specialInstructions: '',
  270 + remarks: '',
  271 + pieceWeightHead: '',
  272 + surface: '',
  273 + tolerance: '',
  274 + performance: '',
  275 + component: '',
  276 + packaging: ''
  277 + },
  278 + supplierList: [],
  279 + specialTermsList: [],
  280 + executionStandardList: [],
  281 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  282 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  283 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  284 + totalQuantity: 0,
  285 + totalAmountIncludingTax: 0,
  286 + productLineList: [],
  287 + newProductLineList: [],
  288 + productList: [],
  289 + regionOptions: [],
  290 + }
  291 + },
  292 + onLoad(query) {
  293 + this.id = (query && query.id) ? query.id : ''
  294 + },
  295 + created() {
  296 + this.loadSuppliers()
  297 + this.loadExtraOptions()
  298 + this.loadRegionOptions()
  299 + this.loadDetail()
  300 + },
  301 + methods: {
  302 + async loadRegionOptions() {
  303 + try {
  304 + const res = await getArea()
  305 + const list = res.data || []
  306 + this.regionOptions = (list || []).map(it => ({ label: it.name || '', value: it.id || '' }))
  307 + } catch (e) {
  308 + this.regionOptions = []
  309 + }
  310 + },
  311 + async loadDetail() {
  312 + if (!this.id) return
  313 + try {
  314 + const res = await getContractApi(this.id)
  315 + const data = res && res.data ? res.data : {}
  316 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  317 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  318 + const m = { ...data, includesPackagingFeeName, includesTransportFeeName }
  319 + this.form = {
  320 + ...this.form,
  321 + id: m.id || '',
  322 + code: m.code || '',
  323 + supplier: m.supplier || '',
  324 + supplierName: m.supplierName || '',
  325 + buyer: m.buyer || (m.customer && m.customer.id) || '',
  326 + buyerName: m.buyerName || (m.customer && m.customer.name) || '',
  327 + stockUpCompanyId: m.stockUpCompanyId || '',
  328 + stockUpCompanyName: m.stockUpCompanyName || '',
  329 + orderDate: m.orderDate || '',
  330 + designatedConsignee: m.designatedConsignee || '',
  331 + specialTerms: m.specialTerms || '',
  332 + specialTermsName: m.specialTermsName || '',
  333 + executionStandard: m.executionStandard || '',
  334 + executionStandardName: m.executionStandardName || '',
  335 + executionStandardRemarks: m.executionStandardRemarks || '',
  336 + includesPackagingFee: !!m.includesPackagingFee,
  337 + includesPackagingFeeName,
  338 + includesTransportFee: !!m.includesTransportFee,
  339 + includesTransportFeeName,
  340 + unit: m.unit || this.form.unit,
  341 + totalAmountCapital: m.totalAmountCapital || '',
  342 + depositInfo: m.depositInfo || '',
  343 + packagingRequirements: m.packagingRequirements || '',
  344 + paymentTerms: m.paymentTerms || '',
  345 + transportMode: m.transportMode || '',
  346 + foreignDestination: (m.foreignDestination || ''),
  347 + specialInstructions: m.specialInstructions || '',
  348 + remarks: m.remarks || '',
  349 + pieceWeightHead: m.pieceWeightHead || '',
  350 + surface: m.surface || '',
  351 + tolerance: m.tolerance || '',
  352 + performance: m.performance || '',
  353 + component: m.component || '',
  354 + packaging: m.packaging || '',
  355 + workshopId: m.workshopId || '',
  356 + workshopName: m.workshopName || '',
  357 + region: m.region || '',
  358 + regionName: m.regionName || '',
  359 + deptName: m.deptName || '',
  360 + deptId: m.deptId || '',
  361 + }
  362 +
  363 + const fileId = (this.uploadType === 'seal') ? m.signedContractFileId : (this.uploadType === 'formal') ? m.formalFileId : m.standardFileId
  364 + const fileName = (this.uploadType === 'seal') ? m.signedContractFileName : (this.uploadType === 'formal') ? m.formalFileName : m.standardFileName
  365 + const standardized = (this.uploadType === 'formal') ? m.formalStandardized : (this.uploadType === 'standard') ? m.standardStandardized : ''
  366 + this.fileInfo = { id: fileId || '', name: fileName || '' }
  367 + this.standardStandardized = (standardized === true || standardized === false) ? standardized : ''
  368 + this.standardStandardizedName = (this.standardStandardized === true) ? '是' : (this.standardStandardized === false) ? '否' : ''
  369 +
  370 + const lines = Array.isArray(m.contractDistributorLineList) ? m.contractDistributorLineList : []
  371 + this.productLineList = lines
  372 + this.onProductsChange(lines)
  373 + } catch (e) { }
  374 + },
  375 + onProductsChange(products) {
  376 + const list = Array.isArray(products) ? products : []
  377 + this.newProductLineList = list
  378 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  379 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  380 + this.totalQuantity = sumQ
  381 + this.totalAmountIncludingTax = sumT
  382 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  383 + },
  384 + async loadSuppliers() {
  385 + try {
  386 + const results = await getDicByCodes(['SUPPLIER'])
  387 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  388 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  389 + } catch (e) { this.supplierList = [] }
  390 + },
  391 + async loadExtraOptions() {
  392 + try {
  393 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  394 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  395 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  396 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  397 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  398 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  399 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  400 + } catch (e) {
  401 + this.specialTermsList = []
  402 + this.executionStandardList = []
  403 + this.productList = []
  404 + }
  405 + },
  406 + displayLabel(field) {
  407 + const m = this.form
  408 + const map = { supplierName: '请选择供方', buyerName: '请选择需方', workshopName: '请选择生产厂', regionName: '请选择区域' }
  409 + const val = m[field]
  410 + return val ? String(val) : map[field]
  411 + },
  412 + async openSheet(field) {
  413 + if (field === 'standardStandardized') {
  414 + const options = this.yesNoList
  415 + const current = this.standardStandardized
  416 + const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
  417 + this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, field, value: match ? match.value : '' }
  418 + return
  419 + }
  420 + const setSheet = (title, options) => {
  421 + const current = this.form[field]
  422 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  423 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  424 + }
  425 + if (field === 'workshopId') {
  426 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  427 + const _data = res.data || {}
  428 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  429 + const opts = (list || []).map(it => ({ label: it.name, value: it.id }))
  430 + setSheet('生产厂', opts)
  431 + } else if (field === 'supplier') {
  432 + setSheet('供方', this.supplierList)
  433 + } else if (field === 'specialTerms') {
  434 + setSheet('特别条款要求', this.specialTermsList)
  435 + } else if (field === 'executionStandard') {
  436 + setSheet('执行标准', this.executionStandardList)
  437 + } else if (field === 'includesPackagingFee') {
  438 + setSheet('单价中是否已包含包装费', this.yesNoList)
  439 + } else if (field === 'includesTransportFee') {
  440 + setSheet('单价中是否已包含运费', this.yesNoList)
  441 + } else if (field === 'region') {
  442 + setSheet('区域', this.regionOptions)
  443 + }
  444 + },
  445 + onSheetConfirm({ value, label }) {
  446 + const field = this.sheet.field
  447 + if (!field) return
  448 + const v = (value === undefined || value === null) ? '' : value
  449 + if (field === 'standardStandardized') {
  450 + this.standardStandardized = v
  451 + this.standardStandardizedName = label || ''
  452 + return
  453 + }
  454 + this.form[field] = v
  455 + this.form[field + 'Name'] = label || ''
  456 + },
  457 + openRelate(fieldKey) {
  458 + let config = {}
  459 + if (fieldKey === 'buyer') {
  460 + config = { title: '需方', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '名称', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  461 + } else if (fieldKey === 'stockUpCompanyId') {
  462 + config = { title: '备货单位/人(生产标准)', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  463 + }
  464 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  465 + this.sheet.visible = false
  466 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  467 + this.$nextTick(() => { this.relate.visible = true })
  468 + },
  469 + onRelateConfirm({ items }) {
  470 + const _fieldKey = this.relate.fieldKey
  471 + const first = (items && items.length > 0) ? items[0] : null
  472 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  473 + if (_fieldKey === 'stockUpCompanyId') {
  474 + this.form.stockUpCompanyName = (first && first.name) ? first.name : ''
  475 + } else {
  476 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  477 + }
  478 + },
  479 + validateRequired() {
  480 + const checks = [
  481 + { key: 'code', label: '编号' },
  482 + { key: 'supplier', label: '供方' },
  483 + { key: 'buyer', label: '需方' },
  484 + { key: 'stockUpCompanyId', label: '备货单位/人(生产标准)' },
  485 + { key: 'orderDate', label: '订货日期' },
  486 + { key: 'unit', label: '单位' },
  487 + { key: 'workshopId', label: '生产厂' },
  488 + { key: 'region', label: '区域' },
  489 + { key: 'specialTerms', label: '特别条款要求' },
  490 + ]
  491 + for (const it of checks) {
  492 + const val = this.form[it.key]
  493 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  494 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  495 + }
  496 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  497 + if (list.length === 0) {
  498 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  499 + }
  500 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  501 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  502 + for (const [idx, it] of list.entries()) {
  503 + if (
  504 + strEmpty(it.productName) ||
  505 + strEmpty(it.industry) ||
  506 + strEmpty(it.quality) ||
  507 + strEmpty(it.brand) ||
  508 + numEmpty(it.quantity) ||
  509 + strEmpty(it.deliveryDate)
  510 + ) {
  511 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  512 + }
  513 + }
  514 + if (this.$refs.productRel && !this.$refs.productRel.validate()) return false
  515 + return true
  516 + },
  517 + async onSubmit() {
  518 + if (!this.fileInfo.id) {
  519 + uni.showToast({ title: '请上传合同附件', icon: 'error' })
  520 + return
  521 + }
  522 + if (this.uploadType !== 'seal' && !this.standardStandardized && this.standardStandardized !== false) {
  523 + uni.showToast({ title: '请选择合同是否规范', icon: 'error' })
  524 + return
  525 + }
  526 + if (!this.validateRequired()) return
  527 + const confirmRes = await new Promise(resolve => {
  528 + uni.showModal({
  529 + title: '确认提交',
  530 + content: this.uploadType === 'seal' ? '确定提交双方盖章合同吗?' : this.uploadType === 'formal' ? '确定提交正式合同吗?' : '确定提交标准合同吗?',
  531 + confirmText: '确定',
  532 + cancelText: '取消',
  533 + success: resolve
  534 + })
  535 + })
  536 + if (!(confirmRes && confirmRes.confirm)) return
  537 + const clean = (obj) => {
  538 + const out = {}
  539 + Object.keys(obj || {}).forEach(k => {
  540 + const v = obj[k]
  541 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  542 + const isUndef = v === undefined || v === null
  543 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  544 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  545 + })
  546 + return out
  547 + }
  548 + const lines = (this.newProductLineList || []).map(it => clean(it))
  549 + const payload = clean({
  550 + ...this.form,
  551 + id: this.form.id,
  552 + type: 'INTL_INVENTORY_AGMT',
  553 + totalQuantity: this.totalQuantity,
  554 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  555 + contractDistributorLineList: lines,
  556 + })
  557 +
  558 + let api = uploadStandardContract
  559 + if (this.uploadType === 'seal') {
  560 + api = uploadSignedContractFile
  561 + payload.signedContractFileId = this.fileInfo.id
  562 + payload.signedContractFileName = this.fileInfo.name
  563 + } else if (this.uploadType === 'formal') {
  564 + api = uploadFormalContract
  565 + payload.formalFileId = this.fileInfo.id
  566 + payload.formalFileName = this.fileInfo.name
  567 + payload.formalStandardized = this.standardStandardized
  568 + } else {
  569 + api = uploadStandardContract
  570 + payload.standardFileId = this.fileInfo.id
  571 + payload.standardFileName = this.fileInfo.name
  572 + payload.standardStandardized = this.standardStandardized
  573 + }
  574 +
  575 + try {
  576 + await api(payload)
  577 + uni.showToast({ title: '提交成功', icon: 'none' })
  578 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_foreign_stock/index' }) }, 400)
  579 + } catch (e) {
  580 + uni.showToast({ title: e.msg || '提交失败', icon: 'none' })
  581 + }
  582 + }
  583 + }
  584 +}
  585 +</script>
  586 +
  587 +<style lang="scss" scoped>
  588 +.total {
  589 + .total-text {
  590 + font-weight: 600;
  591 + font-size: 32rpx;
  592 + color: rgba(0, 0, 0, 0.9);
  593 + padding-bottom: 28rpx;
  594 + border-bottom: 2rpx solid #E7E7E7;
  595 + }
  596 +
  597 + .total-item {
  598 + display: flex;
  599 + align-items: center;
  600 + }
  601 +
  602 + .total-item-text {
  603 + font-weight: 400;
  604 + font-size: 28rpx;
  605 + color: rgba(0, 0, 0, 0.6);
  606 + line-height: 32rpx;
  607 + width: 240rpx;
  608 + padding: 12rpx 0;
  609 + }
  610 +
  611 + .total-item-price {
  612 + font-weight: 600;
  613 + font-size: 32rpx;
  614 + color: rgba(0, 0, 0, 0.9);
  615 + line-height: 32rpx;
  616 + }
  617 +
  618 + .text-red {
  619 + color: #D54941;
  620 + }
  621 +}
  622 +
  623 +.page {
  624 + display: flex;
  625 + flex-direction: column;
  626 + height: 100%;
  627 +}
  628 +
  629 +.scroll {
  630 + flex: 1;
  631 + padding: 12rpx 0 392rpx !important;
  632 +}
  633 +
  634 +.footer {
  635 + z-index: 2;
  636 + position: fixed;
  637 + left: 0;
  638 + right: 0;
  639 + bottom: 0;
  640 + padding: 32rpx;
  641 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  642 + background: #fff;
  643 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  644 +}
  645 +
  646 +.footer .btn {
  647 + height: 80rpx;
  648 + line-height: 80rpx;
  649 + border-radius: 12rpx;
  650 + font-size: 32rpx;
  651 +}
  652 +
  653 +.footer .submit {
  654 + background: $theme-primary;
  655 + color: #fff;
  656 +}
  657 +
  658 +.quality {
  659 + background-color: #fff;
  660 + display: flex;
  661 + align-items: center;
  662 + padding: 24rpx 32rpx;
  663 + border-bottom: 1rpx solid #f0f0f0;
  664 + margin-top: 20rpx;
  665 +
  666 + .title {
  667 + font-size: 32rpx;
  668 + color: rgba(0, 0, 0, 0.9);
  669 + font-weight: 600;
  670 + }
  671 +
  672 + .opCollapse {
  673 + color: rgba(0, 0, 0, 0.6);
  674 + width: 32rpx;
  675 + height: 28rpx;
  676 + margin-right: 16rpx;
  677 + }
  678 +}
  679 +
  680 +::v-deep .uni-list {
  681 + background: transparent;
  682 +}
  683 +
  684 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  685 + color: rgba(0, 0, 0, 0.9);
  686 +}
  687 +
  688 +::v-deep .uni-list .uni-input-placeholder {
  689 + z-index: 1;
  690 +}
  691 +
  692 +::v-deep .uni-list .uni-input-input {
  693 + background-color: #ffffff;
  694 +}
  695 +
  696 +::v-deep .uni-list-item__extra-text {
  697 + font-size: 32rpx;
  698 +}
  699 +
  700 +::v-deep .uni-list-item__content-title {
  701 + font-size: 32rpx;
  702 + color: rgba(0, 0, 0, 0.9);
  703 +}
  704 +
  705 +::v-deep .uni-list-item__container {
  706 + padding: 32rpx;
  707 +}
  708 +
  709 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  710 + font-size: 32rpx;
  711 + color: rgba(0, 0, 0, 0.4);
  712 +}
  713 +
  714 +::v-deep .uni-list-item__container .uni-easyinput__content {
  715 + border: none;
  716 + background-color: #ffffff !important;
  717 +}
  718 +
  719 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  720 + padding-left: 0 !important;
  721 + height: 48rpx;
  722 + line-height: 48rpx;
  723 + font-size: 32rpx;
  724 +}
  725 +
  726 +::v-deep .uni-list-item__container .item-title,
  727 +::v-deep .uni-list-item__container .uni-list-item__content {
  728 + flex: none;
  729 + min-height: 48rpx;
  730 + line-height: 48rpx;
  731 + font-size: 32rpx;
  732 + position: relative;
  733 + width: 210rpx;
  734 + margin-right: 32rpx;
  735 + color: rgba(0, 0, 0, 0.9);
  736 +}
  737 +
  738 +::v-deep .uni-list-item__container .item-title .required {
  739 + color: red;
  740 + position: absolute;
  741 + top: 50%;
  742 + transform: translateY(-50%);
  743 + left: -16rpx;
  744 +}
  745 +
  746 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  747 + color: rgba(0, 0, 0, 0.4) !important;
  748 +}
  749 +
  750 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  751 + color: rgba(0, 0, 0, 0.9) !important;
  752 +}
  753 +</style>
... ...
... ... @@ -89,11 +89,9 @@
89 89 </template>
90 90 </uni-list-item>
91 91
92   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
93   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
94   - <template v-slot:body>
95   - <view class="item-title"><text>目的地</text></view>
96   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  92 + <uni-list-item title="目的地">
  93 + <template v-slot:footer>
  94 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
97 95 </template>
98 96 </uni-list-item>
99 97 <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
... ... @@ -230,7 +228,6 @@
230 228 import SingleSelectSheet from '@/components/single-select/index.vue'
231 229 import RelateSelectSheet from '@/components/relate-select/index.vue'
232 230 import ProductRel from './productRel.vue'
233   -import CitySelector from '@/components/city-selector/index.vue'
234 231 import { getRetailCodeApi, createContractApi, getCustomerRemarks, getCustomerSpecificQualityRequirements, getDeptApi, getContractApi } from '@/api/contract'
235 232 import { getDicByCodes } from '@/utils/dic'
236 233 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -239,7 +236,7 @@ import { getArea } from '@/api/credit_manage.js'
239 236
240 237 export default {
241 238 name: 'AddContractForeignUnplan',
242   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  239 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
243 240 data() {
244 241 return {
245 242 copyId: '',
... ... @@ -266,8 +263,7 @@ export default {
266 263 includesTransportFeeName: '否',
267 264 unit: '美元、公斤、美元/公斤',
268 265 totalAmountCapital: '',
269   - destinationId: [],
270   - destinationLabel: '',
  266 + foreignDestination: '',
271 267 workshopIdName: '',
272 268 workshopId: '',
273 269 deptName: '',
... ... @@ -315,11 +311,6 @@ export default {
315 311 this.loadRegionOptions()
316 312 if (!this.copyId) this.form.orderDate = this.formatDate(new Date())
317 313 if (this.copyId) this.loadCopyDetail(this.copyId)
318   - this.$nextTick(() => {
319   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
320   - this.initDestinationLabel()
321   - }
322   - })
323 314 },
324 315 watch: {
325 316 'form.buyer': {
... ... @@ -403,8 +394,7 @@ export default {
403 394 packagingRequirements: m.packagingRequirements || '',
404 395 paymentTerms: m.paymentTerms || '',
405 396 transportMode: m.transportMode || '',
406   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
407   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  397 + foreignDestination: (m.foreignDestination || ''),
408 398 specialInstructions: m.specialInstructions || '',
409 399 remarks: m.remarks || '',
410 400 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -552,20 +542,6 @@ export default {
552 542 const val = m[field]
553 543 return val ? String(val) : map[field]
554 544 },
555   - openCitySelector() {
556   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
557   - },
558   - async initDestinationLabel() {
559   - const comp = this.$refs.citySelectorRef
560   - if (comp && typeof comp.getLabel === 'function') {
561   - const label = await comp.getLabel()
562   - this.form.destinationLabel = label || ''
563   - }
564   - },
565   - onCityChange(payload) {
566   - const label = payload && payload.label != null ? payload.label : ''
567   - this.form.destinationLabel = label
568   - },
569 545 async openSheet(field) {
570 546 const setSheet = (title, options) => {
571 547 const current = this.form[field]
... ... @@ -666,13 +642,9 @@ export default {
666 642 return out
667 643 }
668 644 const lines = (this.productLineList || []).map(it => clean(it))
669   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
670   - // 区id
671   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
672 645 const payload = clean({
673   - ...formForSubmit,
  646 + ...this.form,
674 647 operateType: isCopy ? 'COPY' : 'ADD',
675   - destination,
676 648 type: 'INTL_OPEN_SPEC_AGMT',
677 649 totalQuantity: this.totalQuantity,
678 650 // totalAmountExcludingTax: this.totalAmountExcludingTax,
... ...
... ... @@ -50,7 +50,7 @@
50 50 '-' }}</text></view>
51 51 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode || '-'
52 52 }}</text></view>
53   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel ||
  53 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination ||
54 54 '-'
55 55 }}</text></view>
56 56 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
... ... @@ -187,8 +187,7 @@ export default {
187 187 packagingRequirements: '',
188 188 paymentTerms: '',
189 189 transportMode: '',
190   - destinationId: '',
191   - destinationLabel: '',
  190 + foreignDestination: '',
192 191 specialInstructions: '',
193 192 remarks: '',
194 193 pieceWeightHead: '',
... ... @@ -392,6 +391,13 @@ export default {
392 391 uploadContract(id, type = 'formal') {
393 392 if (!id) return
394 393 this.uploadId = id
  394 + if (type === 'standard' && this.detail?.canEdit) {
  395 + const query = `?id=${encodeURIComponent(id)}&uploadType=${encodeURIComponent(type)}`
  396 + uni.navigateTo({
  397 + url: '/pages/contract_foreign_unplan/uploadStandard' + query
  398 + })
  399 + return
  400 + }
395 401 this.uploadType = type
396 402 this.$refs.uploadPopup.open()
397 403 },
... ... @@ -529,8 +535,7 @@ export default {
529 535 regionName: data.regionName || '',
530 536 deptName: data.deptName || '',
531 537 includesPackagingFeeName, includesTransportFeeName,
532   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
533   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  538 + foreignDestination: (data.foreignDestination || ''),
534 539 }
535 540 this.detail = await fillStandardApprovedName(this.detail)
536 541 this.detail = await fillFormalApprovedName(this.detail)
... ...
... ... @@ -93,11 +93,9 @@
93 93 <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
94 94 </template>
95 95 </uni-list-item>
96   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
97   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
98   - <template v-slot:body>
99   - <view class="item-title"><text>目的地</text></view>
100   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  96 + <uni-list-item title="目的地">
  97 + <template v-slot:footer>
  98 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
101 99 </template>
102 100 </uni-list-item>
103 101
... ... @@ -217,7 +215,6 @@
217 215 import SingleSelectSheet from '@/components/single-select/index.vue'
218 216 import RelateSelectSheet from '@/components/relate-select/index.vue'
219 217 import ProductRel from './productRel.vue'
220   -import CitySelector from '@/components/city-selector/index.vue'
221 218 import { getContractApi, updateContractApi } from '@/api/contract'
222 219 import { getDicByCodes } from '@/utils/dic'
223 220 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -226,7 +223,7 @@ import { getArea } from '@/api/credit_manage.js'
226 223
227 224 export default {
228 225 name: 'ModifyContractForeignUnplan',
229   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  226 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
230 227 data() {
231 228 return {
232 229 id: '',
... ... @@ -263,8 +260,7 @@ export default {
263 260 packagingRequirements: '',
264 261 paymentTerms: '',
265 262 transportMode: '',
266   - destinationId: [],
267   - destinationLabel: '',
  263 + foreignDestination: '',
268 264 specialInstructions: '',
269 265 remarks: '',
270 266 pieceWeightHead: '',
... ... @@ -297,11 +293,6 @@ export default {
297 293 this.loadExtraOptions()
298 294 this.loadRegionOptions()
299 295 this.loadDetail()
300   - this.$nextTick(() => {
301   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
302   - this.initDestinationLabel()
303   - }
304   - })
305 296 },
306 297 methods: {
307 298 async loadRegionOptions() {
... ... @@ -348,8 +339,7 @@ export default {
348 339 packagingRequirements: m.packagingRequirements || '',
349 340 paymentTerms: m.paymentTerms || '',
350 341 transportMode: m.transportMode || '',
351   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
352   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  342 + foreignDestination: (m.foreignDestination || ''),
353 343 specialInstructions: m.specialInstructions || '',
354 344 remarks: m.remarks || '',
355 345 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -370,20 +360,6 @@ export default {
370 360 this.onProductsChange(lines)
371 361 } catch (e) { }
372 362 },
373   - async initDestinationLabel() {
374   - const comp = this.$refs.citySelectorRef
375   - if (comp && typeof comp.getLabel === 'function') {
376   - const label = await comp.getLabel()
377   - this.form.destinationLabel = label || ''
378   - }
379   - },
380   - openCitySelector() {
381   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
382   - },
383   - onCityChange(payload) {
384   - const label = payload && payload.label != null ? payload.label : ''
385   - this.form.destinationLabel = label
386   - },
387 363 onProductsChange(products) {
388 364 const list = Array.isArray(products) ? products : []
389 365 this.newProductLineList = list
... ... @@ -548,12 +524,9 @@ export default {
548 524 return out
549 525 }
550 526 const lines = (this.newProductLineList || []).map(it => clean(it))
551   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
552   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
553 527 const payload = clean({
554   - ...formForSubmit,
  528 + ...this.form,
555 529 id: this.form.id,
556   - destination,
557 530 type: 'INTL_OPEN_SPEC_AGMT',
558 531 totalQuantity: this.totalQuantity,
559 532 // totalAmountExcludingTax: this.totalAmountExcludingTax,
... ... @@ -811,4 +784,4 @@ export default {
811 784 }
812 785 }
813 786
814   -</style>
\ No newline at end of file
  787 +</style>
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput v-model="form.code" :inputBorder="false" disabled />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.supplier ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openSheet('supplier')" :rightText="displayLabel('supplierName')" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>供方</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.buyer ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openRelate('buyer')" :rightText="form.buyerName || '请选择需方'" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>需方</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item class="select-item" :class="form.stockUpCompanyId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openRelate('stockUpCompanyId')" :rightText="form.stockUpCompanyName || '请选择备货单位'" showArrow>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>备货单位/人(生产标准)</text></view>
  29 + </template>
  30 + </uni-list-item>
  31 +
  32 + <uni-list-item class="select-item" :class="form.workshopId ? 'is-filled' : 'is-empty'" clickable
  33 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" showArrow>
  34 + <template v-slot:body>
  35 + <view class="item-title"><text class="required">*</text><text>生产厂</text></view>
  36 + </template>
  37 + </uni-list-item>
  38 + <uni-list-item class="select-item" :class="form.deptName ? 'is-filled' : 'is-empty'">
  39 + <template v-slot:body>
  40 + <view class="item-title"><text class="required">*</text><text>办事处</text></view>
  41 + </template>
  42 + <template v-slot:footer>
  43 + <view class="serial-number-row">
  44 + <uni-easyinput v-model="form.deptName" :inputBorder="false" disabled />
  45 + </view>
  46 + </template>
  47 + </uni-list-item>
  48 + <uni-list-item class="select-item" :class="form.region ? 'is-filled' : 'is-empty'" clickable
  49 + @click="openSheet('region')" :rightText="displayLabel('regionName')" showArrow>
  50 + <template v-slot:body>
  51 + <view class="item-title"><text class="required">*</text><text>区域</text></view>
  52 + </template>
  53 + </uni-list-item>
  54 +
  55 + <uni-list-item title="订货日期">
  56 + <template v-slot:footer>
  57 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  58 + </template>
  59 + </uni-list-item>
  60 +
  61 + <uni-list-item title="单位">
  62 + <template v-slot:footer>
  63 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  64 + </template>
  65 + </uni-list-item>
  66 +
  67 + <ProductRel ref="productRel" mode="add" :deliveryDate="form.orderDate" :deliveryDateBase="form.deliveryDate"
  68 + :list="productLineList" @change="onProductsChange" :options="productList" />
  69 +
  70 + <uni-list-item title="合计金额(大写)">
  71 + <template v-slot:footer>
  72 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false" disabled />
  73 + </template>
  74 + </uni-list-item>
  75 + <uni-list-item title="交付定金、数额、时间">
  76 + <template v-slot:footer>
  77 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  78 + </template>
  79 + </uni-list-item>
  80 + <uni-list-item title="包装要求">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求" :inputBorder="false" />
  83 + </template>
  84 + </uni-list-item>
  85 + <uni-list-item title="付款方式、付款期限">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  88 + </template>
  89 + </uni-list-item>
  90 + <uni-list-item title="运输方式">
  91 + <template v-slot:footer>
  92 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  93 + </template>
  94 + </uni-list-item>
  95 + <uni-list-item title="目的地">
  96 + <template v-slot:footer>
  97 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
  98 + </template>
  99 + </uni-list-item>
  100 +
  101 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
  102 + @click="openSheet('includesPackagingFee')" :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  103 + <template v-slot:body>
  104 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  105 + </template>
  106 + </uni-list-item>
  107 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'" clickable
  108 + @click="openSheet('includesTransportFee')" :rightText="form.includesTransportFeeName || '请选择'" showArrow>
  109 + <template v-slot:body>
  110 + <view class="item-title"><text>单价中是否已包含运费</text></view>
  111 + </template>
  112 + </uni-list-item>
  113 + <uni-list-item title="需方指定收货人">
  114 + <template v-slot:footer>
  115 + <uni-easyinput v-model="form.designatedConsignee" placeholder="请输入需方指定收货人" :inputBorder="false" />
  116 + </template>
  117 + </uni-list-item>
  118 + <uni-list-item class="select-item" :class="form.specialTermsName ? 'is-filled' : 'is-empty'" clickable
  119 + @click="openSheet('specialTerms')" :rightText="form.specialTermsName || '请选择'" showArrow>
  120 + <template v-slot:body>
  121 + <view class="item-title"><text class="required">*</text><text>特别条款要求</text></view>
  122 + </template>
  123 + </uni-list-item>
  124 + <uni-list-item class="select-item" :class="form.executionStandardName ? 'is-filled' : 'is-empty'" clickable
  125 + @click="openSheet('executionStandard')" :rightText="form.executionStandardName || '请选择'" showArrow>
  126 + <template v-slot:body>
  127 + <view class="item-title"><text>执行标准</text></view>
  128 + </template>
  129 + </uni-list-item>
  130 + <uni-list-item v-if="form.executionStandard === 'OTHER'" title="其他">
  131 + <template v-slot:footer>
  132 + <uni-easyinput v-model="form.executionStandardRemarks" placeholder="请输入其他标准备注" :inputBorder="false" />
  133 + </template>
  134 + </uni-list-item>
  135 + <uni-list-item title="特别说明" style="margin-top: 20rpx;">
  136 + <template v-slot:footer>
  137 + <uni-easyinput v-model="form.specialInstructions" placeholder="请输入特别说明" :inputBorder="false" />
  138 + </template>
  139 + </uni-list-item>
  140 + <uni-list-item title="备注">
  141 + <template v-slot:footer>
  142 + <uni-easyinput v-model="form.remarks" placeholder="请输入备注" :inputBorder="false" maxlength="2000" />
  143 + </template>
  144 + </uni-list-item>
  145 +
  146 + <view class="quality">
  147 + <image class="opCollapse" src="/static/images/title.png" />
  148 + <text class="title">具体质量要求</text>
  149 + </view>
  150 + <uni-list-item title="件重条头">
  151 + <template v-slot:footer>
  152 + <uni-easyinput v-model="form.pieceWeightHead" placeholder="请输入" :inputBorder="false" />
  153 + </template>
  154 + </uni-list-item>
  155 + <uni-list-item title="表面">
  156 + <template v-slot:footer>
  157 + <uni-easyinput v-model="form.surface" placeholder="请输入" :inputBorder="false" />
  158 + </template>
  159 + </uni-list-item>
  160 + <uni-list-item title="公差">
  161 + <template v-slot:footer>
  162 + <uni-easyinput v-model="form.tolerance" placeholder="请输入" :inputBorder="false" />
  163 + </template>
  164 + </uni-list-item>
  165 + <uni-list-item title="性能">
  166 + <template v-slot:footer>
  167 + <uni-easyinput v-model="form.performance" placeholder="请输入" :inputBorder="false" />
  168 + </template>
  169 + </uni-list-item>
  170 + <uni-list-item title="成分">
  171 + <template v-slot:footer>
  172 + <uni-easyinput v-model="form.component" placeholder="请输入" :inputBorder="false" />
  173 + </template>
  174 + </uni-list-item>
  175 + <uni-list-item title="包装">
  176 + <template v-slot:footer>
  177 + <uni-easyinput v-model="form.packaging" placeholder="请输入" :inputBorder="false" />
  178 + </template>
  179 + </uni-list-item>
  180 +
  181 + <uni-list-item title="标准合同附件" style="margin-top: 20rpx;">
  182 + <template v-slot:footer>
  183 + <FileUpload v-model="fileInfo" />
  184 + </template>
  185 + </uni-list-item>
  186 + <uni-list-item class="select-item" :class="standardStandardizedName ? 'is-filled' : 'is-empty'" clickable
  187 + @click="openSheet('standardStandardized')" :rightText="standardStandardizedName || '请选择'" showArrow>
  188 + <template v-slot:body>
  189 + <view class="item-title"><text class="required">*</text><text>合同是否规范</text></view>
  190 + </template>
  191 + </uni-list-item>
  192 +
  193 + <view class="footer">
  194 + <div class="total">
  195 + <div class="total-text">合计</div>
  196 + <div class="total-item" style="padding: 20rpx 0;">
  197 + <div class="total-item-text">数量</div>
  198 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  199 + </div>
  200 + </div>
  201 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  202 + </view>
  203 + </uni-list>
  204 + </scroll-view>
  205 +
  206 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  207 + @confirm="onSheetConfirm" />
  208 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  209 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  210 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  211 + </view>
  212 +</template>
  213 +
  214 +<script>
  215 +import SingleSelectSheet from '@/components/single-select/index.vue'
  216 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  217 +import ProductRel from './productRel.vue'
  218 +import FileUpload from '@/components/file-upload/index.vue'
  219 +import { getContractApi, uploadStandardContract } from '@/api/contract'
  220 +import { getDicByCodes } from '@/utils/dic'
  221 +import { formatCurrencyToChinese } from '@/utils/common'
  222 +import { workshopQueryApi } from '@/api/devManage'
  223 +import { getArea } from '@/api/credit_manage.js'
  224 +
  225 +export default {
  226 + name: 'UploadContractForeignUnplan',
  227 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, FileUpload },
  228 + data() {
  229 + return {
  230 + id: '',
  231 + uploadType: 'standard',
  232 + fileInfo: { id: '', name: '' },
  233 + standardStandardized: '',
  234 + standardStandardizedName: '',
  235 + form: {
  236 + id: '',
  237 + code: '',
  238 + supplier: '',
  239 + supplierName: '',
  240 + buyer: '',
  241 + buyerName: '',
  242 + stockUpCompanyId: '',
  243 + stockUpCompanyName: '',
  244 + workshopId: '',
  245 + workshopName: '',
  246 + region: '',
  247 + regionName: '',
  248 + deptName: '',
  249 + deptId: '',
  250 + orderDate: '',
  251 + deliveryDate: '',
  252 + designatedConsignee: '',
  253 + specialTerms: '',
  254 + specialTermsName: '',
  255 + executionStandard: '',
  256 + executionStandardName: '',
  257 + executionStandardRemarks: '',
  258 + includesPackagingFee: false,
  259 + includesPackagingFeeName: '否',
  260 + includesTransportFee: false,
  261 + includesTransportFeeName: '否',
  262 + unit: '美元、公斤、美元/公斤',
  263 + totalAmountCapital: '',
  264 + depositInfo: '',
  265 + packagingRequirements: '',
  266 + paymentTerms: '',
  267 + transportMode: '',
  268 + foreignDestination: '',
  269 + specialInstructions: '',
  270 + remarks: '',
  271 + pieceWeightHead: '',
  272 + surface: '',
  273 + tolerance: '',
  274 + performance: '',
  275 + component: '',
  276 + packaging: ''
  277 + },
  278 + supplierList: [],
  279 + specialTermsList: [],
  280 + executionStandardList: [],
  281 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  282 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  283 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  284 + totalQuantity: 0,
  285 + totalAmountIncludingTax: 0,
  286 + productLineList: [],
  287 + newProductLineList: [],
  288 + productList: [],
  289 + regionOptions: []
  290 + }
  291 + },
  292 + onLoad(query) {
  293 + this.id = (query && query.id) ? query.id : ''
  294 + this.uploadType = (query && query.uploadType) ? query.uploadType : 'standard'
  295 + },
  296 + created() {
  297 + this.loadSuppliers()
  298 + this.loadExtraOptions()
  299 + this.loadRegionOptions()
  300 + this.loadDetail()
  301 + },
  302 + methods: {
  303 + async loadRegionOptions() {
  304 + try {
  305 + const res = await getArea()
  306 + const list = res.data || []
  307 + this.regionOptions = (list || []).map(it => ({ label: it.name || '', value: it.id || '' }))
  308 + } catch (e) {
  309 + this.regionOptions = []
  310 + }
  311 + },
  312 + async loadDetail() {
  313 + if (!this.id) return
  314 + try {
  315 + const res = await getContractApi(this.id)
  316 + const data = res && res.data ? res.data : {}
  317 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  318 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  319 + const m = { ...data, includesPackagingFeeName, includesTransportFeeName }
  320 + this.form = {
  321 + ...this.form,
  322 + id: m.id || '',
  323 + code: m.code || '',
  324 + supplier: m.supplier || '',
  325 + supplierName: m.supplierName || '',
  326 + buyer: m.buyer || (m.customer && m.customer.id) || '',
  327 + buyerName: m.buyerName || (m.customer && m.customer.name) || '',
  328 + stockUpCompanyId: m.stockUpCompanyId || '',
  329 + stockUpCompanyName: m.stockUpCompanyName || '',
  330 + orderDate: m.orderDate || '',
  331 + designatedConsignee: m.designatedConsignee || '',
  332 + specialTerms: m.specialTerms || '',
  333 + specialTermsName: m.specialTermsName || '',
  334 + executionStandard: m.executionStandard || '',
  335 + executionStandardName: m.executionStandardName || '',
  336 + executionStandardRemarks: m.executionStandardRemarks || '',
  337 + includesPackagingFee: !!m.includesPackagingFee,
  338 + includesPackagingFeeName,
  339 + includesTransportFee: !!m.includesTransportFee,
  340 + includesTransportFeeName,
  341 + unit: m.unit || this.form.unit,
  342 + totalAmountCapital: m.totalAmountCapital || '',
  343 + depositInfo: m.depositInfo || '',
  344 + packagingRequirements: m.packagingRequirements || '',
  345 + paymentTerms: m.paymentTerms || '',
  346 + transportMode: m.transportMode || '',
  347 + foreignDestination: (m.foreignDestination || ''),
  348 + specialInstructions: m.specialInstructions || '',
  349 + remarks: m.remarks || '',
  350 + pieceWeightHead: m.pieceWeightHead || '',
  351 + surface: m.surface || '',
  352 + tolerance: m.tolerance || '',
  353 + performance: m.performance || '',
  354 + component: m.component || '',
  355 + packaging: m.packaging || '',
  356 + workshopId: m.workshopId || '',
  357 + workshopName: m.workshopName || '',
  358 + region: m.region || '',
  359 + regionName: m.regionName || '',
  360 + deptName: m.deptName || '',
  361 + deptId: m.deptId || ''
  362 + }
  363 + this.fileInfo = { id: m.standardFileId || '', name: m.standardFileName || '' }
  364 + this.standardStandardized = (m.standardStandardized === true || m.standardStandardized === false) ? m.standardStandardized : ''
  365 + this.standardStandardizedName = (this.standardStandardized === true) ? '是' : (this.standardStandardized === false) ? '否' : ''
  366 + const lines = Array.isArray(m.contractDistributorLineList) ? m.contractDistributorLineList : []
  367 + this.productLineList = lines
  368 + this.onProductsChange(lines)
  369 + } catch (e) { }
  370 + },
  371 + onProductsChange(products) {
  372 + const list = Array.isArray(products) ? products : []
  373 + this.newProductLineList = list
  374 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  375 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  376 + this.totalQuantity = sumQ
  377 + this.totalAmountIncludingTax = sumT
  378 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  379 + },
  380 + async loadSuppliers() {
  381 + try {
  382 + const results = await getDicByCodes(['SUPPLIER'])
  383 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  384 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  385 + } catch (e) { this.supplierList = [] }
  386 + },
  387 + async loadExtraOptions() {
  388 + try {
  389 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  390 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  391 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  392 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  393 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  394 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  395 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  396 + } catch (e) {
  397 + this.specialTermsList = []
  398 + this.executionStandardList = []
  399 + this.productList = []
  400 + }
  401 + },
  402 + displayLabel(field) {
  403 + const m = this.form
  404 + const map = { supplierName: '请选择供方', buyerName: '请选择需方', workshopName: '请选择生产厂', regionName: '请选择区域' }
  405 + const val = m[field]
  406 + return val ? String(val) : map[field]
  407 + },
  408 + async openSheet(field) {
  409 + if (field === 'standardStandardized') {
  410 + const options = this.yesNoList
  411 + const current = this.standardStandardized
  412 + const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
  413 + this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, field, value: match ? match.value : '' }
  414 + return
  415 + }
  416 + const setSheet = (title, options) => {
  417 + const current = this.form[field]
  418 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  419 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  420 + }
  421 + if (field === 'workshopId') {
  422 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  423 + const _data = res.data || {}
  424 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  425 + const opts = (list || []).map(it => ({ label: it.name, value: it.id }))
  426 + setSheet('生产厂', opts)
  427 + } else if (field === 'supplier') {
  428 + setSheet('供方', this.supplierList)
  429 + } else if (field === 'specialTerms') {
  430 + setSheet('特别条款要求', this.specialTermsList)
  431 + } else if (field === 'executionStandard') {
  432 + setSheet('执行标准', this.executionStandardList)
  433 + } else if (field === 'includesPackagingFee') {
  434 + setSheet('单价中是否已包含包装费', this.yesNoList)
  435 + } else if (field === 'includesTransportFee') {
  436 + setSheet('单价中是否已包含运费', this.yesNoList)
  437 + } else if (field === 'region') {
  438 + setSheet('区域', this.regionOptions)
  439 + }
  440 + },
  441 + onSheetConfirm({ value, label }) {
  442 + const field = this.sheet.field
  443 + if (!field) return
  444 + const v = (value === undefined || value === null) ? '' : value
  445 + if (field === 'standardStandardized') {
  446 + this.standardStandardized = v
  447 + this.standardStandardizedName = label || ''
  448 + return
  449 + }
  450 + this.form[field] = v
  451 + this.form[field + 'Name'] = label || ''
  452 + },
  453 + openRelate(fieldKey) {
  454 + let config = {}
  455 + if (fieldKey === 'buyer') {
  456 + config = { title: '需方', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '名称', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  457 + } else if (fieldKey === 'stockUpCompanyId') {
  458 + config = { title: '备货单位/人(生产标准)', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  459 + }
  460 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  461 + this.sheet.visible = false
  462 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  463 + this.$nextTick(() => { this.relate.visible = true })
  464 + },
  465 + onRelateConfirm({ items }) {
  466 + const _fieldKey = this.relate.fieldKey
  467 + const first = (items && items.length > 0) ? items[0] : null
  468 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  469 + if (_fieldKey === 'stockUpCompanyId') {
  470 + this.form.stockUpCompanyName = (first && first.name) ? first.name : ''
  471 + } else {
  472 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  473 + }
  474 + },
  475 + validateRequired() {
  476 + const checks = [
  477 + { key: 'code', label: '编号' },
  478 + { key: 'supplier', label: '供方' },
  479 + { key: 'buyer', label: '需方' },
  480 + { key: 'stockUpCompanyId', label: '备货单位/人(生产标准)' },
  481 + { key: 'orderDate', label: '订货日期' },
  482 + { key: 'unit', label: '单位' },
  483 + { key: 'workshopId', label: '生产厂' },
  484 + { key: 'region', label: '区域' },
  485 + { key: 'specialTerms', label: '特别条款要求' },
  486 + ]
  487 + for (const it of checks) {
  488 + const val = this.form[it.key]
  489 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  490 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  491 + }
  492 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  493 + if (list.length === 0) {
  494 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  495 + }
  496 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  497 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  498 + for (const [idx, it] of list.entries()) {
  499 + if (
  500 + strEmpty(it.productName) ||
  501 + strEmpty(it.industry) ||
  502 + strEmpty(it.quality) ||
  503 + strEmpty(it.brand) ||
  504 + numEmpty(it.quantity) ||
  505 + numEmpty(it.unitPrice) ||
  506 + strEmpty(it.deliveryDate)
  507 + ) {
  508 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  509 + }
  510 + }
  511 + if (this.$refs.productRel && !this.$refs.productRel.validate()) return false
  512 + return true
  513 + },
  514 + async onSubmit() {
  515 + if (!this.fileInfo.id) {
  516 + uni.showToast({ title: '请上传合同附件', icon: 'error' })
  517 + return
  518 + }
  519 + if (!this.standardStandardized && this.standardStandardized !== false) {
  520 + uni.showToast({ title: '请选择合同是否规范', icon: 'error' })
  521 + return
  522 + }
  523 + if (!this.validateRequired()) return
  524 + const confirmRes = await new Promise(resolve => {
  525 + uni.showModal({ title: '确认提交', content: '确定提交标准合同吗?', confirmText: '确定', cancelText: '取消', success: resolve })
  526 + })
  527 + if (!(confirmRes && confirmRes.confirm)) return
  528 + const clean = (obj) => {
  529 + const out = {}
  530 + Object.keys(obj || {}).forEach(k => {
  531 + const v = obj[k]
  532 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  533 + const isUndef = v === undefined || v === null
  534 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  535 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  536 + })
  537 + return out
  538 + }
  539 + const lines = (this.newProductLineList || []).map(it => clean(it))
  540 + const payload = clean({
  541 + ...this.form,
  542 + id: this.form.id,
  543 + type: 'INTL_OPEN_SPEC_AGMT',
  544 + totalQuantity: this.totalQuantity,
  545 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  546 + contractDistributorLineList: lines,
  547 + standardFileId: this.fileInfo.id,
  548 + standardFileName: this.fileInfo.name,
  549 + standardStandardized: this.standardStandardized,
  550 + })
  551 + try {
  552 + await uploadStandardContract(payload)
  553 + uni.showToast({ title: '提交成功', icon: 'none' })
  554 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_foreign_unplan/index' }) }, 400)
  555 + } catch (e) {
  556 + uni.showToast({ title: e.msg || '提交失败', icon: 'none' })
  557 + }
  558 + }
  559 + }
  560 +}
  561 +</script>
  562 +
  563 +<style lang="scss" scoped>
  564 +.total {
  565 + .total-text {
  566 + font-weight: 600;
  567 + font-size: 32rpx;
  568 + color: rgba(0, 0, 0, 0.9);
  569 + padding-bottom: 28rpx;
  570 + border-bottom: 2rpx solid #E7E7E7;
  571 + }
  572 +
  573 + .total-item {
  574 + display: flex;
  575 + align-items: center;
  576 + }
  577 +
  578 + .total-item-text {
  579 + font-weight: 400;
  580 + font-size: 28rpx;
  581 + color: rgba(0, 0, 0, 0.6);
  582 + line-height: 32rpx;
  583 + width: 240rpx;
  584 + padding: 12rpx 0;
  585 + }
  586 +
  587 + .total-item-price {
  588 + font-weight: 600;
  589 + font-size: 32rpx;
  590 + color: rgba(0, 0, 0, 0.9);
  591 + line-height: 32rpx;
  592 + }
  593 +
  594 + .text-red {
  595 + color: #D54941;
  596 + }
  597 +}
  598 +
  599 +.page {
  600 + display: flex;
  601 + flex-direction: column;
  602 + height: 100%;
  603 +}
  604 +
  605 +.scroll {
  606 + flex: 1;
  607 + padding: 12rpx 0 392rpx !important;
  608 +}
  609 +
  610 +.footer {
  611 + z-index: 2;
  612 + position: fixed;
  613 + left: 0;
  614 + right: 0;
  615 + bottom: 0;
  616 + padding: 32rpx;
  617 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  618 + background: #fff;
  619 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  620 +}
  621 +
  622 +.footer .btn {
  623 + height: 80rpx;
  624 + line-height: 80rpx;
  625 + border-radius: 12rpx;
  626 + font-size: 32rpx;
  627 +}
  628 +
  629 +.footer .submit {
  630 + background: $theme-primary;
  631 + color: #fff;
  632 +}
  633 +
  634 +.quality {
  635 + background-color: #fff;
  636 + display: flex;
  637 + align-items: center;
  638 + padding: 24rpx 32rpx;
  639 + border-bottom: 1rpx solid #f0f0f0;
  640 + margin-top: 20rpx;
  641 +
  642 + .title {
  643 + font-size: 32rpx;
  644 + color: rgba(0, 0, 0, 0.9);
  645 + font-weight: 600;
  646 + }
  647 +
  648 + .opCollapse {
  649 + color: rgba(0, 0, 0, 0.6);
  650 + width: 32rpx;
  651 + height: 28rpx;
  652 + margin-right: 16rpx;
  653 + }
  654 +}
  655 +
  656 +::v-deep .uni-list {
  657 + background: transparent;
  658 +}
  659 +
  660 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  661 + color: rgba(0, 0, 0, 0.9);
  662 +}
  663 +
  664 +::v-deep .uni-list .uni-input-placeholder {
  665 + z-index: 1;
  666 +}
  667 +
  668 +::v-deep .uni-list .uni-input-input {
  669 + background-color: #ffffff;
  670 +}
  671 +
  672 +::v-deep .uni-list-item__extra-text {
  673 + font-size: 32rpx;
  674 +}
  675 +
  676 +::v-deep .uni-list-item__content-title {
  677 + font-size: 32rpx;
  678 + color: rgba(0, 0, 0, 0.9);
  679 +}
  680 +
  681 +::v-deep .uni-list-item__container {
  682 + padding: 32rpx;
  683 +}
  684 +
  685 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  686 + font-size: 32rpx;
  687 + color: rgba(0, 0, 0, 0.4);
  688 +}
  689 +
  690 +::v-deep .uni-list-item__container .uni-easyinput__content {
  691 + border: none;
  692 + background-color: #ffffff !important;
  693 +}
  694 +
  695 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  696 + padding-left: 0 !important;
  697 + height: 48rpx;
  698 + line-height: 48rpx;
  699 + font-size: 32rpx;
  700 +}
  701 +
  702 +::v-deep .uni-list-item__container .item-title,
  703 +::v-deep .uni-list-item__container .uni-list-item__content {
  704 + flex: none;
  705 + min-height: 48rpx;
  706 + line-height: 48rpx;
  707 + font-size: 32rpx;
  708 + position: relative;
  709 + width: 210rpx;
  710 + margin-right: 32rpx;
  711 + color: rgba(0, 0, 0, 0.9);
  712 +}
  713 +
  714 +::v-deep .uni-list-item__container .item-title .required {
  715 + color: red;
  716 + position: absolute;
  717 + top: 50%;
  718 + transform: translateY(-50%);
  719 + left: -16rpx;
  720 +}
  721 +
  722 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  723 + color: rgba(0, 0, 0, 0.4) !important;
  724 +}
  725 +
  726 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  727 + color: rgba(0, 0, 0, 0.9) !important;
  728 +}
  729 +</style>
... ...
... ... @@ -89,11 +89,9 @@
89 89 </template>
90 90 </uni-list-item>
91 91
92   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
93   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
94   - <template v-slot:body>
95   - <view class="item-title"><text>目的地</text></view>
96   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  92 + <uni-list-item title="目的地">
  93 + <template v-slot:footer>
  94 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
97 95 </template>
98 96 </uni-list-item>
99 97 <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
... ... @@ -230,7 +228,6 @@
230 228 import SingleSelectSheet from '@/components/single-select/index.vue'
231 229 import RelateSelectSheet from '@/components/relate-select/index.vue'
232 230 import ProductRel from './productRel.vue'
233   -import CitySelector from '@/components/city-selector/index.vue'
234 231 import { getRetailCodeApi, createContractApi, getCustomerRemarks, getCustomerSpecificQualityRequirements, getDeptApi, getContractApi } from '@/api/contract'
235 232 import { getDicByCodes } from '@/utils/dic'
236 233 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -239,7 +236,7 @@ import { getArea } from '@/api/credit_manage.js'
239 236
240 237 export default {
241 238 name: 'AddContractProcess',
242   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  239 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
243 240 data() {
244 241 return {
245 242 copyId: '',
... ... @@ -266,8 +263,7 @@ export default {
266 263 includesTransportFeeName: '否',
267 264 unit: '元、公斤、元/公斤',
268 265 totalAmountCapital: '',
269   - destinationId: [],
270   - destinationLabel: '',
  266 + foreignDestination: '',
271 267 workshopIdName: '',
272 268 workshopId: '',
273 269 deptName: '',
... ... @@ -318,11 +314,6 @@ export default {
318 314 this.loadRegionOptions()
319 315 if (!this.copyId) this.form.orderDate = this.formatDate(new Date())
320 316 if (this.copyId) this.loadCopyDetail(this.copyId)
321   - this.$nextTick(() => {
322   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
323   - this.initDestinationLabel()
324   - }
325   - })
326 317 },
327 318 watch: {
328 319 'form.buyer': {
... ... @@ -402,8 +393,7 @@ export default {
402 393 packagingRequirements: m.packagingRequirements || '',
403 394 paymentTerms: m.paymentTerms || '',
404 395 transportMode: m.transportMode || '',
405   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
406   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  396 + foreignDestination: (m.foreignDestination || ''),
407 397 specialInstructions: m.specialInstructions || '',
408 398 remarks: m.remarks || '',
409 399 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -564,20 +554,6 @@ export default {
564 554 const val = m[field]
565 555 return val ? String(val) : map[field]
566 556 },
567   - openCitySelector() {
568   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
569   - },
570   - async initDestinationLabel() {
571   - const comp = this.$refs.citySelectorRef
572   - if (comp && typeof comp.getLabel === 'function') {
573   - const label = await comp.getLabel()
574   - this.form.destinationLabel = label || ''
575   - }
576   - },
577   - onCityChange(payload) {
578   - const label = payload && payload.label != null ? payload.label : ''
579   - this.form.destinationLabel = label
580   - },
581 557 async openSheet(field) {
582 558 const setSheet = (title, options) => {
583 559 const current = this.form[field]
... ... @@ -677,13 +653,9 @@ export default {
677 653 return out
678 654 }
679 655 const lines = (this.productLineList || []).map(it => clean(it))
680   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
681   - // 区id
682   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
683 656 const payload = clean({
684   - ...formForSubmit,
  657 + ...this.form,
685 658 operateType: isCopy ? 'COPY' : 'ADD',
686   - destination,
687 659 type: 'PROCESS_STD_AGMT',
688 660 totalQuantity: this.totalQuantity,
689 661 totalAmountExcludingTax: this.totalAmountExcludingTax,
... ...
... ... @@ -38,7 +38,7 @@ statusStyl<template>
38 38 '-' }}</text></view>
39 39 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode || '-'
40 40 }}</text></view>
41   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel || '-'
  41 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination || '-'
42 42 }}</text></view>
43 43 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
44 44 detail.includesPackagingFeeName || '-' }}</text></view>
... ... @@ -164,8 +164,7 @@ export default {
164 164 packagingRequirements: '',
165 165 paymentTerms: '',
166 166 transportMode: '',
167   - destinationId: '',
168   - destinationLabel: '',
  167 + foreignDestination: '',
169 168 specialInstructions: '',
170 169 remarks: '',
171 170 pieceWeightHead: '',
... ... @@ -422,8 +421,7 @@ export default {
422 421 regionName: data.regionName || '',
423 422 deptName: data.deptName || '',
424 423 includesPackagingFeeName, includesTransportFeeName,
425   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
426   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  424 + foreignDestination: (data.foreignDestination || ''),
427 425 }
428 426 this.detail = await fillStandardApprovedName(this.detail)
429 427 const lines = Array.isArray(data.contractStdProcessingLineList) ? data.contractStdProcessingLineList : []
... ...
... ... @@ -70,11 +70,9 @@
70 70 <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
71 71 </template>
72 72 </uni-list-item>
73   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
74   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
75   - <template v-slot:body>
76   - <view class="item-title"><text>目的地</text></view>
77   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  73 + <uni-list-item title="目的地">
  74 + <template v-slot:footer>
  75 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
78 76 </template>
79 77 </uni-list-item>
80 78
... ... @@ -195,7 +193,6 @@
195 193 import SingleSelectSheet from '@/components/single-select/index.vue'
196 194 import RelateSelectSheet from '@/components/relate-select/index.vue'
197 195 import ProductRel from './productRel.vue'
198   -import CitySelector from '@/components/city-selector/index.vue'
199 196 import { getContractApi, updateContractApi } from '@/api/contract'
200 197 import { getDicByCodes } from '@/utils/dic'
201 198 import { formatCurrencyToChinese } from '@/utils/common'
... ... @@ -204,7 +201,7 @@ import { getArea } from '@/api/credit_manage.js'
204 201
205 202 export default {
206 203 name: 'ModifyContractProcess',
207   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector },
  204 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
208 205 data() {
209 206 return {
210 207 id: '',
... ... @@ -241,8 +238,7 @@ export default {
241 238 packagingRequirements: '',
242 239 paymentTerms: '',
243 240 transportMode: '',
244   - destinationId: [],
245   - destinationLabel: '',
  241 + foreignDestination: '',
246 242 specialInstructions: '',
247 243 remarks: '',
248 244 pieceWeightHead: '',
... ... @@ -278,11 +274,6 @@ export default {
278 274 this.loadExtraOptions()
279 275 this.loadRegionOptions()
280 276 this.loadDetail()
281   - this.$nextTick(() => {
282   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
283   - this.initDestinationLabel()
284   - }
285   - })
286 277 },
287 278 methods: {
288 279 async loadRegionOptions() {
... ... @@ -329,8 +320,7 @@ export default {
329 320 packagingRequirements: m.packagingRequirements || '',
330 321 paymentTerms: m.paymentTerms || '',
331 322 transportMode: m.transportMode || '',
332   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
333   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  323 + foreignDestination: (m.foreignDestination || ''),
334 324 specialInstructions: m.specialInstructions || '',
335 325 remarks: m.remarks || '',
336 326 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -351,20 +341,6 @@ export default {
351 341 this.onProductsChange(lines)
352 342 } catch (e) { }
353 343 },
354   - async initDestinationLabel() {
355   - const comp = this.$refs.citySelectorRef
356   - if (comp && typeof comp.getLabel === 'function') {
357   - const label = await comp.getLabel()
358   - this.form.destinationLabel = label || ''
359   - }
360   - },
361   - openCitySelector() {
362   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
363   - },
364   - onCityChange(payload) {
365   - const label = payload && payload.label != null ? payload.label : ''
366   - this.form.destinationLabel = label
367   - },
368 344 onProductsChange(products) {
369 345 const list = Array.isArray(products) ? products : []
370 346 this.newProductLineList = list
... ... @@ -511,7 +487,6 @@ export default {
511 487 return true
512 488 },
513 489 async onSubmit() {
514   - console.log('onSubmit__payload', payload)
515 490 if (!this.validateRequired()) return
516 491 const confirmRes = await new Promise(resolve => {
517 492 uni.showModal({ title: '提示', content: '确定保存当前加工标准合同吗?', confirmText: '确定', cancelText: '取消', success: resolve })
... ... @@ -529,12 +504,9 @@ export default {
529 504 return out
530 505 }
531 506 const lines = (this.newProductLineList || []).map(it => clean(it))
532   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
533   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
534 507 const payload = clean({
535   - ...formForSubmit,
  508 + ...this.form,
536 509 id: this.form.id,
537   - destination,
538 510 type: 'PROCESS_STD_AGMT',
539 511 sumQuantity: this.sumQuantity,
540 512 sumAmountExcl: this.sumAmountExcl,
... ... @@ -792,4 +764,4 @@ export default {
792 764 }
793 765 }
794 766
795   -</style>
\ No newline at end of file
  767 +</style>
... ...
... ... @@ -29,7 +29,7 @@
29 29 '-' }}</text></view>
30 30 <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode || '-'
31 31 }}</text></view>
32   - <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationLabel || '-'
  32 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.foreignDestination || '-'
33 33 }}</text></view>
34 34 <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
35 35 detail.includesPackagingFeeName || '-' }}</text></view>
... ... @@ -120,8 +120,7 @@ export default {
120 120 packagingRequirements: '',
121 121 paymentTerms: '',
122 122 transportMode: '',
123   - destinationId: '',
124   - destinationLabel: '',
  123 + foreignDestination: '',
125 124 specialInstructions: '',
126 125 remarks: '',
127 126 pieceWeightHead: '',
... ... @@ -155,8 +154,7 @@ export default {
155 154 ...this.detail,
156 155 ...data,
157 156 includesPackagingFeeName, includesTransportFeeName,
158   - destinationId: data.provinceId && data.cityId && data.districtId ? [data.provinceId, data.cityId, data.districtId] : '',
159   - destinationLabel: data.provinceName && data.cityName && data.districtName ? `${data.provinceName} / ${data.cityName} / ${data.districtName}` : '',
  157 + foreignDestination: (data.foreignDestination || ''),
160 158 }
161 159 const lines = Array.isArray(data.contractStdProcessingLineList) ? data.contractStdProcessingLineList : []
162 160 this.productList = lines
... ... @@ -164,6 +162,10 @@ export default {
164 162 this.detail = { ...this.detail }
165 163 this.productList = []
166 164 }
  165 + },
  166 + getFormValues() {
  167 + const m = this.detail || {}
  168 + return JSON.parse(JSON.stringify(m))
167 169 }
168 170 }
169 171 }
... ... @@ -280,4 +282,4 @@ export default {
280 282 color: rgba(0, 0, 0, 0.6);
281 283 font-size: 32rpx;
282 284 }
283   -</style>
\ No newline at end of file
  285 +</style>
... ...
... ... @@ -70,11 +70,9 @@
70 70 <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
71 71 </template>
72 72 </uni-list-item>
73   - <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
74   - @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
75   - <template v-slot:body>
76   - <view class="item-title"><text>目的地</text></view>
77   - <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  73 + <uni-list-item title="目的地">
  74 + <template v-slot:footer>
  75 + <uni-easyinput v-model="form.foreignDestination" placeholder="请输入目的地" :inputBorder="false" />
78 76 </template>
79 77 </uni-list-item>
80 78
... ... @@ -206,7 +204,6 @@
206 204 import SingleSelectSheet from '@/components/single-select/index.vue'
207 205 import RelateSelectSheet from '@/components/relate-select/index.vue'
208 206 import ProductRel from './productRel.vue'
209   -import CitySelector from '@/components/city-selector/index.vue'
210 207 import FileUpload from '@/components/file-upload/index.vue'
211 208 import { getContractApi, uploadStandardContract } from '@/api/contract'
212 209 import { getDicByCodes } from '@/utils/dic'
... ... @@ -216,7 +213,7 @@ import { getArea } from '@/api/credit_manage.js'
216 213
217 214 export default {
218 215 name: 'UploadStandardContractProcess',
219   - components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  216 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, FileUpload },
220 217 data() {
221 218 return {
222 219 id: '',
... ... @@ -253,8 +250,7 @@ export default {
253 250 packagingRequirements: '',
254 251 paymentTerms: '',
255 252 transportMode: '',
256   - destinationId: [],
257   - destinationLabel: '',
  253 + foreignDestination: '',
258 254 specialInstructions: '',
259 255 remarks: '',
260 256 pieceWeightHead: '',
... ... @@ -293,11 +289,6 @@ export default {
293 289 this.loadExtraOptions()
294 290 this.loadRegionOptions()
295 291 this.loadDetail()
296   - this.$nextTick(() => {
297   - if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
298   - this.initDestinationLabel()
299   - }
300   - })
301 292 },
302 293 methods: {
303 294 async loadRegionOptions() {
... ... @@ -344,8 +335,7 @@ export default {
344 335 packagingRequirements: m.packagingRequirements || '',
345 336 paymentTerms: m.paymentTerms || '',
346 337 transportMode: m.transportMode || '',
347   - destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
348   - destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  338 + foreignDestination: (m.foreignDestination || ''),
349 339 specialInstructions: m.specialInstructions || '',
350 340 remarks: m.remarks || '',
351 341 pieceWeightHead: m.pieceWeightHead || '',
... ... @@ -372,20 +362,6 @@ export default {
372 362 this.onProductsChange(lines)
373 363 } catch (e) { }
374 364 },
375   - async initDestinationLabel() {
376   - const comp = this.$refs.citySelectorRef
377   - if (comp && typeof comp.getLabel === 'function') {
378   - const label = await comp.getLabel()
379   - this.form.destinationLabel = label || ''
380   - }
381   - },
382   - openCitySelector() {
383   - this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
384   - },
385   - onCityChange(payload) {
386   - const label = payload && payload.label != null ? payload.label : ''
387   - this.form.destinationLabel = label
388   - },
389 365 onProductsChange(products) {
390 366 const list = Array.isArray(products) ? products : []
391 367 this.newProductLineList = list
... ... @@ -569,12 +545,9 @@ export default {
569 545 return out
570 546 }
571 547 const lines = (this.newProductLineList || []).map(it => clean(it))
572   - const { destinationLabel, destinationId, ...formForSubmit } = this.form;
573   - const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
574 548 const payload = clean({
575   - ...formForSubmit,
  549 + ...this.form,
576 550 id: this.form.id,
577   - destination,
578 551 type: 'PROCESS_STD_AGMT',
579 552 sumQuantity: this.totalQuantity,
580 553 sumAmountExcl: this.totalAmountExcludingTax,
... ...
... ... @@ -563,7 +563,7 @@ export default {
563 563 })
564 564 return
565 565 }
566   - if (!this.standardStandardized && this.standardStandardized !== false) {
  566 + if (this.form.standardStandardized !== true && this.form.standardStandardized !== false) {
567 567 uni.showToast({
568 568 title: '请选择合同是否规范',
569 569 icon: 'error'
... ... @@ -596,7 +596,7 @@ export default {
596 596 contractDistributorLineList: lines,
597 597 standardFileId: this.fileInfo.id,
598 598 standardFileName: this.fileInfo.name,
599   - standardStandardized: this.standardStandardized,
  599 + standardStandardized: this.form.standardStandardized,
600 600 })
601 601
602 602 uni.showModal({
... ...
... ... @@ -279,6 +279,12 @@ export default {
279 279 visible: true,
280 280 variant: 'outline',
281 281 event: 'print'
  282 + },
  283 + {
  284 + text: '拆分',
  285 + visible: true,
  286 + variant: 'outline',
  287 + event: 'split'
282 288 }
283 289 ],
284 290 uploadId: '',
... ... @@ -293,6 +299,7 @@ export default {
293 299 const a = this.detail.standardApproved || false
294 300 const e = this.detail.showExamine || false
295 301 const f = this.detail.standardShowExamine || false
  302 + const g = this.detail.canSplit || false
296 303 return [
297 304 { ...this.buttons[0], visible: (s === 'DRAFT' && this.$auth.hasPermi('contract-manage:distribution-inventory-contract:modify')) },
298 305 { ...this.buttons[1], visible: (s === 'DRAFT' && this.$auth.hasPermi('contract-manage:distribution-inventory-contract:delete')) },
... ... @@ -308,6 +315,7 @@ export default {
308 315 { ...this.buttons[8], visible: (s === 'STANDARD' && f && a === 'AUDIT' && this.$auth.hasPermi('contract-manage:distribution-inventory-contract:standard-approve')) },
309 316 { ...this.buttons[12], visible: (s !== 'DELETED' && this.$auth.hasPermi('contract-manage:distribution-inventory-contract:copy')) },
310 317 { ...this.buttons[13], visible: true },
  318 + { ...this.buttons[14], visible: g },
311 319 ]
312 320 }
313 321 },
... ... @@ -351,9 +359,16 @@ export default {
351 359 url: '/pages/contract_stock/modify' + query
352 360 })
353 361 },
354   - uploadContract(id, type = 'formal'){
  362 + uploadContract(id, type = 'formal') {
355 363 if (!id) return
356 364 this.uploadId = id
  365 + if ((type === 'uploadParent' || type === 'upload') && this.detail?.canEdit) {
  366 + const query = `?id=${encodeURIComponent(id)}`
  367 + uni.navigateTo({
  368 + url: '/pages/contract_stock/uploadStandard' + query
  369 + })
  370 + return
  371 + }
357 372 this.uploadType = type
358 373 this.$refs.uploadPopup.open()
359 374 },
... ... @@ -434,8 +449,8 @@ export default {
434 449 if (e === 'edit') return this.onEdit(btn && btn.params)
435 450 if (e === 'delete') return this.onDelete(btn && btn.params)
436 451 if (e === 'lock') return this.onLock()
437   - if (e === 'upload') return this.uploadContract(this.detail.id || '')
438   - if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '')
  452 + if (e === 'upload') return this.uploadContract(this.detail.id || '', 'upload')
  453 + if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '', 'uploadParent')
439 454 if (e === 'uploadStandard') return this.uploadContract(this.detail.id || '', 'standard')
440 455 if (e === 'audit1') return this.onAudit(this.detail.id || '', 'FORMAL_CONTRACT')
441 456 if (e === 'audit2') return this.onAudit(this.detail.parentId || '', 'FORMAL_CONTRACT')
... ... @@ -445,6 +460,12 @@ export default {
445 460 if (e === 'auditDetail3') return this.onAuditDetail(this.detail.id || '', 'STANDARD_CONTRACT')
446 461 if (e === 'copy') return this.onCopy(this.detail)
447 462 if (e === 'print') return this.onPrint(this.detail.id || '')
  463 + if (e === 'split') return this.onSplit(this.detail.id || '')
  464 + },
  465 + onSplit(id) {
  466 + uni.navigateTo({
  467 + url: '/pages/contract_stock/split?id=' + id || ''
  468 + })
448 469 },
449 470 onPrint(id) {
450 471 printFile(id)
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="lock-page">
  5 + <view class="block" v-for="(item, idx) in items" :key="idx">
  6 + <view class="block-header">
  7 + <uni-data-checkbox
  8 + multiple
  9 + mode="default"
  10 + :localdata="[{ text: '拆分数量', value: 'LOCKED' }]"
  11 + :modelValue="item.locked ? ['LOCKED'] : []"
  12 + :disabled="true"
  13 + @change="onLockChange(idx, $event)"
  14 + />
  15 + <view class="ops" @click="toggleItem(idx)">
  16 + <image class="opIcon"
  17 + :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" />
  18 + <text class="opText">{{ item.collapsed ? '收起' : '展开' }}</text>
  19 + </view>
  20 + </view>
  21 +
  22 + <uni-list v-show="item.collapsed">
  23 + <uni-list-item title="产品名称">
  24 + <template v-slot:footer>
  25 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  26 + </template>
  27 + </uni-list-item>
  28 + <uni-list-item title="行业">
  29 + <template v-slot:footer>
  30 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  31 + </template>
  32 + </uni-list-item>
  33 + <uni-list-item title="牌号">
  34 + <template v-slot:footer>
  35 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  36 + </template>
  37 + </uni-list-item>
  38 + <uni-list-item title="品质">
  39 + <template v-slot:footer>
  40 + <uni-easyinput v-model="item.quality" placeholder="请输入品质" :clearable="false" disabled />
  41 + </template>
  42 + </uni-list-item>
  43 + <uni-list-item title="规格(mm)">
  44 + <template v-slot:footer>
  45 + <view class="value value-spec">
  46 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  47 + <view v-if="item.thickness" class="value-spec_box">
  48 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+' + item.thicknessTolPos : item.thicknessTolPos }}
  49 + </view>
  50 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+' + item.thicknessTolNeg : item.thicknessTolNeg }}
  51 + </view>
  52 + </view>
  53 + <view v-if="item.width" class="value-spec_val p12">*</view>
  54 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  55 + <view v-if="item.width" class="value-spec_box">
  56 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' + item.widthTolPos : item.widthTolPos }}
  57 + </view>
  58 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' + item.widthTolNeg : item.widthTolNeg }}
  59 + </view>
  60 + </view>
  61 + <view v-if="item.length" class="value-spec_val p12">*</view>
  62 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  63 + <view v-if="item.length" class="value-spec_box">
  64 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' + item.lengthTolPos : item.lengthTolPos }}
  65 + </view>
  66 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' + item.lengthTolNeg : item.lengthTolNeg }}
  67 + </view>
  68 + </view>
  69 + </view>
  70 + </template>
  71 + </uni-list-item>
  72 + <uni-list-item title="物料编码">
  73 + <template v-slot:footer>
  74 + <uni-easyinput v-model="item.materialCode" placeholder="请输入物料编码" :clearable="false" disabled />
  75 + </template>
  76 + </uni-list-item>
  77 + <uni-list-item title="状态">
  78 + <template v-slot:footer>
  79 + <uni-easyinput v-model="item.status" placeholder="请输入状态" :clearable="false" disabled />
  80 + </template>
  81 + </uni-list-item>
  82 + <uni-list-item title="数量">
  83 + <template v-slot:footer>
  84 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" disabled placeholder="不可编辑" />
  85 + </template>
  86 + </uni-list-item>
  87 + <uni-list-item title="本次锁价数量">
  88 + <template v-slot:footer>
  89 + <uni-easyinput v-model="item.currentQuantity" type="number" :inputBorder="false" placeholder="请输入本次拆分数量" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'currentQuantity', 3)" />
  90 + </template>
  91 + </uni-list-item>
  92 + <uni-list-item title="单价">
  93 + <template v-slot:footer>
  94 + <uni-easyinput v-model="item.unitPrice" type="digit" :inputBorder="false" disabled placeholder="不可编辑" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'unitPrice', 0)" />
  95 + </template>
  96 + </uni-list-item>
  97 + <uni-list-item title="不含税金额">
  98 + <template v-slot:footer>
  99 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false" disabled placeholder="" />
  100 + </template>
  101 + </uni-list-item>
  102 + <uni-list-item title="总金额">
  103 + <template v-slot:footer>
  104 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled placeholder="" />
  105 + </template>
  106 + </uni-list-item>
  107 + <uni-list-item title="发货日期">
  108 + <template v-slot:footer>
  109 + <uni-easyinput v-model="item.deliveryDate" :inputBorder="false" disabled />
  110 + </template>
  111 + </uni-list-item>
  112 + </uni-list>
  113 +
  114 + <uni-list v-show="!item.collapsed">
  115 + <uni-list-item title="产品名称">
  116 + <template v-slot:footer>
  117 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  118 + </template>
  119 + </uni-list-item>
  120 + <uni-list-item title="行业">
  121 + <template v-slot:footer>
  122 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  123 + </template>
  124 + </uni-list-item>
  125 + <uni-list-item title="牌号">
  126 + <template v-slot:footer>
  127 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  128 + </template>
  129 + </uni-list-item>
  130 +
  131 + </uni-list>
  132 + </view>
  133 + <view class="footer">
  134 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  135 + </view>
  136 + </view>
  137 + </scroll-view>
  138 +
  139 + </view>
  140 +</template>
  141 +
  142 +<script>
  143 +import { getContractApi, splitQuantityLock } from '@/api/contract'
  144 +
  145 +export default {
  146 + name: 'ContractUnplanLock',
  147 + data() {
  148 + return {
  149 + id: '',
  150 + items: [],
  151 + planQty: 30,
  152 + }
  153 + },
  154 + onLoad(options) {
  155 + const id = options && options.id ? options.id : ''
  156 + this.id = id
  157 + this.loadDetail()
  158 + },
  159 + methods: {
  160 + onLockChange(idx, e) {
  161 + const it = this.items[idx]
  162 + if (!it) return
  163 + const arr = e && e.detail && e.detail.value ? e.detail.value : []
  164 + it.locked = Array.isArray(arr) && arr.length > 0
  165 + this.$set(this.items, idx, it)
  166 + },
  167 + async loadDetail() {
  168 + if (!this.id) return
  169 + try {
  170 + const res = await getContractApi(this.id)
  171 + const data = res && res.data ? res.data : {}
  172 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  173 + const init = lines.map(v => ({
  174 + locked: true,
  175 + collapsed: true,
  176 + raw: v,
  177 + productName: v.rawProductName || v.productName || '',
  178 + industry: v.industry || '',
  179 + brand: v.rawProductGrade || v.brand || '',
  180 + quality: v.quality || '',
  181 + thickness: v.thickness || '',
  182 + thicknessTolPos: v.thicknessTolPos || '',
  183 + thicknessTolNeg: v.thicknessTolNeg || '',
  184 + width: v.width || '',
  185 + widthTolPos: v.widthTolPos || '',
  186 + widthTolNeg: v.widthTolNeg || '',
  187 + length: v.length || '',
  188 + lengthTolPos: v.lengthTolPos || '',
  189 + lengthTolNeg: v.lengthTolNeg || '',
  190 + materialCode: v.materialCode || '',
  191 + status: v.status || '',
  192 + quantity: v.productQuantity || v.quantity || '',
  193 + currentQuantity: v.currentQuantity === 0 ? 0 : (v.currentQuantity || ''),
  194 + unitPrice: v.unitPrice || '',
  195 + amountExcludingTax: v.amountExcludingTax || 0,
  196 + totalAmount: v.totalAmount || 0,
  197 + deliveryDate: v.deliveryDate || '',
  198 + specDisplay: ''
  199 + }))
  200 + this.items = init.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  201 + this.recalculateAll()
  202 + } catch (e) {
  203 + this.items = []
  204 + }
  205 + },
  206 + toggleItem(idx) {
  207 + const it = this.items[idx]
  208 + if (!it) return
  209 + it.collapsed = !it.collapsed
  210 + this.$set(this.items, idx, it)
  211 + },
  212 + onImmediateChange(idx) {
  213 + this.$nextTick(() => this.recalculate(idx))
  214 + },
  215 + onNumberBlur(idx, field, digits) {
  216 + const it = this.items[idx]
  217 + if (!it) return
  218 + const raw = it[field]
  219 + if (raw === '' || raw === null || raw === undefined) {
  220 + this.$set(this.items, idx, it)
  221 + this.recalculate(idx)
  222 + return
  223 + }
  224 + const num = this.toNumber(raw)
  225 + const rounded = this.round(num, digits)
  226 + it[field] = rounded
  227 + this.$set(this.items, idx, it)
  228 + this.recalculate(idx)
  229 + },
  230 + recalculate(idx) {
  231 + const TAX_RATE = 0.13
  232 + const it = this.items[idx]
  233 + if (!it) return
  234 + const qty = this.toNumber(it.quantity)
  235 + const price = this.toNumber(it.unitPrice)
  236 + const total = this.round(qty * price, 2)
  237 + const excl = this.round(total / (1 + TAX_RATE), 2)
  238 + it.amountExcludingTax = excl
  239 + it.totalAmount = total
  240 + this.$set(this.items, idx, it)
  241 + },
  242 + recalculateAll() {
  243 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
  244 + },
  245 + toNumber(val) {
  246 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  247 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  248 + return isNaN(n) ? 0 : n
  249 + },
  250 + round(val, digits = 2) {
  251 + const n = Number(val)
  252 + if (isNaN(n)) return 0
  253 + const m = Math.pow(10, digits)
  254 + return Math.round(n * m) / m
  255 + },
  256 + specOf(item) {
  257 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/ ')
  258 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/ ')
  259 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/ ')
  260 + return [t, w, l].filter(Boolean).join(' × ')
  261 + },
  262 + formatCurrency(val) {
  263 + if (val == null || val === '') return ''
  264 + const num = Number(val)
  265 + const pre = isNaN(num) ? '' : '¥'
  266 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  267 + return `${pre}${fixed}`
  268 + },
  269 + onReset() {
  270 + this.items = this.items.map((it, i) => ({
  271 + ...it,
  272 + quantity: '',
  273 + currentQuantity: '',
  274 + unitPrice: '',
  275 + amountExcludingTax: 0
  276 + }))
  277 + },
  278 + async onSubmit() {
  279 + const selected = this.items.filter(it => it.locked).map(it => {
  280 + const raw = { ...(it.raw || {}) }
  281 + const qty = this.toNumber(it.quantity)
  282 + const curQtyRaw = it.currentQuantity
  283 + const price = this.toNumber(it.unitPrice)
  284 + const total = this.toNumber(it.totalAmount)
  285 + const excl = this.toNumber(it.amountExcludingTax)
  286 + if (Object.prototype.hasOwnProperty.call(raw, 'productQuantity')) raw.productQuantity = qty
  287 + else raw.quantity = qty
  288 + raw.currentQuantity = (curQtyRaw === '' || curQtyRaw === null || curQtyRaw === undefined) ? null : this.toNumber(curQtyRaw)
  289 + raw.unitPrice = price
  290 + raw.totalAmount = total
  291 + raw.amountExcludingTax = excl
  292 + return raw
  293 + })
  294 + if (!selected.length) {
  295 + uni.showToast({ title: '未选择任何拆分项', icon: 'none' })
  296 + return
  297 + }
  298 + const invalidQty = selected.find(r => {
  299 + const q = this.toNumber(r.currentQuantity)
  300 + return !(q > 0)
  301 + })
  302 + if (invalidQty) {
  303 + uni.showToast({ title: '请填写本次拆分数量', icon: 'none' })
  304 + return
  305 + }
  306 + this.selectedItems = selected
  307 + const payload = {
  308 + id: this.id,
  309 + contractDistributorLineList: selected
  310 + }
  311 +
  312 + uni.showModal({
  313 + title: '确认提交',
  314 + content: '确定提交拆分吗?',
  315 + success: (res) => {
  316 + if (res.confirm) {
  317 + splitQuantityLock(payload).then(() => {
  318 + uni.showToast({ title: '拆分已提交', icon: 'success' })
  319 + setTimeout(() => {
  320 + uni.navigateTo({ url: '/pages/contract_stock/index' })
  321 + }, 500)
  322 + }).catch((err) => {
  323 + uni.showToast({ title: err.msg ||'提交失败', icon: 'none' })
  324 + })
  325 + }
  326 + }
  327 + })
  328 + }
  329 + }
  330 +}
  331 +</script>
  332 +
  333 +<style lang="scss" scoped>
  334 +.page {
  335 + display: flex;
  336 + flex-direction: column;
  337 + height: 100%;
  338 +}
  339 +
  340 +.scroll {
  341 + flex: 1;
  342 + padding: 12rpx 0 392rpx !important;
  343 +}
  344 +
  345 +.header {
  346 + background-color: #fff;
  347 + display: flex;
  348 + align-items: center;
  349 + padding: 24rpx 32rpx;
  350 + border-bottom: 1rpx solid #f0f0f0;
  351 +}
  352 +
  353 +.title {
  354 + font-size: 32rpx;
  355 + color: rgba(0, 0, 0, 0.9);
  356 + font-weight: 600;
  357 +}
  358 +
  359 +.opCollapse {
  360 + width: 24rpx;
  361 + height: 24rpx;
  362 + margin-right: 16rpx;
  363 + margin-top: 8rpx;
  364 +}
  365 +
  366 +.block {
  367 + background: #fff;
  368 + margin-top: 20rpx;
  369 +}
  370 +
  371 +.block-header {
  372 + display: flex;
  373 + align-items: center;
  374 + padding: 24rpx 32rpx;
  375 + border-bottom: 1rpx solid #f0f0f0;
  376 +}
  377 +
  378 +.block-header ::v-deep .uni-data-checklist .checkbox__inner {
  379 + width: 36rpx;
  380 + height: 36rpx;
  381 +}
  382 +.block-header ::v-deep .uni-data-checklist .checklist-text {
  383 + font-size: 28rpx;
  384 + margin-left: 12rpx;
  385 +}
  386 +
  387 +.block-title {
  388 + margin-left: 12rpx;
  389 + font-size: 28rpx;
  390 + color: rgba(0, 0, 0, 0.9);
  391 +}
  392 +
  393 +.ops {
  394 + margin-left: auto;
  395 + display: flex;
  396 + align-items: center;
  397 + color: $theme-primary;
  398 + font-size: 28rpx;
  399 +}
  400 +
  401 +.opIcon {
  402 + width: 40rpx;
  403 + height: 40rpx;
  404 +}
  405 +
  406 +.opText {
  407 + margin-left: 8rpx;
  408 + color: $theme-primary;
  409 +}
  410 +
  411 +::v-deep .uni-list {
  412 + .uni-easyinput {
  413 + display: flex;
  414 +
  415 + .uni-input-input {
  416 + color: rgba(0, 0, 0, 0.9);
  417 + }
  418 + }
  419 +
  420 + .uni-input-placeholder {
  421 + z-index: 1;
  422 + }
  423 +
  424 + .uni-input-input {
  425 + background-color: #ffffff;
  426 + }
  427 +
  428 + background: transparent;
  429 +
  430 + &-item {
  431 + &__extra-text {
  432 + font-size: 32rpx;
  433 + }
  434 +
  435 + &__content-title {
  436 + font-size: 32rpx;
  437 + color: rgba(0, 0, 0, 0.9);
  438 + }
  439 +
  440 + &__container {
  441 + padding: 32rpx;
  442 +
  443 + .uni-easyinput {
  444 + &__placeholder-class {
  445 + font-size: 32rpx;
  446 + color: rgba(0, 0, 0, 0.4);
  447 + }
  448 +
  449 + &__content {
  450 + border: none;
  451 + background-color: #ffffff !important;
  452 +
  453 + &-input {
  454 + padding-left: 0 !important;
  455 + height: 48rpx;
  456 + line-height: 48rpx;
  457 + font-size: 32rpx;
  458 + }
  459 +
  460 + .content-clear-icon {
  461 + font-size: 44rpx !important;
  462 + }
  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 + position: relative;
  473 + width: 210rpx;
  474 + margin-right: 32rpx;
  475 + color: rgba(0, 0, 0, 0.9);
  476 +
  477 + .required {
  478 + color: red;
  479 + position: absolute;
  480 + top: 50%;
  481 + transform: translateY(-50%);
  482 + left: -16rpx;
  483 + }
  484 + }
  485 + }
  486 +
  487 + &.select-item {
  488 + &.is-empty {
  489 + .uni-list-item__extra-text {
  490 + color: rgba(0, 0, 0, 0.4) !important;
  491 + }
  492 + }
  493 +
  494 + &.is-filled {
  495 + .uni-list-item__extra-text {
  496 + color: rgba(0, 0, 0, 0.9) !important;
  497 + }
  498 + }
  499 + }
  500 +
  501 + &.mgb10 {
  502 + margin-bottom: 20rpx;
  503 + }
  504 + }
  505 +}
  506 +
  507 +// ::v-deep .uni-list-item__container {
  508 +// padding: 32rpx;
  509 +// }
  510 +
  511 +::v-deep .is-disabled {
  512 + background-color: transparent !important;
  513 +}
  514 +// ::v-deep .uni-list-item__content-title {
  515 +// font-size: 28rpx;
  516 +// color: rgba(0, 0, 0, 0.9);
  517 +// }
  518 +
  519 +// ::v-deep .uni-list-item__extra-text {
  520 +// font-size: 32rpx;
  521 +// }
  522 +
  523 +::v-deep .uni-easyinput {
  524 + width: 100%;
  525 +}
  526 +
  527 +::v-deep .uni-easyinput__placeholder-class {
  528 + font-size: 32rpx;
  529 + color: rgba(0, 0, 0, 0.4);
  530 +}
  531 +
  532 +::v-deep .uni-easyinput__content {
  533 + border: none;
  534 + display: flex;
  535 +}
  536 +
  537 +::v-deep .uni-easyinput__content-input {
  538 + padding-left: 0 !important;
  539 + height: 48rpx;
  540 + line-height: 48rpx;
  541 + font-size: 32rpx;
  542 + color: rgba(0, 0, 0, 0.9);
  543 +}
  544 +
  545 +.amount-item .item-title {
  546 + display: flex;
  547 + align-items: center;
  548 +}
  549 +
  550 +.amount-row {
  551 + display: flex;
  552 + align-items: center;
  553 +}
  554 +
  555 +.amount-row .unit {
  556 + margin-left: 12rpx;
  557 + color: rgba(0, 0, 0, 0.6);
  558 +}
  559 +
  560 +.summary {
  561 + margin-top: 20rpx;
  562 + background: #fff;
  563 + padding-bottom: 12rpx;
  564 +}
  565 +
  566 +.title-header {
  567 + display: flex;
  568 + align-items: center;
  569 + padding: 20rpx 32rpx;
  570 +}
  571 +
  572 +.title-header_icon {
  573 + width: 24rpx;
  574 + height: 24rpx;
  575 + margin-right: 16rpx;
  576 +}
  577 +
  578 +.sum-card {
  579 + background: #f3f3f3;
  580 + border-radius: 16rpx;
  581 + padding: 24rpx;
  582 + margin: 0 32rpx 20rpx;
  583 +}
  584 +
  585 +.row {
  586 + display: flex;
  587 + margin-bottom: 16rpx;
  588 +}
  589 +
  590 +.row .label {
  591 + width: 140rpx;
  592 + color: rgba(0, 0, 0, 0.6);
  593 + font-size: 28rpx;
  594 +}
  595 +
  596 +.row .value {
  597 + flex: 1;
  598 + text-align: right;
  599 + color: rgba(0, 0, 0, 0.9);
  600 + font-size: 28rpx;
  601 +}
  602 +
  603 +.row .amount {
  604 + color: #D54941;
  605 +}
  606 +
  607 +.total {
  608 + .total-text {
  609 + font-weight: 600;
  610 + font-size: 32rpx;
  611 + color: rgba(0, 0, 0, 0.9);
  612 + padding-bottom: 28rpx;
  613 + border-bottom: 2rpx solid #E7E7E7;
  614 + }
  615 +
  616 + .total-item {
  617 + display: flex;
  618 + align-items: center;
  619 +
  620 + .total-item-text {
  621 + font-weight: 400;
  622 + font-size: 28rpx;
  623 + color: rgba(0, 0, 0, 0.6);
  624 + line-height: 32rpx;
  625 + width: 240rpx;
  626 + padding: 12rpx 0;
  627 + }
  628 +
  629 + .total-item-price {
  630 + font-weight: 600;
  631 + font-size: 32rpx;
  632 + color: rgba(0, 0, 0, 0.9);
  633 + line-height: 32rpx;
  634 + }
  635 +
  636 + .text-red {
  637 + color: #D54941;
  638 + }
  639 + }
  640 +
  641 +}
  642 +
  643 +.footer {
  644 + z-index: 2;
  645 + position: fixed;
  646 + left: 0;
  647 + right: 0;
  648 + bottom: 0;
  649 + padding: 32rpx;
  650 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  651 + background: #fff;
  652 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  653 +
  654 + .btn {
  655 + height: 80rpx;
  656 + line-height: 80rpx;
  657 + border-radius: 12rpx;
  658 + font-size: 32rpx;
  659 + }
  660 +
  661 + .submit {
  662 + background: $theme-primary;
  663 + color: #fff;
  664 + }
  665 +}
  666 +
  667 +.btn {
  668 + height: 80rpx;
  669 + line-height: 80rpx;
  670 + border-radius: 12rpx;
  671 + font-size: 32rpx;
  672 + flex: 1;
  673 +}
  674 +
  675 +.submit {
  676 + background: $theme-primary;
  677 + color: #fff;
  678 +}
  679 +.value-spec {
  680 + height: 48rpx;
  681 + display: flex;
  682 + align-items: center;
  683 + color: #000000;
  684 + // justify-content: end;
  685 + &_box {
  686 + position: relative;
  687 + width: 60rpx;
  688 + height: 48rpx;
  689 +
  690 + &_1 {
  691 + font-size: 16rpx;
  692 + position: absolute;
  693 + top: -10rpx;
  694 + left: 0;
  695 + }
  696 +
  697 + &_2 {
  698 + font-size: 16rpx;
  699 + position: absolute;
  700 + bottom: -10rpx;
  701 + left: 0;
  702 + }
  703 + }
  704 +
  705 + &_val {
  706 + font-size: 28rpx;
  707 +
  708 + &.p12 {
  709 + padding-right: 12rpx;
  710 + }
  711 + }
  712 + }
  713 + .row-spec {
  714 + height: 60rpx;
  715 + align-items: center;
  716 + }
  717 +</style>
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput v-model="form.code" :inputBorder="false" disabled />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.supplier ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openSheet('supplier')" :rightText="displayLabel('supplierName')" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>供方</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.buyer ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openRelate('buyer')" :rightText="form.buyerName || '请选择需方'" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>需方</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item class="select-item" :class="form.stockUpCompanyId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openRelate('stockUpCompanyId')" :rightText="form.stockUpCompanyName || '请选择备货单位'" showArrow>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>备货单位/人(生产标准)</text></view>
  29 + </template>
  30 + </uni-list-item>
  31 +
  32 + <uni-list-item class="select-item" :class="form.workshopId ? 'is-filled' : 'is-empty'" clickable
  33 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" showArrow>
  34 + <template v-slot:body>
  35 + <view class="item-title"><text class="required">*</text><text>生产厂</text></view>
  36 + </template>
  37 + </uni-list-item>
  38 +
  39 + <uni-list-item title="订货日期">
  40 + <template v-slot:footer>
  41 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  42 + </template>
  43 + </uni-list-item>
  44 +
  45 + <uni-list-item title="单位">
  46 + <template v-slot:footer>
  47 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  48 + </template>
  49 + </uni-list-item>
  50 + <uni-list-item title="办事处">
  51 + <template v-slot:footer>
  52 + <uni-easyinput v-model="form.deptName" :inputBorder="false" disabled placeholder="自动获取" />
  53 + </template>
  54 + </uni-list-item>
  55 + <uni-list-item class="select-item" :class="form.region ? 'is-filled' : 'is-empty'" clickable
  56 + @click="openSheet('region')" :rightText="displayLabel('regionName')" showArrow>
  57 + <template v-slot:body>
  58 + <view class="item-title"><text class="required">*</text><text>区域</text></view>
  59 + </template>
  60 + </uni-list-item>
  61 +
  62 + <ProductRel ref="productRel" mode="add" :deliveryDate="form.orderDate" :deliveryDateBase="form.deliveryDate"
  63 + :list="productLineList" @change="onProductsChange" :options="productList" />
  64 +
  65 + <uni-list-item title="合计人民币金额(大写)">
  66 + <template v-slot:footer>
  67 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false" disabled />
  68 + </template>
  69 + </uni-list-item>
  70 + <uni-list-item title="交付定金、数额、时间">
  71 + <template v-slot:footer>
  72 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  73 + </template>
  74 + </uni-list-item>
  75 + <uni-list-item title="包装要求">
  76 + <template v-slot:footer>
  77 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求" :inputBorder="false" />
  78 + </template>
  79 + </uni-list-item>
  80 + <uni-list-item title="付款方式、付款期限">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  83 + </template>
  84 + </uni-list-item>
  85 + <uni-list-item title="运输方式">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  88 + </template>
  89 + </uni-list-item>
  90 + <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
  91 + @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
  92 + <template v-slot:body>
  93 + <view class="item-title"><text>目的地</text></view>
  94 + <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  95 + </template>
  96 + </uni-list-item>
  97 +
  98 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
  99 + @click="openSheet('includesPackagingFee')" :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  100 + <template v-slot:body>
  101 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  102 + </template>
  103 + </uni-list-item>
  104 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'" clickable
  105 + @click="openSheet('includesTransportFee')" :rightText="form.includesTransportFeeName || '请选择'" showArrow>
  106 + <template v-slot:body>
  107 + <view class="item-title"><text>单价中是否已包含运费</text></view>
  108 + </template>
  109 + </uni-list-item>
  110 + <uni-list-item title="需方指定收货人">
  111 + <template v-slot:footer>
  112 + <uni-easyinput v-model="form.designatedConsignee" placeholder="请输入需方指定收货人" :inputBorder="false" />
  113 + </template>
  114 + </uni-list-item>
  115 +
  116 + <uni-list-item class="select-item" :class="form.specialTermsName ? 'is-filled' : 'is-empty'" clickable
  117 + @click="openSheet('specialTerms')" :rightText="form.specialTermsName || '请选择'" 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 + <uni-list-item class="select-item" :class="form.executionStandardName ? 'is-filled' : 'is-empty'" clickable
  123 + @click="openSheet('executionStandard')" :rightText="form.executionStandardName || '请选择'" showArrow>
  124 + <template v-slot:body>
  125 + <view class="item-title"><text>执行标准</text></view>
  126 + </template>
  127 + </uni-list-item>
  128 + <uni-list-item v-if="form.executionStandard === 'OTHER'" title="其他">
  129 + <template v-slot:footer>
  130 + <uni-easyinput v-model="form.executionStandardRemarks" placeholder="请输入其他标准备注" :inputBorder="false" />
  131 + </template>
  132 + </uni-list-item>
  133 + <uni-list-item title="特别说明" style="margin-top: 20rpx;">
  134 + <template v-slot:footer>
  135 + <uni-easyinput v-model="form.specialInstructions" placeholder="请输入特别说明" :inputBorder="false" />
  136 + </template>
  137 + </uni-list-item>
  138 + <uni-list-item title="备注">
  139 + <template v-slot:footer>
  140 + <uni-easyinput v-model="form.remarks" placeholder="请输入备注" :inputBorder="false" maxlength="2000" />
  141 + </template>
  142 + </uni-list-item>
  143 +
  144 + <view class="quality">
  145 + <image class="opCollapse" src="/static/images/title.png" />
  146 + <text class="title">具体质量要求</text>
  147 + </view>
  148 + <uni-list-item title="件重条头">
  149 + <template v-slot:footer>
  150 + <uni-easyinput v-model="form.pieceWeightHead" placeholder="请输入" :inputBorder="false" />
  151 + </template>
  152 + </uni-list-item>
  153 + <uni-list-item title="表面">
  154 + <template v-slot:footer>
  155 + <uni-easyinput v-model="form.surface" placeholder="请输入" :inputBorder="false" />
  156 + </template>
  157 + </uni-list-item>
  158 + <uni-list-item title="公差">
  159 + <template v-slot:footer>
  160 + <uni-easyinput v-model="form.tolerance" placeholder="请输入" :inputBorder="false" />
  161 + </template>
  162 + </uni-list-item>
  163 + <uni-list-item title="性能">
  164 + <template v-slot:footer>
  165 + <uni-easyinput v-model="form.performance" placeholder="请输入" :inputBorder="false" />
  166 + </template>
  167 + </uni-list-item>
  168 + <uni-list-item title="成分">
  169 + <template v-slot:footer>
  170 + <uni-easyinput v-model="form.component" placeholder="请输入" :inputBorder="false" />
  171 + </template>
  172 + </uni-list-item>
  173 + <uni-list-item title="包装">
  174 + <template v-slot:footer>
  175 + <uni-easyinput v-model="form.packaging" placeholder="请输入" :inputBorder="false" />
  176 + </template>
  177 + </uni-list-item>
  178 +
  179 + <uni-list-item :title="uploadType === 'formal' ? '正式合同附件' : '标准合同附件'" style="margin-top: 20rpx;">
  180 + <template v-slot:footer>
  181 + <FileUpload v-model="fileInfo" />
  182 + </template>
  183 + </uni-list-item>
  184 + <uni-list-item class="select-item" :class="standardStandardizedName ? 'is-filled' : 'is-empty'" clickable
  185 + @click="openSheet('standardStandardized')" :rightText="standardStandardizedName || '请选择'" showArrow>
  186 + <template v-slot:body>
  187 + <view class="item-title"><text class="required">*</text><text>合同是否规范</text></view>
  188 + </template>
  189 + </uni-list-item>
  190 +
  191 + <view class="footer">
  192 + <div class="total">
  193 + <div class="total-text">合计</div>
  194 + <div class="total-item" style="padding: 20rpx 0;">
  195 + <div class="total-item-text">数量</div>
  196 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  197 + </div>
  198 + </div>
  199 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  200 + </view>
  201 + </uni-list>
  202 + </scroll-view>
  203 +
  204 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  205 + @confirm="onSheetConfirm" />
  206 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  207 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  208 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  209 + </view>
  210 +</template>
  211 +
  212 +<script>
  213 +import SingleSelectSheet from '@/components/single-select/index.vue'
  214 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  215 +import ProductRel from './productRel.vue'
  216 +import CitySelector from '@/components/city-selector/index.vue'
  217 +import FileUpload from '@/components/file-upload/index.vue'
  218 +import { getContractApi, uploadFormalContract, uploadStandardContract } from '@/api/contract'
  219 +import { getDicByCodes } from '@/utils/dic'
  220 +import { formatCurrencyToChinese } from '@/utils/common'
  221 +import { workshopQueryApi } from '@/api/devManage'
  222 +import { getArea } from '@/api/credit_manage.js'
  223 +
  224 +export default {
  225 + name: 'UploadContractStock',
  226 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  227 + data() {
  228 + return {
  229 + id: '',
  230 + uploadType: 'formal',
  231 + fileInfo: { id: '', name: '' },
  232 + standardStandardized: '',
  233 + standardStandardizedName: '',
  234 + form: {
  235 + id: '',
  236 + code: '',
  237 + supplier: '',
  238 + supplierName: '',
  239 + buyer: '',
  240 + buyerName: '',
  241 + stockUpCompanyId: '',
  242 + stockUpCompanyName: '',
  243 + workshopId: '',
  244 + workshopName: '',
  245 + deptName: '',
  246 + deptId: '',
  247 + region: '',
  248 + regionName: '',
  249 + orderDate: '',
  250 + deliveryDate: '',
  251 + designatedConsignee: '',
  252 + specialTerms: '',
  253 + specialTermsName: '',
  254 + executionStandard: '',
  255 + executionStandardName: '',
  256 + executionStandardRemarks: '',
  257 + includesPackagingFee: false,
  258 + includesPackagingFeeName: '否',
  259 + includesTransportFee: false,
  260 + includesTransportFeeName: '否',
  261 + unit: '元、公斤、元/公斤',
  262 + totalAmountCapital: '',
  263 + depositInfo: '',
  264 + packagingRequirements: '',
  265 + paymentTerms: '',
  266 + transportMode: '',
  267 + destinationId: [],
  268 + destinationLabel: '',
  269 + specialInstructions: '',
  270 + remarks: '',
  271 + pieceWeightHead: '',
  272 + surface: '',
  273 + tolerance: '',
  274 + performance: '',
  275 + component: '',
  276 + packaging: ''
  277 + },
  278 + supplierList: [],
  279 + specialTermsList: [],
  280 + executionStandardList: [],
  281 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  282 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  283 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  284 + totalQuantity: 0,
  285 + totalAmountExcludingTax: 0,
  286 + totalAmountIncludingTax: 0,
  287 + productLineList: [],
  288 + newProductLineList: [],
  289 + productList: [],
  290 + regionOptions: [],
  291 + }
  292 + },
  293 + onLoad(query) {
  294 + this.id = (query && query.id) ? query.id : ''
  295 + // this.uploadType = (query && query.uploadType) ? query.uploadType : 'formal'
  296 + },
  297 + created() {
  298 + this.loadSuppliers()
  299 + this.loadExtraOptions()
  300 + this.loadDetail()
  301 + this.loadRegionOptions()
  302 + this.$nextTick(() => {
  303 + if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
  304 + this.initDestinationLabel()
  305 + }
  306 + })
  307 + },
  308 + methods: {
  309 + async loadRegionOptions() {
  310 + try {
  311 + const res = await getArea()
  312 + const list = res.data || []
  313 + this.regionOptions = (list || []).map(it => ({ label: it.name || '', value: it.id || '' }))
  314 + } catch (e) {
  315 + this.regionOptions = []
  316 + }
  317 + },
  318 + async loadDetail() {
  319 + if (!this.id) return
  320 + try {
  321 + const res = await getContractApi(this.id)
  322 + const data = res && res.data ? res.data : {}
  323 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  324 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  325 + const m = { ...data, includesPackagingFeeName, includesTransportFeeName }
  326 + this.form = {
  327 + ...this.form,
  328 + id: m.id || '',
  329 + code: m.code || '',
  330 + supplier: m.supplier || '',
  331 + supplierName: m.supplierName || '',
  332 + buyer: m.buyer || (m.customer && m.customer.id) || '',
  333 + buyerName: m.buyerName || (m.customer && m.customer.name) || '',
  334 + stockUpCompanyId: m.stockUpCompanyId || '',
  335 + stockUpCompanyName: m.stockUpCompanyName || '',
  336 + deptName: m.deptName || '',
  337 + deptId: m.deptId || '',
  338 + region: m.region || '',
  339 + regionName: m.regionName || '',
  340 + orderDate: m.orderDate || '',
  341 + designatedConsignee: m.designatedConsignee || '',
  342 + specialTerms: m.specialTerms || '',
  343 + specialTermsName: m.specialTermsName || '',
  344 + executionStandard: m.executionStandard || '',
  345 + executionStandardName: m.executionStandardName || '',
  346 + executionStandardRemarks: m.executionStandardRemarks || '',
  347 + includesPackagingFee: !!m.includesPackagingFee,
  348 + includesPackagingFeeName,
  349 + includesTransportFee: !!m.includesTransportFee,
  350 + includesTransportFeeName,
  351 + unit: m.unit || this.form.unit,
  352 + totalAmountCapital: m.totalAmountCapital || '',
  353 + depositInfo: m.depositInfo || '',
  354 + packagingRequirements: m.packagingRequirements || '',
  355 + paymentTerms: m.paymentTerms || '',
  356 + transportMode: m.transportMode || '',
  357 + destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
  358 + destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  359 + specialInstructions: m.specialInstructions || '',
  360 + remarks: m.remarks || '',
  361 + pieceWeightHead: m.pieceWeightHead || '',
  362 + surface: m.surface || '',
  363 + tolerance: m.tolerance || '',
  364 + performance: m.performance || '',
  365 + component: m.component || '',
  366 + packaging: m.packaging || '',
  367 + workshopId: m.workshopId || '',
  368 + workshopName: m.workshopName || '',
  369 + }
  370 + const fileId = this.uploadType === 'formal' ? m.formalFileId : m.standardFileId
  371 + const fileName = this.uploadType === 'formal' ? m.formalFileName : m.standardFileName
  372 + const standardized = this.uploadType === 'formal' ? m.formalStandardized : m.standardStandardized
  373 + this.fileInfo = { id: fileId || '', name: fileName || '' }
  374 + this.standardStandardized = (standardized === true || standardized === false) ? standardized : ''
  375 + this.standardStandardizedName = (this.standardStandardized === true) ? '是' : (this.standardStandardized === false) ? '否' : ''
  376 + const lines = Array.isArray(m.contractDistributorLineList) ? m.contractDistributorLineList : []
  377 + this.productLineList = lines
  378 + this.onProductsChange(lines)
  379 + } catch (e) { }
  380 + },
  381 + async initDestinationLabel() {
  382 + const comp = this.$refs.citySelectorRef
  383 + if (comp && typeof comp.getLabel === 'function') {
  384 + const label = await comp.getLabel()
  385 + this.form.destinationLabel = label || ''
  386 + }
  387 + },
  388 + openCitySelector() {
  389 + this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
  390 + },
  391 + onCityChange(payload) {
  392 + const label = payload && payload.label != null ? payload.label : ''
  393 + this.form.destinationLabel = label
  394 + },
  395 + onProductsChange(products) {
  396 + const list = Array.isArray(products) ? products : []
  397 + this.newProductLineList = list
  398 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  399 + const sumE = list.reduce((acc, it) => acc + (parseFloat(it.amountExcludingTax) || 0), 0)
  400 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  401 + this.totalQuantity = sumQ
  402 + this.totalAmountExcludingTax = sumE
  403 + this.totalAmountIncludingTax = sumT
  404 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  405 + },
  406 + async loadSuppliers() {
  407 + try {
  408 + const results = await getDicByCodes(['SUPPLIER'])
  409 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  410 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  411 + } catch (e) { this.supplierList = [] }
  412 + },
  413 + async loadExtraOptions() {
  414 + try {
  415 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  416 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  417 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  418 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  419 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  420 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  421 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  422 + } catch (e) {
  423 + this.specialTermsList = []
  424 + this.executionStandardList = []
  425 + this.productList = []
  426 + }
  427 + },
  428 + displayLabel(field) {
  429 + const m = this.form
  430 + const map = { supplierName: '请选择供方', buyerName: '请选择需方', workshopName: '请选择生产厂', regionName: '请选择区域' }
  431 + const val = m[field]
  432 + return val ? String(val) : map[field]
  433 + },
  434 + async openSheet(field) {
  435 + if (field === 'standardStandardized') {
  436 + const options = this.yesNoList
  437 + const current = this.standardStandardized
  438 + const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
  439 + this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, field, value: match ? match.value : '' }
  440 + return
  441 + }
  442 + const setSheet = (title, options) => {
  443 + const current = this.form[field]
  444 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  445 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  446 + }
  447 + if (field === 'workshopId') {
  448 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  449 + const _data = res.data || {}
  450 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  451 + const opts = (list || []).map(it => ({
  452 + label: it.name,
  453 + value: it.id
  454 + }))
  455 + setSheet('生产厂', opts)
  456 + } else if (field === 'supplier') {
  457 + setSheet('供方', this.supplierList)
  458 + } else if (field === 'specialTerms') {
  459 + setSheet('特别条款要求', this.specialTermsList)
  460 + } else if (field === 'executionStandard') {
  461 + setSheet('执行标准', this.executionStandardList)
  462 + } else if (field === 'includesPackagingFee') {
  463 + setSheet('单价中是否已包含包装费', this.yesNoList)
  464 + } else if (field === 'includesTransportFee') {
  465 + setSheet('单价中是否已包含运费', this.yesNoList)
  466 + } else if (field === 'region') {
  467 + setSheet('区域', this.regionOptions)
  468 + }
  469 + },
  470 + onSheetConfirm({ value, label }) {
  471 + const field = this.sheet.field
  472 + if (!field) return
  473 + const v = (value === undefined || value === null) ? '' : value
  474 + if (field === 'standardStandardized') {
  475 + this.standardStandardized = v
  476 + this.standardStandardizedName = label || ''
  477 + return
  478 + }
  479 + this.form[field] = v
  480 + this.form[field + 'Name'] = label || ''
  481 + },
  482 + openRelate(fieldKey) {
  483 + let config = {}
  484 + if (fieldKey === 'buyer') {
  485 + config = { title: '需方', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '名称', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  486 + } else if (fieldKey === 'stockUpCompanyId') {
  487 + config = { title: '备货单位/人(生产标准)', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  488 + }
  489 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  490 + this.sheet.visible = false
  491 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  492 + this.$nextTick(() => { this.relate.visible = true })
  493 + },
  494 + onRelateConfirm({ items }) {
  495 + const _fieldKey = this.relate.fieldKey
  496 + const first = (items && items.length > 0) ? items[0] : null
  497 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  498 + if (_fieldKey === 'stockUpCompanyId') {
  499 + this.form.stockUpCompanyName = (first && first.name) ? first.name : ''
  500 + } else {
  501 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  502 + }
  503 + },
  504 + validateRequired() {
  505 + const checks = [
  506 + { key: 'code', label: '编号' },
  507 + { key: 'supplier', label: '供方' },
  508 + { key: 'buyer', label: '需方' },
  509 + { key: 'orderDate', label: '订货日期' },
  510 + { key: 'unit', label: '单位' },
  511 + { key: 'workshopId', label: '生产厂' },
  512 + { key: 'specialTerms', label: '特别条款要求' },
  513 + ]
  514 + for (const it of checks) {
  515 + const val = this.form[it.key]
  516 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  517 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  518 + }
  519 + if (!this.$refs.productRel.validate()) return false
  520 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  521 + if (list.length === 0) {
  522 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  523 + }
  524 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  525 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  526 + for (const [idx, it] of list.entries()) {
  527 + if (
  528 + strEmpty(it.productName) ||
  529 + strEmpty(it.industry) ||
  530 + strEmpty(it.quality) ||
  531 + strEmpty(it.brand) ||
  532 + numEmpty(it.quantity) ||
  533 + strEmpty(it.deliveryDate)
  534 + ) {
  535 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  536 + }
  537 + }
  538 + return true
  539 + },
  540 + async onSubmit() {
  541 + if (!this.fileInfo.id) {
  542 + uni.showToast({ title: '请上传合同附件', icon: 'error' })
  543 + return
  544 + }
  545 + if (!this.standardStandardized && this.standardStandardized !== false) {
  546 + uni.showToast({ title: '请选择合同是否规范', icon: 'error' })
  547 + return
  548 + }
  549 + if (!this.validateRequired()) return
  550 + const confirmRes = await new Promise(resolve => {
  551 + uni.showModal({
  552 + title: '确认提交',
  553 + content: this.uploadType === 'formal' ? '确定提交正式合同吗?' : '确定提交标准合同吗?',
  554 + confirmText: '确定',
  555 + cancelText: '取消',
  556 + success: resolve
  557 + })
  558 + })
  559 + if (!(confirmRes && confirmRes.confirm)) return
  560 + const clean = (obj) => {
  561 + const out = {}
  562 + Object.keys(obj || {}).forEach(k => {
  563 + const v = obj[k]
  564 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  565 + const isUndef = v === undefined || v === null
  566 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  567 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  568 + })
  569 + return out
  570 + }
  571 + const lines = (this.newProductLineList || []).map(it => clean(it))
  572 + const { destinationLabel, destinationId, ...formForSubmit } = this.form
  573 + const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : ''
  574 + const fileIdKey = this.uploadType === 'formal' ? 'formalFileId' : 'standardFileId'
  575 + const fileNameKey = this.uploadType === 'formal' ? 'formalFileName' : 'standardFileName'
  576 + const standardizedKey = this.uploadType === 'formal' ? 'formalStandardized' : 'standardStandardized'
  577 + const payload = clean({
  578 + ...formForSubmit,
  579 + id: this.form.id,
  580 + destination,
  581 + type: 'DIST_STOCK_CONTRACT',
  582 + totalQuantity: this.totalQuantity,
  583 + totalAmountExcludingTax: this.totalAmountExcludingTax,
  584 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  585 + contractDistributorLineList: lines,
  586 + [fileIdKey]: this.fileInfo.id,
  587 + [fileNameKey]: this.fileInfo.name,
  588 + [standardizedKey]: this.standardStandardized,
  589 + })
  590 + const api = this.uploadType === 'formal' ? uploadFormalContract : uploadStandardContract
  591 + try {
  592 + await uploadFormalContract(payload)
  593 + uni.showToast({ title: '提交成功', icon: 'none' })
  594 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_stock/index' }) }, 400)
  595 + } catch (e) {
  596 + uni.showToast({ title: e.msg || '提交失败', icon: 'none' })
  597 + }
  598 + }
  599 + }
  600 +}
  601 +</script>
  602 +
  603 +<style lang="scss" scoped>
  604 +.total {
  605 + .total-text {
  606 + font-weight: 600;
  607 + font-size: 32rpx;
  608 + color: rgba(0, 0, 0, 0.9);
  609 + padding-bottom: 28rpx;
  610 + border-bottom: 2rpx solid #E7E7E7;
  611 + }
  612 +
  613 + .total-item {
  614 + display: flex;
  615 + align-items: center;
  616 + }
  617 +
  618 + .total-item-text {
  619 + font-weight: 400;
  620 + font-size: 28rpx;
  621 + color: rgba(0, 0, 0, 0.6);
  622 + line-height: 32rpx;
  623 + width: 240rpx;
  624 + padding: 12rpx 0;
  625 + }
  626 +
  627 + .total-item-price {
  628 + font-weight: 600;
  629 + font-size: 32rpx;
  630 + color: rgba(0, 0, 0, 0.9);
  631 + line-height: 32rpx;
  632 + }
  633 +
  634 + .text-red {
  635 + color: #D54941;
  636 + }
  637 +}
  638 +
  639 +.page {
  640 + display: flex;
  641 + flex-direction: column;
  642 + height: 100%;
  643 +}
  644 +
  645 +.scroll {
  646 + flex: 1;
  647 + padding: 12rpx 0 392rpx !important;
  648 +}
  649 +
  650 +.footer {
  651 + z-index: 2;
  652 + position: fixed;
  653 + left: 0;
  654 + right: 0;
  655 + bottom: 0;
  656 + padding: 32rpx;
  657 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  658 + background: #fff;
  659 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  660 +}
  661 +
  662 +.footer .btn {
  663 + height: 80rpx;
  664 + line-height: 80rpx;
  665 + border-radius: 12rpx;
  666 + font-size: 32rpx;
  667 +}
  668 +
  669 +.footer .submit {
  670 + background: $theme-primary;
  671 + color: #fff;
  672 +}
  673 +
  674 +.quality {
  675 + background-color: #fff;
  676 + display: flex;
  677 + align-items: center;
  678 + padding: 24rpx 32rpx;
  679 + border-bottom: 1rpx solid #f0f0f0;
  680 + margin-top: 20rpx;
  681 +
  682 + .title {
  683 + font-size: 32rpx;
  684 + color: rgba(0, 0, 0, 0.9);
  685 + font-weight: 600;
  686 + }
  687 +
  688 + .opCollapse {
  689 + color: rgba(0, 0, 0, 0.6);
  690 + width: 32rpx;
  691 + height: 28rpx;
  692 + margin-right: 16rpx;
  693 + }
  694 +}
  695 +
  696 +::v-deep .uni-list {
  697 + background: transparent;
  698 +}
  699 +
  700 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  701 + color: rgba(0, 0, 0, 0.9);
  702 +}
  703 +
  704 +::v-deep .uni-list .uni-input-placeholder {
  705 + z-index: 1;
  706 +}
  707 +
  708 +::v-deep .uni-list .uni-input-input {
  709 + background-color: #ffffff;
  710 +}
  711 +
  712 +::v-deep .uni-list-item__extra-text {
  713 + font-size: 32rpx;
  714 +}
  715 +
  716 +::v-deep .uni-list-item__content-title {
  717 + font-size: 32rpx;
  718 + color: rgba(0, 0, 0, 0.9);
  719 +}
  720 +
  721 +::v-deep .uni-list-item__container {
  722 + padding: 32rpx;
  723 +}
  724 +
  725 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  726 + font-size: 32rpx;
  727 + color: rgba(0, 0, 0, 0.4);
  728 +}
  729 +
  730 +::v-deep .uni-list-item__container .uni-easyinput__content {
  731 + border: none;
  732 + background-color: #ffffff !important;
  733 +}
  734 +
  735 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  736 + padding-left: 0 !important;
  737 + height: 48rpx;
  738 + line-height: 48rpx;
  739 + font-size: 32rpx;
  740 +}
  741 +
  742 +::v-deep .uni-list-item__container .item-title,
  743 +::v-deep .uni-list-item__container .uni-list-item__content {
  744 + flex: none;
  745 + min-height: 48rpx;
  746 + line-height: 48rpx;
  747 + font-size: 32rpx;
  748 + position: relative;
  749 + width: 210rpx;
  750 + margin-right: 32rpx;
  751 + color: rgba(0, 0, 0, 0.9);
  752 +}
  753 +
  754 +::v-deep .uni-list-item__container .item-title .required {
  755 + color: red;
  756 + position: absolute;
  757 + top: 50%;
  758 + transform: translateY(-50%);
  759 + left: -16rpx;
  760 +}
  761 +
  762 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  763 + color: rgba(0, 0, 0, 0.4) !important;
  764 +}
  765 +
  766 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  767 + color: rgba(0, 0, 0, 0.9) !important;
  768 +}
  769 +</style>
... ...
... ... @@ -372,6 +372,13 @@ export default {
372 372 uploadContract(id, type = 'formal') {
373 373 if (!id) return
374 374 this.uploadId = id
  375 + if (type === 'standard' && this.detail?.canEdit) {
  376 + const query = `?id=${encodeURIComponent(id)}&uploadType=${encodeURIComponent(type)}`
  377 + uni.navigateTo({
  378 + url: '/pages/contract_unplan/uploadStandard' + query
  379 + })
  380 + return
  381 + }
375 382 this.uploadType = type
376 383 this.$refs.uploadPopup.open()
377 384 },
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput v-model="form.code" :inputBorder="false" disabled />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.supplier ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openSheet('supplier')" :rightText="displayLabel('supplierName')" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>供方</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.buyer ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openRelate('buyer')" :rightText="form.buyerName || '请选择需方'" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>需方</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item class="select-item" :class="form.stockUpCompanyId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openRelate('stockUpCompanyId')" :rightText="form.stockUpCompanyName || '请选择备货单位'" showArrow>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>备货单位/人(生产标准)</text></view>
  29 + </template>
  30 + </uni-list-item>
  31 +
  32 + <uni-list-item class="select-item" :class="form.workshopId ? 'is-filled' : 'is-empty'" clickable
  33 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" showArrow>
  34 + <template v-slot:body>
  35 + <view class="item-title"><text class="required">*</text><text>生产厂</text></view>
  36 + </template>
  37 + </uni-list-item>
  38 +
  39 + <uni-list-item title="订货日期">
  40 + <template v-slot:footer>
  41 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  42 + </template>
  43 + </uni-list-item>
  44 +
  45 + <uni-list-item title="单位">
  46 + <template v-slot:footer>
  47 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  48 + </template>
  49 + </uni-list-item>
  50 + <uni-list-item title="办事处">
  51 + <template v-slot:footer>
  52 + <uni-easyinput v-model="form.deptName" :inputBorder="false" disabled placeholder="自动获取" />
  53 + </template>
  54 + </uni-list-item>
  55 + <uni-list-item class="select-item" :class="form.region ? 'is-filled' : 'is-empty'" clickable
  56 + @click="openSheet('region')" :rightText="displayLabel('regionName')" showArrow>
  57 + <template v-slot:body>
  58 + <view class="item-title"><text class="required">*</text><text>区域</text></view>
  59 + </template>
  60 + </uni-list-item>
  61 +
  62 + <ProductRel ref="productRel" mode="add" :deliveryDate="form.orderDate" :deliveryDateBase="form.deliveryDate"
  63 + :list="productLineList" @change="onProductsChange" :options="productList" />
  64 +
  65 + <uni-list-item title="合计人民币金额(大写)">
  66 + <template v-slot:footer>
  67 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false" disabled />
  68 + </template>
  69 + </uni-list-item>
  70 + <uni-list-item title="交付定金、数额、时间">
  71 + <template v-slot:footer>
  72 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  73 + </template>
  74 + </uni-list-item>
  75 + <uni-list-item title="包装要求">
  76 + <template v-slot:footer>
  77 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求" :inputBorder="false" />
  78 + </template>
  79 + </uni-list-item>
  80 + <uni-list-item title="付款方式、付款期限">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  83 + </template>
  84 + </uni-list-item>
  85 + <uni-list-item title="运输方式">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  88 + </template>
  89 + </uni-list-item>
  90 + <uni-list-item class="select-item"
  91 + :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
  92 + @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
  93 + <template v-slot:body>
  94 + <view class="item-title"><text>目的地</text></view>
  95 + <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  96 + </template>
  97 + </uni-list-item>
  98 +
  99 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
  100 + @click="openSheet('includesPackagingFee')" :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  101 + <template v-slot:body>
  102 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  103 + </template>
  104 + </uni-list-item>
  105 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'" clickable
  106 + @click="openSheet('includesTransportFee')" :rightText="form.includesTransportFeeName || '请选择'" showArrow>
  107 + <template v-slot:body>
  108 + <view class="item-title"><text>单价中是否已包含运费</text></view>
  109 + </template>
  110 + </uni-list-item>
  111 + <uni-list-item title="需方指定收货人">
  112 + <template v-slot:footer>
  113 + <uni-easyinput v-model="form.designatedConsignee" placeholder="请输入需方指定收货人" :inputBorder="false" />
  114 + </template>
  115 + </uni-list-item>
  116 +
  117 + <uni-list-item class="select-item" :class="form.specialTermsName ? 'is-filled' : 'is-empty'" clickable
  118 + @click="openSheet('specialTerms')" :rightText="form.specialTermsName || '请选择'" showArrow>
  119 + <template v-slot:body>
  120 + <view class="item-title"><text class="required">*</text><text>特别条款要求</text></view>
  121 + </template>
  122 + </uni-list-item>
  123 + <uni-list-item class="select-item" :class="form.executionStandardName ? 'is-filled' : 'is-empty'" clickable
  124 + @click="openSheet('executionStandard')" :rightText="form.executionStandardName || '请选择'" showArrow>
  125 + <template v-slot:body>
  126 + <view class="item-title"><text>执行标准</text></view>
  127 + </template>
  128 + </uni-list-item>
  129 + <uni-list-item v-if="form.executionStandard === 'OTHER'" title="其他">
  130 + <template v-slot:footer>
  131 + <uni-easyinput v-model="form.executionStandardRemarks" placeholder="请输入其他标准备注" :inputBorder="false" />
  132 + </template>
  133 + </uni-list-item>
  134 + <uni-list-item title="特别说明" style="margin-top: 20rpx;">
  135 + <template v-slot:footer>
  136 + <uni-easyinput v-model="form.specialInstructions" placeholder="请输入特别说明" :inputBorder="false" />
  137 + </template>
  138 + </uni-list-item>
  139 + <uni-list-item title="备注">
  140 + <template v-slot:footer>
  141 + <uni-easyinput v-model="form.remarks" placeholder="请输入备注" :inputBorder="false" maxlength="2000" />
  142 + </template>
  143 + </uni-list-item>
  144 +
  145 + <view class="quality">
  146 + <image class="opCollapse" src="/static/images/title.png" />
  147 + <text class="title">具体质量要求</text>
  148 + </view>
  149 + <uni-list-item title="件重条头">
  150 + <template v-slot:footer>
  151 + <uni-easyinput v-model="form.pieceWeightHead" placeholder="请输入" :inputBorder="false" />
  152 + </template>
  153 + </uni-list-item>
  154 + <uni-list-item title="表面">
  155 + <template v-slot:footer>
  156 + <uni-easyinput v-model="form.surface" placeholder="请输入" :inputBorder="false" />
  157 + </template>
  158 + </uni-list-item>
  159 + <uni-list-item title="公差">
  160 + <template v-slot:footer>
  161 + <uni-easyinput v-model="form.tolerance" placeholder="请输入" :inputBorder="false" />
  162 + </template>
  163 + </uni-list-item>
  164 + <uni-list-item title="性能">
  165 + <template v-slot:footer>
  166 + <uni-easyinput v-model="form.performance" placeholder="请输入" :inputBorder="false" />
  167 + </template>
  168 + </uni-list-item>
  169 + <uni-list-item title="成分">
  170 + <template v-slot:footer>
  171 + <uni-easyinput v-model="form.component" placeholder="请输入" :inputBorder="false" />
  172 + </template>
  173 + </uni-list-item>
  174 + <uni-list-item title="包装">
  175 + <template v-slot:footer>
  176 + <uni-easyinput v-model="form.packaging" placeholder="请输入" :inputBorder="false" />
  177 + </template>
  178 + </uni-list-item>
  179 +
  180 + <uni-list-item :title="uploadType === 'formal' ? '正式合同附件' : '标准合同附件'" style="margin-top: 20rpx;">
  181 + <template v-slot:footer>
  182 + <FileUpload v-model="fileInfo" />
  183 + </template>
  184 + </uni-list-item>
  185 + <uni-list-item class="select-item" :class="standardStandardizedName ? 'is-filled' : 'is-empty'" clickable
  186 + @click="openSheet('standardStandardized')" :rightText="standardStandardizedName || '请选择'" showArrow>
  187 + <template v-slot:body>
  188 + <view class="item-title"><text class="required">*</text><text>合同是否规范</text></view>
  189 + </template>
  190 + </uni-list-item>
  191 +
  192 + <view class="footer">
  193 + <div class="total">
  194 + <div class="total-text">合计</div>
  195 + <div class="total-item" style="padding: 20rpx 0;">
  196 + <div class="total-item-text">数量</div>
  197 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  198 + </div>
  199 + </div>
  200 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  201 + </view>
  202 + </uni-list>
  203 + </scroll-view>
  204 +
  205 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  206 + @confirm="onSheetConfirm" />
  207 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  208 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  209 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  210 + </view>
  211 +</template>
  212 +
  213 +<script>
  214 +import SingleSelectSheet from '@/components/single-select/index.vue'
  215 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  216 +import ProductRel from './productRel.vue'
  217 +import CitySelector from '@/components/city-selector/index.vue'
  218 +import FileUpload from '@/components/file-upload/index.vue'
  219 +import { getContractApi, uploadFormalContract, uploadStandardContract } from '@/api/contract'
  220 +import { getDicByCodes } from '@/utils/dic'
  221 +import { formatCurrencyToChinese } from '@/utils/common'
  222 +import { workshopQueryApi } from '@/api/devManage'
  223 +import { getArea } from '@/api/credit_manage.js'
  224 +
  225 +export default {
  226 + name: 'UploadContractUnplan',
  227 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  228 + data() {
  229 + return {
  230 + id: '',
  231 + uploadType: 'formal',
  232 + fileInfo: { id: '', name: '' },
  233 + standardStandardized: '',
  234 + standardStandardizedName: '',
  235 + form: {
  236 + id: '',
  237 + code: '',
  238 + supplier: '',
  239 + supplierName: '',
  240 + buyer: '',
  241 + buyerName: '',
  242 + stockUpCompanyId: '',
  243 + stockUpCompanyName: '',
  244 + workshopId: '',
  245 + workshopName: '',
  246 + deptName: '',
  247 + deptId: '',
  248 + region: '',
  249 + regionName: '',
  250 + orderDate: '',
  251 + deliveryDate: '',
  252 + designatedConsignee: '',
  253 + specialTerms: '',
  254 + specialTermsName: '',
  255 + executionStandard: '',
  256 + executionStandardName: '',
  257 + executionStandardRemarks: '',
  258 + includesPackagingFee: false,
  259 + includesPackagingFeeName: '否',
  260 + includesTransportFee: false,
  261 + includesTransportFeeName: '否',
  262 + unit: '元、公斤、元/公斤',
  263 + totalAmountCapital: '',
  264 + depositInfo: '',
  265 + packagingRequirements: '',
  266 + paymentTerms: '',
  267 + transportMode: '',
  268 + destinationId: [],
  269 + destinationLabel: '',
  270 + specialInstructions: '',
  271 + remarks: '',
  272 + pieceWeightHead: '',
  273 + surface: '',
  274 + tolerance: '',
  275 + performance: '',
  276 + component: '',
  277 + packaging: ''
  278 + },
  279 + supplierList: [],
  280 + specialTermsList: [],
  281 + executionStandardList: [],
  282 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  283 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  284 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  285 + totalQuantity: 0,
  286 + totalAmountExcludingTax: 0,
  287 + totalAmountIncludingTax: 0,
  288 + productLineList: [],
  289 + newProductLineList: [],
  290 + productList: [],
  291 + regionOptions: [],
  292 + }
  293 + },
  294 + onLoad(query) {
  295 + this.id = (query && query.id) ? query.id : ''
  296 + this.uploadType = (query && query.uploadType) ? query.uploadType : 'formal'
  297 + },
  298 + created() {
  299 + this.loadSuppliers()
  300 + this.loadExtraOptions()
  301 + this.loadDetail()
  302 + this.loadRegionOptions()
  303 + this.$nextTick(() => {
  304 + if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
  305 + this.initDestinationLabel()
  306 + }
  307 + })
  308 + },
  309 + methods: {
  310 + async loadRegionOptions() {
  311 + try {
  312 + const res = await getArea()
  313 + const list = res.data || []
  314 + this.regionOptions = (list || []).map(it => ({ label: it.name || '', value: it.id || '' }))
  315 + } catch (e) {
  316 + this.regionOptions = []
  317 + }
  318 + },
  319 + async loadDetail() {
  320 + if (!this.id) return
  321 + try {
  322 + const res = await getContractApi(this.id)
  323 + const data = res && res.data ? res.data : {}
  324 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  325 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  326 + const m = { ...data, includesPackagingFeeName, includesTransportFeeName }
  327 + this.form = {
  328 + ...this.form,
  329 + id: m.id || '',
  330 + code: m.code || '',
  331 + supplier: m.supplier || '',
  332 + supplierName: m.supplierName || '',
  333 + buyer: m.buyer || (m.customer && m.customer.id) || '',
  334 + buyerName: m.buyerName || (m.customer && m.customer.name) || '',
  335 + stockUpCompanyId: m.stockUpCompanyId || '',
  336 + stockUpCompanyName: m.stockUpCompanyName || '',
  337 + deptName: m.deptName || '',
  338 + deptId: m.deptId || '',
  339 + region: m.region || '',
  340 + regionName: m.regionName || '',
  341 + orderDate: m.orderDate || '',
  342 + designatedConsignee: m.designatedConsignee || '',
  343 + specialTerms: m.specialTerms || '',
  344 + specialTermsName: m.specialTermsName || '',
  345 + executionStandard: m.executionStandard || '',
  346 + executionStandardName: m.executionStandardName || '',
  347 + executionStandardRemarks: m.executionStandardRemarks || '',
  348 + includesPackagingFee: !!m.includesPackagingFee,
  349 + includesPackagingFeeName,
  350 + includesTransportFee: !!m.includesTransportFee,
  351 + includesTransportFeeName,
  352 + unit: m.unit || this.form.unit,
  353 + totalAmountCapital: m.totalAmountCapital || '',
  354 + depositInfo: m.depositInfo || '',
  355 + packagingRequirements: m.packagingRequirements || '',
  356 + paymentTerms: m.paymentTerms || '',
  357 + transportMode: m.transportMode || '',
  358 + destinationId: (m.provinceId && m.cityId && m.districtId) ? [m.provinceId, m.cityId, m.districtId] : (Array.isArray(m.destinationId) ? m.destinationId : []),
  359 + destinationLabel: (m.provinceName && m.cityName && m.districtName) ? `${m.provinceName} / ${m.cityName} / ${m.districtName}` : (m.destinationLabel || ''),
  360 + specialInstructions: m.specialInstructions || '',
  361 + remarks: m.remarks || '',
  362 + pieceWeightHead: m.pieceWeightHead || '',
  363 + surface: m.surface || '',
  364 + tolerance: m.tolerance || '',
  365 + performance: m.performance || '',
  366 + component: m.component || '',
  367 + packaging: m.packaging || '',
  368 + workshopId: m.workshopId || '',
  369 + workshopName: m.workshopName || '',
  370 + }
  371 + const fileId = this.uploadType === 'formal' ? m.formalFileId : m.standardFileId
  372 + const fileName = this.uploadType === 'formal' ? m.formalFileName : m.standardFileName
  373 + const standardized = this.uploadType === 'formal' ? m.formalStandardized : m.standardStandardized
  374 + this.fileInfo = { id: fileId || '', name: fileName || '' }
  375 + this.standardStandardized = (standardized === true || standardized === false) ? standardized : ''
  376 + this.standardStandardizedName = (this.standardStandardized === true) ? '是' : (this.standardStandardized === false) ? '否' : ''
  377 + const lines = Array.isArray(m.contractDistributorLineList) ? m.contractDistributorLineList : []
  378 + this.productLineList = lines
  379 + this.onProductsChange(lines)
  380 + } catch (e) { }
  381 + },
  382 + async initDestinationLabel() {
  383 + const comp = this.$refs.citySelectorRef
  384 + if (comp && typeof comp.getLabel === 'function') {
  385 + const label = await comp.getLabel()
  386 + this.form.destinationLabel = label || ''
  387 + }
  388 + },
  389 + openCitySelector() {
  390 + this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
  391 + },
  392 + onCityChange(payload) {
  393 + const label = payload && payload.label != null ? payload.label : ''
  394 + this.form.destinationLabel = label
  395 + },
  396 + onProductsChange(products) {
  397 + const list = Array.isArray(products) ? products : []
  398 + this.newProductLineList = list
  399 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  400 + const sumE = list.reduce((acc, it) => acc + (parseFloat(it.amountExcludingTax) || 0), 0)
  401 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  402 + this.totalQuantity = sumQ
  403 + this.totalAmountExcludingTax = sumE
  404 + this.totalAmountIncludingTax = sumT
  405 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  406 + },
  407 + async loadSuppliers() {
  408 + try {
  409 + const results = await getDicByCodes(['SUPPLIER'])
  410 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  411 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  412 + } catch (e) { this.supplierList = [] }
  413 + },
  414 + async loadExtraOptions() {
  415 + try {
  416 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  417 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  418 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  419 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  420 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  421 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  422 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  423 + } catch (e) {
  424 + this.specialTermsList = []
  425 + this.executionStandardList = []
  426 + this.productList = []
  427 + }
  428 + },
  429 + displayLabel(field) {
  430 + const m = this.form
  431 + const map = { supplierName: '请选择供方', buyerName: '请选择需方', workshopName: '请选择生产厂', regionName: '请选择区域' }
  432 + const val = m[field]
  433 + return val ? String(val) : map[field]
  434 + },
  435 + async openSheet(field) {
  436 + if (field === 'standardStandardized') {
  437 + const options = this.yesNoList
  438 + const current = this.standardStandardized
  439 + const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
  440 + this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, field, value: match ? match.value : '' }
  441 + return
  442 + }
  443 + const setSheet = (title, options) => {
  444 + const current = this.form[field]
  445 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  446 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  447 + }
  448 + if (field === 'workshopId') {
  449 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  450 + const _data = res.data || {}
  451 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  452 + const opts = (list || []).map(it => ({ label: it.name, value: it.id }))
  453 + setSheet('生产厂', opts)
  454 + } else if (field === 'supplier') {
  455 + setSheet('供方', this.supplierList)
  456 + } else if (field === 'specialTerms') {
  457 + setSheet('特别条款要求', this.specialTermsList)
  458 + } else if (field === 'executionStandard') {
  459 + setSheet('执行标准', this.executionStandardList)
  460 + } else if (field === 'includesPackagingFee') {
  461 + setSheet('单价中是否已包含包装费', this.yesNoList)
  462 + } else if (field === 'includesTransportFee') {
  463 + setSheet('单价中是否已包含运费', this.yesNoList)
  464 + } else if (field === 'region') {
  465 + setSheet('区域', this.regionOptions)
  466 + }
  467 + },
  468 + onSheetConfirm({ value, label }) {
  469 + const field = this.sheet.field
  470 + if (!field) return
  471 + const v = (value === undefined || value === null) ? '' : value
  472 + if (field === 'standardStandardized') {
  473 + this.standardStandardized = v
  474 + this.standardStandardizedName = label || ''
  475 + return
  476 + }
  477 + this.form[field] = v
  478 + this.form[field + 'Name'] = label || ''
  479 + },
  480 + openRelate(fieldKey) {
  481 + let config = {}
  482 + if (fieldKey === 'buyer') {
  483 + config = { title: '需方', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '名称', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  484 + } else if (fieldKey === 'stockUpCompanyId') {
  485 + config = { title: '备货单位/人(生产标准)', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  486 + }
  487 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  488 + this.sheet.visible = false
  489 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  490 + this.$nextTick(() => { this.relate.visible = true })
  491 + },
  492 + onRelateConfirm({ items }) {
  493 + const _fieldKey = this.relate.fieldKey
  494 + const first = (items && items.length > 0) ? items[0] : null
  495 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  496 + if (_fieldKey === 'stockUpCompanyId') {
  497 + this.form.stockUpCompanyName = (first && first.name) ? first.name : ''
  498 + } else {
  499 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  500 + }
  501 + },
  502 + validateRequired() {
  503 + const checks = [
  504 + { key: 'code', label: '编号' },
  505 + { key: 'supplier', label: '供方' },
  506 + { key: 'buyer', label: '需方' },
  507 + { key: 'orderDate', label: '订货日期' },
  508 + { key: 'unit', label: '单位' },
  509 + { key: 'workshopId', label: '生产厂' },
  510 + { key: 'specialTerms', label: '特别条款要求' },
  511 + ]
  512 + for (const it of checks) {
  513 + const val = this.form[it.key]
  514 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  515 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  516 + }
  517 + if (this.$refs.productRel && !this.$refs.productRel.validate()) return false
  518 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  519 + if (list.length === 0) {
  520 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  521 + }
  522 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  523 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  524 + for (const [idx, it] of list.entries()) {
  525 + if (
  526 + strEmpty(it.productName) ||
  527 + strEmpty(it.industry) ||
  528 + strEmpty(it.quality) ||
  529 + strEmpty(it.brand) ||
  530 + numEmpty(it.quantity) ||
  531 + strEmpty(it.unitPrice) ||
  532 + strEmpty(it.deliveryDate)
  533 + ) {
  534 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  535 + }
  536 + }
  537 + return true
  538 + },
  539 + async onSubmit() {
  540 + if (!this.fileInfo.id) {
  541 + uni.showToast({ title: '请上传合同附件', icon: 'error' })
  542 + return
  543 + }
  544 + if (!this.standardStandardized && this.standardStandardized !== false) {
  545 + uni.showToast({ title: '请选择合同是否规范', icon: 'error' })
  546 + return
  547 + }
  548 + if (!this.validateRequired()) return
  549 + const confirmRes = await new Promise(resolve => {
  550 + uni.showModal({
  551 + title: '确认提交',
  552 + content: this.uploadType === 'formal' ? '确定提交正式合同吗?' : '确定提交标准合同吗?',
  553 + confirmText: '确定',
  554 + cancelText: '取消',
  555 + success: resolve
  556 + })
  557 + })
  558 + if (!(confirmRes && confirmRes.confirm)) return
  559 + const clean = (obj) => {
  560 + const out = {}
  561 + Object.keys(obj || {}).forEach(k => {
  562 + const v = obj[k]
  563 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  564 + const isUndef = v === undefined || v === null
  565 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  566 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  567 + })
  568 + return out
  569 + }
  570 + const lines = (this.newProductLineList || []).map(it => clean(it))
  571 + const { destinationLabel, destinationId, ...formForSubmit } = this.form
  572 + const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : ''
  573 + const fileIdKey = this.uploadType === 'formal' ? 'formalFileId' : 'standardFileId'
  574 + const fileNameKey = this.uploadType === 'formal' ? 'formalFileName' : 'standardFileName'
  575 + const standardizedKey = this.uploadType === 'formal' ? 'formalStandardized' : 'standardStandardized'
  576 + const payload = clean({
  577 + ...formForSubmit,
  578 + id: this.form.id,
  579 + destination,
  580 + type: 'DRAFT_DIST_AGMT',
  581 + totalQuantity: this.totalQuantity,
  582 + totalAmountExcludingTax: this.totalAmountExcludingTax,
  583 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  584 + contractDistributorLineList: lines,
  585 + [fileIdKey]: this.fileInfo.id,
  586 + [fileNameKey]: this.fileInfo.name,
  587 + [standardizedKey]: this.standardStandardized,
  588 + })
  589 + const api = this.uploadType === 'formal' ? uploadFormalContract : uploadStandardContract
  590 + try {
  591 + await api(payload)
  592 + uni.showToast({ title: '提交成功', icon: 'none' })
  593 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_unplan/index' }) }, 400)
  594 + } catch (e) {
  595 + uni.showToast({ title: e.msg || '提交失败', icon: 'none' })
  596 + }
  597 + }
  598 + }
  599 +}
  600 +</script>
  601 +
  602 +<style lang="scss" scoped>
  603 +.total {
  604 + .total-text {
  605 + font-weight: 600;
  606 + font-size: 32rpx;
  607 + color: rgba(0, 0, 0, 0.9);
  608 + padding-bottom: 28rpx;
  609 + border-bottom: 2rpx solid #E7E7E7;
  610 + }
  611 +
  612 + .total-item {
  613 + display: flex;
  614 + align-items: center;
  615 + }
  616 +
  617 + .total-item-text {
  618 + font-weight: 400;
  619 + font-size: 28rpx;
  620 + color: rgba(0, 0, 0, 0.6);
  621 + line-height: 32rpx;
  622 + width: 240rpx;
  623 + padding: 12rpx 0;
  624 + }
  625 +
  626 + .total-item-price {
  627 + font-weight: 600;
  628 + font-size: 32rpx;
  629 + color: rgba(0, 0, 0, 0.9);
  630 + line-height: 32rpx;
  631 + }
  632 +
  633 + .text-red {
  634 + color: #D54941;
  635 + }
  636 +}
  637 +
  638 +.page {
  639 + display: flex;
  640 + flex-direction: column;
  641 + height: 100%;
  642 +}
  643 +
  644 +.scroll {
  645 + flex: 1;
  646 + padding: 12rpx 0 392rpx !important;
  647 +}
  648 +
  649 +.footer {
  650 + z-index: 2;
  651 + position: fixed;
  652 + left: 0;
  653 + right: 0;
  654 + bottom: 0;
  655 + padding: 32rpx;
  656 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  657 + background: #fff;
  658 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  659 +}
  660 +
  661 +.footer .btn {
  662 + height: 80rpx;
  663 + line-height: 80rpx;
  664 + border-radius: 12rpx;
  665 + font-size: 32rpx;
  666 +}
  667 +
  668 +.footer .submit {
  669 + background: $theme-primary;
  670 + color: #fff;
  671 +}
  672 +
  673 +.quality {
  674 + background-color: #fff;
  675 + display: flex;
  676 + align-items: center;
  677 + padding: 24rpx 32rpx;
  678 + border-bottom: 1rpx solid #f0f0f0;
  679 + margin-top: 20rpx;
  680 +
  681 + .title {
  682 + font-size: 32rpx;
  683 + color: rgba(0, 0, 0, 0.9);
  684 + font-weight: 600;
  685 + }
  686 +
  687 + .opCollapse {
  688 + color: rgba(0, 0, 0, 0.6);
  689 + width: 32rpx;
  690 + height: 28rpx;
  691 + margin-right: 16rpx;
  692 + }
  693 +}
  694 +
  695 +::v-deep .uni-list {
  696 + background: transparent;
  697 +}
  698 +
  699 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  700 + color: rgba(0, 0, 0, 0.9);
  701 +}
  702 +
  703 +::v-deep .uni-list .uni-input-placeholder {
  704 + z-index: 1;
  705 +}
  706 +
  707 +::v-deep .uni-list .uni-input-input {
  708 + background-color: #ffffff;
  709 +}
  710 +
  711 +::v-deep .uni-list-item__extra-text {
  712 + font-size: 32rpx;
  713 +}
  714 +
  715 +::v-deep .uni-list-item__content-title {
  716 + font-size: 32rpx;
  717 + color: rgba(0, 0, 0, 0.9);
  718 +}
  719 +
  720 +::v-deep .uni-list-item__container {
  721 + padding: 32rpx;
  722 +}
  723 +
  724 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  725 + font-size: 32rpx;
  726 + color: rgba(0, 0, 0, 0.4);
  727 +}
  728 +
  729 +::v-deep .uni-list-item__container .uni-easyinput__content {
  730 + border: none;
  731 + background-color: #ffffff !important;
  732 +}
  733 +
  734 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  735 + padding-left: 0 !important;
  736 + height: 48rpx;
  737 + line-height: 48rpx;
  738 + font-size: 32rpx;
  739 +}
  740 +
  741 +::v-deep .uni-list-item__container .item-title,
  742 +::v-deep .uni-list-item__container .uni-list-item__content {
  743 + flex: none;
  744 + min-height: 48rpx;
  745 + line-height: 48rpx;
  746 + font-size: 32rpx;
  747 + position: relative;
  748 + width: 210rpx;
  749 + margin-right: 32rpx;
  750 + color: rgba(0, 0, 0, 0.9);
  751 +}
  752 +
  753 +::v-deep .uni-list-item__container .item-title .required {
  754 + color: red;
  755 + position: absolute;
  756 + top: 50%;
  757 + transform: translateY(-50%);
  758 + left: -16rpx;
  759 +}
  760 +
  761 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  762 + color: rgba(0, 0, 0, 0.4) !important;
  763 +}
  764 +
  765 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  766 + color: rgba(0, 0, 0, 0.9) !important;
  767 +}
  768 +</style>
... ...