Commit f59f3e8820aacf496fcbf7e8ca0cfa6d6b547c6c

Authored by gesilong
1 parent fa0eccb5

commit:标准合同上传附件可编辑信息

... ... @@ -372,6 +372,14 @@
372 372 }
373 373 },
374 374 {
  375 + "path": "pages/contract_retail/uploadStandard",
  376 + "style": {
  377 + "navigationBarTitleText": "上传合同附件",
  378 + "navigationBarBackgroundColor": "#ffffff",
  379 + "navigationBarTextStyle": "black"
  380 + }
  381 + },
  382 + {
375 383 "path": "pages/contract_stock/index",
376 384 "style": {
377 385 "navigationBarTitleText": "经销库存合同",
... ... @@ -492,6 +500,14 @@
492 500 }
493 501 },
494 502 {
  503 + "path": "pages/contract_process/uploadStandard",
  504 + "style": {
  505 + "navigationBarTitleText": "上传合同附件",
  506 + "navigationBarBackgroundColor": "#ffffff",
  507 + "navigationBarTextStyle": "black"
  508 + }
  509 + },
  510 + {
495 511 "path": "pages/contract_foreign_std/index",
496 512 "style": {
497 513 "navigationBarTitleText": "外贸标准合同",
... ... @@ -524,6 +540,14 @@
524 540 }
525 541 },
526 542 {
  543 + "path": "pages/contract_foreign_std/uploadStandard",
  544 + "style": {
  545 + "navigationBarTitleText": "上传合同附件",
  546 + "navigationBarBackgroundColor": "#ffffff",
  547 + "navigationBarTextStyle": "black"
  548 + }
  549 + },
  550 + {
527 551 "path": "pages/contract_foreign_stock/index",
528 552 "style": {
529 553 "navigationBarTitleText": "外贸库存合同",
... ...
... ... @@ -303,6 +303,18 @@ export default {
303 303 uploadContract(id, type = 'standard') {
304 304 if (!id) return
305 305 this.uploadId = id
  306 + if (type === 'standard' && this.detail?.canEdit) {
  307 + const id = this.detail.id || this.detail.code || ''
  308 + if (!id) {
  309 + uni.showToast({ title: '缺少合同ID', icon: 'none' })
  310 + return
  311 + }
  312 + const query = id ? ('?id=' + encodeURIComponent(id)) : ''
  313 + uni.navigateTo({
  314 + url: '/pages/contract_foreign_std/uploadStandard' + query
  315 + })
  316 + return
  317 + }
306 318 this.uploadType = type
307 319 this.$refs.uploadPopup.open()
308 320 },
... ...
  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 + <uni-list-item class="select-item" :class="form.stockUpCompanyId ? 'is-filled' : 'is-empty'" clickable
  25 + @click="openRelate('stockUpCompanyId')" :rightText="form.stockUpCompanyName || '请选择备货单位'" showArrow>
  26 + <template v-slot:body>
  27 + <view class="item-title"><text class="required">*</text><text>备货单位/人(生产标准)</text></view>
  28 + </template>
  29 + </uni-list-item>
  30 +
  31 + <uni-list-item class="select-item" :class="form.workshopId ? 'is-filled' : 'is-empty'" clickable
  32 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" showArrow>
  33 + <template v-slot:body>
  34 + <view class="item-title"><text class="required">*</text><text>生产厂</text></view>
  35 + </template>
  36 + </uni-list-item>
  37 + <uni-list-item class="select-item" :class="form.deptName ? 'is-filled' : 'is-empty'">
  38 + <template v-slot:body>
  39 + <view class="item-title"><text class="required">*</text><text>办事处</text></view>
  40 + </template>
  41 + <template v-slot:footer>
  42 + <view class="serial-number-row">
  43 + <uni-easyinput v-model="form.deptName" :inputBorder="false" disabled />
  44 + </view>
  45 + </template>
  46 + </uni-list-item>
  47 + <uni-list-item class="select-item" :class="form.region ? 'is-filled' : 'is-empty'" clickable
  48 + @click="openSheet('region')" :rightText="displayLabel('regionName')" showArrow>
  49 + <template v-slot:body>
  50 + <view class="item-title"><text class="required">*</text><text>区域</text></view>
  51 + </template>
  52 + </uni-list-item>
  53 +
  54 + <uni-list-item title="订货日期">
  55 + <template v-slot:footer>
  56 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  57 + </template>
  58 + </uni-list-item>
  59 +
  60 + <uni-list-item title="单位">
  61 + <template v-slot:footer>
  62 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  63 + </template>
  64 + </uni-list-item>
  65 + <ProductRel ref="productRel" mode="add" :deliveryDateBase="form.deliveryDate" :deliveryDate="form.orderDate"
  66 + :list="productLineList" @change="onProductsChange" :options="productList" />
  67 + <uni-list-item title="合计人民币金额(大写)">
  68 + <template v-slot:footer>
  69 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false" disabled />
  70 + </template>
  71 + </uni-list-item>
  72 + <uni-list-item title="交付定金、数额、时间">
  73 + <template v-slot:footer>
  74 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  75 + </template>
  76 + </uni-list-item>
  77 + <uni-list-item title="包装要求">
  78 + <template v-slot:footer>
  79 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求" :inputBorder="false" />
  80 + </template>
  81 + </uni-list-item>
  82 + <uni-list-item title="付款方式、付款期限">
  83 + <template v-slot:footer>
  84 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  85 + </template>
  86 + </uni-list-item>
  87 + <uni-list-item title="运输方式">
  88 + <template v-slot:footer>
  89 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  90 + </template>
  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" />
  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">
  197 + <div class="total-item-text">数量</div>
  198 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  199 + </div>
  200 + <div class="total-item">
  201 + <div class="total-item-text">总金额</div>
  202 + <div class="total-item-price text-red">¥{{ (totalAmountIncludingTax || 0).toFixed(2) }}</div>
  203 + </div>
  204 + </div>
  205 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  206 + </view>
  207 + </uni-list>
  208 + </scroll-view>
  209 +
  210 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  211 + @confirm="onSheetConfirm" />
  212 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  213 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  214 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  215 + </view>
  216 +</template>
  217 +
  218 +<script>
  219 +import SingleSelectSheet from '@/components/single-select/index.vue'
  220 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  221 +import ProductRel from './productRel.vue'
  222 +import CitySelector from '@/components/city-selector/index.vue'
  223 +import FileUpload from '@/components/file-upload/index.vue'
  224 +import { getContractApi, uploadStandardContract } from '@/api/contract'
  225 +import { getDicByCodes } from '@/utils/dic'
  226 +import { formatCurrencyToChinese } from '@/utils/common'
  227 +import { workshopQueryApi } from '@/api/devManage'
  228 +import { getArea } from '@/api/credit_manage.js'
  229 +
  230 +export default {
  231 + name: 'UploadStandardContractForeignStd',
  232 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  233 + data() {
  234 + return {
  235 + id: '',
  236 + fileInfo: { id: '', name: '' },
  237 + standardStandardized: '',
  238 + standardStandardizedName: '',
  239 + form: {
  240 + id: '',
  241 + code: '',
  242 + supplier: '',
  243 + supplierName: '',
  244 + buyer: '',
  245 + buyerName: '',
  246 + stockUpCompanyId: '',
  247 + stockUpCompanyName: '',
  248 + workshopId: '',
  249 + workshopName: '',
  250 + region: '',
  251 + regionName: '',
  252 + deptName: '',
  253 + deptId: '',
  254 + orderDate: '',
  255 + deliveryDate: '',
  256 + designatedConsignee: '',
  257 + specialTerms: '',
  258 + specialTermsName: '',
  259 + executionStandard: '',
  260 + executionStandardName: '',
  261 + executionStandardRemarks: '',
  262 + includesPackagingFee: false,
  263 + includesPackagingFeeName: '否',
  264 + includesTransportFee: false,
  265 + includesTransportFeeName: '否',
  266 + unit: '美元、公斤、美元/公斤',
  267 + totalAmountCapital: '',
  268 + depositInfo: '',
  269 + packagingRequirements: '',
  270 + paymentTerms: '',
  271 + transportMode: '',
  272 + destinationId: [],
  273 + destinationLabel: '',
  274 + specialInstructions: '',
  275 + remarks: '',
  276 + pieceWeightHead: '',
  277 + surface: '',
  278 + tolerance: '',
  279 + performance: '',
  280 + component: '',
  281 + packaging: ''
  282 + },
  283 + supplierList: [],
  284 + specialTermsList: [],
  285 + executionStandardList: [],
  286 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  287 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  288 + relate: {
  289 + visible: false,
  290 + title: '选择',
  291 + source: '',
  292 + display: [],
  293 + multiple: false,
  294 + rowKey: 'id',
  295 + selectedKeys: [],
  296 + fieldKey: ''
  297 + },
  298 + totalQuantity: 0,
  299 + totalAmountIncludingTax: 0,
  300 + productLineList: [],
  301 + newProductLineList: [],
  302 + productList: [],
  303 + regionOptions: []
  304 + }
  305 + },
  306 + onLoad(query) {
  307 + this.id = (query && query.id) ? query.id : ''
  308 + },
  309 + created() {
  310 + this.loadSuppliers()
  311 + this.loadExtraOptions()
  312 + this.loadRegionOptions()
  313 + this.loadDetail()
  314 + this.$nextTick(() => {
  315 + if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
  316 + this.initDestinationLabel()
  317 + }
  318 + })
  319 + },
  320 + methods: {
  321 + async loadRegionOptions() {
  322 + try {
  323 + const res = await getArea()
  324 + const list = res.data || []
  325 + this.regionOptions = (list || []).map(it => ({ label: it.name || '', value: it.id || '' }))
  326 + } catch (e) {
  327 + this.regionOptions = []
  328 + }
  329 + },
  330 + async loadDetail() {
  331 + if (!this.id) return
  332 + try {
  333 + const res = await getContractApi(this.id)
  334 + const data = res && res.data ? res.data : {}
  335 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  336 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  337 + const m = { ...data, includesPackagingFeeName, includesTransportFeeName }
  338 + this.form = {
  339 + ...this.form,
  340 + id: m.id || '',
  341 + code: m.code || '',
  342 + supplier: m.supplier || '',
  343 + supplierName: m.supplierName || '',
  344 + buyer: m.buyer || (m.customer && m.customer.id) || '',
  345 + buyerName: m.buyerName || (m.customer && m.customer.name) || '',
  346 + stockUpCompanyId: m.stockUpCompanyId || '',
  347 + stockUpCompanyName: m.stockUpCompanyName || '',
  348 + orderDate: m.orderDate || '',
  349 + designatedConsignee: m.designatedConsignee || '',
  350 + specialTerms: m.specialTerms || '',
  351 + specialTermsName: m.specialTermsName || '',
  352 + executionStandard: m.executionStandard || '',
  353 + executionStandardName: m.executionStandardName || '',
  354 + executionStandardRemarks: m.executionStandardRemarks || '',
  355 + includesPackagingFee: !!m.includesPackagingFee,
  356 + includesPackagingFeeName,
  357 + includesTransportFee: !!m.includesTransportFee,
  358 + includesTransportFeeName,
  359 + unit: m.unit || this.form.unit,
  360 + totalAmountCapital: m.totalAmountCapital || '',
  361 + depositInfo: m.depositInfo || '',
  362 + packagingRequirements: m.packagingRequirements || '',
  363 + paymentTerms: m.paymentTerms || '',
  364 + 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 || ''),
  367 + specialInstructions: m.specialInstructions || '',
  368 + remarks: m.remarks || '',
  369 + pieceWeightHead: m.pieceWeightHead || '',
  370 + surface: m.surface || '',
  371 + tolerance: m.tolerance || '',
  372 + performance: m.performance || '',
  373 + component: m.component || '',
  374 + packaging: m.packaging || '',
  375 + workshopId: m.workshopId || '',
  376 + workshopName: m.workshopName || '',
  377 + region: m.region || '',
  378 + regionName: m.regionName || '',
  379 + deptName: m.deptName || '',
  380 + deptId: m.deptId || ''
  381 + }
  382 + this.fileInfo = { id: m.standardFileId || '', name: m.standardFileName || '' }
  383 + this.standardStandardized = (m.standardStandardized === true || m.standardStandardized === false) ? m.standardStandardized : ''
  384 + this.standardStandardizedName = (this.standardStandardized === true) ? '是' : (this.standardStandardized === false) ? '否' : ''
  385 + const lines = Array.isArray(m.contractDistributorLineList) ? m.contractDistributorLineList : []
  386 + this.productLineList = lines
  387 + this.onProductsChange(lines)
  388 + } catch (e) { }
  389 + },
  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 + onProductsChange(products) {
  405 + const list = Array.isArray(products) ? products : []
  406 + this.newProductLineList = list
  407 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  408 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  409 + this.totalQuantity = sumQ
  410 + this.totalAmountIncludingTax = sumT
  411 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  412 + },
  413 + async loadSuppliers() {
  414 + try {
  415 + const results = await getDicByCodes(['SUPPLIER'])
  416 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  417 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  418 + } catch (e) { this.supplierList = [] }
  419 + },
  420 + async loadExtraOptions() {
  421 + try {
  422 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  423 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  424 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  425 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  426 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  427 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  428 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  429 + } catch (e) {
  430 + this.specialTermsList = []
  431 + this.executionStandardList = []
  432 + this.productList = []
  433 + }
  434 + },
  435 + displayLabel(field) {
  436 + const m = this.form
  437 + const map = { supplierName: '请选择供方', buyerName: '请选择需方', workshopName: '请选择生产厂', regionName: '请选择区域' }
  438 + const val = m[field]
  439 + return val ? String(val) : map[field]
  440 + },
  441 + async openSheet(field) {
  442 + if (field === 'standardStandardized') {
  443 + const options = this.yesNoList
  444 + const current = this.standardStandardized
  445 + const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
  446 + this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, field, value: match ? match.value : '' }
  447 + return
  448 + }
  449 + const setSheet = (title, options) => {
  450 + const current = this.form[field]
  451 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  452 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  453 + }
  454 + if (field === 'workshopId') {
  455 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  456 + const _data = res.data || {}
  457 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  458 + const opts = (list || []).map(it => ({
  459 + label: it.name,
  460 + value: it.id
  461 + }))
  462 + setSheet('生产厂', opts)
  463 + } else if (field === 'supplier') {
  464 + setSheet('供方', this.supplierList)
  465 + } else if (field === 'specialTerms') {
  466 + setSheet('特别条款要求', this.specialTermsList)
  467 + } else if (field === 'executionStandard') {
  468 + setSheet('执行标准', this.executionStandardList)
  469 + } else if (field === 'includesPackagingFee') {
  470 + setSheet('单价中是否已包含包装费', this.yesNoList)
  471 + } else if (field === 'includesTransportFee') {
  472 + setSheet('单价中是否已包含运费', this.yesNoList)
  473 + } else if (field === 'region') {
  474 + setSheet('区域', this.regionOptions)
  475 + }
  476 + },
  477 + onSheetConfirm({ value, label }) {
  478 + const field = this.sheet.field
  479 + if (!field) return
  480 + const v = (value === undefined || value === null) ? '' : value
  481 + if (field === 'standardStandardized') {
  482 + this.standardStandardized = v
  483 + this.standardStandardizedName = label || ''
  484 + return
  485 + }
  486 + this.form[field] = v
  487 + this.form[field + 'Name'] = label || ''
  488 + },
  489 + openRelate(fieldKey) {
  490 + let config = {}
  491 + if (fieldKey === 'buyer') {
  492 + config = {
  493 + title: '需方',
  494 + source: 'customer',
  495 + rowKey: 'id',
  496 + multiple: false,
  497 + display: [
  498 + { label: '名称', field: 'name' },
  499 + { label: '编号', field: 'code' },
  500 + { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }
  501 + ]
  502 + }
  503 + } else if (fieldKey === 'stockUpCompanyId') {
  504 + config = {
  505 + title: '备货单位/人(生产标准)',
  506 + source: 'customer',
  507 + rowKey: 'id',
  508 + multiple: false,
  509 + display: [
  510 + { label: '姓名', field: 'name' },
  511 + { label: '编号', field: 'code' },
  512 + { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }
  513 + ]
  514 + }
  515 + }
  516 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  517 + this.sheet.visible = false
  518 + this.relate = {
  519 + ...this.relate,
  520 + title: config.title,
  521 + source: config.source,
  522 + display: config.display,
  523 + multiple: config.multiple,
  524 + rowKey: config.rowKey,
  525 + selectedKeys,
  526 + fieldKey
  527 + }
  528 + this.$nextTick(() => { this.relate.visible = true })
  529 + },
  530 + onRelateConfirm({ items }) {
  531 + const _fieldKey = this.relate.fieldKey
  532 + const first = (items && items.length > 0) ? items[0] : null
  533 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  534 + if (_fieldKey === 'stockUpCompanyId') {
  535 + this.form.stockUpCompanyName = (first && first.name) ? first.name : ''
  536 + } else {
  537 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  538 + }
  539 + },
  540 + validateRequired() {
  541 + const checks = [
  542 + { key: 'code', label: '编号' },
  543 + { key: 'supplier', label: '供方' },
  544 + { key: 'buyer', label: '需方' },
  545 + { key: 'stockUpCompanyId', label: '备货单位/人(生产标准)' },
  546 + { key: 'orderDate', label: '订货日期' },
  547 + { key: 'unit', label: '单位' },
  548 + { key: 'workshopId', label: '生产厂' },
  549 + { key: 'region', label: '区域' },
  550 + { key: 'specialTerms', label: '特别条款要求' }
  551 + ]
  552 + for (const it of checks) {
  553 + const val = this.form[it.key]
  554 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  555 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  556 + }
  557 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  558 + if (list.length === 0) {
  559 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  560 + }
  561 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  562 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  563 + for (const [idx, it] of list.entries()) {
  564 + if (
  565 + strEmpty(it.productName) ||
  566 + strEmpty(it.industry) ||
  567 + strEmpty(it.quality) ||
  568 + strEmpty(it.brand) ||
  569 + numEmpty(it.quantity) ||
  570 + numEmpty(it.unitPrice) ||
  571 + strEmpty(it.deliveryDate)
  572 + ) {
  573 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  574 + }
  575 + }
  576 + if (this.$refs.productRel && !this.$refs.productRel.validate()) return false
  577 + return true
  578 + },
  579 + async onSubmit() {
  580 + if (!this.fileInfo.id) {
  581 + uni.showToast({ title: '请上传合同附件', icon: 'error' })
  582 + return
  583 + }
  584 + if (!this.standardStandardized && this.standardStandardized !== false) {
  585 + uni.showToast({ title: '请选择合同是否规范', icon: 'error' })
  586 + return
  587 + }
  588 + if (!this.validateRequired()) return
  589 + const confirmRes = await new Promise(resolve => {
  590 + uni.showModal({ title: '提示', content: '确定提交标准合同吗?', confirmText: '确定', cancelText: '取消', success: resolve })
  591 + })
  592 + if (!(confirmRes && confirmRes.confirm)) return
  593 + const clean = (obj) => {
  594 + const out = {}
  595 + Object.keys(obj || {}).forEach(k => {
  596 + const v = obj[k]
  597 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  598 + const isUndef = v === undefined || v === null
  599 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  600 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  601 + })
  602 + return out
  603 + }
  604 + 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 + const payload = clean({
  608 + ...formForSubmit,
  609 + id: this.form.id,
  610 + destination,
  611 + type: 'INTL_STD_CONTRACT',
  612 + totalQuantity: this.totalQuantity,
  613 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  614 + contractDistributorLineList: lines,
  615 + standardFileId: this.fileInfo.id,
  616 + standardFileName: this.fileInfo.name,
  617 + standardStandardized: this.standardStandardized
  618 + })
  619 + try {
  620 + await uploadStandardContract(payload)
  621 + uni.showToast({ title: '提交成功', icon: 'none' })
  622 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_foreign_std/index' }) }, 400)
  623 + } catch (e) {
  624 + uni.showToast({ title: e.msg || '提交失败', icon: 'none' })
  625 + }
  626 + }
  627 + }
  628 +}
  629 +</script>
  630 +
  631 +<style lang="scss" scoped>
  632 +.total {
  633 + .total-text {
  634 + font-weight: 600;
  635 + font-size: 32rpx;
  636 + color: rgba(0, 0, 0, 0.9);
  637 + padding-bottom: 28rpx;
  638 + border-bottom: 2rpx solid #E7E7E7;
  639 + }
  640 +
  641 + .total-item {
  642 + display: flex;
  643 + align-items: center;
  644 + }
  645 +
  646 + .total-item-text {
  647 + font-weight: 400;
  648 + font-size: 28rpx;
  649 + color: rgba(0, 0, 0, 0.6);
  650 + line-height: 32rpx;
  651 + width: 240rpx;
  652 + padding: 12rpx 0;
  653 + }
  654 +
  655 + .total-item-price {
  656 + font-weight: 600;
  657 + font-size: 32rpx;
  658 + color: rgba(0, 0, 0, 0.9);
  659 + line-height: 32rpx;
  660 + }
  661 +
  662 + .text-red {
  663 + color: #D54941;
  664 + }
  665 +}
  666 +
  667 +.page {
  668 + display: flex;
  669 + flex-direction: column;
  670 + height: 100%;
  671 +}
  672 +
  673 +.scroll {
  674 + flex: 1;
  675 + padding: 12rpx 0 392rpx !important;
  676 +}
  677 +
  678 +.footer {
  679 + z-index: 2;
  680 + position: fixed;
  681 + left: 0;
  682 + right: 0;
  683 + bottom: 0;
  684 + padding: 32rpx;
  685 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  686 + background: #fff;
  687 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  688 +}
  689 +
  690 +.footer .btn {
  691 + height: 80rpx;
  692 + line-height: 80rpx;
  693 + border-radius: 12rpx;
  694 + font-size: 32rpx;
  695 +}
  696 +
  697 +.footer .submit {
  698 + background: $theme-primary;
  699 + color: #fff;
  700 +}
  701 +
  702 +.quality {
  703 + background-color: #fff;
  704 + display: flex;
  705 + align-items: center;
  706 + padding: 24rpx 32rpx;
  707 + border-bottom: 1rpx solid #f0f0f0;
  708 + margin-top: 20rpx;
  709 +
  710 + .title {
  711 + font-size: 32rpx;
  712 + color: rgba(0, 0, 0, 0.9);
  713 + font-weight: 600;
  714 + }
  715 +
  716 + .opCollapse {
  717 + color: rgba(0, 0, 0, 0.6);
  718 + width: 32rpx;
  719 + height: 28rpx;
  720 + margin-right: 16rpx;
  721 + }
  722 +}
  723 +
  724 +::v-deep .uni-list {
  725 + background: transparent;
  726 +}
  727 +
  728 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  729 + color: rgba(0, 0, 0, 0.9);
  730 +}
  731 +
  732 +::v-deep .uni-list .uni-input-placeholder {
  733 + z-index: 1;
  734 +}
  735 +
  736 +::v-deep .uni-list .uni-input-input {
  737 + background-color: #ffffff;
  738 +}
  739 +
  740 +::v-deep .uni-list-item__extra-text {
  741 + font-size: 32rpx;
  742 +}
  743 +
  744 +::v-deep .uni-list-item__content-title {
  745 + font-size: 32rpx;
  746 + color: rgba(0, 0, 0, 0.9);
  747 +}
  748 +
  749 +::v-deep .uni-list-item__container {
  750 + padding: 32rpx;
  751 +}
  752 +
  753 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  754 + font-size: 32rpx;
  755 + color: rgba(0, 0, 0, 0.4);
  756 +}
  757 +
  758 +::v-deep .uni-list-item__container .uni-easyinput__content {
  759 + border: none;
  760 + background-color: #ffffff !important;
  761 +}
  762 +
  763 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  764 + padding-left: 0 !important;
  765 + height: 48rpx;
  766 + line-height: 48rpx;
  767 + font-size: 32rpx;
  768 +}
  769 +
  770 +::v-deep .uni-list-item__container .item-title,
  771 +::v-deep .uni-list-item__container .uni-list-item__content {
  772 + flex: none;
  773 + min-height: 48rpx;
  774 + line-height: 48rpx;
  775 + font-size: 32rpx;
  776 + position: relative;
  777 + width: 210rpx;
  778 + margin-right: 32rpx;
  779 + color: rgba(0, 0, 0, 0.9);
  780 +}
  781 +
  782 +::v-deep .uni-list-item__container .item-title .required {
  783 + color: red;
  784 + position: absolute;
  785 + top: 50%;
  786 + transform: translateY(-50%);
  787 + left: -16rpx;
  788 +}
  789 +
  790 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  791 + color: rgba(0, 0, 0, 0.4) !important;
  792 +}
  793 +
  794 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  795 + color: rgba(0, 0, 0, 0.9) !important;
  796 +}
  797 +</style>
