Commit 91ec5a27faecd1a966548d17aac53f5774a1ecb6

Authored by gesilong
1 parent cd0d970b

commit: 经销标准合同新增/查看

1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 import { ContentTypeEnum } from '@/utils/httpEnum'; 2 import { ContentTypeEnum } from '@/utils/httpEnum';
3 - 3 +const region = 'cloud-api';
4 export const statusStyle = [ 4 export const statusStyle = [
5 { color: '#2BA471', bgColor:'#E3F9E9',text: '审核通过' }, 5 { color: '#2BA471', bgColor:'#E3F9E9',text: '审核通过' },
6 { color: '#D54941', bgColor:'#FFF0ED',text: '已驳回' }, 6 { color: '#D54941', bgColor:'#FFF0ED',text: '已驳回' },
@@ -83,3 +83,25 @@ export function getRetailCodeApi() { @@ -83,3 +83,25 @@ export function getRetailCodeApi() {
83 method: 'get', 83 method: 'get',
84 }) 84 })
85 } 85 }
  86 +
  87 +// 新增合同
  88 +export function createContractApi(data) {
  89 + return request({
  90 + url: `${baseUrl}/contractDistributorStandard`,
  91 + method: 'post',
  92 + data,
  93 + contentType: ContentTypeEnum.JSON
  94 + })
  95 +}
  96 +
  97 +// 查看合同
  98 +export function getContractApi(id) {
  99 + return request({
  100 + url: `${baseUrl}/contractDistributorStandard`,
  101 + method: 'get',
  102 + params: { id },
  103 + contentType: ContentTypeEnum.JSON,
  104 + region
  105 + })
  106 +}
  107 +
