Commit 6d179fa86bef9ef35f95e5d41474acc9d8caa44c

Authored by gesilong
1 parent 3fe2cf72

commit: 锁规锁价功能

... ... @@ -84,6 +84,15 @@ export function getRetailCodeApi() {
84 84 })
85 85 }
86 86
  87 +//获取锁规信息
  88 +export function showContract(id) {
  89 + return request({
  90 + url: `${baseUrl}/specLockDelayApplication/showContract`,
  91 + method: 'get',
  92 + params: { id }
  93 + })
  94 +}
  95 +
87 96 // 新增合同
88 97 export function createContractApi(data) {
89 98 return request({
... ... @@ -93,6 +102,15 @@ export function createContractApi(data) {
93 102 contentType: ContentTypeEnum.JSON
94 103 })
95 104 }
  105 +// 申请延期锁规
  106 +export function specLockDelayApplication(data) {
  107 + return request({
  108 + url: `${baseUrl}/specLockDelayApplication`,
  109 + method: 'post',
  110 + data,
  111 + contentType: ContentTypeEnum.JSON
  112 + })
  113 +}
96 114 // 上传标准合同
97 115 export function uploadStandardContract(data) {
98 116 return request({
... ... @@ -113,6 +131,36 @@ export function uploadFormalContract(data) {
113 131 region
114 132 })
115 133 }
  134 +// 上传双方盖章合同
  135 +export function uploadSignedContractFile(data) {
  136 + return request({
  137 + url: `${baseUrl}/contractDistributorStandard/uploadSignedContractFile`,
  138 + method: 'post',
  139 + data,
  140 + contentType: ContentTypeEnum.JSON,
  141 + region
  142 + })
  143 +}
  144 +// 锁规
  145 +export function specificationLock(data) {
  146 + return request({
  147 + url: `${baseUrl}/contractDistributorStandard/specificationLock`,
  148 + method: 'post',
  149 + data,
  150 + contentType: ContentTypeEnum.JSON,
  151 + region
  152 + })
  153 +}
  154 +// 锁价
  155 +export function priceLock(data) {
  156 + return request({
  157 + url: `${baseUrl}/contractDistributorStandard/priceLock`,
  158 + method: 'post',
  159 + data,
  160 + contentType: ContentTypeEnum.JSON,
  161 + region
  162 + })
  163 +}
116 164
117 165 // 删除合同
118 166 export function deleteContractApi(id) {
... ...
... ... @@ -242,6 +242,13 @@
242 242 "navigationBarTextStyle": "black"
243 243 }
244 244 },{
  245 + "path": "pages/contract_stock/lock",
  246 + "style": {
  247 + "navigationBarTitleText": "锁价",
  248 + "navigationBarBackgroundColor": "#ffffff",
  249 + "navigationBarTextStyle": "black"
  250 + }
  251 + },{
245 252 "path": "pages/contract_unplan/index",
246 253 "style": {
247 254 "navigationBarTitleText": "经销未锁规合同",
... ... @@ -269,7 +276,21 @@
269 276 "navigationBarBackgroundColor": "#ffffff",
270 277 "navigationBarTextStyle": "black"
271 278 }
  279 + },{
  280 + "path": "pages/contract_unplan/lock",
  281 + "style": {
  282 + "navigationBarTitleText": "锁规",
  283 + "navigationBarBackgroundColor": "#ffffff",
  284 + "navigationBarTextStyle": "black"
  285 + }
272 286 }, {
  287 + "path": "pages/contract_unplan/lock_apply",
  288 + "style": {
  289 + "navigationBarTitleText": "锁规延期申请",
  290 + "navigationBarBackgroundColor": "#ffffff",
  291 + "navigationBarTextStyle": "black"
  292 + }
  293 + },{
273 294 "path": "pages/contract_process/index",
274 295 "style": {
275 296 "navigationBarTitleText": "加工标准合同",
... ... @@ -353,7 +374,14 @@
353 374 "navigationBarBackgroundColor": "#ffffff",
354 375 "navigationBarTextStyle": "black"
355 376 }
356   - }, {
  377 + },{
  378 + "path": "pages/contract_foreign_stock/lock",
  379 + "style": {
  380 + "navigationBarTitleText": "锁价",
  381 + "navigationBarBackgroundColor": "#ffffff",
  382 + "navigationBarTextStyle": "black"
  383 + }
  384 + },{
357 385 "path": "pages/contract_foreign_unplan/index",
358 386 "style": {
359 387 "navigationBarTitleText": "外贸未锁规合同",
... ... @@ -381,6 +409,20 @@
381 409 "navigationBarBackgroundColor": "#ffffff",
382 410 "navigationBarTextStyle": "black"
383 411 }
  412 + },{
  413 + "path": "pages/contract_foreign_unplan/lock",
  414 + "style": {
  415 + "navigationBarTitleText": "锁规",
  416 + "navigationBarBackgroundColor": "#ffffff",
  417 + "navigationBarTextStyle": "black"
  418 + }
  419 + },{
  420 + "path": "pages/contract_foreign_unplan/lock_apply",
  421 + "style": {
  422 + "navigationBarTitleText": "锁规延期申请",
  423 + "navigationBarBackgroundColor": "#ffffff",
  424 + "navigationBarTextStyle": "black"
  425 + }
384 426 }
385 427 ],
386 428 "subPackages": [{
... ...
... ... @@ -76,7 +76,7 @@
76 76 <uni-popup ref="uploadPopup" type="bottom" :mask-click="false" :safe-area="true">
77 77 <view class="upload-dialog">
78 78 <view class="upload-header">
79   - <text class="title">上传规范性合同</text>
  79 + <text class="title">{{ uploadType === 'standard' ? '上传规范性合同' : '上传双方盖章合同' }}</text>
80 80 <uni-icons type="closeempty" style="position: absolute; right: 16px;" size="22" @click="$refs.uploadPopup.close()" />
81 81 </view>
82 82 <view class="upload-body">
... ... @@ -85,7 +85,7 @@
85 85 <FileUpload v-model="fileInfo" />
86 86 </view>
87 87 <view v-if="fileInfo && fileInfo.name" class="upload-show">{{ fileInfo.name }}</view>
88   - <view class="row1" @click="openStandardizedSheet">
  88 + <view class="row1" @click="openStandardizedSheet" v-if="uploadType === 'standard'">
89 89 <view class="label1">合同是否规范</view>
90 90 <uni-icons type="right" size="18" v-if="!standardStandardizedName" ></uni-icons>
91 91 <view class="value" v-else >{{standardStandardizedName}}</view>
... ... @@ -101,7 +101,7 @@
101 101 </template>
102 102
103 103 <script>
104   -import { getContractApi, deleteContractApi, uploadStandardContract } from '@/api/contract'
  104 +import { getContractApi, deleteContractApi, uploadStandardContract, uploadSignedContractFile } from '@/api/contract'
105 105 import ProductRel from './productRel.vue'
106 106 import DetailButtons from '@/components/detail-buttons/index.vue'
107 107 import FileUpload from '@/components/file-upload/index.vue'
... ... @@ -113,6 +113,7 @@ export default {
113 113 return {
114 114 id: '',
115 115 uploadId: '',
  116 + uploadType: 'standard',
116 117 fileInfo: { id: '', name: '' },
117 118 yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
118 119 standardStandardized: '',
... ... @@ -178,6 +179,12 @@ export default {
178 179 event: 'upload'
179 180 },
180 181 {
  182 + text: '上传双方盖章合同',
  183 + visible: true,
  184 + variant: 'outline',
  185 + event: 'uploadSeal'
  186 + },
  187 + {
181 188 text: '审核',
182 189 visible: true,
183 190 variant: 'primary',
... ... @@ -201,8 +208,8 @@ export default {
201 208 // { ...this.buttons[0], visible: (s === 'DRAFT') },
202 209 { ...this.buttons[1], visible: (s === 'DRAFT') },
203 210 { ...this.buttons[2], visible: (s !== 'DELETED' && t !== 'AUDIT' && t !== 'PASS') },
204   - { ...this.buttons[3], visible: (s === 'STANDARD' && t === 'AUDIT') },
205   - { ...this.buttons[4], visible: (s === 'STANDARD') }
  211 + { ...this.buttons[3], visible: (s === 'STANDARD') },
  212 + // { ...this.buttons[4], visible: (s === 'STANDARD') }
206 213 ]
207 214 }
208 215 },
... ... @@ -245,9 +252,10 @@ export default {
245 252 url: '/pages/contract_foreign_std/modify' + query
246 253 })
247 254 },
248   - uploadContract(id){
  255 + uploadContract(id, type = 'standard'){
249 256 if (!id) return
250 257 this.uploadId = id
  258 + this.uploadType = type
251 259 this.$refs.uploadPopup.open()
252 260 },
253 261 onUploadSubmit() {
... ... @@ -258,27 +266,32 @@ export default {
258 266 })
259 267 return
260 268 }
261   - if (!this.standardStandardized) {
  269 + if (!this.standardStandardized && this.uploadType === 'standard') {
262 270 uni.showToast({
263 271 title: '请选择合同是否规范',
264 272 icon: 'error'
265 273 })
266 274 return
267 275 }
268   - const data = {
  276 + const data = this.uploadType === 'standard' ? {
269 277 id: this.id,
270 278 standardFileId: this.fileInfo.id,
271 279 standardFileName: this.fileInfo.name,
272 280 standardStandardized: this.standardStandardized
  281 + } : {
  282 + id: this.id,
  283 + signedContractFileId: this.fileInfo.id,
  284 + signedContractFileName: this.fileInfo.name,
273 285 }
  286 + const api = this.uploadType === 'standard' ? uploadStandardContract : uploadSignedContractFile
274 287 uni.showModal({
275 288 title: '确认提交',
276   - content: '确定提交标准合同吗?',
  289 + content: '确定提交' + (this.uploadType === 'standard' ? '标准合同' : '双方盖章合同') + '吗?',
277 290 success: (res) => {
278 291 if (res.confirm) {
279   - uploadStandardContract({...this.detail, ...data}).then(() => {
  292 + api({...this.detail, ...data}).then(() => {
280 293 uni.showToast({
281   - title: '上传标准合同成功',
  294 + title: '上传' + (this.uploadType === 'standard' ? '标准合同' : '双方盖章合同') + '成功',
282 295 icon: 'success'
283 296 })
284 297 setTimeout(() => {
... ... @@ -314,6 +327,7 @@ export default {
314 327 if (e === 'edit') return this.onEdit(btn && btn.params)
315 328 if (e === 'delete') return this.onDelete(btn && btn.params)
316 329 if (e === 'upload') return this.uploadContract(this.detail.id || '')
  330 + if (e === 'uploadSeal') return this.uploadContract(this.detail.id || '', 'seal')
317 331 // if (e === 'audit') return this.onAudit(btn && btn.params)
318 332 // if (e === 'auditDetail') return this.onAuditDetail(btn && btn.params)
319 333 },
... ...
... ... @@ -179,6 +179,12 @@ export default {
179 179 }
180 180 },
181 181 {
  182 + text: '锁价',
  183 + visible: true,
  184 + variant: 'outline',
  185 + event: 'lock'
  186 + },
  187 + {
182 188 text: '上传正式合同附件',
183 189 visible: true,
184 190 variant: 'outline',
... ... @@ -215,13 +221,15 @@ export default {
215 221 displayButtons() {
216 222 const s = this.detail && this.detail.status || ''
217 223 const t = this.detail.standardApproved || ''
  224 + const l = this.detail.priceSpecLocked || ''
218 225 return [
219 226 { ...this.buttons[0]},
220 227 // { ...this.buttons[0], visible: (s === 'DRAFT') },
221 228 { ...this.buttons[1], visible: (s === 'DRAFT') },
222   - { ...this.buttons[2], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
223   - { ...this.buttons[3], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  229 + { ...this.buttons[2], visible: (s === 'FORMAL' && !l) },
  230 + { ...this.buttons[3], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
224 231 { ...this.buttons[4], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  232 + { ...this.buttons[5], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
225 233 ]
226 234 }
227 235 },
... ... @@ -333,12 +341,18 @@ export default {
333 341 const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
334 342 this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, value: match ? match.value : '' }
335 343 },
  344 + onLock() {
  345 + uni.navigateTo({
  346 + url: '/pages/contract_foreign_stock/lock?id=' + this.detail.id || ''
  347 + })
  348 + },
336 349 handleButtonClick(btn) {
337 350 if (!btn || btn.disabled) return
338 351 if (typeof btn.onClick === 'function') return btn.onClick(this.detail, btn.params)
339 352 const e = btn.event || ''
340 353 if (e === 'edit') return this.onEdit(btn && btn.params)
341 354 if (e === 'delete') return this.onDelete(btn && btn.params)
  355 + if (e === 'lock') return this.onLock()
342 356 if (e === 'upload') return this.uploadContract(this.detail.id || '')
343 357 if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '')
344 358 if (e === 'uploadStandard') return this.uploadContract(this.detail.id || '', 'standard')
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="lock-page">
  5 + <view class="block" v-for="(item, idx) in items" :key="idx">
  6 + <view class="block-header">
  7 + <uni-data-checkbox
  8 + multiple
  9 + mode="default"
  10 + :localdata="[{ text: '锁价', value: 'LOCKED' }]"
  11 + :modelValue="item.locked ? ['LOCKED'] : []"
  12 + :disabled="true"
  13 + @change="onLockChange(idx, $event)"
  14 + />
  15 + <view class="ops" @click="toggleItem(idx)">
  16 + <image class="opIcon"
  17 + :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" />
  18 + <text class="opText">{{ item.collapsed ? '收起' : '展开' }}</text>
  19 + </view>
  20 + </view>
  21 +
  22 + <uni-list v-show="item.collapsed">
  23 + <uni-list-item title="产品名称">
  24 + <template v-slot:footer>
  25 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  26 + </template>
  27 + </uni-list-item>
  28 + <uni-list-item title="行业">
  29 + <template v-slot:footer>
  30 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  31 + </template>
  32 + </uni-list-item>
  33 + <uni-list-item title="牌号">
  34 + <template v-slot:footer>
  35 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  36 + </template>
  37 + </uni-list-item>
  38 + <uni-list-item title="品质">
  39 + <template v-slot:footer>
  40 + <uni-easyinput v-model="item.quality" placeholder="请输入品质" :clearable="false" disabled />
  41 + </template>
  42 + </uni-list-item>
  43 + <uni-list-item title="规格">
  44 + <template v-slot:footer>
  45 + <uni-easyinput v-model="item.specDisplay" placeholder="自动拼接规格" :clearable="false" disabled />
  46 + </template>
  47 + </uni-list-item>
  48 + <uni-list-item title="状态">
  49 + <template v-slot:footer>
  50 + <uni-easyinput v-model="item.status" placeholder="请输入状态" :clearable="false" disabled />
  51 + </template>
  52 + </uni-list-item>
  53 + <uni-list-item title="数量">
  54 + <template v-slot:footer>
  55 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" disabled placeholder="不可编辑" />
  56 + </template>
  57 + </uni-list-item>
  58 + <uni-list-item title="单价">
  59 + <template v-slot:footer>
  60 + <uni-easyinput v-model="item.unitPrice" type="number" :inputBorder="false" placeholder="请输入单价" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'unitPrice', 0)" />
  61 + </template>
  62 + </uni-list-item>
  63 + <uni-list-item title="不含税金额">
  64 + <template v-slot:footer>
  65 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  66 + </template>
  67 + </uni-list-item>
  68 + <uni-list-item title="总金额">
  69 + <template v-slot:footer>
  70 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  71 + </template>
  72 + </uni-list-item>
  73 + <uni-list-item title="发货日期">
  74 + <template v-slot:footer>
  75 + <uni-easyinput v-model="item.deliveryDate" :inputBorder="false" disabled />
  76 + </template>
  77 + </uni-list-item>
  78 + </uni-list>
  79 +
  80 + <uni-list v-show="!item.collapsed">
  81 + <uni-list-item title="产品名称">
  82 + <template v-slot:footer>
  83 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  84 + </template>
  85 + </uni-list-item>
  86 + <uni-list-item title="行业">
  87 + <template v-slot:footer>
  88 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  89 + </template>
  90 + </uni-list-item>
  91 + <uni-list-item title="牌号">
  92 + <template v-slot:footer>
  93 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  94 + </template>
  95 + </uni-list-item>
  96 + </uni-list>
  97 + </view>
  98 + </view>
  99 + </scroll-view>
  100 +
  101 + <view class="footer">
  102 + <div class="total">
  103 + <div class="total-text">
  104 + 合计
  105 + </div>
  106 + <div class="total-item">
  107 + <div class="total-item-text">
  108 + 数量
  109 + </div>
  110 + <div class="total-item-price">
  111 + {{ (sumQuantity || 0).toFixed(2) }}t
  112 + </div>
  113 + </div>
  114 + <div class="total-item">
  115 + <div class="total-item-text">
  116 + 不含税金额
  117 + </div>
  118 + <div class="total-item-price text-red">
  119 + ¥{{ (sumAmountExcl || 0).toFixed(2) }}
  120 + </div>
  121 + </div>
  122 + <div class="total-item">
  123 + <div class="total-item-text">
  124 + 总金额
  125 + </div>
  126 + <div class="total-item-price text-red">
  127 + ¥{{ (sumTotal || 0).toFixed(2) }}
  128 + </div>
  129 + </div>
  130 + </div>
  131 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  132 + </view>
  133 + </view>
  134 +</template>
  135 +
  136 +<script>
  137 +import { getContractApi, priceLock } from '@/api/contract'
  138 +import { formatCurrencyToChinese } from '@/utils/common'
  139 +
  140 +export default {
  141 + name: 'ContractUnplanLock',
  142 + data() {
  143 + return {
  144 + id: '',
  145 + items: [],
  146 + planQty: 30,
  147 + }
  148 + },
  149 + computed: {
  150 + sumQuantity() {
  151 + const qty = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.quantity), 0)
  152 + return this.round(qty, 2)
  153 + },
  154 + sumAmountExcl() {
  155 + const sum = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.amountExcludingTax), 0)
  156 + return this.round(sum, 2)
  157 + },
  158 + sumTotal() { return this.totalAmount },
  159 + totalAmount() {
  160 + let sum = 0
  161 + for (const it of this.items) {
  162 + if (!it.locked) continue
  163 + sum += this.toNumber(it.quantity) * this.toNumber(it.unitPrice)
  164 + }
  165 + return this.round(sum, 2)
  166 + },
  167 + totalExclTax() {
  168 + const TAX_RATE = 0.13
  169 + const total = this.totalAmount
  170 + return this.round(total / (1 + TAX_RATE), 2)
  171 + },
  172 + totalQtyDisplay() {
  173 + const qty = this.round(this.items.reduce((p, c) => p + this.toNumber(c.quantity), 0), 3)
  174 + return `${qty}t/${this.planQty}t`
  175 + }
  176 + },
  177 + onLoad(options) {
  178 + const id = options && options.id ? options.id : ''
  179 + this.id = id
  180 + this.loadDetail()
  181 + },
  182 + methods: {
  183 + onLockChange(idx, e) {
  184 + const it = this.items[idx]
  185 + if (!it) return
  186 + const arr = e && e.detail && e.detail.value ? e.detail.value : []
  187 + it.locked = Array.isArray(arr) && arr.length > 0
  188 + this.$set(this.items, idx, it)
  189 + },
  190 + async loadDetail() {
  191 + if (!this.id) return
  192 + try {
  193 + const res = await getContractApi(this.id)
  194 + const data = res && res.data ? res.data : {}
  195 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  196 + const init = lines.map(v => ({
  197 + locked: true,
  198 + collapsed: true,
  199 + raw: v,
  200 + productName: v.rawProductName || v.productName || '',
  201 + industry: v.industry || '',
  202 + brand: v.rawProductGrade || v.brand || '',
  203 + quality: v.quality || '',
  204 + thickness: v.thickness || '',
  205 + thicknessTolPos: v.thicknessTolPos || '',
  206 + thicknessTolNeg: v.thicknessTolNeg || '',
  207 + width: v.width || '',
  208 + widthTolPos: v.widthTolPos || '',
  209 + widthTolNeg: v.widthTolNeg || '',
  210 + length: v.length || '',
  211 + lengthTolPos: v.lengthTolPos || '',
  212 + lengthTolNeg: v.lengthTolNeg || '',
  213 + status: v.status || '',
  214 + quantity: v.productQuantity || v.quantity || '',
  215 + unitPrice: v.unitPrice || '',
  216 + amountExcludingTax: v.amountExcludingTax || 0,
  217 + totalAmount: v.totalAmount || 0,
  218 + deliveryDate: v.deliveryDate || '',
  219 + specDisplay: ''
  220 + }))
  221 + this.items = init.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  222 + this.recalculateAll()
  223 + } catch (e) {
  224 + this.items = []
  225 + }
  226 + },
  227 + toggleItem(idx) {
  228 + const it = this.items[idx]
  229 + if (!it) return
  230 + it.collapsed = !it.collapsed
  231 + this.$set(this.items, idx, it)
  232 + },
  233 + onImmediateChange(idx) {
  234 + this.$nextTick(() => this.recalculate(idx))
  235 + },
  236 + onNumberBlur(idx, field, digits) {
  237 + const it = this.items[idx]
  238 + if (!it) return
  239 + const raw = it[field]
  240 + if (raw === '' || raw === null || raw === undefined) {
  241 + this.$set(this.items, idx, it)
  242 + this.recalculate(idx)
  243 + return
  244 + }
  245 + const num = this.toNumber(raw)
  246 + const rounded = this.round(num, digits)
  247 + it[field] = rounded
  248 + this.$set(this.items, idx, it)
  249 + this.recalculate(idx)
  250 + },
  251 + recalculate(idx) {
  252 + const TAX_RATE = 0.13
  253 + const it = this.items[idx]
  254 + if (!it) return
  255 + const qty = this.toNumber(it.quantity)
  256 + const price = this.toNumber(it.unitPrice)
  257 + const total = this.round(qty * price, 2)
  258 + const excl = this.round(total / (1 + TAX_RATE), 2)
  259 + it.amountExcludingTax = excl
  260 + it.totalAmount = total
  261 + this.$set(this.items, idx, it)
  262 + },
  263 + recalculateAll() {
  264 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
  265 + },
  266 + toNumber(val) {
  267 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  268 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  269 + return isNaN(n) ? 0 : n
  270 + },
  271 + round(val, digits = 2) {
  272 + const n = Number(val)
  273 + if (isNaN(n)) return 0
  274 + const m = Math.pow(10, digits)
  275 + return Math.round(n * m) / m
  276 + },
  277 + specOf(item) {
  278 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/ ')
  279 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/ ')
  280 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/ ')
  281 + return [t, w, l].filter(Boolean).join(' × ')
  282 + },
  283 + formatCurrency(val) {
  284 + if (val == null || val === '') return ''
  285 + const num = Number(val)
  286 + const pre = isNaN(num) ? '' : '¥'
  287 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  288 + return `${pre}${fixed}`
  289 + },
  290 + onReset() {
  291 + this.items = this.items.map((it, i) => ({
  292 + ...it,
  293 + quantity: '',
  294 + unitPrice: '',
  295 + amountExcludingTax: 0
  296 + }))
  297 + },
  298 + async onSubmit() {
  299 + const selected = this.items.filter(it => it.locked).map(it => {
  300 + const raw = { ...(it.raw || {}) }
  301 + const qty = this.toNumber(it.quantity)
  302 + const price = this.toNumber(it.unitPrice)
  303 + const total = this.toNumber(it.totalAmount)
  304 + const excl = this.toNumber(it.amountExcludingTax)
  305 + if (Object.prototype.hasOwnProperty.call(raw, 'productQuantity')) raw.productQuantity = qty
  306 + else raw.quantity = qty
  307 + raw.unitPrice = price
  308 + raw.totalAmount = total
  309 + raw.amountExcludingTax = excl
  310 + return raw
  311 + })
  312 + if (!selected.length) {
  313 + uni.showToast({ title: '未选择任何锁价项', icon: 'none' })
  314 + return
  315 + }
  316 + const invalid = selected.find(r => {
  317 + const p = this.toNumber(r.unitPrice)
  318 + return !( p > 0)
  319 + })
  320 + if (invalid) {
  321 + uni.showToast({ title: '请填写单价', icon: 'none' })
  322 + return
  323 + }
  324 + this.selectedItems = selected
  325 + const payload = {
  326 + id: this.id,
  327 + totalAmountCapital: formatCurrencyToChinese(this.sumTotal),
  328 + totalAmountExcludingTax: this.sumAmountExcl,
  329 + totalAmountIncludingTax: this.sumTotal,
  330 + totalQuantity: this.sumQuantity,
  331 + type:'INTL_INVENTORY_AGMT',
  332 + contractDistributorLineList: selected
  333 + }
  334 +
  335 + uni.showModal({
  336 + title: '确认提交',
  337 + content: '确定提交锁价吗?',
  338 + success: (res) => {
  339 + if (res.confirm) {
  340 + priceLock(payload).then(() => {
  341 + uni.showToast({ title: '锁价已提交', icon: 'success' })
  342 + setTimeout(() => {
  343 + uni.navigateTo({ url: '/pages/contract_foreign_stock/index' })
  344 + }, 500)
  345 + }).catch(() => {
  346 + uni.showToast({ title: '提交失败', icon: 'none' })
  347 + })
  348 + }
  349 + }
  350 + })
  351 + }
  352 + }
  353 +}
  354 +</script>
  355 +
  356 +<style lang="scss" scoped>
  357 +.page {
  358 + display: flex;
  359 + flex-direction: column;
  360 + height: 100%;
  361 +}
  362 +
  363 +.scroll {
  364 + flex: 1;
  365 + padding: 12rpx 0 480rpx !important;
  366 +}
  367 +
  368 +.header {
  369 + background-color: #fff;
  370 + display: flex;
  371 + align-items: center;
  372 + padding: 24rpx 32rpx;
  373 + border-bottom: 1rpx solid #f0f0f0;
  374 +}
  375 +
  376 +.title {
  377 + font-size: 32rpx;
  378 + color: rgba(0, 0, 0, 0.9);
  379 + font-weight: 600;
  380 +}
  381 +
  382 +.opCollapse {
  383 + width: 24rpx;
  384 + height: 24rpx;
  385 + margin-right: 16rpx;
  386 + margin-top: 8rpx;
  387 +}
  388 +
  389 +.block {
  390 + background: #fff;
  391 + margin-top: 20rpx;
  392 +}
  393 +
  394 +.block-header {
  395 + display: flex;
  396 + align-items: center;
  397 + padding: 24rpx 32rpx;
  398 + border-bottom: 1rpx solid #f0f0f0;
  399 +}
  400 +
  401 +.block-header ::v-deep .uni-data-checklist .checkbox__inner {
  402 + width: 36rpx;
  403 + height: 36rpx;
  404 +}
  405 +.block-header ::v-deep .uni-data-checklist .checklist-text {
  406 + font-size: 28rpx;
  407 + margin-left: 12rpx;
  408 +}
  409 +
  410 +.block-title {
  411 + margin-left: 12rpx;
  412 + font-size: 28rpx;
  413 + color: rgba(0, 0, 0, 0.9);
  414 +}
  415 +
  416 +.ops {
  417 + margin-left: auto;
  418 + display: flex;
  419 + align-items: center;
  420 + color: $theme-primary;
  421 + font-size: 28rpx;
  422 +}
  423 +
  424 +.opIcon {
  425 + width: 40rpx;
  426 + height: 40rpx;
  427 +}
  428 +
  429 +.opText {
  430 + margin-left: 8rpx;
  431 + color: $theme-primary;
  432 +}
  433 +
  434 +::v-deep .uni-list {
  435 + .uni-easyinput {
  436 + display: flex;
  437 +
  438 + .uni-input-input {
  439 + color: rgba(0, 0, 0, 0.9);
  440 + }
  441 + }
  442 +
  443 + .uni-input-placeholder {
  444 + z-index: 1;
  445 + }
  446 +
  447 + .uni-input-input {
  448 + background-color: #ffffff;
  449 + }
  450 +
  451 + background: transparent;
  452 +
  453 + &-item {
  454 + &__extra-text {
  455 + font-size: 32rpx;
  456 + }
  457 +
  458 + &__content-title {
  459 + font-size: 32rpx;
  460 + color: rgba(0, 0, 0, 0.9);
  461 + }
  462 +
  463 + &__container {
  464 + padding: 32rpx;
  465 +
  466 + .uni-easyinput {
  467 + &__placeholder-class {
  468 + font-size: 32rpx;
  469 + color: rgba(0, 0, 0, 0.4);
  470 + }
  471 +
  472 + &__content {
  473 + border: none;
  474 + background-color: #ffffff !important;
  475 +
  476 + &-input {
  477 + padding-left: 0 !important;
  478 + height: 48rpx;
  479 + line-height: 48rpx;
  480 + font-size: 32rpx;
  481 + }
  482 +
  483 + .content-clear-icon {
  484 + font-size: 44rpx !important;
  485 + }
  486 + }
  487 + }
  488 +
  489 + .item-title,
  490 + .uni-list-item__content {
  491 + flex: none;
  492 + min-height: 48rpx;
  493 + line-height: 48rpx;
  494 + font-size: 32rpx;
  495 + position: relative;
  496 + width: 162rpx;
  497 + margin-right: 32rpx;
  498 + color: rgba(0, 0, 0, 0.9);
  499 +
  500 + .required {
  501 + color: red;
  502 + position: absolute;
  503 + top: 50%;
  504 + transform: translateY(-50%);
  505 + left: -16rpx;
  506 + }
  507 + }
  508 + }
  509 +
  510 + &.select-item {
  511 + &.is-empty {
  512 + .uni-list-item__extra-text {
  513 + color: rgba(0, 0, 0, 0.4) !important;
  514 + }
  515 + }
  516 +
  517 + &.is-filled {
  518 + .uni-list-item__extra-text {
  519 + color: rgba(0, 0, 0, 0.9) !important;
  520 + }
  521 + }
  522 + }
  523 +
  524 + &.mgb10 {
  525 + margin-bottom: 20rpx;
  526 + }
  527 + }
  528 +}
  529 +
  530 +// ::v-deep .uni-list-item__container {
  531 +// padding: 32rpx;
  532 +// }
  533 +
  534 +::v-deep .is-disabled {
  535 + background-color: transparent !important;
  536 +}
  537 +// ::v-deep .uni-list-item__content-title {
  538 +// font-size: 28rpx;
  539 +// color: rgba(0, 0, 0, 0.9);
  540 +// }
  541 +
  542 +// ::v-deep .uni-list-item__extra-text {
  543 +// font-size: 32rpx;
  544 +// }
  545 +
  546 +::v-deep .uni-easyinput {
  547 + width: 100%;
  548 +}
  549 +
  550 +::v-deep .uni-easyinput__placeholder-class {
  551 + font-size: 32rpx;
  552 + color: rgba(0, 0, 0, 0.4);
  553 +}
  554 +
  555 +::v-deep .uni-easyinput__content {
  556 + border: none;
  557 + display: flex;
  558 +}
  559 +
  560 +::v-deep .uni-easyinput__content-input {
  561 + padding-left: 0 !important;
  562 + height: 48rpx;
  563 + line-height: 48rpx;
  564 + font-size: 32rpx;
  565 + color: rgba(0, 0, 0, 0.9);
  566 +}
  567 +
  568 +.amount-item .item-title {
  569 + display: flex;
  570 + align-items: center;
  571 +}
  572 +
  573 +.amount-row {
  574 + display: flex;
  575 + align-items: center;
  576 +}
  577 +
  578 +.amount-row .unit {
  579 + margin-left: 12rpx;
  580 + color: rgba(0, 0, 0, 0.6);
  581 +}
  582 +
  583 +.summary {
  584 + margin-top: 20rpx;
  585 + background: #fff;
  586 + padding-bottom: 12rpx;
  587 +}
  588 +
  589 +.title-header {
  590 + display: flex;
  591 + align-items: center;
  592 + padding: 20rpx 32rpx;
  593 +}
  594 +
  595 +.title-header_icon {
  596 + width: 24rpx;
  597 + height: 24rpx;
  598 + margin-right: 16rpx;
  599 +}
  600 +
  601 +.sum-card {
  602 + background: #f3f3f3;
  603 + border-radius: 16rpx;
  604 + padding: 24rpx;
  605 + margin: 0 32rpx 20rpx;
  606 +}
  607 +
  608 +.row {
  609 + display: flex;
  610 + margin-bottom: 16rpx;
  611 +}
  612 +
  613 +.row .label {
  614 + width: 140rpx;
  615 + color: rgba(0, 0, 0, 0.6);
  616 + font-size: 28rpx;
  617 +}
  618 +
  619 +.row .value {
  620 + flex: 1;
  621 + text-align: right;
  622 + color: rgba(0, 0, 0, 0.9);
  623 + font-size: 28rpx;
  624 +}
  625 +
  626 +.row .amount {
  627 + color: #D54941;
  628 +}
  629 +
  630 +.total {
  631 + .total-text {
  632 + font-weight: 600;
  633 + font-size: 32rpx;
  634 + color: rgba(0, 0, 0, 0.9);
  635 + padding-bottom: 28rpx;
  636 + border-bottom: 2rpx solid #E7E7E7;
  637 + }
  638 +
  639 + .total-item {
  640 + display: flex;
  641 + align-items: center;
  642 +
  643 + .total-item-text {
  644 + font-weight: 400;
  645 + font-size: 28rpx;
  646 + color: rgba(0, 0, 0, 0.6);
  647 + line-height: 32rpx;
  648 + width: 240rpx;
  649 + padding: 24rpx 0;
  650 + }
  651 +
  652 + .total-item-price {
  653 + font-weight: 600;
  654 + font-size: 32rpx;
  655 + color: rgba(0, 0, 0, 0.9);
  656 + line-height: 32rpx;
  657 + }
  658 +
  659 + .text-red {
  660 + color: #D54941;
  661 + }
  662 + }
  663 +
  664 +}
  665 +
  666 +.footer {
  667 + z-index: 2;
  668 + position: fixed;
  669 + left: 0;
  670 + right: 0;
  671 + bottom: 0;
  672 + padding: 32rpx;
  673 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  674 + background: #fff;
  675 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  676 +
  677 + .btn {
  678 + height: 80rpx;
  679 + line-height: 80rpx;
  680 + border-radius: 12rpx;
  681 + font-size: 32rpx;
  682 + }
  683 +
  684 + .submit {
  685 + background: $theme-primary;
  686 + color: #fff;
  687 + }
  688 +}
  689 +
  690 +.btn {
  691 + height: 80rpx;
  692 + line-height: 80rpx;
  693 + border-radius: 12rpx;
  694 + font-size: 32rpx;
  695 + flex: 1;
  696 +}
  697 +
  698 +.submit {
  699 + background: $theme-primary;
  700 + color: #fff;
  701 +}
  702 +</style>
\ No newline at end of file
... ...
... ... @@ -180,6 +180,18 @@ export default {
180 180 }
181 181 },
182 182 {
  183 + text: '锁规',
  184 + visible: true,
  185 + variant: 'outline',
  186 + event: 'lock',
  187 + },
  188 + {
  189 + text: '锁规延期申请',
  190 + visible: true,
  191 + variant: 'outline',
  192 + event: 'lockApply',
  193 + },
  194 + {
183 195 text: '上传正式合同附件',
184 196 visible: true,
185 197 variant: 'outline',
... ... @@ -222,13 +234,16 @@ export default {
222 234 displayButtons() {
223 235 const s = this.detail && this.detail.status || ''
224 236 const t = this.detail.standardApproved || ''
  237 + const l = this.detail.priceSpecLocked || ''
225 238 return [
226 239 { ...this.buttons[0]},
227 240 // { ...this.buttons[0], visible: (s === 'DRAFT') },
228 241 { ...this.buttons[1], visible: (s === 'DRAFT') },
229   - { ...this.buttons[2], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
230   - { ...this.buttons[3], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
231   - { ...this.buttons[4], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  242 + { ...this.buttons[2], visible: (s === 'FORMAL' && !l) },
  243 + { ...this.buttons[3], visible: (s === 'FORMAL' && !l) },
  244 + { ...this.buttons[4], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
  245 + { ...this.buttons[5], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  246 + { ...this.buttons[6], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
232 247 // { ...this.buttons[3], visible: (s === 'STANDARD' && t === 'AUDIT') },
233 248 // { ...this.buttons[4], visible: (s === 'STANDARD') }
234 249 ]
... ... @@ -266,6 +281,16 @@ export default {
266 281 }
267 282 })
268 283 },
  284 + onLock() {
  285 + uni.navigateTo({
  286 + url: '/pages/contract_foreign_unplan/lock?id=' + this.detail.id || ''
  287 + })
  288 + },
  289 + onLockApply() {
  290 + uni.navigateTo({
  291 + url: '/pages/contract_foreign_unplan/lock_apply?id=' + this.detail.id || ''
  292 + })
  293 + },
269 294 onEdit() {
270 295 const id = this.detail.id || this.detail.code || ''
271 296 const query = id ? ('?id=' + encodeURIComponent(id)) : ''
... ... @@ -348,6 +373,8 @@ export default {
348 373 const e = btn.event || ''
349 374 if (e === 'edit') return this.onEdit(btn && btn.params)
350 375 if (e === 'delete') return this.onDelete(btn && btn.params)
  376 + if (e === 'lock') return this.onLock()
  377 + if (e === 'lockApply') return this.onLockApply()
351 378 if (e === 'upload') return this.uploadContract(this.detail.id || '')
352 379 if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '')
353 380 if (e === 'uploadStandard') return this.uploadContract(this.detail.id || '', 'standard')
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="lock-page">
  5 + <view class="block" v-for="(item, idx) in items" :key="idx">
  6 + <view class="block-header">
  7 + <uni-data-checkbox
  8 + multiple
  9 + mode="default"
  10 + :localdata="[{ text: '锁规', value: 'LOCKED' }]"
  11 + :modelValue="item.locked ? ['LOCKED'] : []"
  12 + @change="onLockChange(idx, $event)"
  13 + />
  14 + <view class="ops" @click="toggleItem(idx)">
  15 + <image class="opIcon"
  16 + :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" />
  17 + <text class="opText">{{ item.collapsed ? '收起' : '展开' }}</text>
  18 + </view>
  19 + </view>
  20 +
  21 + <uni-list v-show="item.collapsed">
  22 + <uni-list-item title="产品名称">
  23 + <template v-slot:footer>
  24 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  25 + </template>
  26 + </uni-list-item>
  27 + <uni-list-item title="行业">
  28 + <template v-slot:footer>
  29 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  30 + </template>
  31 + </uni-list-item>
  32 + <uni-list-item title="牌号">
  33 + <template v-slot:footer>
  34 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  35 + </template>
  36 + </uni-list-item>
  37 + <uni-list-item title="品质">
  38 + <template v-slot:footer>
  39 + <uni-easyinput v-model="item.quality" placeholder="请输入品质" :clearable="false" disabled />
  40 + </template>
  41 + </uni-list-item>
  42 + <uni-list-item title="规格">
  43 + <template v-slot:footer>
  44 + <uni-easyinput v-model="item.specDisplay" placeholder="自动拼接规格" :clearable="false" disabled />
  45 + </template>
  46 + </uni-list-item>
  47 + <uni-list-item title="状态">
  48 + <template v-slot:footer>
  49 + <uni-easyinput v-model="item.status" placeholder="请输入状态" :clearable="false" disabled />
  50 + </template>
  51 + </uni-list-item>
  52 + <uni-list-item title="数量">
  53 + <template v-slot:footer>
  54 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" placeholder="请输入数量" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'quantity', 0)" />
  55 + </template>
  56 + </uni-list-item>
  57 + <uni-list-item title="单价">
  58 + <template v-slot:footer>
  59 + <uni-easyinput v-model="item.unitPrice" type="number" :inputBorder="false" placeholder="请输入单价" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'unitPrice', 0)" />
  60 + </template>
  61 + </uni-list-item>
  62 + <uni-list-item title="不含税金额">
  63 + <template v-slot:footer>
  64 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  65 + </template>
  66 + </uni-list-item>
  67 + <uni-list-item title="总金额">
  68 + <template v-slot:footer>
  69 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  70 + </template>
  71 + </uni-list-item>
  72 + <uni-list-item title="发货日期">
  73 + <template v-slot:footer>
  74 + <uni-easyinput v-model="item.deliveryDate" :inputBorder="false" disabled />
  75 + </template>
  76 + </uni-list-item>
  77 + </uni-list>
  78 +
  79 + <uni-list v-show="!item.collapsed">
  80 + <uni-list-item title="产品名称">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  83 + </template>
  84 + </uni-list-item>
  85 + <uni-list-item title="行业">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  88 + </template>
  89 + </uni-list-item>
  90 + <uni-list-item title="牌号">
  91 + <template v-slot:footer>
  92 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  93 + </template>
  94 + </uni-list-item>
  95 + </uni-list>
  96 + </view>
  97 + </view>
  98 + </scroll-view>
  99 +
  100 + <view class="footer">
  101 + <div class="total">
  102 + <div class="total-text">
  103 + 合计
  104 + </div>
  105 + <div class="total-item">
  106 + <div class="total-item-text">
  107 + 数量
  108 + </div>
  109 + <div class="total-item-price">
  110 + {{ (sumQuantity || 0).toFixed(2) }}t
  111 + </div>
  112 + </div>
  113 + <div class="total-item">
  114 + <div class="total-item-text">
  115 + 不含税金额
  116 + </div>
  117 + <div class="total-item-price text-red">
  118 + ¥{{ (sumAmountExcl || 0).toFixed(2) }}
  119 + </div>
  120 + </div>
  121 + <div class="total-item">
  122 + <div class="total-item-text">
  123 + 总金额
  124 + </div>
  125 + <div class="total-item-price text-red">
  126 + ¥{{ (sumTotal || 0).toFixed(2) }}
  127 + </div>
  128 + </div>
  129 + </div>
  130 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  131 + </view>
  132 + </view>
  133 +</template>
  134 +
  135 +<script>
  136 +import { getContractApi, specificationLock } from '@/api/contract'
  137 +import { formatCurrencyToChinese } from '@/utils/common'
  138 +
  139 +export default {
  140 + name: 'ContractUnplanLock',
  141 + data() {
  142 + return {
  143 + id: '',
  144 + items: [],
  145 + planQty: 30,
  146 + }
  147 + },
  148 + computed: {
  149 + sumQuantity() {
  150 + const qty = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.quantity), 0)
  151 + return this.round(qty, 2)
  152 + },
  153 + sumAmountExcl() {
  154 + const sum = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.amountExcludingTax), 0)
  155 + return this.round(sum, 2)
  156 + },
  157 + sumTotal() { return this.totalAmount },
  158 + totalAmount() {
  159 + let sum = 0
  160 + for (const it of this.items) {
  161 + if (!it.locked) continue
  162 + sum += this.toNumber(it.quantity) * this.toNumber(it.unitPrice)
  163 + }
  164 + return this.round(sum, 2)
  165 + },
  166 + totalExclTax() {
  167 + const TAX_RATE = 0.13
  168 + const total = this.totalAmount
  169 + return this.round(total / (1 + TAX_RATE), 2)
  170 + },
  171 + totalQtyDisplay() {
  172 + const qty = this.round(this.items.reduce((p, c) => p + this.toNumber(c.quantity), 0), 3)
  173 + return `${qty}t/${this.planQty}t`
  174 + }
  175 + },
  176 + onLoad(options) {
  177 + const id = options && options.id ? options.id : ''
  178 + this.id = id
  179 + this.loadDetail()
  180 + },
  181 + methods: {
  182 + onLockChange(idx, e) {
  183 + const it = this.items[idx]
  184 + if (!it) return
  185 + const arr = e && e.detail && e.detail.value ? e.detail.value : []
  186 + it.locked = Array.isArray(arr) && arr.length > 0
  187 + this.$set(this.items, idx, it)
  188 + },
  189 + async loadDetail() {
  190 + if (!this.id) return
  191 + try {
  192 + const res = await getContractApi(this.id)
  193 + const data = res && res.data ? res.data : {}
  194 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  195 + const init = lines.map(v => ({
  196 + locked: false,
  197 + collapsed: true,
  198 + raw: v,
  199 + productName: v.rawProductName || v.productName || '',
  200 + industry: v.industry || '',
  201 + brand: v.rawProductGrade || v.brand || '',
  202 + quality: v.quality || '',
  203 + thickness: v.thickness || '',
  204 + thicknessTolPos: v.thicknessTolPos || '',
  205 + thicknessTolNeg: v.thicknessTolNeg || '',
  206 + width: v.width || '',
  207 + widthTolPos: v.widthTolPos || '',
  208 + widthTolNeg: v.widthTolNeg || '',
  209 + length: v.length || '',
  210 + lengthTolPos: v.lengthTolPos || '',
  211 + lengthTolNeg: v.lengthTolNeg || '',
  212 + status: v.status || '',
  213 + quantity: v.productQuantity || v.quantity || '',
  214 + unitPrice: v.unitPrice || '',
  215 + amountExcludingTax: v.amountExcludingTax || 0,
  216 + totalAmount: v.totalAmount || 0,
  217 + deliveryDate: v.deliveryDate || '',
  218 + specDisplay: ''
  219 + }))
  220 + this.items = init.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  221 + this.recalculateAll()
  222 + } catch (e) {
  223 + this.items = []
  224 + }
  225 + },
  226 + toggleItem(idx) {
  227 + const it = this.items[idx]
  228 + if (!it) return
  229 + it.collapsed = !it.collapsed
  230 + this.$set(this.items, idx, it)
  231 + },
  232 + onImmediateChange(idx) {
  233 + this.$nextTick(() => this.recalculate(idx))
  234 + },
  235 + onNumberBlur(idx, field, digits) {
  236 + const it = this.items[idx]
  237 + if (!it) return
  238 + const raw = it[field]
  239 + if (raw === '' || raw === null || raw === undefined) {
  240 + this.$set(this.items, idx, it)
  241 + this.recalculate(idx)
  242 + return
  243 + }
  244 + const num = this.toNumber(raw)
  245 + const rounded = this.round(num, digits)
  246 + it[field] = rounded
  247 + this.$set(this.items, idx, it)
  248 + this.recalculate(idx)
  249 + },
  250 + recalculate(idx) {
  251 + const TAX_RATE = 0.13
  252 + const it = this.items[idx]
  253 + if (!it) return
  254 + const qty = this.toNumber(it.quantity)
  255 + const price = this.toNumber(it.unitPrice)
  256 + const total = this.round(qty * price, 2)
  257 + const excl = this.round(total / (1 + TAX_RATE), 2)
  258 + it.amountExcludingTax = excl
  259 + it.totalAmount = total
  260 + this.$set(this.items, idx, it)
  261 + },
  262 + recalculateAll() {
  263 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
  264 + },
  265 + toNumber(val) {
  266 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  267 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  268 + return isNaN(n) ? 0 : n
  269 + },
  270 + round(val, digits = 2) {
  271 + const n = Number(val)
  272 + if (isNaN(n)) return 0
  273 + const m = Math.pow(10, digits)
  274 + return Math.round(n * m) / m
  275 + },
  276 + specOf(item) {
  277 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/ ')
  278 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/ ')
  279 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/ ')
  280 + return [t, w, l].filter(Boolean).join(' × ')
  281 + },
  282 + formatCurrency(val) {
  283 + if (val == null || val === '') return ''
  284 + const num = Number(val)
  285 + const pre = isNaN(num) ? '' : '¥'
  286 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  287 + return `${pre}${fixed}`
  288 + },
  289 + onReset() {
  290 + this.items = this.items.map((it, i) => ({
  291 + ...it,
  292 + quantity: '',
  293 + unitPrice: '',
  294 + amountExcludingTax: 0
  295 + }))
  296 + },
  297 + async onSubmit() {
  298 + const selected = this.items.filter(it => it.locked).map(it => {
  299 + const raw = { ...(it.raw || {}) }
  300 + const qty = this.toNumber(it.quantity)
  301 + const price = this.toNumber(it.unitPrice)
  302 + const total = this.toNumber(it.totalAmount)
  303 + const excl = this.toNumber(it.amountExcludingTax)
  304 + if (Object.prototype.hasOwnProperty.call(raw, 'productQuantity')) raw.productQuantity = qty
  305 + else raw.quantity = qty
  306 + raw.unitPrice = price
  307 + raw.totalAmount = total
  308 + raw.amountExcludingTax = excl
  309 + return raw
  310 + })
  311 + if (!selected.length) {
  312 + uni.showToast({ title: '未选择任何锁规项', icon: 'none' })
  313 + return
  314 + }
  315 + const invalid = selected.find(r => {
  316 + const q = this.toNumber(r.productQuantity != null ? r.productQuantity : r.quantity)
  317 + const p = this.toNumber(r.unitPrice)
  318 + return !(q > 0 && p > 0)
  319 + })
  320 + if (invalid) {
  321 + uni.showToast({ title: '请填写数量和单价', icon: 'none' })
  322 + return
  323 + }
  324 + this.selectedItems = selected
  325 + const payload = {
  326 + id: this.id,
  327 + totalAmountCapital: formatCurrencyToChinese(this.sumTotal),
  328 + totalAmountExcludingTax: this.sumAmountExcl,
  329 + totalAmountIncludingTax: this.sumTotal,
  330 + totalQuantity: this.sumQuantity,
  331 + type:'INTL_OPEN_SPEC_AGMT',
  332 + contractDistributorLineList: selected
  333 + }
  334 +
  335 + uni.showModal({
  336 + title: '确认提交',
  337 + content: '确定提交锁规吗?',
  338 + success: (res) => {
  339 + if (res.confirm) {
  340 + specificationLock(payload).then(() => {
  341 + uni.showToast({ title: '锁规已提交', icon: 'success' })
  342 + setTimeout(() => {
  343 + uni.navigateTo({ url: '/pages/contract_foreign_unplan/index' })
  344 + }, 500)
  345 + }).catch(() => {
  346 + uni.showToast({ title: '提交失败', icon: 'none' })
  347 + })
  348 + }
  349 + }
  350 + })
  351 + }
  352 + }
  353 +}
  354 +</script>
  355 +
  356 +<style lang="scss" scoped>
  357 +.page {
  358 + display: flex;
  359 + flex-direction: column;
  360 + height: 100%;
  361 +}
  362 +
  363 +.scroll {
  364 + flex: 1;
  365 + padding: 12rpx 0 480rpx !important;
  366 +}
  367 +
  368 +.header {
  369 + background-color: #fff;
  370 + display: flex;
  371 + align-items: center;
  372 + padding: 24rpx 32rpx;
  373 + border-bottom: 1rpx solid #f0f0f0;
  374 +}
  375 +
  376 +.title {
  377 + font-size: 32rpx;
  378 + color: rgba(0, 0, 0, 0.9);
  379 + font-weight: 600;
  380 +}
  381 +
  382 +.opCollapse {
  383 + width: 24rpx;
  384 + height: 24rpx;
  385 + margin-right: 16rpx;
  386 + margin-top: 8rpx;
  387 +}
  388 +
  389 +.block {
  390 + background: #fff;
  391 + margin-top: 20rpx;
  392 +}
  393 +
  394 +.block-header {
  395 + display: flex;
  396 + align-items: center;
  397 + padding: 24rpx 32rpx;
  398 + border-bottom: 1rpx solid #f0f0f0;
  399 +}
  400 +
  401 +.block-header ::v-deep .uni-data-checklist .checkbox__inner {
  402 + width: 36rpx;
  403 + height: 36rpx;
  404 +}
  405 +.block-header ::v-deep .uni-data-checklist .checklist-text {
  406 + font-size: 28rpx;
  407 + margin-left: 12rpx;
  408 +}
  409 +
  410 +.block-title {
  411 + margin-left: 12rpx;
  412 + font-size: 28rpx;
  413 + color: rgba(0, 0, 0, 0.9);
  414 +}
  415 +
  416 +.ops {
  417 + margin-left: auto;
  418 + display: flex;
  419 + align-items: center;
  420 + color: $theme-primary;
  421 + font-size: 28rpx;
  422 +}
  423 +
  424 +.opIcon {
  425 + width: 40rpx;
  426 + height: 40rpx;
  427 +}
  428 +
  429 +.opText {
  430 + margin-left: 8rpx;
  431 + color: $theme-primary;
  432 +}
  433 +
  434 +::v-deep .uni-list {
  435 + .uni-easyinput {
  436 + display: flex;
  437 +
  438 + .uni-input-input {
  439 + color: rgba(0, 0, 0, 0.9);
  440 + }
  441 + }
  442 +
  443 + .uni-input-placeholder {
  444 + z-index: 1;
  445 + }
  446 +
  447 + .uni-input-input {
  448 + background-color: #ffffff;
  449 + }
  450 +
  451 + background: transparent;
  452 +
  453 + &-item {
  454 + &__extra-text {
  455 + font-size: 32rpx;
  456 + }
  457 +
  458 + &__content-title {
  459 + font-size: 32rpx;
  460 + color: rgba(0, 0, 0, 0.9);
  461 + }
  462 +
  463 + &__container {
  464 + padding: 32rpx;
  465 +
  466 + .uni-easyinput {
  467 + &__placeholder-class {
  468 + font-size: 32rpx;
  469 + color: rgba(0, 0, 0, 0.4);
  470 + }
  471 +
  472 + &__content {
  473 + border: none;
  474 + background-color: #ffffff !important;
  475 +
  476 + &-input {
  477 + padding-left: 0 !important;
  478 + height: 48rpx;
  479 + line-height: 48rpx;
  480 + font-size: 32rpx;
  481 + }
  482 +
  483 + .content-clear-icon {
  484 + font-size: 44rpx !important;
  485 + }
  486 + }
  487 + }
  488 +
  489 + .item-title,
  490 + .uni-list-item__content {
  491 + flex: none;
  492 + min-height: 48rpx;
  493 + line-height: 48rpx;
  494 + font-size: 32rpx;
  495 + position: relative;
  496 + width: 162rpx;
  497 + margin-right: 32rpx;
  498 + color: rgba(0, 0, 0, 0.9);
  499 +
  500 + .required {
  501 + color: red;
  502 + position: absolute;
  503 + top: 50%;
  504 + transform: translateY(-50%);
  505 + left: -16rpx;
  506 + }
  507 + }
  508 + }
  509 +
  510 + &.select-item {
  511 + &.is-empty {
  512 + .uni-list-item__extra-text {
  513 + color: rgba(0, 0, 0, 0.4) !important;
  514 + }
  515 + }
  516 +
  517 + &.is-filled {
  518 + .uni-list-item__extra-text {
  519 + color: rgba(0, 0, 0, 0.9) !important;
  520 + }
  521 + }
  522 + }
  523 +
  524 + &.mgb10 {
  525 + margin-bottom: 20rpx;
  526 + }
  527 + }
  528 +}
  529 +
  530 +// ::v-deep .uni-list-item__container {
  531 +// padding: 32rpx;
  532 +// }
  533 +
  534 +::v-deep .is-disabled {
  535 + background-color: transparent !important;
  536 +}
  537 +// ::v-deep .uni-list-item__content-title {
  538 +// font-size: 28rpx;
  539 +// color: rgba(0, 0, 0, 0.9);
  540 +// }
  541 +
  542 +// ::v-deep .uni-list-item__extra-text {
  543 +// font-size: 32rpx;
  544 +// }
  545 +
  546 +::v-deep .uni-easyinput {
  547 + width: 100%;
  548 +}
  549 +
  550 +::v-deep .uni-easyinput__placeholder-class {
  551 + font-size: 32rpx;
  552 + color: rgba(0, 0, 0, 0.4);
  553 +}
  554 +
  555 +::v-deep .uni-easyinput__content {
  556 + border: none;
  557 + display: flex;
  558 +}
  559 +
  560 +::v-deep .uni-easyinput__content-input {
  561 + padding-left: 0 !important;
  562 + height: 48rpx;
  563 + line-height: 48rpx;
  564 + font-size: 32rpx;
  565 + color: rgba(0, 0, 0, 0.9);
  566 +}
  567 +
  568 +.amount-item .item-title {
  569 + display: flex;
  570 + align-items: center;
  571 +}
  572 +
  573 +.amount-row {
  574 + display: flex;
  575 + align-items: center;
  576 +}
  577 +
  578 +.amount-row .unit {
  579 + margin-left: 12rpx;
  580 + color: rgba(0, 0, 0, 0.6);
  581 +}
  582 +
  583 +.summary {
  584 + margin-top: 20rpx;
  585 + background: #fff;
  586 + padding-bottom: 12rpx;
  587 +}
  588 +
  589 +.title-header {
  590 + display: flex;
  591 + align-items: center;
  592 + padding: 20rpx 32rpx;
  593 +}
  594 +
  595 +.title-header_icon {
  596 + width: 24rpx;
  597 + height: 24rpx;
  598 + margin-right: 16rpx;
  599 +}
  600 +
  601 +.sum-card {
  602 + background: #f3f3f3;
  603 + border-radius: 16rpx;
  604 + padding: 24rpx;
  605 + margin: 0 32rpx 20rpx;
  606 +}
  607 +
  608 +.row {
  609 + display: flex;
  610 + margin-bottom: 16rpx;
  611 +}
  612 +
  613 +.row .label {
  614 + width: 140rpx;
  615 + color: rgba(0, 0, 0, 0.6);
  616 + font-size: 28rpx;
  617 +}
  618 +
  619 +.row .value {
  620 + flex: 1;
  621 + text-align: right;
  622 + color: rgba(0, 0, 0, 0.9);
  623 + font-size: 28rpx;
  624 +}
  625 +
  626 +.row .amount {
  627 + color: #D54941;
  628 +}
  629 +
  630 +.total {
  631 + .total-text {
  632 + font-weight: 600;
  633 + font-size: 32rpx;
  634 + color: rgba(0, 0, 0, 0.9);
  635 + padding-bottom: 28rpx;
  636 + border-bottom: 2rpx solid #E7E7E7;
  637 + }
  638 +
  639 + .total-item {
  640 + display: flex;
  641 + align-items: center;
  642 +
  643 + .total-item-text {
  644 + font-weight: 400;
  645 + font-size: 28rpx;
  646 + color: rgba(0, 0, 0, 0.6);
  647 + line-height: 32rpx;
  648 + width: 240rpx;
  649 + padding: 24rpx 0;
  650 + }
  651 +
  652 + .total-item-price {
  653 + font-weight: 600;
  654 + font-size: 32rpx;
  655 + color: rgba(0, 0, 0, 0.9);
  656 + line-height: 32rpx;
  657 + }
  658 +
  659 + .text-red {
  660 + color: #D54941;
  661 + }
  662 + }
  663 +
  664 +}
  665 +
  666 +.footer {
  667 + z-index: 2;
  668 + position: fixed;
  669 + left: 0;
  670 + right: 0;
  671 + bottom: 0;
  672 + padding: 32rpx;
  673 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  674 + background: #fff;
  675 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  676 +
  677 + .btn {
  678 + height: 80rpx;
  679 + line-height: 80rpx;
  680 + border-radius: 12rpx;
  681 + font-size: 32rpx;
  682 + }
  683 +
  684 + .submit {
  685 + background: $theme-primary;
  686 + color: #fff;
  687 + }
  688 +}
  689 +
  690 +.btn {
  691 + height: 80rpx;
  692 + line-height: 80rpx;
  693 + border-radius: 12rpx;
  694 + font-size: 32rpx;
  695 + flex: 1;
  696 +}
  697 +
  698 +.submit {
  699 + background: $theme-primary;
  700 + color: #fff;
  701 +}
  702 +</style>
\ No newline at end of file
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="detail-page">
  5 + <view class="section">
  6 + <uni-list>
  7 + <uni-list-item title="客户名称">
  8 + <template v-slot:footer>
  9 + <uni-easyinput v-model="detail.customerName" :clearable="false" disabled />
  10 + </template>
  11 + </uni-list-item>
  12 + <uni-list-item title="订单编号">
  13 + <template v-slot:footer>
  14 + <uni-easyinput v-model="detail.contractCode" :clearable="false" disabled />
  15 + </template>
  16 + </uni-list-item>
  17 + <uni-list-item title="办事处">
  18 + <template v-slot:footer>
  19 + <uni-easyinput v-model="detail.deptName" :clearable="false" disabled />
  20 + </template>
  21 + </uni-list-item>
  22 + <uni-list-item title="所属分厂">
  23 + <template v-slot:footer>
  24 + <uni-easyinput v-model="detail.workshopName" :clearable="false" disabled />
  25 + </template>
  26 + </uni-list-item>
  27 + <uni-list-item title="订单类型">
  28 + <template v-slot:footer>
  29 + <uni-easyinput v-model="detail.contractType" :clearable="false" disabled />
  30 + </template>
  31 + </uni-list-item>
  32 + <uni-list-item title="原订货日期">
  33 + <template v-slot:footer>
  34 + <uni-easyinput v-model="detail.orderDate" :clearable="false" disabled />
  35 + </template>
  36 + </uni-list-item>
  37 + <uni-list-item title="第几次申请">
  38 + <template v-slot:footer>
  39 + <uni-easyinput v-model="detail.applicationCount" :clearable="false" disabled />
  40 + </template>
  41 + </uni-list-item>
  42 + <uni-list-item title="制单日期">
  43 + <template v-slot:footer>
  44 + <uni-easyinput v-model="detail.contractDocumentDate" :clearable="false" disabled />
  45 + </template>
  46 + </uni-list-item>
  47 + <uni-list-item title="数量">
  48 + <template v-slot:footer>
  49 + <uni-easyinput v-model="detail.totalQuantity" :clearable="false" disabled />
  50 + </template>
  51 + </uni-list-item>
  52 + </uni-list>
  53 + </view>
  54 +
  55 + <view class="section1">
  56 + <uni-list>
  57 + <uni-list-item title="现申请锁规格日期">
  58 + <template v-slot:footer>
  59 + <uni-datetime-picker type="date" v-model="form.specLockDate" />
  60 + </template>
  61 + </uni-list-item>
  62 + <uni-list-item title="延迟原因">
  63 + <template v-slot:footer>
  64 + <uni-easyinput v-model="form.delayReason" placeholder="请输入原因" :inputBorder="false" />
  65 + </template>
  66 + </uni-list-item>
  67 + </uni-list>
  68 + </view>
  69 + </view>
  70 + </scroll-view>
  71 + <view class="footer">
  72 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  73 + </view>
  74 + </view>
  75 +</template>
  76 +
  77 +<script>
  78 +import { showContract, specLockDelayApplication } from '@/api/contract'
  79 +export default {
  80 + name: 'LockApplyForeignUnplan',
  81 + data() {
  82 + return {
  83 + id: '',
  84 + detail: {
  85 + contractCode: '',
  86 + customerName: '',
  87 + deptName: '',
  88 + workshopName: '',
  89 + orderType: '',
  90 + orderTypeName: '',
  91 + orderDate: '',
  92 + applicationCount: '',
  93 + contractDocumentDate: '',
  94 + totalQuantity: ''
  95 + },
  96 + form: { specLockDate: '', delayReason: '' }
  97 + }
  98 + },
  99 + onLoad(options) {
  100 + const id = options && options.id ? options.id : ''
  101 + this.id = id
  102 + this.loadDetail()
  103 + },
  104 + methods: {
  105 + async loadDetail() {
  106 + if (!this.id) return
  107 + try {
  108 + const res = await showContract(this.id)
  109 + const data = res && res.data ? res.data : {}
  110 + this.detail = {
  111 + contractCode: data.contractCode || '',
  112 + customerName: data.customerName || '',
  113 + deptName: data.deptName || '',
  114 + workshopName: data.workshopName || '',
  115 + orderType: data.orderType || '',
  116 + contractType: data.contractType === 'DRAFT_DIST_AGMT' ? '经销订单' : '外贸订单',
  117 + orderDate: (data.orderDate || '').slice(0, 10),
  118 + applicationCount: data.applicationCount || '',
  119 + contractDocumentDate: (data.contractDocumentDate || '').slice(0, 10),
  120 + totalQuantity: data.totalQuantity || ''
  121 + }
  122 + } catch (e) {
  123 + this.detail = { ...this.detail }
  124 + }
  125 + },
  126 +
  127 + onSubmit() {
  128 + const date = this.form.specLockDate
  129 + const reason = this.form.delayReason
  130 + const emptyDate = !date
  131 + if (emptyDate) {
  132 + uni.showToast({ title: '请填写日期', icon: 'none' })
  133 + return
  134 + }
  135 + uni.showModal({
  136 + title: '确认提交',
  137 + content: '确定提交锁规无规格申请吗?',
  138 + success: (res) => {
  139 + if (res.confirm) {
  140 + specLockDelayApplication({
  141 + ...this.detail,
  142 + specLockDate: date,
  143 + delayReason: reason
  144 + }).then(res => {
  145 + if (res.code === 200) {
  146 + uni.showToast({ title: '提交成功', icon: 'success' })
  147 + setTimeout(() => {
  148 + uni.navigateTo({ url: '/pages/contract_foreign_unplan/index' })
  149 + }, 1000)
  150 + } else {
  151 + uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
  152 + }
  153 + })
  154 + }
  155 + }
  156 + })
  157 + }
  158 + }
  159 +}
  160 +</script>
  161 +
  162 +<style lang="scss" scoped>
  163 +.page {
  164 + display: flex;
  165 + flex-direction: column;
  166 + height: 100%;
  167 +}
  168 +
  169 +.scroll {
  170 + flex: 1;
  171 + padding: 8rpx 0 144rpx;
  172 +}
  173 +
  174 +.detail-page {
  175 + background: #f3f3f3;
  176 +}
  177 +
  178 +.section {
  179 + background: #fff;
  180 + margin-bottom: 20rpx;
  181 +}
  182 +.section1 {
  183 + background: #fff;
  184 + margin-bottom: 20rpx;
  185 +}
  186 +
  187 +.row {
  188 + display: flex;
  189 + margin-bottom: 20rpx;
  190 + align-items: center;
  191 +}
  192 +
  193 +.row:last-child {
  194 + margin-bottom: 0;
  195 +}
  196 +
  197 +.label {
  198 + width: 280rpx;
  199 + color: rgba(0, 0, 0, 0.6);
  200 + font-size: 28rpx;
  201 +}
  202 +
  203 +.value {
  204 + flex: 1;
  205 + text-align: right;
  206 + color: rgba(0, 0, 0, 0.9);
  207 + font-size: 28rpx;
  208 +}
  209 +
  210 +.customer {
  211 + font-weight: 600;
  212 + font-size: 36rpx;
  213 + color: rgba(0, 0, 0, 0.9);
  214 + padding-bottom: 12rpx;
  215 +}
  216 +
  217 +.footer {
  218 + position: fixed;
  219 + left: 0; right: 0; bottom: 0;
  220 + padding: 24rpx 32rpx 48rpx;
  221 + background: #fff;
  222 + box-shadow: 0 -8rpx 24rpx rgba(0,0,0,0.06);
  223 +}
  224 +.footer .btn { height: 80rpx; line-height: 80rpx; border-radius: 12rpx; font-size: 32rpx; }
  225 +.footer .submit { background: $theme-primary; color: #fff; }
  226 +
  227 +::v-deep .uni-list {
  228 + .uni-easyinput {
  229 + display: flex;
  230 +
  231 + .uni-input-input {
  232 + color: rgba(0, 0, 0, 0.9);
  233 + }
  234 + }
  235 +
  236 + .uni-input-placeholder {
  237 + z-index: 1;
  238 + }
  239 +
  240 + .uni-input-input {
  241 + background-color: #ffffff;
  242 + }
  243 +
  244 + background: transparent;
  245 +
  246 + &-item {
  247 + &__extra-text {
  248 + font-size: 32rpx;
  249 + }
  250 +
  251 + &__content-title {
  252 + font-size: 32rpx;
  253 + color: rgba(0, 0, 0, 0.9);
  254 + }
  255 +
  256 + &__container {
  257 + padding: 32rpx;
  258 +
  259 + .uni-easyinput {
  260 + &__placeholder-class {
  261 + font-size: 32rpx;
  262 + color: rgba(0, 0, 0, 0.4);
  263 + }
  264 +
  265 + &__content {
  266 + border: none;
  267 + background-color: #ffffff !important;
  268 +
  269 + &-input {
  270 + padding-left: 0 !important;
  271 + height: 48rpx;
  272 + line-height: 48rpx;
  273 + font-size: 32rpx;
  274 + }
  275 +
  276 + .content-clear-icon {
  277 + font-size: 44rpx !important;
  278 + }
  279 + }
  280 + }
  281 +
  282 + .item-title,
  283 + .uni-list-item__content {
  284 + flex: none;
  285 + min-height: 48rpx;
  286 + line-height: 48rpx;
  287 + font-size: 32rpx;
  288 + position: relative;
  289 + width: 162rpx;
  290 + margin-right: 32rpx;
  291 + color: rgba(0, 0, 0, 0.9);
  292 +
  293 + .required {
  294 + color: red;
  295 + position: absolute;
  296 + top: 50%;
  297 + transform: translateY(-50%);
  298 + left: -16rpx;
  299 + }
  300 + }
  301 + }
  302 +
  303 + &.select-item {
  304 + &.is-empty {
  305 + .uni-list-item__extra-text {
  306 + color: rgba(0, 0, 0, 0.4) !important;
  307 + }
  308 + }
  309 +
  310 + &.is-filled {
  311 + .uni-list-item__extra-text {
  312 + color: rgba(0, 0, 0, 0.9) !important;
  313 + }
  314 + }
  315 + }
  316 +
  317 + &.mgb10 {
  318 + margin-bottom: 20rpx;
  319 + }
  320 + }
  321 +}
  322 +
  323 +// ::v-deep .uni-list-item__container {
  324 +// padding: 32rpx;
  325 +// }
  326 +
  327 +::v-deep .is-disabled {
  328 + background-color: transparent !important;
  329 +}
  330 +// ::v-deep .uni-list-item__content-title {
  331 +// font-size: 28rpx;
  332 +// color: rgba(0, 0, 0, 0.9);
  333 +// }
  334 +
  335 +// ::v-deep .uni-list-item__extra-text {
  336 +// font-size: 32rpx;
  337 +// }
  338 +
  339 +::v-deep .uni-easyinput {
  340 + width: 100%;
  341 +}
  342 +
  343 +::v-deep .uni-easyinput__placeholder-class {
  344 + font-size: 32rpx;
  345 + color: rgba(0, 0, 0, 0.4);
  346 +}
  347 +
  348 +::v-deep .uni-easyinput__content {
  349 + border: none;
  350 + display: flex;
  351 +}
  352 +
  353 +::v-deep .uni-easyinput__content-input {
  354 + padding-left: 0 !important;
  355 + height: 48rpx;
  356 + line-height: 48rpx;
  357 + font-size: 32rpx;
  358 + color: rgba(0, 0, 0, 0.9);
  359 +}
  360 +</style>
\ No newline at end of file
... ...
... ... @@ -178,6 +178,12 @@ export default {
178 178 }
179 179 },
180 180 {
  181 + text: '锁价',
  182 + visible: true,
  183 + variant: 'outline',
  184 + event: 'lock',
  185 + },
  186 + {
181 187 text: '上传正式合同附件',
182 188 visible: true,
183 189 variant: 'outline',
... ... @@ -216,13 +222,15 @@ export default {
216 222 displayButtons() {
217 223 const s = this.detail && this.detail.status || ''
218 224 const t = this.detail.formalApproved || ''
  225 + const l = this.detail.priceSpecLocked || ''
219 226 return [
220 227 { ...this.buttons[0]},
221 228 // { ...this.buttons[0], visible: (s === 'DRAFT') },
222 229 { ...this.buttons[1], visible: (s === 'DRAFT') },
223   - { ...this.buttons[2], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
224   - { ...this.buttons[3], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  230 + { ...this.buttons[2], visible: (s === 'FORMAL' && !l) },
  231 + { ...this.buttons[3], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
225 232 { ...this.buttons[4], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  233 + { ...this.buttons[5], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
226 234 // { ...this.buttons[3], visible: (s === 'STANDARD' && t === 'AUDIT') },
227 235 // { ...this.buttons[4], visible: (s === 'STANDARD') }
228 236 ]
... ... @@ -336,12 +344,18 @@ export default {
336 344 const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
337 345 this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, value: match ? match.value : '' }
338 346 },
  347 + onLock() {
  348 + uni.navigateTo({
  349 + url: '/pages/contract_stock/lock?id=' + this.detail.id || ''
  350 + })
  351 + },
339 352 handleButtonClick(btn) {
340 353 if (!btn || btn.disabled) return
341 354 if (typeof btn.onClick === 'function') return btn.onClick(this.detail, btn.params)
342 355 const e = btn.event || ''
343 356 if (e === 'edit') return this.onEdit(btn && btn.params)
344 357 if (e === 'delete') return this.onDelete(btn && btn.params)
  358 + if (e === 'lock') return this.onLock()
345 359 if (e === 'upload') return this.uploadContract(this.detail.id || '')
346 360 if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '')
347 361 if (e === 'uploadStandard') return this.uploadContract(this.detail.id || '', 'standard')
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="lock-page">
  5 + <view class="block" v-for="(item, idx) in items" :key="idx">
  6 + <view class="block-header">
  7 + <uni-data-checkbox
  8 + multiple
  9 + mode="default"
  10 + :localdata="[{ text: '锁价', value: 'LOCKED' }]"
  11 + :modelValue="item.locked ? ['LOCKED'] : []"
  12 + :disabled="true"
  13 + @change="onLockChange(idx, $event)"
  14 + />
  15 + <view class="ops" @click="toggleItem(idx)">
  16 + <image class="opIcon"
  17 + :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" />
  18 + <text class="opText">{{ item.collapsed ? '收起' : '展开' }}</text>
  19 + </view>
  20 + </view>
  21 +
  22 + <uni-list v-show="item.collapsed">
  23 + <uni-list-item title="产品名称">
  24 + <template v-slot:footer>
  25 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  26 + </template>
  27 + </uni-list-item>
  28 + <uni-list-item title="行业">
  29 + <template v-slot:footer>
  30 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  31 + </template>
  32 + </uni-list-item>
  33 + <uni-list-item title="牌号">
  34 + <template v-slot:footer>
  35 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  36 + </template>
  37 + </uni-list-item>
  38 + <uni-list-item title="品质">
  39 + <template v-slot:footer>
  40 + <uni-easyinput v-model="item.quality" placeholder="请输入品质" :clearable="false" disabled />
  41 + </template>
  42 + </uni-list-item>
  43 + <uni-list-item title="规格">
  44 + <template v-slot:footer>
  45 + <uni-easyinput v-model="item.specDisplay" placeholder="自动拼接规格" :clearable="false" disabled />
  46 + </template>
  47 + </uni-list-item>
  48 + <uni-list-item title="状态">
  49 + <template v-slot:footer>
  50 + <uni-easyinput v-model="item.status" placeholder="请输入状态" :clearable="false" disabled />
  51 + </template>
  52 + </uni-list-item>
  53 + <uni-list-item title="数量">
  54 + <template v-slot:footer>
  55 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" disabled placeholder="不可编辑" />
  56 + </template>
  57 + </uni-list-item>
  58 + <uni-list-item title="单价">
  59 + <template v-slot:footer>
  60 + <uni-easyinput v-model="item.unitPrice" type="number" :inputBorder="false" placeholder="请输入单价" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'unitPrice', 0)" />
  61 + </template>
  62 + </uni-list-item>
  63 + <uni-list-item title="不含税金额">
  64 + <template v-slot:footer>
  65 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  66 + </template>
  67 + </uni-list-item>
  68 + <uni-list-item title="总金额">
  69 + <template v-slot:footer>
  70 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  71 + </template>
  72 + </uni-list-item>
  73 + <uni-list-item title="发货日期">
  74 + <template v-slot:footer>
  75 + <uni-easyinput v-model="item.deliveryDate" :inputBorder="false" disabled />
  76 + </template>
  77 + </uni-list-item>
  78 + </uni-list>
  79 +
  80 + <uni-list v-show="!item.collapsed">
  81 + <uni-list-item title="产品名称">
  82 + <template v-slot:footer>
  83 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  84 + </template>
  85 + </uni-list-item>
  86 + <uni-list-item title="行业">
  87 + <template v-slot:footer>
  88 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  89 + </template>
  90 + </uni-list-item>
  91 + <uni-list-item title="牌号">
  92 + <template v-slot:footer>
  93 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  94 + </template>
  95 + </uni-list-item>
  96 + </uni-list>
  97 + </view>
  98 + </view>
  99 + </scroll-view>
  100 +
  101 + <view class="footer">
  102 + <div class="total">
  103 + <div class="total-text">
  104 + 合计
  105 + </div>
  106 + <div class="total-item">
  107 + <div class="total-item-text">
  108 + 数量
  109 + </div>
  110 + <div class="total-item-price">
  111 + {{ (sumQuantity || 0).toFixed(2) }}t
  112 + </div>
  113 + </div>
  114 + <div class="total-item">
  115 + <div class="total-item-text">
  116 + 不含税金额
  117 + </div>
  118 + <div class="total-item-price text-red">
  119 + ¥{{ (sumAmountExcl || 0).toFixed(2) }}
  120 + </div>
  121 + </div>
  122 + <div class="total-item">
  123 + <div class="total-item-text">
  124 + 总金额
  125 + </div>
  126 + <div class="total-item-price text-red">
  127 + ¥{{ (sumTotal || 0).toFixed(2) }}
  128 + </div>
  129 + </div>
  130 + </div>
  131 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  132 + </view>
  133 + </view>
  134 +</template>
  135 +
  136 +<script>
  137 +import { getContractApi, priceLock } from '@/api/contract'
  138 +import { formatCurrencyToChinese } from '@/utils/common'
  139 +
  140 +export default {
  141 + name: 'ContractUnplanLock',
  142 + data() {
  143 + return {
  144 + id: '',
  145 + items: [],
  146 + planQty: 30,
  147 + }
  148 + },
  149 + computed: {
  150 + sumQuantity() {
  151 + const qty = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.quantity), 0)
  152 + return this.round(qty, 2)
  153 + },
  154 + sumAmountExcl() {
  155 + const sum = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.amountExcludingTax), 0)
  156 + return this.round(sum, 2)
  157 + },
  158 + sumTotal() { return this.totalAmount },
  159 + totalAmount() {
  160 + let sum = 0
  161 + for (const it of this.items) {
  162 + if (!it.locked) continue
  163 + sum += this.toNumber(it.quantity) * this.toNumber(it.unitPrice)
  164 + }
  165 + return this.round(sum, 2)
  166 + },
  167 + totalExclTax() {
  168 + const TAX_RATE = 0.13
  169 + const total = this.totalAmount
  170 + return this.round(total / (1 + TAX_RATE), 2)
  171 + },
  172 + totalQtyDisplay() {
  173 + const qty = this.round(this.items.reduce((p, c) => p + this.toNumber(c.quantity), 0), 3)
  174 + return `${qty}t/${this.planQty}t`
  175 + }
  176 + },
  177 + onLoad(options) {
  178 + const id = options && options.id ? options.id : ''
  179 + this.id = id
  180 + this.loadDetail()
  181 + },
  182 + methods: {
  183 + onLockChange(idx, e) {
  184 + const it = this.items[idx]
  185 + if (!it) return
  186 + const arr = e && e.detail && e.detail.value ? e.detail.value : []
  187 + it.locked = Array.isArray(arr) && arr.length > 0
  188 + this.$set(this.items, idx, it)
  189 + },
  190 + async loadDetail() {
  191 + if (!this.id) return
  192 + try {
  193 + const res = await getContractApi(this.id)
  194 + const data = res && res.data ? res.data : {}
  195 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  196 + const init = lines.map(v => ({
  197 + locked: true,
  198 + collapsed: true,
  199 + raw: v,
  200 + productName: v.rawProductName || v.productName || '',
  201 + industry: v.industry || '',
  202 + brand: v.rawProductGrade || v.brand || '',
  203 + quality: v.quality || '',
  204 + thickness: v.thickness || '',
  205 + thicknessTolPos: v.thicknessTolPos || '',
  206 + thicknessTolNeg: v.thicknessTolNeg || '',
  207 + width: v.width || '',
  208 + widthTolPos: v.widthTolPos || '',
  209 + widthTolNeg: v.widthTolNeg || '',
  210 + length: v.length || '',
  211 + lengthTolPos: v.lengthTolPos || '',
  212 + lengthTolNeg: v.lengthTolNeg || '',
  213 + status: v.status || '',
  214 + quantity: v.productQuantity || v.quantity || '',
  215 + unitPrice: v.unitPrice || '',
  216 + amountExcludingTax: v.amountExcludingTax || 0,
  217 + totalAmount: v.totalAmount || 0,
  218 + deliveryDate: v.deliveryDate || '',
  219 + specDisplay: ''
  220 + }))
  221 + this.items = init.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  222 + this.recalculateAll()
  223 + } catch (e) {
  224 + this.items = []
  225 + }
  226 + },
  227 + toggleItem(idx) {
  228 + const it = this.items[idx]
  229 + if (!it) return
  230 + it.collapsed = !it.collapsed
  231 + this.$set(this.items, idx, it)
  232 + },
  233 + onImmediateChange(idx) {
  234 + this.$nextTick(() => this.recalculate(idx))
  235 + },
  236 + onNumberBlur(idx, field, digits) {
  237 + const it = this.items[idx]
  238 + if (!it) return
  239 + const raw = it[field]
  240 + if (raw === '' || raw === null || raw === undefined) {
  241 + this.$set(this.items, idx, it)
  242 + this.recalculate(idx)
  243 + return
  244 + }
  245 + const num = this.toNumber(raw)
  246 + const rounded = this.round(num, digits)
  247 + it[field] = rounded
  248 + this.$set(this.items, idx, it)
  249 + this.recalculate(idx)
  250 + },
  251 + recalculate(idx) {
  252 + const TAX_RATE = 0.13
  253 + const it = this.items[idx]
  254 + if (!it) return
  255 + const qty = this.toNumber(it.quantity)
  256 + const price = this.toNumber(it.unitPrice)
  257 + const total = this.round(qty * price, 2)
  258 + const excl = this.round(total / (1 + TAX_RATE), 2)
  259 + it.amountExcludingTax = excl
  260 + it.totalAmount = total
  261 + this.$set(this.items, idx, it)
  262 + },
  263 + recalculateAll() {
  264 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
  265 + },
  266 + toNumber(val) {
  267 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  268 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  269 + return isNaN(n) ? 0 : n
  270 + },
  271 + round(val, digits = 2) {
  272 + const n = Number(val)
  273 + if (isNaN(n)) return 0
  274 + const m = Math.pow(10, digits)
  275 + return Math.round(n * m) / m
  276 + },
  277 + specOf(item) {
  278 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/ ')
  279 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/ ')
  280 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/ ')
  281 + return [t, w, l].filter(Boolean).join(' × ')
  282 + },
  283 + formatCurrency(val) {
  284 + if (val == null || val === '') return ''
  285 + const num = Number(val)
  286 + const pre = isNaN(num) ? '' : '¥'
  287 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  288 + return `${pre}${fixed}`
  289 + },
  290 + onReset() {
  291 + this.items = this.items.map((it, i) => ({
  292 + ...it,
  293 + quantity: '',
  294 + unitPrice: '',
  295 + amountExcludingTax: 0
  296 + }))
  297 + },
  298 + async onSubmit() {
  299 + const selected = this.items.filter(it => it.locked).map(it => {
  300 + const raw = { ...(it.raw || {}) }
  301 + const qty = this.toNumber(it.quantity)
  302 + const price = this.toNumber(it.unitPrice)
  303 + const total = this.toNumber(it.totalAmount)
  304 + const excl = this.toNumber(it.amountExcludingTax)
  305 + if (Object.prototype.hasOwnProperty.call(raw, 'productQuantity')) raw.productQuantity = qty
  306 + else raw.quantity = qty
  307 + raw.unitPrice = price
  308 + raw.totalAmount = total
  309 + raw.amountExcludingTax = excl
  310 + return raw
  311 + })
  312 + if (!selected.length) {
  313 + uni.showToast({ title: '未选择任何锁价项', icon: 'none' })
  314 + return
  315 + }
  316 + const invalid = selected.find(r => {
  317 + const p = this.toNumber(r.unitPrice)
  318 + return !( p > 0)
  319 + })
  320 + if (invalid) {
  321 + uni.showToast({ title: '请填写单价', icon: 'none' })
  322 + return
  323 + }
  324 + this.selectedItems = selected
  325 + const payload = {
  326 + id: this.id,
  327 + totalAmountCapital: formatCurrencyToChinese(this.sumTotal),
  328 + totalAmountExcludingTax: this.sumAmountExcl,
  329 + totalAmountIncludingTax: this.sumTotal,
  330 + totalQuantity: this.sumQuantity,
  331 + type:'DIST_STOCK_CONTRACT',
  332 + contractDistributorLineList: selected
  333 + }
  334 +
  335 + uni.showModal({
  336 + title: '确认提交',
  337 + content: '确定提交锁价吗?',
  338 + success: (res) => {
  339 + if (res.confirm) {
  340 + priceLock(payload).then(() => {
  341 + uni.showToast({ title: '锁价已提交', icon: 'success' })
  342 + setTimeout(() => {
  343 + uni.navigateTo({ url: '/pages/contract_stock/index' })
  344 + }, 500)
  345 + }).catch(() => {
  346 + uni.showToast({ title: '提交失败', icon: 'none' })
  347 + })
  348 + }
  349 + }
  350 + })
  351 + }
  352 + }
  353 +}
  354 +</script>
  355 +
  356 +<style lang="scss" scoped>
  357 +.page {
  358 + display: flex;
  359 + flex-direction: column;
  360 + height: 100%;
  361 +}
  362 +
  363 +.scroll {
  364 + flex: 1;
  365 + padding: 12rpx 0 480rpx !important;
  366 +}
  367 +
  368 +.header {
  369 + background-color: #fff;
  370 + display: flex;
  371 + align-items: center;
  372 + padding: 24rpx 32rpx;
  373 + border-bottom: 1rpx solid #f0f0f0;
  374 +}
  375 +
  376 +.title {
  377 + font-size: 32rpx;
  378 + color: rgba(0, 0, 0, 0.9);
  379 + font-weight: 600;
  380 +}
  381 +
  382 +.opCollapse {
  383 + width: 24rpx;
  384 + height: 24rpx;
  385 + margin-right: 16rpx;
  386 + margin-top: 8rpx;
  387 +}
  388 +
  389 +.block {
  390 + background: #fff;
  391 + margin-top: 20rpx;
  392 +}
  393 +
  394 +.block-header {
  395 + display: flex;
  396 + align-items: center;
  397 + padding: 24rpx 32rpx;
  398 + border-bottom: 1rpx solid #f0f0f0;
  399 +}
  400 +
  401 +.block-header ::v-deep .uni-data-checklist .checkbox__inner {
  402 + width: 36rpx;
  403 + height: 36rpx;
  404 +}
  405 +.block-header ::v-deep .uni-data-checklist .checklist-text {
  406 + font-size: 28rpx;
  407 + margin-left: 12rpx;
  408 +}
  409 +
  410 +.block-title {
  411 + margin-left: 12rpx;
  412 + font-size: 28rpx;
  413 + color: rgba(0, 0, 0, 0.9);
  414 +}
  415 +
  416 +.ops {
  417 + margin-left: auto;
  418 + display: flex;
  419 + align-items: center;
  420 + color: $theme-primary;
  421 + font-size: 28rpx;
  422 +}
  423 +
  424 +.opIcon {
  425 + width: 40rpx;
  426 + height: 40rpx;
  427 +}
  428 +
  429 +.opText {
  430 + margin-left: 8rpx;
  431 + color: $theme-primary;
  432 +}
  433 +
  434 +::v-deep .uni-list {
  435 + .uni-easyinput {
  436 + display: flex;
  437 +
  438 + .uni-input-input {
  439 + color: rgba(0, 0, 0, 0.9);
  440 + }
  441 + }
  442 +
  443 + .uni-input-placeholder {
  444 + z-index: 1;
  445 + }
  446 +
  447 + .uni-input-input {
  448 + background-color: #ffffff;
  449 + }
  450 +
  451 + background: transparent;
  452 +
  453 + &-item {
  454 + &__extra-text {
  455 + font-size: 32rpx;
  456 + }
  457 +
  458 + &__content-title {
  459 + font-size: 32rpx;
  460 + color: rgba(0, 0, 0, 0.9);
  461 + }
  462 +
  463 + &__container {
  464 + padding: 32rpx;
  465 +
  466 + .uni-easyinput {
  467 + &__placeholder-class {
  468 + font-size: 32rpx;
  469 + color: rgba(0, 0, 0, 0.4);
  470 + }
  471 +
  472 + &__content {
  473 + border: none;
  474 + background-color: #ffffff !important;
  475 +
  476 + &-input {
  477 + padding-left: 0 !important;
  478 + height: 48rpx;
  479 + line-height: 48rpx;
  480 + font-size: 32rpx;
  481 + }
  482 +
  483 + .content-clear-icon {
  484 + font-size: 44rpx !important;
  485 + }
  486 + }
  487 + }
  488 +
  489 + .item-title,
  490 + .uni-list-item__content {
  491 + flex: none;
  492 + min-height: 48rpx;
  493 + line-height: 48rpx;
  494 + font-size: 32rpx;
  495 + position: relative;
  496 + width: 162rpx;
  497 + margin-right: 32rpx;
  498 + color: rgba(0, 0, 0, 0.9);
  499 +
  500 + .required {
  501 + color: red;
  502 + position: absolute;
  503 + top: 50%;
  504 + transform: translateY(-50%);
  505 + left: -16rpx;
  506 + }
  507 + }
  508 + }
  509 +
  510 + &.select-item {
  511 + &.is-empty {
  512 + .uni-list-item__extra-text {
  513 + color: rgba(0, 0, 0, 0.4) !important;
  514 + }
  515 + }
  516 +
  517 + &.is-filled {
  518 + .uni-list-item__extra-text {
  519 + color: rgba(0, 0, 0, 0.9) !important;
  520 + }
  521 + }
  522 + }
  523 +
  524 + &.mgb10 {
  525 + margin-bottom: 20rpx;
  526 + }
  527 + }
  528 +}
  529 +
  530 +// ::v-deep .uni-list-item__container {
  531 +// padding: 32rpx;
  532 +// }
  533 +
  534 +::v-deep .is-disabled {
  535 + background-color: transparent !important;
  536 +}
  537 +// ::v-deep .uni-list-item__content-title {
  538 +// font-size: 28rpx;
  539 +// color: rgba(0, 0, 0, 0.9);
  540 +// }
  541 +
  542 +// ::v-deep .uni-list-item__extra-text {
  543 +// font-size: 32rpx;
  544 +// }
  545 +
  546 +::v-deep .uni-easyinput {
  547 + width: 100%;
  548 +}
  549 +
  550 +::v-deep .uni-easyinput__placeholder-class {
  551 + font-size: 32rpx;
  552 + color: rgba(0, 0, 0, 0.4);
  553 +}
  554 +
  555 +::v-deep .uni-easyinput__content {
  556 + border: none;
  557 + display: flex;
  558 +}
  559 +
  560 +::v-deep .uni-easyinput__content-input {
  561 + padding-left: 0 !important;
  562 + height: 48rpx;
  563 + line-height: 48rpx;
  564 + font-size: 32rpx;
  565 + color: rgba(0, 0, 0, 0.9);
  566 +}
  567 +
  568 +.amount-item .item-title {
  569 + display: flex;
  570 + align-items: center;
  571 +}
  572 +
  573 +.amount-row {
  574 + display: flex;
  575 + align-items: center;
  576 +}
  577 +
  578 +.amount-row .unit {
  579 + margin-left: 12rpx;
  580 + color: rgba(0, 0, 0, 0.6);
  581 +}
  582 +
  583 +.summary {
  584 + margin-top: 20rpx;
  585 + background: #fff;
  586 + padding-bottom: 12rpx;
  587 +}
  588 +
  589 +.title-header {
  590 + display: flex;
  591 + align-items: center;
  592 + padding: 20rpx 32rpx;
  593 +}
  594 +
  595 +.title-header_icon {
  596 + width: 24rpx;
  597 + height: 24rpx;
  598 + margin-right: 16rpx;
  599 +}
  600 +
  601 +.sum-card {
  602 + background: #f3f3f3;
  603 + border-radius: 16rpx;
  604 + padding: 24rpx;
  605 + margin: 0 32rpx 20rpx;
  606 +}
  607 +
  608 +.row {
  609 + display: flex;
  610 + margin-bottom: 16rpx;
  611 +}
  612 +
  613 +.row .label {
  614 + width: 140rpx;
  615 + color: rgba(0, 0, 0, 0.6);
  616 + font-size: 28rpx;
  617 +}
  618 +
  619 +.row .value {
  620 + flex: 1;
  621 + text-align: right;
  622 + color: rgba(0, 0, 0, 0.9);
  623 + font-size: 28rpx;
  624 +}
  625 +
  626 +.row .amount {
  627 + color: #D54941;
  628 +}
  629 +
  630 +.total {
  631 + .total-text {
  632 + font-weight: 600;
  633 + font-size: 32rpx;
  634 + color: rgba(0, 0, 0, 0.9);
  635 + padding-bottom: 28rpx;
  636 + border-bottom: 2rpx solid #E7E7E7;
  637 + }
  638 +
  639 + .total-item {
  640 + display: flex;
  641 + align-items: center;
  642 +
  643 + .total-item-text {
  644 + font-weight: 400;
  645 + font-size: 28rpx;
  646 + color: rgba(0, 0, 0, 0.6);
  647 + line-height: 32rpx;
  648 + width: 240rpx;
  649 + padding: 24rpx 0;
  650 + }
  651 +
  652 + .total-item-price {
  653 + font-weight: 600;
  654 + font-size: 32rpx;
  655 + color: rgba(0, 0, 0, 0.9);
  656 + line-height: 32rpx;
  657 + }
  658 +
  659 + .text-red {
  660 + color: #D54941;
  661 + }
  662 + }
  663 +
  664 +}
  665 +
  666 +.footer {
  667 + z-index: 2;
  668 + position: fixed;
  669 + left: 0;
  670 + right: 0;
  671 + bottom: 0;
  672 + padding: 32rpx;
  673 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  674 + background: #fff;
  675 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  676 +
  677 + .btn {
  678 + height: 80rpx;
  679 + line-height: 80rpx;
  680 + border-radius: 12rpx;
  681 + font-size: 32rpx;
  682 + }
  683 +
  684 + .submit {
  685 + background: $theme-primary;
  686 + color: #fff;
  687 + }
  688 +}
  689 +
  690 +.btn {
  691 + height: 80rpx;
  692 + line-height: 80rpx;
  693 + border-radius: 12rpx;
  694 + font-size: 32rpx;
  695 + flex: 1;
  696 +}
  697 +
  698 +.submit {
  699 + background: $theme-primary;
  700 + color: #fff;
  701 +}
  702 +</style>
\ No newline at end of file
... ...
... ... @@ -180,6 +180,18 @@ export default {
180 180 }
181 181 },
182 182 {
  183 + text: '锁规',
  184 + visible: true,
  185 + variant: 'outline',
  186 + event: 'lock',
  187 + },
  188 + {
  189 + text: '锁规延期申请',
  190 + visible: true,
  191 + variant: 'outline',
  192 + event: 'lockApply'
  193 + },
  194 + {
183 195 text: '上传合同附件',
184 196 visible: true,
185 197 variant: 'outline',
... ... @@ -222,13 +234,16 @@ export default {
222 234 displayButtons() {
223 235 const s = this.detail && this.detail.status || ''
224 236 const t = this.detail.standardApproved || ''
  237 + const l = this.detail.priceSpecLocked || ''
225 238 return [
226 239 { ...this.buttons[0]},
227 240 // { ...this.buttons[0], visible: (s === 'DRAFT') },
228 241 { ...this.buttons[1], visible: (s === 'DRAFT') },
229   - { ...this.buttons[2], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
230   - { ...this.buttons[3], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
231   - { ...this.buttons[4], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  242 + { ...this.buttons[2], visible: (s === 'FORMAL' && !l) },
  243 + { ...this.buttons[3], visible: (s === 'FORMAL' && !l) },
  244 + { ...this.buttons[4], visible: ((s === 'DRAFT' || s === 'FORMAL') && t !== 'AUDIT' && t !== 'PASS') },
  245 + { ...this.buttons[5], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
  246 + { ...this.buttons[6], visible: (s === 'STANDARD' && t !== 'AUDIT' && t !== 'PASS') },
232 247 // { ...this.buttons[3], visible: (s === 'STANDARD' && t === 'AUDIT') },
233 248 // { ...this.buttons[4], visible: (s === 'STANDARD') }
234 249 ]
... ... @@ -273,6 +288,11 @@ export default {
273 288 url: '/pages/contract_unplan/modify' + query
274 289 })
275 290 },
  291 + onLockApply() {
  292 + uni.navigateTo({
  293 + url: '/pages/contract_unplan/lock_apply?id=' + this.detail.id || ''
  294 + })
  295 + },
276 296 uploadContract(id, type = 'formal'){
277 297 if (!id) return
278 298 this.uploadId = id
... ... @@ -342,12 +362,19 @@ export default {
342 362 const match = (options || []).find(o => String(o.value) === String(current) || String(o.label) === String(current))
343 363 this.sheet = { ...this.sheet, visible: true, title: '合同是否规范', options, value: match ? match.value : '' }
344 364 },
  365 + onLock() {
  366 + uni.navigateTo({
  367 + url: '/pages/contract_unplan/lock?id=' + this.detail.id || ''
  368 + })
  369 + },
345 370 handleButtonClick(btn) {
346 371 if (!btn || btn.disabled) return
347 372 if (typeof btn.onClick === 'function') return btn.onClick(this.detail, btn.params)
348 373 const e = btn.event || ''
349 374 if (e === 'edit') return this.onEdit(btn && btn.params)
350 375 if (e === 'delete') return this.onDelete(btn && btn.params)
  376 + if (e === 'lock') return this.onLock()
  377 + if (e === 'lockApply') return this.onLockApply()
351 378 if (e === 'upload') return this.uploadContract(this.detail.id || '')
352 379 if (e === 'uploadParent') return this.uploadContract(this.detail.parentId || '')
353 380 if (e === 'uploadStandard') return this.uploadContract(this.detail.id || '', 'standard')
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="lock-page">
  5 + <view class="block" v-for="(item, idx) in items" :key="idx">
  6 + <view class="block-header">
  7 + <uni-data-checkbox
  8 + multiple
  9 + mode="default"
  10 + :localdata="[{ text: '锁规', value: 'LOCKED' }]"
  11 + :modelValue="item.locked ? ['LOCKED'] : []"
  12 + @change="onLockChange(idx, $event)"
  13 + />
  14 + <view class="ops" @click="toggleItem(idx)">
  15 + <image class="opIcon"
  16 + :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" />
  17 + <text class="opText">{{ item.collapsed ? '收起' : '展开' }}</text>
  18 + </view>
  19 + </view>
  20 +
  21 + <uni-list v-show="item.collapsed">
  22 + <uni-list-item title="产品名称">
  23 + <template v-slot:footer>
  24 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  25 + </template>
  26 + </uni-list-item>
  27 + <uni-list-item title="行业">
  28 + <template v-slot:footer>
  29 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  30 + </template>
  31 + </uni-list-item>
  32 + <uni-list-item title="牌号">
  33 + <template v-slot:footer>
  34 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  35 + </template>
  36 + </uni-list-item>
  37 + <uni-list-item title="品质">
  38 + <template v-slot:footer>
  39 + <uni-easyinput v-model="item.quality" placeholder="请输入品质" :clearable="false" disabled />
  40 + </template>
  41 + </uni-list-item>
  42 + <uni-list-item title="规格">
  43 + <template v-slot:footer>
  44 + <uni-easyinput v-model="item.specDisplay" placeholder="自动拼接规格" :clearable="false" disabled />
  45 + </template>
  46 + </uni-list-item>
  47 + <uni-list-item title="状态">
  48 + <template v-slot:footer>
  49 + <uni-easyinput v-model="item.status" placeholder="请输入状态" :clearable="false" disabled />
  50 + </template>
  51 + </uni-list-item>
  52 + <uni-list-item title="数量">
  53 + <template v-slot:footer>
  54 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" placeholder="请输入数量" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'quantity', 0)" />
  55 + </template>
  56 + </uni-list-item>
  57 + <uni-list-item title="单价">
  58 + <template v-slot:footer>
  59 + <uni-easyinput v-model="item.unitPrice" type="number" :inputBorder="false" placeholder="请输入单价" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'unitPrice', 0)" />
  60 + </template>
  61 + </uni-list-item>
  62 + <uni-list-item title="不含税金额">
  63 + <template v-slot:footer>
  64 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  65 + </template>
  66 + </uni-list-item>
  67 + <uni-list-item title="总金额">
  68 + <template v-slot:footer>
  69 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled placeholder="自动计算" />
  70 + </template>
  71 + </uni-list-item>
  72 + <uni-list-item title="发货日期">
  73 + <template v-slot:footer>
  74 + <uni-easyinput v-model="item.deliveryDate" :inputBorder="false" disabled />
  75 + </template>
  76 + </uni-list-item>
  77 + </uni-list>
  78 +
  79 + <uni-list v-show="!item.collapsed">
  80 + <uni-list-item title="产品名称">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="item.productName" placeholder="请输入产品名称" :clearable="false" disabled />
  83 + </template>
  84 + </uni-list-item>
  85 + <uni-list-item title="行业">
  86 + <template v-slot:footer>
  87 + <uni-easyinput v-model="item.industry" placeholder="请输入行业" :clearable="false" disabled />
  88 + </template>
  89 + </uni-list-item>
  90 + <uni-list-item title="牌号">
  91 + <template v-slot:footer>
  92 + <uni-easyinput v-model="item.brand" placeholder="请输入牌号" :clearable="false" disabled />
  93 + </template>
  94 + </uni-list-item>
  95 + </uni-list>
  96 + </view>
  97 + </view>
  98 + </scroll-view>
  99 +
  100 + <view class="footer">
  101 + <div class="total">
  102 + <div class="total-text">
  103 + 合计
  104 + </div>
  105 + <div class="total-item">
  106 + <div class="total-item-text">
  107 + 数量
  108 + </div>
  109 + <div class="total-item-price">
  110 + {{ (sumQuantity || 0).toFixed(2) }}t
  111 + </div>
  112 + </div>
  113 + <div class="total-item">
  114 + <div class="total-item-text">
  115 + 不含税金额
  116 + </div>
  117 + <div class="total-item-price text-red">
  118 + ¥{{ (sumAmountExcl || 0).toFixed(2) }}
  119 + </div>
  120 + </div>
  121 + <div class="total-item">
  122 + <div class="total-item-text">
  123 + 总金额
  124 + </div>
  125 + <div class="total-item-price text-red">
  126 + ¥{{ (sumTotal || 0).toFixed(2) }}
  127 + </div>
  128 + </div>
  129 + </div>
  130 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  131 + </view>
  132 + </view>
  133 +</template>
  134 +
  135 +<script>
  136 +import { getContractApi, specificationLock } from '@/api/contract'
  137 +import { formatCurrencyToChinese } from '@/utils/common'
  138 +
  139 +export default {
  140 + name: 'ContractUnplanLock',
  141 + data() {
  142 + return {
  143 + id: '',
  144 + items: [],
  145 + planQty: 30,
  146 + }
  147 + },
  148 + computed: {
  149 + sumQuantity() {
  150 + const qty = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.quantity), 0)
  151 + return this.round(qty, 2)
  152 + },
  153 + sumAmountExcl() {
  154 + const sum = this.items.filter(it => it.locked).reduce((p, c) => p + this.toNumber(c.amountExcludingTax), 0)
  155 + return this.round(sum, 2)
  156 + },
  157 + sumTotal() { return this.totalAmount },
  158 + totalAmount() {
  159 + let sum = 0
  160 + for (const it of this.items) {
  161 + if (!it.locked) continue
  162 + sum += this.toNumber(it.quantity) * this.toNumber(it.unitPrice)
  163 + }
  164 + return this.round(sum, 2)
  165 + },
  166 + totalExclTax() {
  167 + const TAX_RATE = 0.13
  168 + const total = this.totalAmount
  169 + return this.round(total / (1 + TAX_RATE), 2)
  170 + },
  171 + totalQtyDisplay() {
  172 + const qty = this.round(this.items.reduce((p, c) => p + this.toNumber(c.quantity), 0), 3)
  173 + return `${qty}t/${this.planQty}t`
  174 + }
  175 + },
  176 + onLoad(options) {
  177 + const id = options && options.id ? options.id : ''
  178 + this.id = id
  179 + this.loadDetail()
  180 + },
  181 + methods: {
  182 + onLockChange(idx, e) {
  183 + const it = this.items[idx]
  184 + if (!it) return
  185 + const arr = e && e.detail && e.detail.value ? e.detail.value : []
  186 + it.locked = Array.isArray(arr) && arr.length > 0
  187 + this.$set(this.items, idx, it)
  188 + },
  189 + async loadDetail() {
  190 + if (!this.id) return
  191 + try {
  192 + const res = await getContractApi(this.id)
  193 + const data = res && res.data ? res.data : {}
  194 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  195 + const init = lines.map(v => ({
  196 + locked: false,
  197 + collapsed: true,
  198 + raw: v,
  199 + productName: v.rawProductName || v.productName || '',
  200 + industry: v.industry || '',
  201 + brand: v.rawProductGrade || v.brand || '',
  202 + quality: v.quality || '',
  203 + thickness: v.thickness || '',
  204 + thicknessTolPos: v.thicknessTolPos || '',
  205 + thicknessTolNeg: v.thicknessTolNeg || '',
  206 + width: v.width || '',
  207 + widthTolPos: v.widthTolPos || '',
  208 + widthTolNeg: v.widthTolNeg || '',
  209 + length: v.length || '',
  210 + lengthTolPos: v.lengthTolPos || '',
  211 + lengthTolNeg: v.lengthTolNeg || '',
  212 + status: v.status || '',
  213 + quantity: v.productQuantity || v.quantity || '',
  214 + unitPrice: v.unitPrice || '',
  215 + amountExcludingTax: v.amountExcludingTax || 0,
  216 + totalAmount: v.totalAmount || 0,
  217 + deliveryDate: v.deliveryDate || '',
  218 + specDisplay: ''
  219 + }))
  220 + this.items = init.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  221 + this.recalculateAll()
  222 + } catch (e) {
  223 + this.items = []
  224 + }
  225 + },
  226 + toggleItem(idx) {
  227 + const it = this.items[idx]
  228 + if (!it) return
  229 + it.collapsed = !it.collapsed
  230 + this.$set(this.items, idx, it)
  231 + },
  232 + onImmediateChange(idx) {
  233 + this.$nextTick(() => this.recalculate(idx))
  234 + },
  235 + onNumberBlur(idx, field, digits) {
  236 + const it = this.items[idx]
  237 + if (!it) return
  238 + const raw = it[field]
  239 + if (raw === '' || raw === null || raw === undefined) {
  240 + this.$set(this.items, idx, it)
  241 + this.recalculate(idx)
  242 + return
  243 + }
  244 + const num = this.toNumber(raw)
  245 + const rounded = this.round(num, digits)
  246 + it[field] = rounded
  247 + this.$set(this.items, idx, it)
  248 + this.recalculate(idx)
  249 + },
  250 + recalculate(idx) {
  251 + const TAX_RATE = 0.13
  252 + const it = this.items[idx]
  253 + if (!it) return
  254 + const qty = this.toNumber(it.quantity)
  255 + const price = this.toNumber(it.unitPrice)
  256 + const total = this.round(qty * price, 2)
  257 + const excl = this.round(total / (1 + TAX_RATE), 2)
  258 + it.amountExcludingTax = excl
  259 + it.totalAmount = total
  260 + this.$set(this.items, idx, it)
  261 + },
  262 + recalculateAll() {
  263 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
  264 + },
  265 + toNumber(val) {
  266 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  267 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  268 + return isNaN(n) ? 0 : n
  269 + },
  270 + round(val, digits = 2) {
  271 + const n = Number(val)
  272 + if (isNaN(n)) return 0
  273 + const m = Math.pow(10, digits)
  274 + return Math.round(n * m) / m
  275 + },
  276 + specOf(item) {
  277 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/ ')
  278 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/ ')
  279 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/ ')
  280 + return [t, w, l].filter(Boolean).join(' × ')
  281 + },
  282 + formatCurrency(val) {
  283 + if (val == null || val === '') return ''
  284 + const num = Number(val)
  285 + const pre = isNaN(num) ? '' : '¥'
  286 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  287 + return `${pre}${fixed}`
  288 + },
  289 + onReset() {
  290 + this.items = this.items.map((it, i) => ({
  291 + ...it,
  292 + quantity: '',
  293 + unitPrice: '',
  294 + amountExcludingTax: 0
  295 + }))
  296 + },
  297 + async onSubmit() {
  298 + const selected = this.items.filter(it => it.locked).map(it => {
  299 + const raw = { ...(it.raw || {}) }
  300 + const qty = this.toNumber(it.quantity)
  301 + const price = this.toNumber(it.unitPrice)
  302 + const total = this.toNumber(it.totalAmount)
  303 + const excl = this.toNumber(it.amountExcludingTax)
  304 + if (Object.prototype.hasOwnProperty.call(raw, 'productQuantity')) raw.productQuantity = qty
  305 + else raw.quantity = qty
  306 + raw.unitPrice = price
  307 + raw.totalAmount = total
  308 + raw.amountExcludingTax = excl
  309 + return raw
  310 + })
  311 + if (!selected.length) {
  312 + uni.showToast({ title: '未选择任何锁规项', icon: 'none' })
  313 + return
  314 + }
  315 + const invalid = selected.find(r => {
  316 + const q = this.toNumber(r.productQuantity != null ? r.productQuantity : r.quantity)
  317 + const p = this.toNumber(r.unitPrice)
  318 + return !(q > 0 && p > 0)
  319 + })
  320 + if (invalid) {
  321 + uni.showToast({ title: '请填写数量和单价', icon: 'none' })
  322 + return
  323 + }
  324 + this.selectedItems = selected
  325 + const payload = {
  326 + id: this.id,
  327 + totalAmountCapital: formatCurrencyToChinese(this.sumTotal),
  328 + totalAmountExcludingTax: this.sumAmountExcl,
  329 + totalAmountIncludingTax: this.sumTotal,
  330 + totalQuantity: this.sumQuantity,
  331 + type:'DRAFT_DIST_AGMT',
  332 + contractDistributorLineList: selected
  333 + }
  334 +
  335 + uni.showModal({
  336 + title: '确认提交',
  337 + content: '确定提交锁规吗?',
  338 + success: (res) => {
  339 + if (res.confirm) {
  340 + specificationLock(payload).then(() => {
  341 + uni.showToast({ title: '锁规已提交', icon: 'success' })
  342 + setTimeout(() => {
  343 + uni.navigateTo({ url: '/pages/contract_unplan/index' })
  344 + }, 500)
  345 + }).catch(() => {
  346 + uni.showToast({ title: '提交失败', icon: 'none' })
  347 + })
  348 + }
  349 + }
  350 + })
  351 + }
  352 + }
  353 +}
  354 +</script>
  355 +
  356 +<style lang="scss" scoped>
  357 +.page {
  358 + display: flex;
  359 + flex-direction: column;
  360 + height: 100%;
  361 +}
  362 +
  363 +.scroll {
  364 + flex: 1;
  365 + padding: 12rpx 0 480rpx !important;
  366 +}
  367 +
  368 +.header {
  369 + background-color: #fff;
  370 + display: flex;
  371 + align-items: center;
  372 + padding: 24rpx 32rpx;
  373 + border-bottom: 1rpx solid #f0f0f0;
  374 +}
  375 +
  376 +.title {
  377 + font-size: 32rpx;
  378 + color: rgba(0, 0, 0, 0.9);
  379 + font-weight: 600;
  380 +}
  381 +
  382 +.opCollapse {
  383 + width: 24rpx;
  384 + height: 24rpx;
  385 + margin-right: 16rpx;
  386 + margin-top: 8rpx;
  387 +}
  388 +
  389 +.block {
  390 + background: #fff;
  391 + margin-top: 20rpx;
  392 +}
  393 +
  394 +.block-header {
  395 + display: flex;
  396 + align-items: center;
  397 + padding: 24rpx 32rpx;
  398 + border-bottom: 1rpx solid #f0f0f0;
  399 +}
  400 +
  401 +.block-header ::v-deep .uni-data-checklist .checkbox__inner {
  402 + width: 36rpx;
  403 + height: 36rpx;
  404 +}
  405 +.block-header ::v-deep .uni-data-checklist .checklist-text {
  406 + font-size: 28rpx;
  407 + margin-left: 12rpx;
  408 +}
  409 +
  410 +.block-title {
  411 + margin-left: 12rpx;
  412 + font-size: 28rpx;
  413 + color: rgba(0, 0, 0, 0.9);
  414 +}
  415 +
  416 +.ops {
  417 + margin-left: auto;
  418 + display: flex;
  419 + align-items: center;
  420 + color: $theme-primary;
  421 + font-size: 28rpx;
  422 +}
  423 +
  424 +.opIcon {
  425 + width: 40rpx;
  426 + height: 40rpx;
  427 +}
  428 +
  429 +.opText {
  430 + margin-left: 8rpx;
  431 + color: $theme-primary;
  432 +}
  433 +
  434 +::v-deep .uni-list {
  435 + .uni-easyinput {
  436 + display: flex;
  437 +
  438 + .uni-input-input {
  439 + color: rgba(0, 0, 0, 0.9);
  440 + }
  441 + }
  442 +
  443 + .uni-input-placeholder {
  444 + z-index: 1;
  445 + }
  446 +
  447 + .uni-input-input {
  448 + background-color: #ffffff;
  449 + }
  450 +
  451 + background: transparent;
  452 +
  453 + &-item {
  454 + &__extra-text {
  455 + font-size: 32rpx;
  456 + }
  457 +
  458 + &__content-title {
  459 + font-size: 32rpx;
  460 + color: rgba(0, 0, 0, 0.9);
  461 + }
  462 +
  463 + &__container {
  464 + padding: 32rpx;
  465 +
  466 + .uni-easyinput {
  467 + &__placeholder-class {
  468 + font-size: 32rpx;
  469 + color: rgba(0, 0, 0, 0.4);
  470 + }
  471 +
  472 + &__content {
  473 + border: none;
  474 + background-color: #ffffff !important;
  475 +
  476 + &-input {
  477 + padding-left: 0 !important;
  478 + height: 48rpx;
  479 + line-height: 48rpx;
  480 + font-size: 32rpx;
  481 + }
  482 +
  483 + .content-clear-icon {
  484 + font-size: 44rpx !important;
  485 + }
  486 + }
  487 + }
  488 +
  489 + .item-title,
  490 + .uni-list-item__content {
  491 + flex: none;
  492 + min-height: 48rpx;
  493 + line-height: 48rpx;
  494 + font-size: 32rpx;
  495 + position: relative;
  496 + width: 162rpx;
  497 + margin-right: 32rpx;
  498 + color: rgba(0, 0, 0, 0.9);
  499 +
  500 + .required {
  501 + color: red;
  502 + position: absolute;
  503 + top: 50%;
  504 + transform: translateY(-50%);
  505 + left: -16rpx;
  506 + }
  507 + }
  508 + }
  509 +
  510 + &.select-item {
  511 + &.is-empty {
  512 + .uni-list-item__extra-text {
  513 + color: rgba(0, 0, 0, 0.4) !important;
  514 + }
  515 + }
  516 +
  517 + &.is-filled {
  518 + .uni-list-item__extra-text {
  519 + color: rgba(0, 0, 0, 0.9) !important;
  520 + }
  521 + }
  522 + }
  523 +
  524 + &.mgb10 {
  525 + margin-bottom: 20rpx;
  526 + }
  527 + }
  528 +}
  529 +
  530 +// ::v-deep .uni-list-item__container {
  531 +// padding: 32rpx;
  532 +// }
  533 +
  534 +::v-deep .is-disabled {
  535 + background-color: transparent !important;
  536 +}
  537 +// ::v-deep .uni-list-item__content-title {
  538 +// font-size: 28rpx;
  539 +// color: rgba(0, 0, 0, 0.9);
  540 +// }
  541 +
  542 +// ::v-deep .uni-list-item__extra-text {
  543 +// font-size: 32rpx;
  544 +// }
  545 +
  546 +::v-deep .uni-easyinput {
  547 + width: 100%;
  548 +}
  549 +
  550 +::v-deep .uni-easyinput__placeholder-class {
  551 + font-size: 32rpx;
  552 + color: rgba(0, 0, 0, 0.4);
  553 +}
  554 +
  555 +::v-deep .uni-easyinput__content {
  556 + border: none;
  557 + display: flex;
  558 +}
  559 +
  560 +::v-deep .uni-easyinput__content-input {
  561 + padding-left: 0 !important;
  562 + height: 48rpx;
  563 + line-height: 48rpx;
  564 + font-size: 32rpx;
  565 + color: rgba(0, 0, 0, 0.9);
  566 +}
  567 +
  568 +.amount-item .item-title {
  569 + display: flex;
  570 + align-items: center;
  571 +}
  572 +
  573 +.amount-row {
  574 + display: flex;
  575 + align-items: center;
  576 +}
  577 +
  578 +.amount-row .unit {
  579 + margin-left: 12rpx;
  580 + color: rgba(0, 0, 0, 0.6);
  581 +}
  582 +
  583 +.summary {
  584 + margin-top: 20rpx;
  585 + background: #fff;
  586 + padding-bottom: 12rpx;
  587 +}
  588 +
  589 +.title-header {
  590 + display: flex;
  591 + align-items: center;
  592 + padding: 20rpx 32rpx;
  593 +}
  594 +
  595 +.title-header_icon {
  596 + width: 24rpx;
  597 + height: 24rpx;
  598 + margin-right: 16rpx;
  599 +}
  600 +
  601 +.sum-card {
  602 + background: #f3f3f3;
  603 + border-radius: 16rpx;
  604 + padding: 24rpx;
  605 + margin: 0 32rpx 20rpx;
  606 +}
  607 +
  608 +.row {
  609 + display: flex;
  610 + margin-bottom: 16rpx;
  611 +}
  612 +
  613 +.row .label {
  614 + width: 140rpx;
  615 + color: rgba(0, 0, 0, 0.6);
  616 + font-size: 28rpx;
  617 +}
  618 +
  619 +.row .value {
  620 + flex: 1;
  621 + text-align: right;
  622 + color: rgba(0, 0, 0, 0.9);
  623 + font-size: 28rpx;
  624 +}
  625 +
  626 +.row .amount {
  627 + color: #D54941;
  628 +}
  629 +
  630 +.total {
  631 + .total-text {
  632 + font-weight: 600;
  633 + font-size: 32rpx;
  634 + color: rgba(0, 0, 0, 0.9);
  635 + padding-bottom: 28rpx;
  636 + border-bottom: 2rpx solid #E7E7E7;
  637 + }
  638 +
  639 + .total-item {
  640 + display: flex;
  641 + align-items: center;
  642 +
  643 + .total-item-text {
  644 + font-weight: 400;
  645 + font-size: 28rpx;
  646 + color: rgba(0, 0, 0, 0.6);
  647 + line-height: 32rpx;
  648 + width: 240rpx;
  649 + padding: 24rpx 0;
  650 + }
  651 +
  652 + .total-item-price {
  653 + font-weight: 600;
  654 + font-size: 32rpx;
  655 + color: rgba(0, 0, 0, 0.9);
  656 + line-height: 32rpx;
  657 + }
  658 +
  659 + .text-red {
  660 + color: #D54941;
  661 + }
  662 + }
  663 +
  664 +}
  665 +
  666 +.footer {
  667 + z-index: 2;
  668 + position: fixed;
  669 + left: 0;
  670 + right: 0;
  671 + bottom: 0;
  672 + padding: 32rpx;
  673 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  674 + background: #fff;
  675 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  676 +
  677 + .btn {
  678 + height: 80rpx;
  679 + line-height: 80rpx;
  680 + border-radius: 12rpx;
  681 + font-size: 32rpx;
  682 + }
  683 +
  684 + .submit {
  685 + background: $theme-primary;
  686 + color: #fff;
  687 + }
  688 +}
  689 +
  690 +.btn {
  691 + height: 80rpx;
  692 + line-height: 80rpx;
  693 + border-radius: 12rpx;
  694 + font-size: 32rpx;
  695 + flex: 1;
  696 +}
  697 +
  698 +.submit {
  699 + background: $theme-primary;
  700 + color: #fff;
  701 +}
  702 +</style>
\ No newline at end of file
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="detail-page">
  5 + <view class="section">
  6 + <uni-list>
  7 + <uni-list-item title="客户名称">
  8 + <template v-slot:footer>
  9 + <uni-easyinput v-model="detail.customerName" :clearable="false" disabled />
  10 + </template>
  11 + </uni-list-item>
  12 + <uni-list-item title="订单编号">
  13 + <template v-slot:footer>
  14 + <uni-easyinput v-model="detail.contractCode" :clearable="false" disabled />
  15 + </template>
  16 + </uni-list-item>
  17 + <uni-list-item title="办事处">
  18 + <template v-slot:footer>
  19 + <uni-easyinput v-model="detail.deptName" :clearable="false" disabled />
  20 + </template>
  21 + </uni-list-item>
  22 + <uni-list-item title="所属分厂">
  23 + <template v-slot:footer>
  24 + <uni-easyinput v-model="detail.workshopName" :clearable="false" disabled />
  25 + </template>
  26 + </uni-list-item>
  27 + <uni-list-item title="订单类型">
  28 + <template v-slot:footer>
  29 + <uni-easyinput v-model="detail.contractType" :clearable="false" disabled />
  30 + </template>
  31 + </uni-list-item>
  32 + <uni-list-item title="原订货日期">
  33 + <template v-slot:footer>
  34 + <uni-easyinput v-model="detail.orderDate" :clearable="false" disabled />
  35 + </template>
  36 + </uni-list-item>
  37 + <uni-list-item title="第几次申请">
  38 + <template v-slot:footer>
  39 + <uni-easyinput v-model="detail.applicationCount" :clearable="false" disabled />
  40 + </template>
  41 + </uni-list-item>
  42 + <uni-list-item title="制单日期">
  43 + <template v-slot:footer>
  44 + <uni-easyinput v-model="detail.contractDocumentDate" :clearable="false" disabled />
  45 + </template>
  46 + </uni-list-item>
  47 + <uni-list-item title="数量">
  48 + <template v-slot:footer>
  49 + <uni-easyinput v-model="detail.totalQuantity" :clearable="false" disabled />
  50 + </template>
  51 + </uni-list-item>
  52 + </uni-list>
  53 + </view>
  54 +
  55 + <view class="section1">
  56 + <uni-list>
  57 + <uni-list-item title="现申请锁规格日期">
  58 + <template v-slot:footer>
  59 + <uni-datetime-picker type="date" v-model="form.specLockDate" />
  60 + </template>
  61 + </uni-list-item>
  62 + <uni-list-item title="延迟原因">
  63 + <template v-slot:footer>
  64 + <uni-easyinput v-model="form.delayReason" placeholder="请输入原因" :inputBorder="false" />
  65 + </template>
  66 + </uni-list-item>
  67 + </uni-list>
  68 + </view>
  69 + </view>
  70 + </scroll-view>
  71 + <view class="footer">
  72 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  73 + </view>
  74 + </view>
  75 +</template>
  76 +
  77 +<script>
  78 +import { showContract, specLockDelayApplication } from '@/api/contract'
  79 +export default {
  80 + name: 'LockApplyForeignUnplan',
  81 + data() {
  82 + return {
  83 + id: '',
  84 + detail: {
  85 + contractCode: '',
  86 + customerName: '',
  87 + deptName: '',
  88 + workshopName: '',
  89 + orderType: '',
  90 + orderTypeName: '',
  91 + orderDate: '',
  92 + applicationCount: '',
  93 + contractDocumentDate: '',
  94 + totalQuantity: ''
  95 + },
  96 + form: { specLockDate: '', delayReason: '' }
  97 + }
  98 + },
  99 + onLoad(options) {
  100 + const id = options && options.id ? options.id : ''
  101 + this.id = id
  102 + this.loadDetail()
  103 + },
  104 + methods: {
  105 + async loadDetail() {
  106 + if (!this.id) return
  107 + try {
  108 + const res = await showContract(this.id)
  109 + const data = res && res.data ? res.data : {}
  110 + this.detail = {
  111 + contractCode: data.contractCode || '',
  112 + customerName: data.customerName || '',
  113 + deptName: data.deptName || '',
  114 + workshopName: data.workshopName || '',
  115 + orderType: data.orderType || '',
  116 + contractType: data.contractType === 'DRAFT_DIST_AGMT' ? '经销订单' : '外贸订单',
  117 + orderDate: (data.orderDate || '').slice(0, 10),
  118 + applicationCount: data.applicationCount || '',
  119 + contractDocumentDate: (data.contractDocumentDate || '').slice(0, 10),
  120 + totalQuantity: data.totalQuantity || ''
  121 + }
  122 + } catch (e) {
  123 + this.detail = { ...this.detail }
  124 + }
  125 + },
  126 +
  127 + onSubmit() {
  128 + const date = this.form.specLockDate
  129 + const reason = this.form.delayReason
  130 + const emptyDate = !date
  131 + if (emptyDate) {
  132 + uni.showToast({ title: '请填写日期', icon: 'none' })
  133 + return
  134 + }
  135 + uni.showModal({
  136 + title: '确认提交',
  137 + content: '确定提交锁规无规格申请吗?',
  138 + success: (res) => {
  139 + if (res.confirm) {
  140 + specLockDelayApplication({
  141 + ...this.detail,
  142 + specLockDate: date,
  143 + delayReason: reason
  144 + }).then(res => {
  145 + if (res.code === 200) {
  146 + uni.showToast({ title: '提交成功', icon: 'success' })
  147 + setTimeout(() => {
  148 + uni.navigateTo({ url: '/pages/contract_unplan/index' })
  149 + }, 1000)
  150 + } else {
  151 + uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
  152 + }
  153 + })
  154 + }
  155 + }
  156 + })
  157 + }
  158 + }
  159 +}
  160 +</script>
  161 +
  162 +<style lang="scss" scoped>
  163 +.page {
  164 + display: flex;
  165 + flex-direction: column;
  166 + height: 100%;
  167 +}
  168 +
  169 +.scroll {
  170 + flex: 1;
  171 + padding: 8rpx 0 144rpx;
  172 +}
  173 +
  174 +.detail-page {
  175 + background: #f3f3f3;
  176 +}
  177 +
  178 +.section {
  179 + background: #fff;
  180 + margin-bottom: 20rpx;
  181 +}
  182 +.section1 {
  183 + background: #fff;
  184 + margin-bottom: 20rpx;
  185 +}
  186 +
  187 +.row {
  188 + display: flex;
  189 + margin-bottom: 20rpx;
  190 + align-items: center;
  191 +}
  192 +
  193 +.row:last-child {
  194 + margin-bottom: 0;
  195 +}
  196 +
  197 +.label {
  198 + width: 280rpx;
  199 + color: rgba(0, 0, 0, 0.6);
  200 + font-size: 28rpx;
  201 +}
  202 +
  203 +.value {
  204 + flex: 1;
  205 + text-align: right;
  206 + color: rgba(0, 0, 0, 0.9);
  207 + font-size: 28rpx;
  208 +}
  209 +
  210 +.customer {
  211 + font-weight: 600;
  212 + font-size: 36rpx;
  213 + color: rgba(0, 0, 0, 0.9);
  214 + padding-bottom: 12rpx;
  215 +}
  216 +
  217 +.footer {
  218 + position: fixed;
  219 + left: 0; right: 0; bottom: 0;
  220 + padding: 24rpx 32rpx 48rpx;
  221 + background: #fff;
  222 + box-shadow: 0 -8rpx 24rpx rgba(0,0,0,0.06);
  223 +}
  224 +.footer .btn { height: 80rpx; line-height: 80rpx; border-radius: 12rpx; font-size: 32rpx; }
  225 +.footer .submit { background: $theme-primary; color: #fff; }
  226 +
  227 +::v-deep .uni-list {
  228 + .uni-easyinput {
  229 + display: flex;
  230 +
  231 + .uni-input-input {
  232 + color: rgba(0, 0, 0, 0.9);
  233 + }
  234 + }
  235 +
  236 + .uni-input-placeholder {
  237 + z-index: 1;
  238 + }
  239 +
  240 + .uni-input-input {
  241 + background-color: #ffffff;
  242 + }
  243 +
  244 + background: transparent;
  245 +
  246 + &-item {
  247 + &__extra-text {
  248 + font-size: 32rpx;
  249 + }
  250 +
  251 + &__content-title {
  252 + font-size: 32rpx;
  253 + color: rgba(0, 0, 0, 0.9);
  254 + }
  255 +
  256 + &__container {
  257 + padding: 32rpx;
  258 +
  259 + .uni-easyinput {
  260 + &__placeholder-class {
  261 + font-size: 32rpx;
  262 + color: rgba(0, 0, 0, 0.4);
  263 + }
  264 +
  265 + &__content {
  266 + border: none;
  267 + background-color: #ffffff !important;
  268 +
  269 + &-input {
  270 + padding-left: 0 !important;
  271 + height: 48rpx;
  272 + line-height: 48rpx;
  273 + font-size: 32rpx;
  274 + }
  275 +
  276 + .content-clear-icon {
  277 + font-size: 44rpx !important;
  278 + }
  279 + }
  280 + }
  281 +
  282 + .item-title,
  283 + .uni-list-item__content {
  284 + flex: none;
  285 + min-height: 48rpx;
  286 + line-height: 48rpx;
  287 + font-size: 32rpx;
  288 + position: relative;
  289 + width: 162rpx;
  290 + margin-right: 32rpx;
  291 + color: rgba(0, 0, 0, 0.9);
  292 +
  293 + .required {
  294 + color: red;
  295 + position: absolute;
  296 + top: 50%;
  297 + transform: translateY(-50%);
  298 + left: -16rpx;
  299 + }
  300 + }
  301 + }
  302 +
  303 + &.select-item {
  304 + &.is-empty {
  305 + .uni-list-item__extra-text {
  306 + color: rgba(0, 0, 0, 0.4) !important;
  307 + }
  308 + }
  309 +
  310 + &.is-filled {
  311 + .uni-list-item__extra-text {
  312 + color: rgba(0, 0, 0, 0.9) !important;
  313 + }
  314 + }
  315 + }
  316 +
  317 + &.mgb10 {
  318 + margin-bottom: 20rpx;
  319 + }
  320 + }
  321 +}
  322 +
  323 +// ::v-deep .uni-list-item__container {
  324 +// padding: 32rpx;
  325 +// }
  326 +
  327 +::v-deep .is-disabled {
  328 + background-color: transparent !important;
  329 +}
  330 +// ::v-deep .uni-list-item__content-title {
  331 +// font-size: 28rpx;
  332 +// color: rgba(0, 0, 0, 0.9);
  333 +// }
  334 +
  335 +// ::v-deep .uni-list-item__extra-text {
  336 +// font-size: 32rpx;
  337 +// }
  338 +
  339 +::v-deep .uni-easyinput {
  340 + width: 100%;
  341 +}
  342 +
  343 +::v-deep .uni-easyinput__placeholder-class {
  344 + font-size: 32rpx;
  345 + color: rgba(0, 0, 0, 0.4);
  346 +}
  347 +
  348 +::v-deep .uni-easyinput__content {
  349 + border: none;
  350 + display: flex;
  351 +}
  352 +
  353 +::v-deep .uni-easyinput__content-input {
  354 + padding-left: 0 !important;
  355 + height: 48rpx;
  356 + line-height: 48rpx;
  357 + font-size: 32rpx;
  358 + color: rgba(0, 0, 0, 0.9);
  359 +}
  360 +</style>
\ No newline at end of file
... ...