... ...
... ... @@ -293,7 +293,19 @@ export default {
293 293 uploadContract(id){
294 294 if (!id) return
295 295 this.uploadId = id
296   - this.$refs.uploadPopup.open()
  296 + if (this.detail?.canEdit) {
  297 + const id = this.detail.id || this.detail.code || ''
  298 + if (!id) {
  299 + uni.showToast({ title: '缺少合同ID', icon: 'none' })
  300 + return
  301 + }
  302 + const query = id ? ('?id=' + encodeURIComponent(id)) : ''
  303 + uni.navigateTo({
  304 + url: '/pages/contract_process/uploadStandard' + query
  305 + })
  306 + }else{
  307 + this.$refs.uploadPopup.open()
  308 + }
297 309 },
298 310 onUploadSubmit() {
299 311 if (!this.fileInfo.id) {
... ...
  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.workshopId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" 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 title="订货日期">
  33 + <template v-slot:footer>
  34 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  35 + </template>
  36 + </uni-list-item>
  37 +
  38 + <uni-list-item title="单位">
  39 + <template v-slot:footer>
  40 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  41 + </template>
  42 + </uni-list-item>
  43 +
  44 + <ProductRel mode="add" :deliveryDate="form.orderDate" :deliveryDateBase="form.deliveryDate" :rawToProdRatioList="rawToProdRatioList" :list="productLineList" @change="onProductsChange" :options="productList" :rawProductList="rawProductList" :rawProductGradeList="rawProductGradeList" />
  45 +
  46 + <uni-list-item title="合计金额(大写)">
  47 + <template v-slot:footer>
  48 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false"
  49 + disabled />
  50 + </template>
  51 + </uni-list-item>
  52 + <uni-list-item title="交付定金、数额、时间">
  53 + <template v-slot:footer>
  54 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  55 + </template>
  56 + </uni-list-item>
  57 + <uni-list-item title="包装要求">
  58 + <template v-slot:footer>
  59 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求"
  60 + :inputBorder="false" />
  61 + </template>
  62 + </uni-list-item>
  63 + <uni-list-item title="付款方式、付款期限">
  64 + <template v-slot:footer>
  65 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  66 + </template>
  67 + </uni-list-item>
  68 + <uni-list-item title="运输方式">
  69 + <template v-slot:footer>
  70 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  71 + </template>
  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" />
  78 + </template>
  79 + </uni-list-item>
  80 +
  81 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'"
  82 + clickable @click="openSheet('includesPackagingFee')"
  83 + :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  84 + <template v-slot:body>
  85 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  86 + </template>
  87 + </uni-list-item>
  88 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'"
  89 + clickable @click="openSheet('includesTransportFee')"
  90 + :rightText="form.includesTransportFeeName || '请选择'" showArrow>
  91 + <template v-slot:body>
  92 + <view class="item-title"><text>单价中是否已包含运费</text></view>
  93 + </template>
  94 + </uni-list-item>
  95 + <uni-list-item title="需方指定收货人">
  96 + <template v-slot:footer>
  97 + <uni-easyinput v-model="form.designatedConsignee" placeholder="请输入需方指定收货人"
  98 + :inputBorder="false" />
  99 + </template>
  100 + </uni-list-item>
  101 +
  102 + <uni-list-item class="select-item" :class="form.specialTermsName ? 'is-filled' : 'is-empty'" clickable
  103 + @click="openSheet('specialTerms')" :rightText="form.specialTermsName || '请选择'" showArrow>
  104 + <template v-slot:body>
  105 + <view class="item-title"><text class="required">*</text><text>特别条款要求</text></view>
  106 + </template>
  107 + </uni-list-item>
  108 + <uni-list-item class="select-item" :class="form.executionStandardName ? 'is-filled' : 'is-empty'" clickable
  109 + @click="openSheet('executionStandard')" :rightText="form.executionStandardName || '请选择'" showArrow>
  110 + <template v-slot:body>
  111 + <view class="item-title"><text>执行标准</text></view>
  112 + </template>
  113 + </uni-list-item>
  114 + <uni-list-item v-if="form.executionStandard === 'OTHER'" title="其他">
  115 + <template v-slot:footer>
  116 + <uni-easyinput v-model="form.executionStandardRemarks" placeholder="请输入其他标准备注"
  117 + :inputBorder="false" />
  118 + </template>
  119 + </uni-list-item>
  120 + <uni-list-item title="特别说明" style="margin-top: 20rpx;">
  121 + <template v-slot:footer>
  122 + <uni-easyinput v-model="form.specialInstructions" placeholder="请输入特别说明" :inputBorder="false" />
  123 + </template>
  124 + </uni-list-item>
  125 + <uni-list-item title="备注">
  126 + <template v-slot:footer>
  127 + <uni-easyinput v-model="form.remarks" placeholder="请输入备注" :inputBorder="false" maxlength="2000" />
  128 + </template>
  129 + </uni-list-item>
  130 +
  131 + <view class="quality">
  132 + <image class="opCollapse" src="/static/images/title.png" />
  133 + <text class="title">具体质量要求</text>
  134 + </view>
  135 + <uni-list-item title="件重条头">
  136 + <template v-slot:footer>
  137 + <uni-easyinput v-model="form.pieceWeightHead" 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.surface" placeholder="请输入" :inputBorder="false" />
  143 + </template>
  144 + </uni-list-item>
  145 + <uni-list-item title="公差">
  146 + <template v-slot:footer>
  147 + <uni-easyinput v-model="form.tolerance" placeholder="请输入" :inputBorder="false" />
  148 + </template>
  149 + </uni-list-item>
  150 + <uni-list-item title="性能">
  151 + <template v-slot:footer>
  152 + <uni-easyinput v-model="form.performance" 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.component" 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.packaging" placeholder="请输入" :inputBorder="false" />
  163 + </template>
  164 + </uni-list-item>
  165 + <uni-list-item title="合同附件" style="margin-top: 20rpx;">
  166 + <template v-slot:footer>
  167 + <FileUpload v-model="fileInfo" />
  168 + </template>
  169 + </uni-list-item>
  170 + <uni-list-item class="select-item" :class="standardStandardizedName ? 'is-filled' : 'is-empty'" clickable
  171 + @click="openSheet('standardStandardized')" :rightText="standardStandardizedName || '请选择'" showArrow>
  172 + <template v-slot:body>
  173 + <view class="item-title"><text class="required">*</text><text>合同是否规范</text></view>
  174 + </template>
  175 + </uni-list-item>
  176 + <view class="footer">
  177 + <div class="total">
  178 + <div class="total-text">合计</div>
  179 + <div class="total-item">
  180 + <div class="total-item-text">数量</div>
  181 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  182 + </div>
  183 + <div class="total-item">
  184 + <div class="total-item-text">不含税金额</div>
  185 + <div class="total-item-price text-red">¥{{ (totalAmountExcludingTax || 0).toFixed(2) }}</div>
  186 + </div>
  187 + <div class="total-item">
  188 + <div class="total-item-text">总金额</div>
  189 + <div class="total-item-price text-red">¥{{ (totalAmountIncludingTax || 0).toFixed(2) }}</div>
  190 + </div>
  191 + </div>
  192 + <button class="btn submit" type="primary" @click="onSubmit">保存</button>
  193 + </view>
  194 + </uni-list>
  195 + </scroll-view>
  196 +
  197 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options"
  198 + v-model="sheet.value" @confirm="onSheetConfirm" />
  199 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  200 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  201 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  202 + </view>
  203 +</template>
  204 +
  205 +<script>
  206 +import SingleSelectSheet from '@/components/single-select/index.vue'
  207 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  208 +import ProductRel from './productRel.vue'
  209 +import CitySelector from '@/components/city-selector/index.vue'
  210 +import FileUpload from '@/components/file-upload/index.vue'
  211 +import { getContractApi, uploadStandardContract } from '@/api/contract'
  212 +import { getDicByCodes } from '@/utils/dic'
  213 +import { formatCurrencyToChinese } from '@/utils/common'
  214 +import { workshopQueryApi } from '@/api/devManage'
  215 +import { getArea } from '@/api/credit_manage.js'
  216 +
  217 +export default {
  218 + name: 'UploadStandardContractProcess',
  219 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  220 + data() {
  221 + return {
  222 + id: '',
  223 + form: {
  224 + id: '',
  225 + code: '',
  226 + supplier: '',
  227 + supplierName: '',
  228 + buyer: '',
  229 + buyerName: '',
  230 + stockUpCompanyId: '',
  231 + stockUpCompanyName: '',
  232 + workshopId: '',
  233 + workshopName: '',
  234 + region: '',
  235 + regionName: '',
  236 + deptName: '',
  237 + deptId: '',
  238 + orderDate: '',
  239 + deliveryDate: '',
  240 + designatedConsignee: '',
  241 + specialTerms: '',
  242 + specialTermsName: '',
  243 + executionStandard: '',
  244 + executionStandardName: '',
  245 + executionStandardRemarks: '',
  246 + includesPackagingFee: false,
  247 + includesPackagingFeeName: '否',
  248 + includesTransportFee: false,
  249 + includesTransportFeeName: '否',
  250 + unit: '元、公斤、元/公斤',
  251 + totalAmountCapital: '',
  252 + depositInfo: '',
  253 + packagingRequirements: '',
  254 + paymentTerms: '',
  255 + transportMode: '',
  256 + destinationId: [],
  257 + destinationLabel: '',
  258 + specialInstructions: '',
  259 + remarks: '',
  260 + pieceWeightHead: '',
  261 + surface: '',
  262 + tolerance: '',
  263 + performance: '',
  264 + component: '',
  265 + packaging: ''
  266 + },
  267 + supplierList: [],
  268 + specialTermsList: [],
  269 + executionStandardList: [],
  270 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  271 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  272 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  273 + fileInfo: { id: '', name: '' },
  274 + standardStandardized: '',
  275 + standardStandardizedName: '',
  276 + totalQuantity: 0,
  277 + totalAmountExcludingTax: 0,
  278 + totalAmountIncludingTax: 0,
  279 + productLineList: [],
  280 + newProductLineList: [],
  281 + productList: [],
  282 + regionOptions: [],
  283 + rawToProdRatioList: [],
  284 + rawProductList: [],
  285 + rawProductGradeList: [],
  286 + }
  287 + },
  288 + onLoad(query) {
  289 + this.id = (query && query.id) ? query.id : ''
  290 + },
  291 + created() {
  292 + this.loadSuppliers()
  293 + this.loadExtraOptions()
  294 + this.loadRegionOptions()
  295 + this.loadDetail()
  296 + this.$nextTick(() => {
  297 + if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
  298 + this.initDestinationLabel()
  299 + }
  300 + })
  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 + 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 || ''),
  349 + specialInstructions: m.specialInstructions || '',
  350 + remarks: m.remarks || '',
  351 + pieceWeightHead: m.pieceWeightHead || '',
  352 + surface: m.surface || '',
  353 + tolerance: m.tolerance || '',
  354 + performance: m.performance || '',
  355 + component: m.component || '',
  356 + packaging: m.packaging || '',
  357 + workshopId: m.workshopId || '',
  358 + workshopName: m.workshopName || '',
  359 + region: m.region || '',
  360 + regionName: m.regionName || '',
  361 + deptName: m.deptName || '',
  362 + deptId: m.deptId || '',
  363 + }
  364 + this.fileInfo = {
  365 + id: m.standardFileId || '',
  366 + name: m.standardFileName || ''
  367 + }
  368 + this.standardStandardized = (m.standardStandardized === true || m.standardStandardized === false) ? m.standardStandardized : ''
  369 + this.standardStandardizedName = (this.standardStandardized === true) ? '是' : (this.standardStandardized === false) ? '否' : ''
  370 + const lines = Array.isArray(m.contractStdProcessingLineList) ? m.contractStdProcessingLineList : []
  371 + this.productLineList = lines
  372 + this.onProductsChange(lines)
  373 + } catch (e) { }
  374 + },
  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 + onProductsChange(products) {
  390 + const list = Array.isArray(products) ? products : []
  391 + this.newProductLineList = list
  392 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.productQuantity) || 0), 0)
  393 + const sumE = list.reduce((acc, it) => acc + (parseFloat(it.amountExcludingTax) || 0), 0)
  394 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  395 + this.totalQuantity = sumQ
  396 + this.totalAmountExcludingTax = sumE
  397 + this.totalAmountIncludingTax = sumT
  398 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  399 + },
  400 + async loadSuppliers() {
  401 + try {
  402 + const results = await getDicByCodes(['SUPPLIER'])
  403 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  404 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  405 + } catch (e) { this.supplierList = [] }
  406 + },
  407 + async loadExtraOptions() {
  408 + try {
  409 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT','RAW_TO_PROD_RATIO', 'RAW_MATERIAL', 'RAW_MATERIAL_GRADE'])
  410 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  411 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  412 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  413 + const c4 = results && results.RAW_TO_PROD_RATIO && results.RAW_TO_PROD_RATIO.data ? results.RAW_TO_PROD_RATIO.data : []
  414 + const c5 = results && results.RAW_MATERIAL && results.RAW_MATERIAL.data ? results.RAW_MATERIAL.data : []
  415 + const c6 = results && results.RAW_MATERIAL_GRADE && results.RAW_MATERIAL_GRADE.data ? results.RAW_MATERIAL_GRADE.data : []
  416 + this.rawToProdRatioList = c4.map(it => ({ label: it.name, value: it.code }))
  417 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  418 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  419 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  420 + console.log('c5', c5)
  421 + this.rawProductList = c5.map(it => ({ label: it.name, value: it.code }))
  422 + this.rawProductGradeList = c6.map(it => ({ label: it.name, value: it.code }))
  423 + } catch (e) {
  424 + this.specialTermsList = []
  425 + this.executionStandardList = []
  426 + this.productList = []
  427 + this.rawToProdRatioList = []
  428 + this.rawProductList = []
  429 + this.rawProductGradeList = []
  430 + }
  431 + },
  432 + displayLabel(field) {
  433 + const m = this.form
  434 + const map = { supplierName: '请选择承揽方', buyerName: '请选择定作方', workshopName: '请选择生产厂' }
  435 + const val = m[field]
  436 + return val ? String(val) : map[field]
  437 + },
  438 + async openSheet(field) {
  439 + const setSheet = (title, options) => {
  440 + const current = this.form[field]
  441 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  442 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  443 + }
  444 + if (field === 'workshopId') {
  445 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  446 + const _data = res.data || {}
  447 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  448 + const opts = (list || []).map(it => ({
  449 + label: it.name ,
  450 + value: it.id
  451 + }))
  452 + setSheet('生产厂', opts)
  453 + } else if (field === 'supplier') {
  454 + setSheet('承揽方', this.supplierList)
  455 + } else if (field === 'specialTerms') {
  456 + setSheet('特别条款要求', this.specialTermsList)
  457 + } else if (field === 'executionStandard') {
  458 + setSheet('执行标准', this.executionStandardList)
  459 + } else if (field === 'includesPackagingFee') {
  460 + setSheet('单价中是否已包含包装费', this.yesNoList)
  461 + } else if (field === 'includesTransportFee') {
  462 + setSheet('单价中是否已包含运费', this.yesNoList)
  463 + } else if (field === 'standardStandardized') {
  464 + const options = this.yesNoList
  465 + const current = this.standardStandardized
  466 + const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
  467 + this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, field, value: match ? match.value : '' }
  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 + } else {
  478 + this.form[field] = v
  479 + this.form[field + 'Name'] = label || ''
  480 + }
  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 + }
  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 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  497 + },
  498 + onRadioSelect(field, nameField, opt) {
  499 + const val = opt && opt.value != null ? opt.value : ''
  500 + const label = opt && opt.label != null ? opt.label : ''
  501 + this.form[field] = val
  502 + this.form[nameField] = label
  503 + if (field === 'executionStandard' && val !== 'OTHER') {
  504 + this.form.executionStandardRemarks = ''
  505 + }
  506 + },
  507 + validateRequired() {
  508 + const checks = [
  509 + { key: 'code', label: '编号' },
  510 + { key: 'supplier', label: '承揽方' },
  511 + { key: 'buyer', label: '定作方' },
  512 + { key: 'orderDate', label: '订货日期' },
  513 + { key: 'workshopId', label: '生产厂' },
  514 + { key: 'unit', label: '单位' },
  515 + { key: 'specialTerms', label: '特别条款要求' },
  516 + ]
  517 + for (const it of checks) {
  518 + const val = this.form[it.key]
  519 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  520 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  521 + }
  522 + if (this.$refs.productRel && !this.$refs.productRel.validate()) return false
  523 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  524 + if (list.length === 0) {
  525 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  526 + }
  527 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  528 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  529 + console.log('list11', list)
  530 + for (const [idx, it] of list.entries()) {
  531 + if (
  532 + strEmpty(it.productName) ||
  533 + strEmpty(it.industry) ||
  534 + strEmpty(it.quality) ||
  535 + numEmpty(it.productQuantity) ||
  536 + strEmpty(it.unitPrice) ||
  537 + strEmpty(it.deliveryDate)
  538 + ) {
  539 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  540 + }
  541 + }
  542 + return true
  543 + },
  544 + async onSubmit() {
  545 + this.form.standardFileId = (this.fileInfo && this.fileInfo.id) ? this.fileInfo.id : ''
  546 + this.form.standardFileName = (this.fileInfo && this.fileInfo.name) ? this.fileInfo.name : ''
  547 + if (!this.fileInfo.id) {
  548 + uni.showToast({ title: '请上传合同附件', icon: 'error' })
  549 + return
  550 + }
  551 + if (!this.standardStandardized && this.standardStandardized !== false) {
  552 + uni.showToast({ title: '请选择合同是否规范', icon: 'error' })
  553 + return
  554 + }
  555 + if (!this.validateRequired()) return
  556 + const confirmRes = await new Promise(resolve => {
  557 + uni.showModal({ title: '提示', content: '确定上传合同附件吗?', confirmText: '确定', cancelText: '取消', success: resolve })
  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 payload = clean({
  575 + ...formForSubmit,
  576 + id: this.form.id,
  577 + destination,
  578 + type: 'PROCESS_STD_AGMT',
  579 + sumQuantity: this.totalQuantity,
  580 + sumAmountExcl: this.totalAmountExcludingTax,
  581 + sumTotal: this.totalAmountIncludingTax,
  582 + contractStdProcessingLineList: lines,
  583 + standardFileId: this.fileInfo.id,
  584 + standardFileName: this.fileInfo.name,
  585 + standardStandardized: this.standardStandardized,
  586 + })
  587 + try {
  588 + await uploadStandardContract(payload)
  589 + uni.showToast({ title: '上传成功', icon: 'none' })
  590 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_process/index' }) }, 400)
  591 + } catch (e) {
  592 + uni.showToast({ title: e.msg ||'上传失败', icon: 'none' })
  593 + }
  594 + }
  595 + }
  596 +}
  597 +</script>
  598 +
  599 +<style lang="scss" scoped>
  600 +.total {
  601 + .total-text {
  602 + font-weight: 600;
  603 + font-size: 32rpx;
  604 + color: rgba(0, 0, 0, 0.9);
  605 + padding-bottom: 28rpx;
  606 + border-bottom: 2rpx solid #E7E7E7;
  607 + }
  608 +
  609 + .total-item {
  610 + display: flex;
  611 + align-items: center;
  612 + }
  613 +
  614 + .total-item-text {
  615 + font-weight: 400;
  616 + font-size: 28rpx;
  617 + color: rgba(0, 0, 0, 0.6);
  618 + line-height: 32rpx;
  619 + width: 240rpx;
  620 + padding: 12rpx 0;
  621 + }
  622 +
  623 + .total-item-price {
  624 + font-weight: 600;
  625 + font-size: 32rpx;
  626 + color: rgba(0, 0, 0, 0.9);
  627 + line-height: 32rpx;
  628 + }
  629 +
  630 + .text-red {
  631 + color: #D54941;
  632 + }
  633 +}
  634 +
  635 +.page {
  636 + display: flex;
  637 + flex-direction: column;
  638 + height: 100%;
  639 +}
  640 +
  641 +.scroll {
  642 + flex: 1;
  643 + padding: 12rpx 0 392rpx !important;
  644 +}
  645 +
  646 +.footer {
  647 + z-index: 2;
  648 + position: fixed;
  649 + left: 0;
  650 + right: 0;
  651 + bottom: 0;
  652 + padding: 32rpx;
  653 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  654 + background: #fff;
  655 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  656 +}
  657 +
  658 +.footer .btn {
  659 + height: 80rpx;
  660 + line-height: 80rpx;
  661 + border-radius: 12rpx;
  662 + font-size: 32rpx;
  663 +}
  664 +
  665 +.footer .submit {
  666 + background: $theme-primary;
  667 + color: #fff;
  668 +}
  669 +
  670 +.group {
  671 + background: #fff;
  672 + padding: 24rpx 32rpx;
  673 + margin-bottom: 20rpx;
  674 +}
  675 +
  676 +.group-title {
  677 + color: rgba(0, 0, 0, 0.9);
  678 + font-size: 32rpx;
  679 + padding-bottom: 16rpx;
  680 +}
  681 +
  682 +.radio-list {
  683 + display: flex;
  684 + flex-direction: column;
  685 +}
  686 +.quality {
  687 + background-color: #fff;
  688 + display: flex;
  689 + align-items: center;
  690 + padding: 24rpx 32rpx;
  691 + border-bottom: 1rpx solid #f0f0f0;
  692 + margin-top: 20rpx;
  693 +
  694 + .title {
  695 + font-size: 32rpx;
  696 + color: rgba(0, 0, 0, 0.9);
  697 + font-weight: 600;
  698 + }
  699 +
  700 + .opCollapse {
  701 + color: rgba(0, 0, 0, 0.6);
  702 + width: 32rpx;
  703 + height: 28rpx;
  704 + margin-right: 16rpx;
  705 + }
  706 +}
  707 +
  708 +.radio-item {
  709 + display: flex;
  710 + align-items: center;
  711 + padding: 24rpx 0;
  712 + border-bottom: 1rpx solid #f0f0f0;
  713 +}
  714 +
  715 +.radio-item:last-child {
  716 + border-bottom: none;
  717 +}
  718 +
  719 +.radio {
  720 + width: 32rpx;
  721 + height: 32rpx;
  722 + border-radius: 50%;
  723 + border: 2rpx solid #DCDCDC;
  724 + margin-right: 20rpx;
  725 + box-sizing: border-box;
  726 +}
  727 +
  728 +.radio.checked {
  729 + background: $theme-primary;
  730 + border-color: $theme-primary;
  731 +}
  732 +
  733 +.radio-item .label {
  734 + font-size: 32rpx;
  735 + color: rgba(0, 0, 0, 0.9);
  736 +}
  737 +
  738 +::v-deep .uni-list {
  739 + background: transparent;
  740 +}
  741 +
  742 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  743 + color: rgba(0, 0, 0, 0.9);
  744 +}
  745 +
  746 +::v-deep .uni-list .uni-input-placeholder {
  747 + z-index: 1;
  748 +}
  749 +
  750 +::v-deep .uni-list .uni-input-input {
  751 + background-color: #ffffff;
  752 +}
  753 +
  754 +::v-deep .uni-list-item__extra-text {
  755 + font-size: 32rpx;
  756 +}
  757 +
  758 +::v-deep .uni-list-item__content-title {
  759 + font-size: 32rpx;
  760 + color: rgba(0, 0, 0, 0.9);
  761 +}
  762 +
  763 +::v-deep .uni-list-item__container {
  764 + padding: 32rpx;
  765 +}
  766 +
  767 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  768 + font-size: 32rpx;
  769 + color: rgba(0, 0, 0, 0.4);
  770 +}
  771 +
  772 +::v-deep .uni-list-item__container .uni-easyinput__content {
  773 + border: none;
  774 + background-color: #ffffff !important;
  775 +}
  776 +
  777 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  778 + padding-left: 0 !important;
  779 + height: 48rpx;
  780 + line-height: 48rpx;
  781 + font-size: 32rpx;
  782 +}
  783 +
  784 +::v-deep .uni-list-item__container .uni-easyinput__content .content-clear-icon {
  785 + font-size: 44rpx !important;
  786 +}
  787 +
  788 +::v-deep .uni-list-item__container .item-title,
  789 +::v-deep .uni-list-item__container .uni-list-item__content {
  790 + flex: none;
  791 + min-height: 48rpx;
  792 + line-height: 48rpx;
  793 + font-size: 32rpx;
  794 + position: relative;
  795 + width: 210rpx;
  796 + margin-right: 32rpx;
  797 + color: rgba(0, 0, 0, 0.9);
  798 +}
  799 +
  800 +::v-deep .uni-list-item__container .item-title .required {
  801 + color: red;
  802 + position: absolute;
  803 + top: 50%;
  804 + transform: translateY(-50%);
  805 + left: -16rpx;
  806 +}
  807 +
  808 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  809 + color: rgba(0, 0, 0, 0.4) !important;
  810 +}
  811 +
  812 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  813 + color: rgba(0, 0, 0, 0.9) !important;
  814 +}
  815 +::v-deep .uni-easyinput {
  816 + &__placeholder-class {
  817 + font-size: 32rpx;
  818 + color: rgba(0, 0, 0, 0.4);
  819 + }
  820 +
  821 + &__content {
  822 + border: none;
  823 + background-color: #ffffff !important;
  824 + height: 100%;
  825 + &-input {
  826 + padding-left: 0 !important;
  827 + height: 48rpx;
  828 + line-height: 48rpx;
  829 + font-size: 32rpx;
  830 + }
  831 +
  832 + .content-clear-icon {
  833 + font-size: 44rpx !important;
  834 + }
  835 + }
  836 + }
  837 +
  838 +</style>