@@ -239,6 +239,7 @@ export default { @@ -239,6 +239,7 @@ export default {
239 } 239 }
240 240
241 .footer { 241 .footer {
  242 + z-index: 2;
242 position: fixed; 243 position: fixed;
243 left: 0; 244 left: 0;
244 right: 0; 245 right: 0;
@@ -33,10 +33,161 @@ @@ -33,10 +33,161 @@
33 <uni-easyinput v-model="form.unit" :inputBorder="false" disabled /> 33 <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
34 </template> 34 </template>
35 </uni-list-item> 35 </uni-list-item>
36 - <ProductRel type="add" v-model="form.productRel" /> 36 + <ProductRel mode="add" :orderDateBase="form.orderDate" @change="onProductsChange" :options="productList" />
  37 + <uni-list-item title="合计人民币金额(大写)">
  38 + <template v-slot:footer>
  39 + <uni-easyinput v-model="form.totalAmountCapital" placeholder="自动计算" :inputBorder="false" disabled />
  40 + </template>
  41 + </uni-list-item>
  42 + <uni-list-item title="交付定金、数额、时间">
  43 + <template v-slot:footer>
  44 + <uni-easyinput v-model="form.depositInfo" placeholder="请输入交付定金、数额、时间" :inputBorder="false" />
  45 + </template>
  46 + </uni-list-item>
  47 + <uni-list-item title="包装要求">
  48 + <template v-slot:footer>
  49 + <uni-easyinput v-model="form.packagingRequirements" placeholder="请输入包装要求"
  50 + :inputBorder="false" />
  51 + </template>
  52 + </uni-list-item>
  53 + <uni-list-item title="付款方式、付款期限">
  54 + <template v-slot:footer>
  55 + <uni-easyinput v-model="form.paymentTerms" placeholder="请输入付款方式、付款期限" :inputBorder="false" />
  56 + </template>
  57 + </uni-list-item>
  58 + <uni-list-item title="运输方式">
  59 + <template v-slot:footer>
  60 + <uni-easyinput v-model="form.transportMode" placeholder="请输入运输方式" :inputBorder="false" />
  61 + </template>
  62 + </uni-list-item>
  63 + <uni-list-item title="目的地">
  64 + <template v-slot:footer>
  65 + <uni-easyinput v-model="form.destinationId" placeholder="请输入目的地" :inputBorder="false" />
  66 + </template>
  67 + </uni-list-item>
  68 + <uni-list-item class="select-item" :class="form.includesPackagingFeeName ? 'is-filled' : 'is-empty'" clickable
  69 + @click="openSheet('includesPackagingFee')" :rightText="form.includesPackagingFeeName || '请选择'" showArrow>
  70 + <template v-slot:body>
  71 + <view class="item-title"><text>单价中是否已包含包装费</text></view>
  72 + </template>
  73 + </uni-list-item>
  74 + <uni-list-item class="select-item" :class="form.includesTransportFeeName ? 'is-filled' : 'is-empty'" clickable
  75 + @click="openSheet('includesTransportFee')" :rightText="form.includesTransportFeeName || '请选择'" showArrow>
  76 + <template v-slot:body>
  77 + <view class="item-title"><text>单价中是否已包含运费</text></view>
  78 + </template>
  79 + </uni-list-item>
  80 + <uni-list-item title="需方指定收货人">
  81 + <template v-slot:footer>
  82 + <uni-easyinput v-model="form.designatedConsignee" placeholder="请输入需方指定收货人"
  83 + :inputBorder="false" />
  84 + </template>
  85 + </uni-list-item>
  86 + <view class="group">
  87 + <view class="group-title">特别条款要求</view>
  88 + <view class="radio-list">
  89 + <view v-for="(opt, i) in specialTermsList" :key="'cr-' + i" class="radio-item"
  90 + @click="onRadioSelect('specialTerms', 'specialTermsName', opt)">
  91 + <view :class="['radio', { checked: form.specialTerms === opt.value }]" />
  92 + <text class="label">{{ opt.label }}</text>
  93 + </view>
  94 + </view>
  95 + </view>
  96 + <view class="group">
  97 + <view class="group-title">执行标准</view>
  98 + <view class="radio-list">
  99 + <view v-for="(opt, i) in executionStandardList" :key="'es-' + i" class="radio-item"
  100 + @click="onRadioSelect('executionStandard', 'executionStandardName', opt)">
  101 + <view :class="['radio', { checked: form.executionStandard === opt.value }]" />
  102 + <text class="label">{{ opt.label }}</text>
  103 + </view>
  104 + </view>
  105 + </view>
  106 + <uni-list-item v-if="form.executionStandard === 'OTHER'" title="其他">
  107 + <template v-slot:footer>
  108 + <uni-easyinput v-model="form.executionStandardRemarks" placeholder="请输入其他标准备注"
  109 + :inputBorder="false" />
  110 + </template>
  111 + </uni-list-item>
  112 + <uni-list-item title="特别说明">
  113 + <template v-slot:footer>
  114 + <uni-easyinput v-model="form.specialInstructions" placeholder="请输入特别说明" :inputBorder="false" />
  115 + </template>
  116 + </uni-list-item>
  117 + <uni-list-item title="备注">
  118 + <template v-slot:footer>
  119 + <uni-easyinput v-model="form.remarks" placeholder="请输入备注" :inputBorder="false" />
  120 + </template>
  121 + </uni-list-item>
  122 + <view class="quality">
  123 + <image class="opCollapse" src="/static/images/title.png" />
  124 + <text class="title">具体质量要求</text>
  125 + </view>
  126 + <uni-list-item title="件重条头">
  127 + <template v-slot:footer>
  128 + <uni-easyinput v-model="form.pieceWeightHead" placeholder="请输入" :inputBorder="false" />
  129 + </template>
  130 + </uni-list-item>
  131 + <uni-list-item title="表面">
  132 + <template v-slot:footer>
  133 + <uni-easyinput v-model="form.surface" placeholder="请输入" :inputBorder="false" />
  134 + </template>
  135 + </uni-list-item>
  136 + <uni-list-item title="公差">
  137 + <template v-slot:footer>
  138 + <uni-easyinput v-model="form.tolerance" placeholder="请输入" :inputBorder="false" />
  139 + </template>
  140 + </uni-list-item>
  141 + <uni-list-item title="性能">
  142 + <template v-slot:footer>
  143 + <uni-easyinput v-model="form.performance" placeholder="请输入" :inputBorder="false" />
  144 + </template>
  145 + </uni-list-item>
  146 + <uni-list-item title="成分">
  147 + <template v-slot:footer>
  148 + <uni-easyinput v-model="form.component" placeholder="请输入" :inputBorder="false" />
  149 + </template>
  150 + </uni-list-item>
  151 + <uni-list-item title="包装">
  152 + <template v-slot:footer>
  153 + <uni-easyinput v-model="form.packaging" placeholder="请输入" :inputBorder="false" />
  154 + </template>
  155 + </uni-list-item>
37 </uni-list> 156 </uni-list>
38 - </scroll-view>  
39 157
  158 + </scroll-view>
  159 + <view class="footer">
  160 + <div class="total">
  161 + <div class="total-text">
  162 + 合计
  163 + </div>
  164 + <div class="total-item">
  165 + <div class="total-item-text">
  166 + 数量
  167 + </div>
  168 + <div class="total-item-price">
  169 + {{ (sumQuantity || 0).toFixed(2) }}t
  170 + </div>
  171 + </div>
  172 + <div class="total-item">
  173 + <div class="total-item-text">
  174 + 不含税金额
  175 + </div>
  176 + <div class="total-item-price text-red">
  177 + ¥{{ (sumAmountExcl || 0).toFixed(2) }}
  178 + </div>
  179 + </div>
  180 + <div class="total-item">
  181 + <div class="total-item-text">
  182 + 总金额
  183 + </div>
  184 + <div class="total-item-price text-red">
  185 + ¥{{ (sumTotal || 0).toFixed(2) }}
  186 + </div>
  187 + </div>
  188 + </div>
  189 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  190 + </view>
40 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" 191 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options"
41 v-model="sheet.value" @confirm="onSheetConfirm" /> 192 v-model="sheet.value" @confirm="onSheetConfirm" />
42 <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source" 193 <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
@@ -49,8 +200,9 @@ @@ -49,8 +200,9 @@
49 import SingleSelectSheet from '@/components/single-select/index.vue' 200 import SingleSelectSheet from '@/components/single-select/index.vue'
50 import RelateSelectSheet from '@/components/relate-select/index.vue' 201 import RelateSelectSheet from '@/components/relate-select/index.vue'
51 import ProductRel from './productRel.vue' 202 import ProductRel from './productRel.vue'
52 -import { getRetailCodeApi } from '@/api/contract' 203 +import { getRetailCodeApi, createContractApi } from '@/api/contract'
53 import { getDicByCodes } from '@/utils/dic' 204 import { getDicByCodes } from '@/utils/dic'
  205 +import { formatCurrencyToChinese } from '@/utils/common'
54 206
55 export default { 207 export default {
56 name: 'AddContractRetail', 208 name: 'AddContractRetail',
@@ -64,19 +216,49 @@ export default { @@ -64,19 +216,49 @@ export default {
64 buyer: '', 216 buyer: '',
65 buyerName: '', 217 buyerName: '',
66 orderDate: '', 218 orderDate: '',
  219 + designatedConsignee: '',
  220 + specialTerms: '',
  221 + specialTermsName: '',
  222 + executionStandard: '',
  223 + executionStandardName: '',
  224 + executionStandardRemarks: '',
  225 + includesPackagingFee: false,
  226 + includesPackagingFeeName: '',
  227 + includesTransportFee: false,
  228 + includesTransportFeeName: '',
67 unit: '元、公斤、元/公斤' 229 unit: '元、公斤、元/公斤'
68 }, 230 },
69 supplierList: [], 231 supplierList: [],
  232 + specialTermsList: [],
  233 + executionStandardList: [],
  234 + yesNoList: [{ label: '是', value: true }, { label: '否', value: false }],
70 sheet: { visible: false, title: '请选择', field: '', options: [], value: '' }, 235 sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
71 - relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' } 236 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' },
  237 + sumQuantity: 0,
  238 + sumAmountExcl: 0,
  239 + sumTotal: 0,
  240 + productLineList: [],
  241 + productList: [],
72 } 242 }
73 }, 243 },
74 created() { 244 created() {
75 this.loadSuppliers() 245 this.loadSuppliers()
  246 + this.loadExtraOptions()
76 this.initCode() 247 this.initCode()
77 this.form.orderDate = this.formatDate(new Date()) 248 this.form.orderDate = this.formatDate(new Date())
78 }, 249 },
79 methods: { 250 methods: {
  251 + onProductsChange(products) {
  252 + const list = Array.isArray(products) ? products : []
  253 + const sumQ = list.reduce((acc, it) => acc + (parseFloat(it.quantity) || 0), 0)
  254 + const sumE = list.reduce((acc, it) => acc + (parseFloat(it.amountExcludingTax) || 0), 0)
  255 + const sumT = list.reduce((acc, it) => acc + (parseFloat(it.totalAmount) || 0), 0)
  256 + this.sumQuantity = sumQ
  257 + this.sumAmountExcl = sumE
  258 + this.sumTotal = sumT
  259 + this.form.totalAmountCapital = formatCurrencyToChinese(sumT)
  260 + this.productLineList = list
  261 + },
80 formatDate(d) { 262 formatDate(d) {
81 const y = d.getFullYear() 263 const y = d.getFullYear()
82 const m = String(d.getMonth() + 1).padStart(2, '0') 264 const m = String(d.getMonth() + 1).padStart(2, '0')
@@ -97,6 +279,21 @@ export default { @@ -97,6 +279,21 @@ export default {
97 this.supplierList = items.map(it => ({ label: it.name, value: it.code })) 279 this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
98 } catch (e) { this.supplierList = [] } 280 } catch (e) { this.supplierList = [] }
99 }, 281 },
  282 + async loadExtraOptions() {
  283 + try {
  284 + const results = await getDicByCodes(['CONDITIONS_REQUIRED', 'APPLICABLE_STANDARD', 'CONTRACT_PRODUCT'])
  285 + const c1 = results && results.CONDITIONS_REQUIRED && results.CONDITIONS_REQUIRED.data ? results.CONDITIONS_REQUIRED.data : []
  286 + const c2 = results && results.APPLICABLE_STANDARD && results.APPLICABLE_STANDARD.data ? results.APPLICABLE_STANDARD.data : []
  287 + const c3 = results && results.CONTRACT_PRODUCT && results.CONTRACT_PRODUCT.data ? results.CONTRACT_PRODUCT.data : []
  288 + this.specialTermsList = c1.map(it => ({ label: it.name, value: it.code }))
  289 + this.executionStandardList = c2.map(it => ({ label: it.name, value: it.code }))
  290 + this.productList = c3.map(it => ({ label: it.name, value: it.code }))
  291 + } catch (e) {
  292 + this.specialTermsList = []
  293 + this.executionStandardList = []
  294 + this.productList = []
  295 + }
  296 + },
100 displayLabel(field) { 297 displayLabel(field) {
101 const m = this.form 298 const m = this.form
102 const map = { supplierName: '请选择供方' } 299 const map = { supplierName: '请选择供方' }
@@ -110,6 +307,8 @@ export default { @@ -110,6 +307,8 @@ export default {
110 this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' } 307 this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
111 } 308 }
112 if (field === 'supplier') setSheet('供方', this.supplierList) 309 if (field === 'supplier') setSheet('供方', this.supplierList)
  310 + if (field === 'includesPackagingFee') setSheet('单价中是否已包含包装费', this.yesNoList)
  311 + if (field === 'includesTransportFee') setSheet('单价中是否已包含运费', this.yesNoList)
113 }, 312 },
114 onSheetConfirm({ value, label }) { 313 onSheetConfirm({ value, label }) {
115 const field = this.sheet.field 314 const field = this.sheet.field
@@ -133,16 +332,188 @@ export default { @@ -133,16 +332,188 @@ export default {
133 const first = (items && items.length > 0) ? items[0] : null 332 const first = (items && items.length > 0) ? items[0] : null
134 this.form[_fieldKey] = (first && first.id) ? first.id : '' 333 this.form[_fieldKey] = (first && first.id) ? first.id : ''
135 this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : '' 334 this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  335 + },
  336 + onRadioSelect(field, nameField, opt) {
  337 + const val = opt && opt.value != null ? opt.value : ''
  338 + const label = opt && opt.label != null ? opt.label : ''
  339 + this.form[field] = val
  340 + this.form[nameField] = label
  341 + if (field === 'executionStandard' && val !== 'OTHER') {
  342 + this.form.executionStandardRemarks = ''
  343 + }
  344 + },
  345 + async onSubmit() {
  346 + if (!this.validateRequired()) return
  347 + const confirmRes = await new Promise(resolve => {
  348 + uni.showModal({ title: '提示', content: '确定新增经销未锁规合同吗?', confirmText: '确定', cancelText: '取消', success: resolve })
  349 + })
  350 + if (!(confirmRes && confirmRes.confirm)) return
  351 + const clean = (obj) => {
  352 + const out = {}
  353 + Object.keys(obj || {}).forEach(k => {
  354 + const v = obj[k]
  355 + const isEmptyString = typeof v === 'string' && v.trim() === ''
  356 + const isUndef = v === undefined || v === null
  357 + const isNaNNumber = typeof v === 'number' && isNaN(v)
  358 + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v
  359 + })
  360 + return out
  361 + }
  362 + const lines = (this.productLineList || []).map(it => clean(it))
  363 + const payload = clean({
  364 + ...this.form,
  365 + type: 'DISTRIB_STD',
  366 + sumQuantity: this.sumQuantity,
  367 + sumAmountExcl: this.sumAmountExcl,
  368 + sumTotal: this.sumTotal,
  369 + contractDistributorLineList: lines
  370 + })
  371 + try {
  372 + await createContractApi(payload)
  373 + uni.showToast({ title: '新增成功', icon: 'none' })
  374 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_retail/index' }) }, 400)
  375 + } catch (e) {
  376 + uni.showToast({ title: '提交失败', icon: 'none' })
  377 + }
  378 + },
  379 + validateRequired() {
  380 + const checks = [
  381 + { key: 'code', label: '编号' },
  382 + { key: 'supplier', label: '供方' },
  383 + { key: 'buyer', label: '需方' },
  384 + { key: 'orderDate', label: '订货日期' }
  385 + ]
  386 + for (const it of checks) {
  387 + const val = this.form[it.key]
  388 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  389 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  390 + }
  391 + if (!Array.isArray(this.productLineList) || this.productLineList.length === 0) {
  392 + uni.showToast({ title: '请至少添加一条产品明细', icon: 'none' }); return false
  393 + }
  394 + for (const [idx, it] of this.productLineList.entries()) {
  395 + if (!it.productName || !it.quantity || !it.unitPrice) {
  396 + uni.showToast({ title: `第${idx + 1}条明细未完整填写`, icon: 'none' }); return false
  397 + }
  398 + }
  399 + return true
136 } 400 }
137 } 401 }
138 } 402 }
139 403
140 </script> 404 </script>
141 <style lang="scss" scoped> 405 <style lang="scss" scoped>
  406 +.total {
  407 + .total-text {
  408 + font-weight: 600;
  409 + font-size: 32rpx;
  410 + color: rgba(0, 0, 0, 0.9);
  411 + padding-bottom: 28rpx;
  412 + border-bottom: 2rpx solid #E7E7E7;
  413 + }
  414 + .total-item {
  415 + display: flex;
  416 + align-items: center;
  417 + .total-item-text {
  418 + font-weight: 400;
  419 + font-size: 28rpx;
  420 + color: rgba(0, 0, 0, 0.6);
  421 + line-height: 32rpx;
  422 + width: 240rpx;
  423 + padding: 24rpx 0;
  424 + }
  425 + .total-item-price {
  426 + font-weight: 600;
  427 + font-size: 32rpx;
  428 + color: rgba(0, 0, 0, 0.9);
  429 + line-height: 32rpx;
  430 + }
  431 + .text-red {
  432 + color: #D54941;
  433 + }
  434 + }
  435 +
  436 +}
142 .page { 437 .page {
  438 + display: flex;
  439 + flex-direction: column;
  440 + height: 100%;
  441 +}
  442 +
  443 +.scroll {
  444 + flex: 1;
  445 + padding: 12rpx 0 480rpx !important;
  446 +}
  447 +
  448 +.footer {
  449 + z-index: 2;
  450 + position: fixed;
  451 + left: 0;
  452 + right: 0;
  453 + bottom: 0;
  454 + padding: 32rpx;
  455 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  456 + background: #fff;
  457 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  458 +
  459 + .btn {
  460 + height: 80rpx;
  461 + line-height: 80rpx;
  462 + border-radius: 12rpx;
  463 + font-size: 32rpx;
  464 + }
  465 +
  466 + .submit {
  467 + background: $theme-primary;
  468 + color: #fff;
  469 + }
  470 +}
  471 +
  472 +.group {
  473 + background: #fff;
  474 + padding: 24rpx 32rpx;
  475 + margin-bottom: 20rpx;
  476 +}
  477 +
  478 +.group-title {
  479 + color: rgba(0, 0, 0, 0.9);
  480 + font-size: 32rpx;
  481 + padding-bottom: 16rpx;
  482 +}
  483 +
  484 +.radio-list {
143 display: flex; 485 display: flex;
144 flex-direction: column; 486 flex-direction: column;
145 - height: 100%; 487 +}
  488 +
  489 +.radio-item {
  490 + display: flex;
  491 + align-items: center;
  492 + padding: 24rpx 0;
  493 + border-bottom: 1rpx solid #f0f0f0;
  494 +}
  495 +
  496 +.radio-item:last-child {
  497 + border-bottom: none;
  498 +}
  499 +
  500 +.radio {
  501 + width: 32rpx;
  502 + height: 32rpx;
  503 + border-radius: 50%;
  504 + border: 2rpx solid #DCDCDC;
  505 + margin-right: 20rpx;
  506 + box-sizing: border-box;
  507 +}
  508 +
  509 +.radio.checked {
  510 + background: $theme-primary;
  511 + border-color: $theme-primary;
  512 +}
  513 +
  514 +.radio-item .label {
  515 + font-size: 32rpx;
  516 + color: rgba(0, 0, 0, 0.9);
146 } 517 }
147 518
148 .scroll { 519 .scroll {
@@ -150,6 +521,29 @@ export default { @@ -150,6 +521,29 @@ export default {
150 padding: 12rpx 0 160rpx; 521 padding: 12rpx 0 160rpx;
151 } 522 }
152 523
  524 +.quality {
  525 + background-color: #fff;
  526 + display: flex;
  527 + align-items: center;
  528 + padding: 24rpx 32rpx;
  529 + border-bottom: 1rpx solid #f0f0f0;
  530 + margin-top: 20rpx;
  531 +
  532 + .title {
  533 + font-size: 32rpx;
  534 + color: rgba(0, 0, 0, 0.9);
  535 + font-weight: 600;
  536 + }
  537 +
  538 + .opCollapse {
  539 + color: rgba(0, 0, 0, 0.6);
  540 + width: 24rpx;
  541 + height: 24rpx;
  542 + margin-right: 16rpx;
  543 + margin-top: 8rpx;
  544 + }
  545 +}
  546 +
153 ::v-deep .uni-list { 547 ::v-deep .uni-list {
154 .uni-easyinput { 548 .uni-easyinput {
155 display: flex; 549 display: flex;
@@ -159,6 +553,10 @@ export default { @@ -159,6 +553,10 @@ export default {
159 } 553 }
160 } 554 }
161 555
  556 + .uni-input-placeholder {
  557 + z-index: 1;
  558 + }
  559 +
162 .uni-input-input { 560 .uni-input-input {
163 background-color: #ffffff; 561 background-color: #ffffff;
164 } 562 }
@@ -186,6 +584,7 @@ export default { @@ -186,6 +584,7 @@ export default {
186 584
187 &__content { 585 &__content {
188 border: none; 586 border: none;
  587 + background-color: #ffffff !important;
189 588
190 &-input { 589 &-input {
191 padding-left: 0 !important; 590 padding-left: 0 !important;
@@ -240,4 +639,4 @@ export default { @@ -240,4 +639,4 @@ export default {
240 } 639 }
241 } 640 }
242 } 641 }
243 -</style>  
  642 +</style>
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="detail-page">
  5 + <view class="section">
  6 + <text class="row customer">{{ detail.code }}</text>
  7 + <view class="row"><text class="label">供方</text><text class="value">{{ detail.supplierName || '-'
  8 + }}</text></view>
  9 + <view class="row"><text class="label">需方</text><text class="value">{{ detail.buyerName || '-'
  10 + }}</text></view>
  11 + <view class="row"><text class="label">订货日期</text><text class="value">{{ detail.orderDate }}</text>
  12 + </view>
  13 + <view class="row"><text class="label">单位</text><text class="value">{{ detail.unit }}</text></view>
  14 + </view>
  15 +
  16 + <view class="section1">
  17 + <ProductRel mode="view" :value="productList" />
  18 + </view>
  19 +
  20 + <view class="section">
  21 + <view class="row"><text class="label">合计人民币金额(大写)</text><text class="value">{{
  22 + detail.totalAmountCapital || '-' }}</text></view>
  23 + <view class="row"><text class="label">交付定金、数额、时间</text><text class="value">{{ detail.depositInfo ||
  24 + '-' }}</text></view>
  25 + <view class="row"><text class="label">包装要求</text><text class="value">{{ detail.packagingRequirements
  26 + || '-' }}</text></view>
  27 + <view class="row"><text class="label">付款方式、付款期限</text><text class="value">{{ detail.paymentTerms ||
  28 + '-' }}</text></view>
  29 + <view class="row"><text class="label">运输方式</text><text class="value">{{ detail.transportMode || '-'
  30 + }}</text></view>
  31 + <view class="row"><text class="label">目的地</text><text class="value">{{ detail.destinationId || '-'
  32 + }}</text></view>
  33 + <view class="row"><text class="label">单价中是否已包含包装费</text><text class="value">{{
  34 + detail.includesPackagingFeeName || '-' }}</text></view>
  35 + <view class="row"><text class="label">单价中是否已包含运费</text><text class="value">{{
  36 + detail.includesTransportFeeName || '-' }}</text></view>
  37 + <view class="row"><text class="label">需方指定收货人</text><text class="value">{{
  38 + detail.designatedConsignee || '-' }}</text></view>
  39 +
  40 + <view class="row"><text class="label">特别条款要求</text><text class="value">{{ detail.specialTermsName ||
  41 + '-' }}</text></view>
  42 + <view class="row"><text class="label">执行标准</text><text class="value">{{ detail.executionStandardName
  43 + || '-' }}</text></view>
  44 + <view class="row" v-if="detail.executionStandard === 'OTHER'"><text class="label">其他</text><text
  45 + class="value">{{ detail.executionStandardRemarks || '-' }}</text></view>
  46 + <view class="row"><text class="label">特别说明</text><text class="value">{{ detail.specialInstructions
  47 + || '-' }}</text></view>
  48 + <view class="row"><text class="label">备注</text><text class="value">{{ detail.remarks || '-'
  49 + }}</text></view>
  50 + </view>
  51 +
  52 + <view class="section">
  53 + <view class="row"><text class="label">规范性合同</text><text class="value">{{ detail.standardFileName || '-'
  54 + }}</text></view>
  55 + <view class="row"><text class="label">合同是否规范</text><text class="value">{{ detail.standardStandardized ? '是' : '否'
  56 + }}</text></view>
  57 + </view>
  58 +
  59 + <view class="section">
  60 + <text class="row customer">具体质量要求</text>
  61 + <view class="row"><text class="label">件重条头</text><text class="value">{{ detail.pieceWeightHead ||
  62 + '-' }}</text></view>
  63 + <view class="row"><text class="label">表面</text><text class="value">{{ detail.surface || '-'
  64 + }}</text></view>
  65 + <view class="row"><text class="label">公差</text><text class="value">{{ detail.tolerance || '-'
  66 + }}</text></view>
  67 + <view class="row"><text class="label">性能</text><text class="value">{{ detail.performance || '-'
  68 + }}</text></view>
  69 + <view class="row"><text class="label">成分</text><text class="value">{{ detail.component || '-'
  70 + }}</text></view>
  71 + <view class="row"><text class="label">包装</text><text class="value">{{ detail.packaging || '-'
  72 + }}</text></view>
  73 + </view>
  74 + </view>
  75 + </scroll-view>
  76 + </view>
  77 +</template>
  78 +
  79 +<script>
  80 +import { getContractApi } from '@/api/contract'
  81 +import ProductRel from './productRel.vue'
  82 +export default {
  83 + name: 'ContractRetailDetail',
  84 + components: { ProductRel },
  85 + data() {
  86 + return {
  87 + id: '',
  88 + detail: {
  89 + code: '',
  90 + supplier: '',
  91 + supplierName: '',
  92 + buyer: '',
  93 + buyerName: '',
  94 + orderDate: '',
  95 + unit: '',
  96 + designatedConsignee: '',
  97 + specialTerms: '',
  98 + specialTermsName: '',
  99 + executionStandard: '',
  100 + executionStandardName: '',
  101 + executionStandardRemarks: '',
  102 + includesPackagingFee: false,
  103 + includesPackagingFeeName: '',
  104 + includesTransportFee: false,
  105 + includesTransportFeeName: '',
  106 + totalAmountCapital: '',
  107 + depositInfo: '',
  108 + packagingRequirements: '',
  109 + paymentTerms: '',
  110 + transportMode: '',
  111 + destinationId: '',
  112 + specialInstructions: '',
  113 + remarks: '',
  114 + pieceWeightHead: '',
  115 + surface: '',
  116 + tolerance: '',
  117 + performance: '',
  118 + component: '',
  119 + packaging: ''
  120 + },
  121 + productList: []
  122 + }
  123 + },
  124 + onLoad(options) {
  125 + const id = options && options.id ? options.id : ''
  126 + this.id = id
  127 + this.loadDetail()
  128 + },
  129 + methods: {
  130 + async loadDetail() {
  131 + if (!this.id) return
  132 + try {
  133 + const res = await getContractApi(this.id)
  134 + const data = res && res.data ? res.data : {}
  135 + const includesPackagingFeeName = data.includesPackagingFeeName || (data.includesPackagingFee ? '是' : '否')
  136 + const includesTransportFeeName = data.includesTransportFeeName || (data.includesTransportFee ? '是' : '否')
  137 + this.detail = { ...this.detail, ...data, includesPackagingFeeName, includesTransportFeeName }
  138 + const lines = Array.isArray(data.contractDistributorLineList) ? data.contractDistributorLineList : []
  139 + this.productList = lines
  140 + } catch (e) {
  141 + this.detail = { ...this.detail }
  142 + this.productList = []
  143 + }
  144 + }
  145 + }
  146 +}
  147 +</script>
  148 +
  149 +<style lang="scss" scoped>
  150 +.page {
  151 + display: flex;
  152 + flex-direction: column;
  153 + height: 100%;
  154 +}
  155 +
  156 +.scroll {
  157 + flex: 1;
  158 + padding: 8rpx 0 144rpx;
  159 +}
  160 +
  161 +.detail-page {
  162 + background: #f3f3f3;
  163 +}
  164 +
  165 +.section {
  166 + padding: 32rpx;
  167 + background: #fff;
  168 + margin-bottom: 20rpx;
  169 +}
  170 +.section1 {
  171 + background: #fff;
  172 + margin-bottom: 20rpx;
  173 +}
  174 +
  175 +.row {
  176 + display: flex;
  177 + margin-bottom: 20rpx;
  178 + align-items: center;
  179 +}
  180 +
  181 +.row:last-child {
  182 + margin-bottom: 0;
  183 +}
  184 +
  185 +.label {
  186 + width: 280rpx;
  187 + color: rgba(0, 0, 0, 0.6);
  188 + font-size: 28rpx;
  189 +}
  190 +
  191 +.value {
  192 + flex: 1;
  193 + text-align: right;
  194 + color: rgba(0, 0, 0, 0.9);
  195 + font-size: 28rpx;
  196 +}
  197 +
  198 +.customer {
  199 + font-weight: 600;
  200 + font-size: 36rpx;
  201 + color: rgba(0, 0, 0, 0.9);
  202 + padding-bottom: 12rpx;
  203 +}
  204 +</style>
@@ -46,7 +46,7 @@ @@ -46,7 +46,7 @@
46 @error="onCardError" 46 @error="onCardError"
47 > 47 >
48 <template v-slot="{ item }"> 48 <template v-slot="{ item }">
49 - <view class="card"> 49 + <view class="card" @click="goDetail(item)">
50 <view class="card-header"> 50 <view class="card-header">
51 <text class="title omit2">{{ item.buyerName }}</text> 51 <text class="title omit2">{{ item.buyerName }}</text>
52 <text v-if="item.status === 'STANDARD'" :class="['status']" :style="{ background: statusMap[item.shippingStatusName] }">{{ item.shippingStatusName }}</text> 52 <text v-if="item.status === 'STANDARD'" :class="['status']" :style="{ background: statusMap[item.shippingStatusName] }">{{ item.shippingStatusName }}</text>
@@ -203,6 +203,11 @@ export default { @@ -203,6 +203,11 @@ export default {
203 onAdd() { 203 onAdd() {
204 uni.navigateTo({ url: '/pages/contract_retail/add' }) 204 uni.navigateTo({ url: '/pages/contract_retail/add' })
205 }, 205 },
  206 + goDetail(item) {
  207 + const id = item && (item.id || item.contractId)
  208 + if (!id) return uni.showToast({ title: '缺少ID,无法查看详情', icon: 'none' })
  209 + uni.navigateTo({ url: `/pages/contract_retail/detail?id=${id}` })
  210 + },
206 fetchList({ pageIndex, pageSize, query, extra }) { 211 fetchList({ pageIndex, pageSize, query, extra }) {
207 console.log('fetchList', pageIndex, pageSize, query, extra) 212 console.log('fetchList', pageIndex, pageSize, query, extra)
208 const params = { pageIndex, pageSize, ...extra, ...query } 213 const params = { pageIndex, pageSize, ...extra, ...query }
@@ -16,9 +16,9 @@ @@ -16,9 +16,9 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item title="产品名称">  
20 - <template v-slot:footer>  
21 - <uni-easyinput v-model="item.name" :inputBorder="false" placeholder="请输入产品名称" /> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
23 </uni-list-item> 23 </uni-list-item>
24 <uni-list-item title="行业"> 24 <uni-list-item title="行业">
@@ -33,9 +33,9 @@ @@ -33,9 +33,9 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item title="产品名称">  
37 - <template v-slot:footer>  
38 - <uni-easyinput v-model="item.name" :inputBorder="false" placeholder="请输入产品名称" /> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow>
  37 + <template v-slot:body>
  38 + <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
40 </uni-list-item> 40 </uni-list-item>
41 <uni-list-item title="行业"> 41 <uni-list-item title="行业">
@@ -109,28 +109,27 @@ @@ -109,28 +109,27 @@
109 </uni-list-item> 109 </uni-list-item>
110 <uni-list-item title="数量"> 110 <uni-list-item title="数量">
111 <template v-slot:footer> 111 <template v-slot:footer>
112 - <uni-easyinput v-model="item.quantity" :inputBorder="false" placeholder="请输入数量" /> 112 + <uni-easyinput v-model="item.quantity" type="number" :inputBorder="false" placeholder="请输入数量" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'quantity', 0)" />
113 </template> 113 </template>
114 </uni-list-item> 114 </uni-list-item>
115 <uni-list-item title="单价"> 115 <uni-list-item title="单价">
116 <template v-slot:footer> 116 <template v-slot:footer>
117 - <uni-easyinput v-model="item.unitPrice" :inputBorder="false" placeholder="请输入单价" /> 117 + <uni-easyinput v-model="item.unitPrice" type="number" :inputBorder="false" placeholder="请输入单价" @input="onImmediateChange(idx)" @blur="onNumberBlur(idx, 'unitPrice', 0)" />
118 </template> 118 </template>
119 </uni-list-item> 119 </uni-list-item>
120 <uni-list-item title="不含税金额"> 120 <uni-list-item title="不含税金额">
121 <template v-slot:footer> 121 <template v-slot:footer>
122 - <uni-easyinput v-model="item.amountExcludingTax" :inputBorder="false"  
123 - placeholder="请输入不含税金额" /> 122 + <uni-easyinput v-model="item.amountExcludingTax" type="number" :inputBorder="false" disabled placeholder="自动计算" />
124 </template> 123 </template>
125 </uni-list-item> 124 </uni-list-item>
126 <uni-list-item title="总金额"> 125 <uni-list-item title="总金额">
127 <template v-slot:footer> 126 <template v-slot:footer>
128 - <uni-easyinput v-model="item.totalAmount" :inputBorder="false" placeholder="请输入总金额" /> 127 + <uni-easyinput v-model="item.totalAmount" type="number" :inputBorder="false" disabled placeholder="自动计算" />
129 </template> 128 </template>
130 </uni-list-item> 129 </uni-list-item>
131 <uni-list-item title="发货日期"> 130 <uni-list-item title="发货日期">
132 <template v-slot:footer> 131 <template v-slot:footer>
133 - <uni-datetime-picker type="date" v-model="item.orderDate" /> 132 + <uni-datetime-picker type="date" v-model="item.orderDate" @change="onDateChange(idx, $event)" />
134 </template> 133 </template>
135 </uni-list-item> 134 </uni-list-item>
136 </uni-list> 135 </uni-list>
@@ -148,7 +147,7 @@ @@ -148,7 +147,7 @@
148 147
149 <view v-else class="view-list" v-show="!collapsedView"> 148 <view v-else class="view-list" v-show="!collapsedView">
150 <view v-for="(item, idx) in items" :key="'v-' + idx" class="card"> 149 <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
151 - <view class="row"><text class="label">产品名称</text><text class="value">{{ item.name }}</text></view> 150 + <view class="row"><text class="label">产品名称</text><text class="value">{{ item.productName }}</text></view>
152 <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view> 151 <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view>
153 <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view> 152 <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
154 <view class="row"><text class="label">品质</text><text class="value">{{ item.quality }}</text></view> 153 <view class="row"><text class="label">品质</text><text class="value">{{ item.quality }}</text></view>
@@ -166,20 +165,35 @@ @@ -166,20 +165,35 @@
166 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.orderDate }}</text></view> 165 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.orderDate }}</text></view>
167 </view> 166 </view>
168 </view> 167 </view>
  168 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
169 </view> 169 </view>
170 </template> 170 </template>
171 <script> 171 <script>
  172 +import SingleSelectSheet from '@/components/single-select/index.vue'
172 export default { 173 export default {
173 name: 'ProductRel', 174 name: 'ProductRel',
174 props: { 175 props: {
175 mode: { type: String, default: 'add' }, 176 mode: { type: String, default: 'add' },
176 value: { type: Array, default: () => [] }, 177 value: { type: Array, default: () => [] },
177 - max: { type: Number, default: 8 } 178 + max: { type: Number, default: 8 },
  179 + orderDateBase: { type: String, default: '' },
  180 + options: { type: Array, default: () => [] }
178 }, 181 },
  182 + components: { SingleSelectSheet },
179 data() { 183 data() {
180 return { 184 return {
181 items: [], 185 items: [],
182 - collapsedView: false 186 + collapsedView: false,
  187 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 }
  188 + }
  189 + },
  190 + computed: {
  191 + selectOptions() {
  192 + const list = Array.isArray(this.options) ? this.options : []
  193 + return list.map(o => ({
  194 + label: o.label != null ? o.label : (o.text != null ? o.text : (o.name != null ? o.name : '')),
  195 + value: o.value != null ? o.value : (o.id != null ? o.id : o.productId)
  196 + }))
183 } 197 }
184 }, 198 },
185 watch: { 199 watch: {
@@ -198,10 +212,34 @@ export default { @@ -198,10 +212,34 @@ export default {
198 created() { 212 created() {
199 const init = Array.isArray(this.value) && this.value.length > 0 ? this.value.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 213 const init = Array.isArray(this.value) && this.value.length > 0 ? this.value.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
200 this.items = init 214 this.items = init
  215 + this.recalculateAll()
201 }, 216 },
202 methods: { 217 methods: {
203 defaultItem() { 218 defaultItem() {
204 - return { name: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: '', totalAmount: '', orderDate: '' } 219 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: 0, unitPrice: 0, amountExcludingTax: 0, totalAmount: 0, orderDate: '' }
  220 + },
  221 + onImmediateChange(idx) {
  222 + this.$nextTick(() => this.recalculate(idx))
  223 + },
  224 + toNumber(val) {
  225 + if (typeof val === 'number') return isNaN(val) ? 0 : val
  226 + const n = parseFloat(String(val).replace(/[^0-9.\-]/g, ''))
  227 + return isNaN(n) ? 0 : n
  228 + },
  229 + round(val, digits = 2) {
  230 + const n = Number(val)
  231 + if (isNaN(n)) return 0
  232 + const m = Math.pow(10, digits)
  233 + return Math.round(n * m) / m
  234 + },
  235 + onNumberBlur(idx, field, digits) {
  236 + const it = this.items[idx]
  237 + if (!it) return
  238 + const num = this.toNumber(it[field])
  239 + const rounded = this.round(num, digits)
  240 + it[field] = rounded
  241 + this.$set(this.items, idx, it)
  242 + this.recalculate(idx)
205 }, 243 },
206 formatCurrency(val) { 244 formatCurrency(val) {
207 if (val == null || val === '') return '' 245 if (val == null || val === '') return ''
@@ -211,10 +249,40 @@ export default { @@ -211,10 +249,40 @@ export default {
211 return `${pre}${fixed}` 249 return `${pre}${fixed}`
212 }, 250 },
213 specOf(item) { 251 specOf(item) {
214 - const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/')  
215 - const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/')  
216 - const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')  
217 - return [t, w, l].filter(Boolean).join(' × ') 252 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/')
  253 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/')
  254 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
  255 + return [t, w, l].filter(Boolean).join(' × ')
  256 + },
  257 + openProductSheet(idx) {
  258 + const opts = this.selectOptions
  259 + const current = this.items[idx] && this.items[idx].productId
  260 + const match = opts.find(o => o.value === current)
  261 + this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' }
  262 + },
  263 + onProductConfirm({ value, label }) {
  264 + const idx = this.sheet.idx
  265 + const it = this.items[idx]
  266 + if (!it) { this.sheet.visible = false; return }
  267 + it.productId = value
  268 + it.productName = label || ''
  269 + this.$set(this.items, idx, it)
  270 + this.sheet.visible = false
  271 + this.emitChange()
  272 + },
  273 + recalculate(idx) {
  274 + const TAX_RATE = 0.13
  275 + const it = this.items[idx]
  276 + if (!it) return
  277 + const qty = this.toNumber(it.quantity)
  278 + const price = this.toNumber(it.unitPrice)
  279 + const total = this.round(qty * price, 2)
  280 + const excl = this.round(total / (1 + TAX_RATE), 2)
  281 + const next = { ...it, totalAmount: total, amountExcludingTax: excl }
  282 + this.$set(this.items, idx, next)
  283 + },
  284 + recalculateAll() {
  285 + for (let i = 0; i < this.items.length; i++) this.recalculate(i)
218 }, 286 },
219 onAdd() { 287 onAdd() {
220 if (this.items.length >= this.max) return uni.showToast({ title: `最多添加${this.max}个`, icon: 'none' }) 288 if (this.items.length >= this.max) return uni.showToast({ title: `最多添加${this.max}个`, icon: 'none' })
@@ -239,6 +307,21 @@ export default { @@ -239,6 +307,21 @@ export default {
239 this.$emit('update:value', out) 307 this.$emit('update:value', out)
240 this.$emit('change', out) 308 this.$emit('change', out)
241 }, 309 },
  310 + onDateChange(idx, e) {
  311 + const it = this.items[idx]
  312 + if (!it) return
  313 + const val = typeof e === 'string' ? e : (e && e.detail && e.detail.value) ? e.detail.value : it.orderDate
  314 + const dateStr = String(val).slice(0, 10)
  315 + const base = this.orderDateBase ? new Date(this.orderDateBase) : null
  316 + const d = new Date(dateStr)
  317 + if (base && !isNaN(d.getTime()) && d.getTime() < base.getTime()) {
  318 + uni.showToast({ title: '发货日期不得早于订货日期', icon: 'none' })
  319 + it.orderDate = this.orderDateBase
  320 + } else {
  321 + it.orderDate = dateStr
  322 + }
  323 + this.$set(this.items, idx, it)
  324 + },
242 toggleViewCollapse() { 325 toggleViewCollapse() {
243 this.collapsedView = !this.collapsedView 326 this.collapsedView = !this.collapsedView
244 } 327 }
@@ -269,6 +352,7 @@ export default { @@ -269,6 +352,7 @@ export default {
269 .title { 352 .title {
270 font-size: 32rpx; 353 font-size: 32rpx;
271 color: rgba(0, 0, 0, 0.9); 354 color: rgba(0, 0, 0, 0.9);
  355 + font-weight: 600;
272 } 356 }
273 357
274 .ops { 358 .ops {
@@ -295,7 +379,7 @@ export default { @@ -295,7 +379,7 @@ export default {
295 width: 24rpx; 379 width: 24rpx;
296 height: 24rpx; 380 height: 24rpx;
297 margin-right: 16rpx; 381 margin-right: 16rpx;
298 - margin-top: 16rpx; 382 + margin-top: 8rpx;
299 } 383 }
300 384
301 385
@@ -344,7 +428,7 @@ export default { @@ -344,7 +428,7 @@ export default {
344 } 428 }
345 429
346 .uni-input-placeholder { 430 .uni-input-placeholder {
347 - z-index: 2; 431 + // z-index: 2;
348 } 432 }
349 } 433 }
350 } 434 }
@@ -51,4 +51,59 @@ export function tansParams(params) { @@ -51,4 +51,59 @@ export function tansParams(params) {
51 } 51 }
52 } 52 }
53 return result 53 return result
  54 +}
  55 +
  56 +// 金额转人民币大写
  57 +export function formatCurrencyToChinese(num) {
  58 + // 处理空值或非数字
  59 + if (!num || isNaN(Number(num))) return '零元整';
  60 +
  61 + // 转换为数字并保留2位小数(避免分以下的单位)
  62 + const n = parseFloat(Number(num).toFixed(2));
  63 + if (n === 0) return '零元整';
  64 +
  65 + const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  66 + const unit = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟'];
  67 + const decUnit = ['角', '分'];
  68 + let str = '';
  69 +
  70 + // 处理整数部分
  71 + const integer = Math.floor(n);
  72 + // 处理小数部分(角、分)
  73 + const decimal = Math.round((n - integer) * 100);
  74 + const hasDecimal = decimal > 0;
  75 +
  76 + // 转换整数部分
  77 + if (integer > 0) {
  78 + let intStr = integer.toString();
  79 + for (let i = 0; i < intStr.length; i++) {
  80 + const digitNum = parseInt(intStr[i]);
  81 + const unitIndex = intStr.length - 1 - i;
  82 + if (digitNum !== 0) {
  83 + str += digit[digitNum] + unit[unitIndex];
  84 + } else {
  85 + // 避免连续多个零
  86 + if (intStr[i - 1] !== '0' || (unitIndex % 4 === 0 && unitIndex > 0)) {
  87 + str += digit[0];
  88 + }
  89 + }
  90 + }
  91 + str += '元';
  92 + } else {
  93 + str += '零元';
  94 + }
  95 +
  96 + // 转换小数部分
  97 + if (hasDecimal) {
  98 + const jiao = Math.floor(decimal / 10);
  99 + const fen = decimal % 10;
  100 + if (jiao > 0) str += digit[jiao] + decUnit[0];
  101 + if (fen > 0) str += digit[fen] + decUnit[1];
  102 + } else {
  103 + str += '整';
  104 + }
  105 +
  106 + // 处理特殊情况(如"零元整"已在开头处理,此处处理多零情况)
  107 + return str.replace(/零+/g, '零').replace(/零([万亿])/g, '$1').replace(/零元/, '元')
  108 + .replace(/零角零分$/, '整').replace(/零分$/, '整');
54 } 109 }