... ...
... ... @@ -368,7 +368,20 @@ export default {
368 368 downloadFile,
369 369 printFile,
370 370 onUpload() {
371   - this.$refs.uploadPopup.open()
  371 + if (this.detail?.canEdit) {
  372 + const id = this.detail.id || this.detail.code || ''
  373 + if (!id) {
  374 + uni.showToast({ title: '缺少合同ID', icon: 'none' })
  375 + return
  376 + }
  377 + const query = id ? ('?id=' + encodeURIComponent(id)) : ''
  378 + uni.navigateTo({
  379 + url: '/pages/contract_retail/uploadStandard' + query
  380 + })
  381 + }else{
  382 + this.$refs.uploadPopup.open()
  383 + }
  384 +
372 385 },
373 386 handleButtonClick(btn) {
374 387 if (!btn || btn.disabled) return
... ...
  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.workshopId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openSheet('workshopId')" :rightText="form.workshopName || '请选择生产厂'" 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 title="订货日期">
  33 + <template v-slot:footer>
  34 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  35 + </template>
  36 + </uni-list-item>
  37 +
  38 + <uni-list-item title="单位">
  39 + <template v-slot:footer>
  40 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  41 + </template>
  42 + </uni-list-item>
  43 + <uni-list-item class="select-item" :class="form.deptName ? 'is-filled' : 'is-empty'">
  44 + <template v-slot:body>
  45 + <view class="item-title"><text class="required">*</text><text>办事处</text></view>
  46 + </template>
  47 + <template v-slot:footer>
  48 + <view class="serial-number-row">
  49 + <uni-easyinput v-model="form.deptName" :inputBorder="false" disabled />
  50 + </view>
  51 + </template>
  52 + </uni-list-item>
  53 + <uni-list-item class="select-item" :class="form.region ? 'is-filled' : 'is-empty'" clickable
  54 + @click="openSheet('region')" :rightText="displayLabel('regionName')" showArrow>
  55 + <template v-slot:body>
  56 + <view class="item-title"><text class="required">*</text><text>区域</text></view>
  57 + </template>
  58 + </uni-list-item>
  59 + <ProductRel ref="productRel" mode="add" :deliveryDateBase="form.deliveryDate" :deliveryDate="form.orderDate" :list="productLineList" @change="onProductsChange" :options="productList" />
  60 +
  61 + <uni-list-item title="合计人民币金额(大写)">
  62 + <template v-slot:footer>
  63 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="" :inputBorder="false"
  64 + disabled />
  65 + </template>
  66 + </uni-list-item>
  67 + <uni-list-item title="交付定金、数额、时间">
  68 + <template v-slot:footer>
  69 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  70 + </template>
  71 + </uni-list-item>
  72 + <uni-list-item title="包装要求">
  73 + <template v-slot:footer>
  74 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求"
  75 + :inputBorder="false" />
  76 + </template>
  77 + </uni-list-item>
  78 + <uni-list-item title="付款方式、付款期限">
  79 + <template v-slot:footer>
  80 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  81 + </template>
  82 + </uni-list-item>
  83 + <uni-list-item title="运输方式">
  84 + <template v-slot:footer>
  85 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  86 + </template>
  87 + </uni-list-item>
  88 + <uni-list-item class="select-item" :class="(Array.isArray(form.destinationId) && form.destinationId.length) ? 'is-filled' : 'is-empty'" clickable
  89 + @click="openCitySelector" :rightText="form.destinationLabel || '请选择'" showArrow>
  90 + <template v-slot:body>
  91 + <view class="item-title"><text>目的地</text></view>
  92 + <CitySelector ref="citySelectorRef" v-model="form.destinationId" @change="onCityChange" />
  93 + </template>
  94 + </uni-list-item>
  95 +
  96 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'"
  97 + clickable @click="openSheet('includesPackagingFee')"
  98 + :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  99 + <template v-slot:body>
  100 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  101 + </template>
  102 + </uni-list-item>
  103 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'"
  104 + clickable @click="openSheet('includesTransportFee')"
  105 + :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="请输入需方指定收货人"
  113 + :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="请输入其他标准备注"
  132 + :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 + <uni-list-item title="合同附件" style="margin-top: 20rpx;">
  181 + <template v-slot:footer>
  182 + <view style="width: 420rpx;">
  183 + <FileUpload v-model="fileInfo" />
  184 + </view>
  185 + </template>
  186 + </uni-list-item>
  187 + <uni-list-item class="select-item"
  188 + :class="(form.standardStandardized === true || form.standardStandardized === false) ? 'is-filled' : 'is-empty'"
  189 + clickable @click="openSheet('standardStandardized')"
  190 + :rightText="form.standardStandardizedName || '请选择'" showArrow>
  191 + <template v-slot:body>
  192 + <view class="item-title"><text>合同是否规范</text></view>
  193 + </template>
  194 + </uni-list-item>
  195 + <view class="footer">
  196 + <div class="total">
  197 + <div class="total-text">合计</div>
  198 + <div class="total-item">
  199 + <div class="total-item-text">数量</div>
  200 + <div class="total-item-price">{{ (totalQuantity || 0).toFixed(2) }}kg</div>
  201 + </div>
  202 + <div class="total-item">
  203 + <div class="total-item-text">不含税金额</div>
  204 + <div class="total-item-price text-red">¥{{ (totalAmountExcludingTax || 0).toFixed(2) }}</div>
  205 + </div>
  206 + <div class="total-item">
  207 + <div class="total-item-text">总金额</div>
  208 + <div class="total-item-price text-red">¥{{ (totalAmountIncludingTax || 0).toFixed(2) }}</div>
  209 + </div>
  210 + </div>
  211 + <button class="btn submit" type="primary" @click="onSubmit">保存</button>
  212 + </view>
  213 + </uni-list>
  214 + </scroll-view>
  215 +
  216 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options"
  217 + v-model="sheet.value" @confirm="onSheetConfirm" />
  218 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  219 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  220 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  221 + </view>
  222 +</template>
  223 +
  224 +<script>
  225 +import SingleSelectSheet from '@/components/single-select/index.vue'
  226 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  227 +import ProductRel from './productRel.vue'
  228 +import CitySelector from '@/components/city-selector/index.vue'
  229 +import FileUpload from '@/components/file-upload/index.vue'
  230 +import { getContractApi, uploadStandardContract } from '@/api/contract'
  231 +import { getDicByCodes } from '@/utils/dic'
  232 +import { formatCurrencyToChinese } from '@/utils/common'
  233 +import { workshopQueryApi } from '@/api/devManage'
  234 +import { getArea } from '@/api/credit_manage.js'
  235 +
  236 +export default {
  237 + name: 'ModifyContractRetail',
  238 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel, CitySelector, FileUpload },
  239 + data() {
  240 + return {
  241 + id: '',
  242 + fileInfo: { id: '', name: '' },
  243 + form: {
  244 + id: '',
  245 + code: '',
  246 + supplier: '',
  247 + supplierName: '',
  248 + buyer: '',
  249 + buyerName: '',
  250 + stockUpCompanyId: '',
  251 + stockUpCompanyName: '',
  252 + region: '',
  253 + regionName: '',
  254 + deptName: '',
  255 + deptId: '',
  256 + workshopId: '',
  257 + workshopName: '',
  258 + orderDate: '',
  259 + deliveryDate: '',
  260 + designatedConsignee: '',
  261 + specialTerms: '',
  262 + specialTermsName: '',
  263 + executionStandard: '',
  264 + executionStandardName: '',
  265 + executionStandardRemarks: '',
  266 + includesPackagingFee: false,
  267 + includesPackagingFeeName: '否',
  268 + includesTransportFee: false,
  269 + includesTransportFeeName: '否',
  270 + unit: '元、公斤、元/公斤',
  271 + totalAmountCapital: '',
  272 + depositInfo: '',
  273 + packagingRequirements: '',
  274 + paymentTerms: '',
  275 + transportMode: '',
  276 + destinationId: [],
  277 + destinationLabel: '',
  278 + specialInstructions: '',
  279 + remarks: '',
  280 + pieceWeightHead: '',
  281 + surface: '',
  282 + tolerance: '',
  283 + performance: '',
  284 + component: '',
  285 + packaging: '',
  286 + standardFileId: '',
  287 + standardFileName: '',
  288 + standardStandardized: '',
  289 + standardStandardizedName: ''
  290 + },
  291 + supplierList: [],
  292 + specialTermsList: [],
  293 + executionStandardList: [],
  294 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
  295 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  296 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  297 + totalQuantity: 0,
  298 + totalAmountExcludingTax: 0,
  299 + totalAmountIncludingTax: 0,
  300 + productLineList: [],
  301 + newProductLineList: [],
  302 + productList: [],
  303 + regionOptions: []
  304 + }
  305 + },
  306 + onLoad(query) {
  307 + this.id = (query && query.id) ? query.id : ''
  308 + },
  309 + created() {
  310 + this.loadSuppliers()
  311 + this.loadExtraOptions()
  312 + this.loadRegionOptions()
  313 + this.loadDetail()
  314 + this.$nextTick(() => {
  315 + if (Array.isArray(this.form.destinationId) && this.form.destinationId.length) {
  316 + this.initDestinationLabel()
  317 + }
  318 + })
  319 + },
  320 + methods: {
  321 + async loadRegionOptions() {
  322 + try {
  323 + const res = await getArea()
  324 + const list = res.data || []
  325 + this.regionOptions = (list || []).map(it => ({ label: it.name || '', value: it.id || '' }))
  326 + } catch (e) {
  327 + this.regionOptions = []
  328 + }
  329 + },
  330 + async loadDetail() {
  331 + if (!this.id) return
  332 + try {
  333 + const res = await getContractApi(this.id)
  334 + const data = res && res.data ? res.data : {}
  335 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  336 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  337 + const standardStandardized = (data.standardStandardized === true || data.standardStandardized === false) ? data.standardStandardized : ''
  338 + const standardStandardizedName = (standardStandardized === true) ? '是' : (standardStandardized === false) ? '否' : ''
  339 + const m = { ...data, includesPackagingFeeName, includesTransportFeeName }
  340 + this.form = {
  341 + ...this.form,
  342 + id: m.id || '',
  343 + code: m.code || '',
  344 + supplier: m.supplier || '',
  345 + supplierName: m.supplierName || '',
  346 + buyer: m.buyer || (m.customer && m.customer.id) || '',
  347 + buyerName: m.buyerName || (m.customer && m.customer.name) || '',
  348 + orderDate: m.orderDate || '',
  349 + designatedConsignee: m.designatedConsignee || '',
  350 + specialTerms: m.specialTerms || '',
  351 + specialTermsName: m.specialTermsName || '',
  352 + executionStandard: m.executionStandard || '',
  353 + executionStandardName: m.executionStandardName || '',
  354 + executionStandardRemarks: m.executionStandardRemarks || '',
  355 + includesPackagingFee: !!m.includesPackagingFee,
  356 + includesPackagingFeeName,
  357 + includesTransportFee: !!m.includesTransportFee,
  358 + includesTransportFeeName,
  359 + unit: m.unit || this.form.unit,
  360 + totalAmountCapital: m.totalAmountCapital || '',
  361 + depositInfo: m.depositInfo || '',
  362 + packagingRequirements: m.packagingRequirements || '',
  363 + paymentTerms: m.paymentTerms || '',
  364 + 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 || ''),
  367 + specialInstructions: m.specialInstructions || '',
  368 + remarks: m.remarks || '',
  369 + pieceWeightHead: m.pieceWeightHead || '',
  370 + surface: m.surface || '',
  371 + tolerance: m.tolerance || '',
  372 + performance: m.performance || '',
  373 + component: m.component || '',
  374 + packaging: m.packaging || '',
  375 + workshopId: m.workshopId || '',
  376 + workshopName: m.workshopName || '',
  377 + stockUpCompanyId: m.stockUpCompanyId || '',
  378 + stockUpCompanyName: m.stockUpCompanyName || '',
  379 + region: m.region || '',
  380 + regionName: m.regionName || '',
  381 + deptName: m.deptName || '',
  382 + deptId: m.deptId || '',
  383 + standardFileId: m.standardFileId || '',
  384 + standardFileName: m.standardFileName || '',
  385 + standardStandardized,
  386 + standardStandardizedName
  387 + }
  388 + this.fileInfo = { id: m.standardFileId || '', name: m.standardFileName || '' }
  389 + const lines = Array.isArray(m.contractDistributorLineList) ? m.contractDistributorLineList : []
  390 + this.productLineList = lines
  391 + this.onProductsChange(lines)
  392 + } catch (e) { }
  393 + },
  394 + async initDestinationLabel() {
  395 + const comp = this.$refs.citySelectorRef
  396 + if (comp && typeof comp.getLabel === 'function') {
  397 + const label = await comp.getLabel()
  398 + this.form.destinationLabel = label || ''
  399 + }
  400 + },
  401 + openCitySelector() {
  402 + this.$refs.citySelectorRef && this.$refs.citySelectorRef.open()
  403 + },
  404 + onCityChange(payload) {
  405 + const label = payload && payload.label != null ? payload.label : ''
  406 + this.form.destinationLabel = label
  407 + },
  408 + onProductsChange(products) {
  409 + const list = Array.isArray(products) ? products : []
  410 + this.newProductLineList = list
  411 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  412 + const sumE = list.reduce((acc, it) => acc + (parseFloat(it.amountExcludingTax) || 0), 0)
  413 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  414 + this.totalQuantity = sumQ
  415 + this.totalAmountExcludingTax = sumE
  416 + this.totalAmountIncludingTax = sumT
  417 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  418 + },
  419 + async loadSuppliers() {
  420 + try {
  421 + const results = await getDicByCodes(['SUPPLIER'])
  422 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  423 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  424 + } catch (e) { this.supplierList = [] }
  425 + },
  426 + async loadExtraOptions() {
  427 + try {
  428 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  429 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  430 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  431 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  432 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  433 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  434 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  435 + } catch (e) {
  436 + this.specialTermsList = []
  437 + this.executionStandardList = []
  438 + this.productList = []
  439 + }
  440 + },
  441 + displayLabel(field) {
  442 + const m = this.form
  443 + const map = { supplierName: '请选择供方', buyerName: '请选择需方', workshopName: '请选择生产厂', regionName: '请选择区域' }
  444 + const val = m[field]
  445 + return val ? String(val) : map[field]
  446 + },
  447 + async openSheet(field) {
  448 + const setSheet = (title, options) => {
  449 + const current = this.form[field]
  450 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  451 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  452 + }
  453 + if (field === 'workshopId') {
  454 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  455 + const _data = res.data || {}
  456 + const list = _data.datas || (Array.isArray(_data) ? _data : [])
  457 + const opts = (list || []).map(it => ({
  458 + label: it.name ,
  459 + value: it.id
  460 + }))
  461 + setSheet('生产厂', opts)
  462 + } else if (field === 'supplier') {
  463 + setSheet('供方', this.supplierList)
  464 + } else if (field === 'specialTerms') {
  465 + setSheet('特别条款要求', this.specialTermsList)
  466 + } else if (field === 'executionStandard') {
  467 + setSheet('执行标准', this.executionStandardList)
  468 + } else if (field === 'includesPackagingFee') {
  469 + setSheet('单价中是否已包含包装费', this.yesNoList)
  470 + } else if (field === 'includesTransportFee') {
  471 + setSheet('单价中是否已包含运费', this.yesNoList)
  472 + } else if (field === 'standardStandardized') {
  473 + setSheet('合同是否规范', this.yesNoList)
  474 + } else if (field === 'region') {
  475 + setSheet('区域', this.regionOptions)
  476 + }
  477 + },
  478 + onSheetConfirm({ value, label }) {
  479 + const field = this.sheet.field
  480 + if (!field) return
  481 + const v = (value === undefined || value === null) ? '' : value
  482 + this.form[field] = v
  483 + this.form[field + 'Name'] = label || ''
  484 + },
  485 + openRelate(fieldKey) {
  486 + let config = {}
  487 + if (fieldKey === 'buyer') {
  488 + config = { title: '需方', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '名称', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  489 + } else if (fieldKey === 'stockUpCompanyId') {
  490 + config = { title: '备货单位/人(生产标准)', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  491 + }
  492 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  493 + this.sheet.visible = false
  494 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  495 + this.$nextTick(() => { this.relate.visible = true })
  496 + },
  497 + onRelateConfirm({ items }) {
  498 + const _fieldKey = this.relate.fieldKey
  499 + const first = (items && items.length > 0) ? items[0] : null
  500 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  501 + if (_fieldKey === 'stockUpCompanyId') {
  502 + this.form.stockUpCompanyName = (first && first.name) ? first.name : ''
  503 + } else {
  504 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  505 + }this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  506 + },
  507 + onRadioSelect(field, nameField, opt) {
  508 + const val = opt && opt.value != null ? opt.value : ''
  509 + const label = opt && opt.label != null ? opt.label : ''
  510 + this.form[field] = val
  511 + this.form[nameField] = label
  512 + if (field === 'executionStandard' && val !== 'OTHER') {
  513 + this.form.executionStandardRemarks = ''
  514 + }
  515 + },
  516 + validateRequired() {
  517 + const checks = [
  518 + { key: 'code', label: '编号' },
  519 + { key: 'supplier', label: '供方' },
  520 + { key: 'buyer', label: '需方' },
  521 + { key: 'orderDate', label: '订货日期' },
  522 + { key: 'unit', label: '单位' },
  523 + { key: 'workshopId', label: '生产厂' },
  524 + { key: 'specialTerms', label: '特别条款要求' },
  525 + { key: 'stockUpCompanyId', label: '备货单位/人(生产标准)' },
  526 + { key: 'region', label: '区域' },
  527 + ]
  528 + for (const it of checks) {
  529 + const val = this.form[it.key]
  530 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  531 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  532 + }
  533 + if (this.$refs.productRel && !this.$refs.productRel.validate()) return false
  534 + const list = Array.isArray(this.newProductLineList) ? this.newProductLineList : []
  535 + if (list.length === 0) {
  536 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  537 + }
  538 + const strEmpty = (v) => (v === undefined || v === null || (typeof v === 'string' && v.trim() === ''))
  539 + const numEmpty = (v) => (v === undefined || v === null || v === '' || (typeof v === 'number' && isNaN(v)))
  540 + for (const [idx, it] of list.entries()) {
  541 + console.log('it111', it)
  542 + if (
  543 + strEmpty(it.productName) ||
  544 + strEmpty(it.industry) ||
  545 + strEmpty(it.quality) ||
  546 + strEmpty(it.brand) ||
  547 + numEmpty(it.quantity) ||
  548 + numEmpty(it.unitPrice) ||
  549 + strEmpty(it.deliveryDate)
  550 + ) {
  551 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  552 + }
  553 + }
  554 + return true
  555 + },
  556 + async onSubmit() {
  557 + this.form.standardFileId = (this.fileInfo && this.fileInfo.id) ? this.fileInfo.id : ''
  558 + this.form.standardFileName = (this.fileInfo && this.fileInfo.name) ? this.fileInfo.name : ''
  559 + if (!this.fileInfo.id) {
  560 + uni.showToast({
  561 + title: '请上传合同附件',
  562 + icon: 'error'
  563 + })
  564 + return
  565 + }
  566 + if (!this.standardStandardized && this.standardStandardized !== false) {
  567 + uni.showToast({
  568 + title: '请选择合同是否规范',
  569 + icon: 'error'
  570 + })
  571 + return
  572 + }
  573 + if (!this.validateRequired()) return
  574 + const clean = (obj) => {
  575 + const out = {}
  576 + Object.keys(obj || {}).forEach(k => {
  577 + const v = obj[k]
  578 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  579 + const isUndef = v === undefined || v === null
  580 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  581 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  582 + })
  583 + return out
  584 + }
  585 + const lines = (this.newProductLineList || []).map(it => clean(it))
  586 + const { destinationLabel, destinationId, ...formForSubmit } = this.form;
  587 + const destination = destinationId && destinationId.length > 0 ? destinationId[destinationId.length - 1] : '';
  588 + const payload = clean({
  589 + ...formForSubmit,
  590 + id: this.form.id,
  591 + destination,
  592 + type: 'DISTRIB_STD',
  593 + totalQuantity: this.totalQuantity,
  594 + totalAmountExcludingTax: this.totalAmountExcludingTax,
  595 + totalAmountIncludingTax: this.totalAmountIncludingTax,
  596 + contractDistributorLineList: lines,
  597 + standardFileId: this.fileInfo.id,
  598 + standardFileName: this.fileInfo.name,
  599 + standardStandardized: this.standardStandardized,
  600 + })
  601 +
  602 + uni.showModal({
  603 + title: '确认提交',
  604 + content: '确定提交标准合同吗?',
  605 + success: async (res) => {
  606 + try {
  607 + await uploadStandardContract(payload)
  608 + uni.showToast({ title: '提交成功', icon: 'none' })
  609 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_retail/index' }) }, 400)
  610 + } catch (e) {
  611 + uni.showToast({ title: e.msg || '提交失败', icon: 'none' })
  612 + }
  613 + }
  614 + })
  615 + }
  616 + }
  617 +}
  618 +</script>
  619 +
  620 +<style lang="scss" scoped>
  621 +.total {
  622 + .total-text {
  623 + font-weight: 600;
  624 + font-size: 32rpx;
  625 + color: rgba(0, 0, 0, 0.9);
  626 + padding-bottom: 28rpx;
  627 + border-bottom: 2rpx solid #E7E7E7;
  628 + }
  629 +
  630 + .total-item {
  631 + display: flex;
  632 + align-items: center;
  633 + }
  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 +.page {
  657 + display: flex;
  658 + flex-direction: column;
  659 + height: 100%;
  660 +}
  661 +
  662 +.scroll {
  663 + flex: 1;
  664 + padding: 12rpx 0 392rpx !important;
  665 +}
  666 +
  667 +.footer {
  668 + z-index: 2;
  669 + position: fixed;
  670 + left: 0;
  671 + right: 0;
  672 + bottom: 0;
  673 + padding: 32rpx;
  674 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  675 + background: #fff;
  676 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  677 +}
  678 +
  679 +.footer .btn {
  680 + height: 80rpx;
  681 + line-height: 80rpx;
  682 + border-radius: 12rpx;
  683 + font-size: 32rpx;
  684 +}
  685 +
  686 +.footer .submit {
  687 + background: $theme-primary;
  688 + color: #fff;
  689 +}
  690 +
  691 +.group {
  692 + background: #fff;
  693 + padding: 24rpx 32rpx;
  694 + margin-bottom: 20rpx;
  695 +}
  696 +
  697 +.group-title {
  698 + color: rgba(0, 0, 0, 0.9);
  699 + font-size: 32rpx;
  700 + padding-bottom: 16rpx;
  701 +}
  702 +
  703 +.radio-list {
  704 + display: flex;
  705 + flex-direction: column;
  706 +}
  707 +.quality {
  708 + background-color: #fff;
  709 + display: flex;
  710 + align-items: center;
  711 + padding: 24rpx 32rpx;
  712 + border-bottom: 1rpx solid #f0f0f0;
  713 + margin-top: 20rpx;
  714 +
  715 + .title {
  716 + font-size: 32rpx;
  717 + color: rgba(0, 0, 0, 0.9);
  718 + font-weight: 600;
  719 + }
  720 +
  721 + .opCollapse {
  722 + color: rgba(0, 0, 0, 0.6);
  723 + width: 32rpx;
  724 + height: 28rpx;
  725 + margin-right: 16rpx;
  726 + }
  727 +}
  728 +
  729 +.radio-item {
  730 + display: flex;
  731 + align-items: center;
  732 + padding: 24rpx 0;
  733 + border-bottom: 1rpx solid #f0f0f0;
  734 +}
  735 +
  736 +.radio-item:last-child {
  737 + border-bottom: none;
  738 +}
  739 +
  740 +.radio {
  741 + width: 32rpx;
  742 + height: 32rpx;
  743 + border-radius: 50%;
  744 + border: 2rpx solid #DCDCDC;
  745 + margin-right: 20rpx;
  746 + box-sizing: border-box;
  747 +}
  748 +
  749 +.radio.checked {
  750 + background: $theme-primary;
  751 + border-color: $theme-primary;
  752 +}
  753 +
  754 +.radio-item .label {
  755 + font-size: 32rpx;
  756 + color: rgba(0, 0, 0, 0.9);
  757 +}
  758 +
  759 +::v-deep .uni-list {
  760 + background: transparent;
  761 +}
  762 +
  763 +::v-deep .uni-list .uni-easyinput .uni-input-input {
  764 + color: rgba(0, 0, 0, 0.9);
  765 +}
  766 +
  767 +::v-deep .uni-list .uni-input-placeholder {
  768 + z-index: 1;
  769 +}
  770 +
  771 +::v-deep .uni-list .uni-input-input {
  772 + background-color: #ffffff;
  773 +}
  774 +
  775 +::v-deep .uni-list-item__extra-text {
  776 + font-size: 32rpx;
  777 +}
  778 +
  779 +::v-deep .uni-list-item__content-title {
  780 + font-size: 32rpx;
  781 + color: rgba(0, 0, 0, 0.9);
  782 +}
  783 +
  784 +::v-deep .uni-list-item__container {
  785 + padding: 32rpx;
  786 +}
  787 +
  788 +::v-deep .uni-list-item__container .uni-easyinput__placeholder-class {
  789 + font-size: 32rpx;
  790 + color: rgba(0, 0, 0, 0.4);
  791 +}
  792 +
  793 +::v-deep .uni-list-item__container .uni-easyinput__content {
  794 + border: none;
  795 + background-color: #ffffff !important;
  796 +}
  797 +
  798 +::v-deep .uni-list-item__container .uni-easyinput__content-input {
  799 + padding-left: 0 !important;
  800 + height: 48rpx;
  801 + line-height: 48rpx;
  802 + font-size: 32rpx;
  803 +}
  804 +
  805 +::v-deep .uni-list-item__container .uni-easyinput__content .content-clear-icon {
  806 + font-size: 44rpx !important;
  807 +}
  808 +
  809 +::v-deep .uni-list-item__container .item-title,
  810 +::v-deep .uni-list-item__container .uni-list-item__content {
  811 + flex: none;
  812 + min-height: 48rpx;
  813 + line-height: 48rpx;
  814 + font-size: 32rpx;
  815 + position: relative;
  816 + width: 210rpx;
  817 + margin-right: 32rpx;
  818 + color: rgba(0, 0, 0, 0.9);
  819 +}
  820 +
  821 +::v-deep .uni-list-item__container .item-title .required {
  822 + color: red;
  823 + position: absolute;
  824 + top: 50%;
  825 + transform: translateY(-50%);
  826 + left: -16rpx;
  827 +}
  828 +
  829 +::v-deep .uni-list-item.select-item.is-empty .uni-list-item__extra-text {
  830 + color: rgba(0, 0, 0, 0.4) !important;
  831 +}
  832 +
  833 +::v-deep .uni-list-item.select-item.is-filled .uni-list-item__extra-text {
  834 + color: rgba(0, 0, 0, 0.9) !important;
  835 +}
  836 +::v-deep .uni-easyinput {
  837 + &__placeholder-class {
  838 + font-size: 32rpx;
  839 + color: rgba(0, 0, 0, 0.4);
  840 + }
  841 +
  842 + &__content {
  843 + border: none;
  844 + background-color: #ffffff !important;
  845 + height: 100%;
  846 + &-input {
  847 + padding-left: 0 !important;
  848 + height: 48rpx;
  849 + line-height: 48rpx;
  850 + font-size: 32rpx;
  851 + }
  852 +
  853 + .content-clear-icon {
  854 + font-size: 44rpx !important;
  855 + }
  856 + }
  857 + }
  858 +
  859 +</style>
... ...