Showing
8 changed files
with
3143 additions
and
502 deletions
| 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 | ||
| 4 | -// 过磅码单分页查询 | 4 | +// 过磅码单(对齐 PC 端 api/warehouse-manage/weight-ticket) |
| 5 | +const baseUrl = '/procurement/weighing/ticket' | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 分页查询过磅单列表 | ||
| 9 | + * params: pageIndex, pageSize, code, planCode, supplierName, companyShortId, | ||
| 10 | + * approvalStatus, createBy, startTime, endTime, deleted(boolean) | ||
| 11 | + */ | ||
| 5 | export function weighTicketQueryApi(params) { | 12 | export function weighTicketQueryApi(params) { |
| 6 | return request({ | 13 | return request({ |
| 7 | - url: '/procurement/weighTicket/query', | 14 | + url: baseUrl + '/query', |
| 8 | method: 'get', | 15 | method: 'get', |
| 9 | params | 16 | params |
| 10 | }) | 17 | }) |
| 11 | } | 18 | } |
| 12 | 19 | ||
| 13 | -// 过磅码单详情 | 20 | +/** |
| 21 | + * 生成过磅单编号(直接返回编号字符串) | ||
| 22 | + */ | ||
| 23 | +export function weighTicketGenerateCodeApi() { | ||
| 24 | + return request({ | ||
| 25 | + url: baseUrl + '/generateCode', | ||
| 26 | + method: 'get' | ||
| 27 | + }) | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * 查询过磅单可选计划列表 | ||
| 32 | + * params: pageIndex, pageSize, code(计划编号), companyName(收料单位) | ||
| 33 | + */ | ||
| 34 | +export function weighingTicketPlansApi(params) { | ||
| 35 | + return request({ | ||
| 36 | + url: baseUrl + '/weighingTicketPlans', | ||
| 37 | + method: 'get', | ||
| 38 | + params | ||
| 39 | + }) | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +/** | ||
| 43 | + * 根据计划id集合查询计划明细行 | ||
| 44 | + * ids: 计划id数组 | ||
| 45 | + */ | ||
| 46 | +export function weighTicketPlanLinesApi(ids) { | ||
| 47 | + return request({ | ||
| 48 | + url: baseUrl + '/planLines', | ||
| 49 | + method: 'get', | ||
| 50 | + params: { ids: (ids || []).join(',') } | ||
| 51 | + }) | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +/** | ||
| 55 | + * 查询过磅单详情 | ||
| 56 | + */ | ||
| 14 | export function weighTicketDetailApi(params) { | 57 | export function weighTicketDetailApi(params) { |
| 15 | return request({ | 58 | return request({ |
| 16 | - url: '/procurement/weighTicket', | 59 | + url: baseUrl, |
| 17 | method: 'get', | 60 | method: 'get', |
| 18 | params | 61 | params |
| 19 | }) | 62 | }) |
| 20 | } | 63 | } |
| 21 | 64 | ||
| 22 | -// 新增 | ||
| 23 | -export function weighTicketSaveApi(data) { | 65 | +/** |
| 66 | + * 提交审核 | ||
| 67 | + */ | ||
| 68 | +export function weighTicketSubmitAuditApi(id) { | ||
| 69 | + return request({ | ||
| 70 | + url: baseUrl + '/submit?id=' + id, | ||
| 71 | + method: 'put' | ||
| 72 | + }) | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +/** | ||
| 76 | + * 作废过磅单 | ||
| 77 | + */ | ||
| 78 | +export function weighTicketCancelApi(id) { | ||
| 79 | + return request({ | ||
| 80 | + url: baseUrl + '/delete?id=' + id, | ||
| 81 | + method: 'put' | ||
| 82 | + }) | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +/** | ||
| 86 | + * 新增过磅单 | ||
| 87 | + */ | ||
| 88 | +export function weighTicketCreateApi(data) { | ||
| 24 | return request({ | 89 | return request({ |
| 25 | - url: '/procurement/weighTicket', | 90 | + url: baseUrl + '/create', |
| 26 | method: 'post', | 91 | method: 'post', |
| 27 | data, | 92 | data, |
| 28 | contentType: ContentTypeEnum.JSON | 93 | contentType: ContentTypeEnum.JSON |
| 29 | }) | 94 | }) |
| 30 | } | 95 | } |
| 31 | 96 | ||
| 32 | -// 编辑 | 97 | +/** |
| 98 | + * 修改过磅单 | ||
| 99 | + */ | ||
| 33 | export function weighTicketUpdateApi(data) { | 100 | export function weighTicketUpdateApi(data) { |
| 34 | return request({ | 101 | return request({ |
| 35 | - url: '/procurement/weighTicket', | 102 | + url: baseUrl, |
| 36 | method: 'put', | 103 | method: 'put', |
| 37 | data, | 104 | data, |
| 38 | contentType: ContentTypeEnum.JSON | 105 | contentType: ContentTypeEnum.JSON |
| 39 | }) | 106 | }) |
| 40 | } | 107 | } |
| 41 | 108 | ||
| 42 | -// 作废 / 恢复 | ||
| 43 | -export function weighTicketDeleteApi(params) { | 109 | +/** |
| 110 | + * 上传签字凭证 | ||
| 111 | + * data: { id, fileIds(逗号分隔), fileNames(逗号分隔) } | ||
| 112 | + */ | ||
| 113 | +export function weighTicketUploadSignApi(data) { | ||
| 44 | return request({ | 114 | return request({ |
| 45 | - url: '/procurement/weighTicket/delete', | 115 | + url: baseUrl + '/attachment/sign', |
| 46 | method: 'put', | 116 | method: 'put', |
| 117 | + data, | ||
| 118 | + contentType: ContentTypeEnum.JSON | ||
| 119 | + }) | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +/** | ||
| 123 | + * 上传延期说明附件 | ||
| 124 | + * data: { id, fileIds(逗号分隔), fileNames(逗号分隔) } | ||
| 125 | + */ | ||
| 126 | +export function weighTicketUploadDelayApi(data) { | ||
| 127 | + return request({ | ||
| 128 | + url: baseUrl + '/attachment/delay', | ||
| 129 | + method: 'put', | ||
| 130 | + data, | ||
| 131 | + contentType: ContentTypeEnum.JSON | ||
| 132 | + }) | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +/** | ||
| 136 | + * 公司简称下拉数据(PC: base-data/short-name) | ||
| 137 | + */ | ||
| 138 | +export function companyShortQueryApi(params) { | ||
| 139 | + return request({ | ||
| 140 | + url: '/basedata/company/short/query', | ||
| 141 | + method: 'get', | ||
| 47 | params | 142 | params |
| 48 | }) | 143 | }) |
| 49 | } | 144 | } |
| @@ -573,6 +573,22 @@ | @@ -573,6 +573,22 @@ | ||
| 573 | } | 573 | } |
| 574 | }, | 574 | }, |
| 575 | { | 575 | { |
| 576 | + "path": "pages/weight-ticket/upload", | ||
| 577 | + "style": { | ||
| 578 | + "navigationBarTitleText": "上传附件", | ||
| 579 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 580 | + "navigationBarTextStyle": "black" | ||
| 581 | + } | ||
| 582 | + }, | ||
| 583 | + { | ||
| 584 | + "path": "pages/weight-ticket/reweigh", | ||
| 585 | + "style": { | ||
| 586 | + "navigationBarTitleText": "复磅", | ||
| 587 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 588 | + "navigationBarTextStyle": "black" | ||
| 589 | + } | ||
| 590 | + }, | ||
| 591 | + { | ||
| 576 | "path": "pages/order_list/index", | 592 | "path": "pages/order_list/index", |
| 577 | "style": { | 593 | "style": { |
| 578 | "navigationBarTitleText": "订货单列表", | 594 | "navigationBarTitleText": "订货单列表", |
| @@ -5,208 +5,132 @@ | @@ -5,208 +5,132 @@ | ||
| 5 | <!-- 编号 --> | 5 | <!-- 编号 --> |
| 6 | <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> | 6 | <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> |
| 7 | <template v-slot:body> | 7 | <template v-slot:body> |
| 8 | - <view class="item-title"><text>编号</text></view> | 8 | + <view class="item-title"><text class="required">*</text><text>编号</text></view> |
| 9 | </template> | 9 | </template> |
| 10 | <template v-slot:footer> | 10 | <template v-slot:footer> |
| 11 | <view class="serial-number-row"> | 11 | <view class="serial-number-row"> |
| 12 | <text class="readonly-text value-code">{{ form.code || '-' }}</text> | 12 | <text class="readonly-text value-code">{{ form.code || '-' }}</text> |
| 13 | - <button class="generate-btn" @click="initCode">点此生成</button> | 13 | + <button class="generate-btn" @click="onGenerateCode">点此生成</button> |
| 14 | </view> | 14 | </view> |
| 15 | </template> | 15 | </template> |
| 16 | </uni-list-item> | 16 | </uni-list-item> |
| 17 | 17 | ||
| 18 | <!-- 类型 --> | 18 | <!-- 类型 --> |
| 19 | - <uni-list-item> | 19 | + <uni-list-item class="select-item" :class="form.type ? 'is-filled' : 'is-empty'"> |
| 20 | <template v-slot:body> | 20 | <template v-slot:body> |
| 21 | <view class="item-title"><text class="required">*</text><text>类型</text></view> | 21 | <view class="item-title"><text class="required">*</text><text>类型</text></view> |
| 22 | </template> | 22 | </template> |
| 23 | <template v-slot:footer> | 23 | <template v-slot:footer> |
| 24 | - <uni-easyinput v-model="form.type" :inputBorder="false" placeholder="请输入类型" /> | 24 | + <picker mode="selector" :range="typeLabels" @change="onTypeChange"> |
| 25 | + <view class="picker-value" :class="{ placeholder: !form.type }"> | ||
| 26 | + {{ getTypeLabel() || '请选择类型' }} | ||
| 27 | + </view> | ||
| 28 | + </picker> | ||
| 25 | </template> | 29 | </template> |
| 26 | </uni-list-item> | 30 | </uni-list-item> |
| 27 | 31 | ||
| 28 | - <!-- 计划编号 --> | ||
| 29 | - <uni-list-item> | 32 | + <!-- 计划编号(弹窗多选计划) --> |
| 33 | + <uni-list-item class="select-item" :class="form.planCode ? 'is-filled' : 'is-empty'" clickable | ||
| 34 | + @click="openPlanSheet" :rightText="form.planCode || '请选择计划'" showArrow> | ||
| 30 | <template v-slot:body> | 35 | <template v-slot:body> |
| 31 | <view class="item-title"><text class="required">*</text><text>计划编号</text></view> | 36 | <view class="item-title"><text class="required">*</text><text>计划编号</text></view> |
| 32 | </template> | 37 | </template> |
| 33 | - <template v-slot:footer> | ||
| 34 | - <uni-easyinput v-model="form.unit" :inputBorder="false" placeholder="请输入计划编号" /> | ||
| 35 | - </template> | ||
| 36 | - </uni-list-item> | ||
| 37 | - | ||
| 38 | - <!-- 时间 --> | ||
| 39 | - <uni-list-item class="select-item" :class="form.firstGrossWeightTime ? 'is-filled' : 'is-empty'"> | ||
| 40 | - <template v-slot:body> | ||
| 41 | - <view class="item-title"><text class="required">*</text><text>时间</text></view> | ||
| 42 | - </template> | ||
| 43 | - <template v-slot:footer> | ||
| 44 | - <uni-datetime-picker type="date" v-model="form.firstGrossWeightTime" /> | ||
| 45 | - </template> | ||
| 46 | - </uni-list-item> | ||
| 47 | - | ||
| 48 | - <!-- 供料单位 --> | ||
| 49 | - <uni-list-item> | ||
| 50 | - <template v-slot:body> | ||
| 51 | - <view class="item-title"><text class="required">*</text><text>供料单位</text></view> | ||
| 52 | - </template> | ||
| 53 | - <template v-slot:footer> | ||
| 54 | - <uni-easyinput v-model="form.supplierName" :inputBorder="false" placeholder="请输入供料单位" /> | ||
| 55 | - </template> | ||
| 56 | </uni-list-item> | 38 | </uni-list-item> |
| 57 | 39 | ||
| 58 | - <!-- 收料单位 --> | ||
| 59 | - <uni-list-item> | ||
| 60 | - <template v-slot:body> | ||
| 61 | - <view class="item-title"><text class="required">*</text><text>收料单位</text></view> | ||
| 62 | - </template> | 40 | + <!-- 单位(禁用) --> |
| 41 | + <uni-list-item title="单位"> | ||
| 63 | <template v-slot:footer> | 42 | <template v-slot:footer> |
| 64 | - <uni-easyinput v-model="form.companyShortName" :inputBorder="false" placeholder="请输入收料单位" /> | 43 | + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled /> |
| 65 | </template> | 44 | </template> |
| 66 | </uni-list-item> | 45 | </uni-list-item> |
| 67 | 46 | ||
| 68 | - <!-- 物料名称 --> | ||
| 69 | - <uni-list-item> | ||
| 70 | - <template v-slot:body> | ||
| 71 | - <view class="item-title"><text class="required">*</text><text>物料名称</text></view> | ||
| 72 | - </template> | 47 | + <!-- 供料单位(带出,禁用) --> |
| 48 | + <uni-list-item title="供料单位"> | ||
| 73 | <template v-slot:footer> | 49 | <template v-slot:footer> |
| 74 | - <uni-easyinput v-model="form.materialName" :inputBorder="false" placeholder="请输入物料名称" /> | 50 | + <uni-easyinput v-model="form.supplierName" :inputBorder="false" disabled placeholder="选择计划后自动带出" /> |
| 75 | </template> | 51 | </template> |
| 76 | </uni-list-item> | 52 | </uni-list-item> |
| 77 | 53 | ||
| 78 | - <!-- 过磅总重 --> | ||
| 79 | - <uni-list-item> | ||
| 80 | - <template v-slot:body> | ||
| 81 | - <view class="item-title"><text class="required">*</text><text>过磅总重</text></view> | ||
| 82 | - </template> | 54 | + <!-- 收料单位(带出,禁用) --> |
| 55 | + <uni-list-item title="收料单位"> | ||
| 83 | <template v-slot:footer> | 56 | <template v-slot:footer> |
| 84 | - <uni-easyinput v-model="form.totalGrossWeight" type="digit" :inputBorder="false" placeholder="请输入过磅总重" @input="calcNetWeight" /> | ||
| 85 | - </template> | ||
| 86 | - </uni-list-item> | ||
| 87 | - | ||
| 88 | - <!-- 实际伙重 --> | ||
| 89 | - <uni-list-item title="实际伙重"> | ||
| 90 | - <template v-slot:footer> | ||
| 91 | - <uni-easyinput v-model="form.actualImpurityWeight" type="digit" :inputBorder="false" placeholder="请输入实际伙重" @input="calcNetWeight" /> | ||
| 92 | - </template> | ||
| 93 | - </uni-list-item> | ||
| 94 | - | ||
| 95 | - <!-- 货物净重 --> | ||
| 96 | - <uni-list-item title="货物净重"> | ||
| 97 | - <template v-slot:footer> | ||
| 98 | - <uni-easyinput v-model="form.netWeight" type="digit" :inputBorder="false" placeholder="请输入货物净重" /> | ||
| 99 | - </template> | ||
| 100 | - </uni-list-item> | ||
| 101 | - | ||
| 102 | - <!-- 净重大写 --> | ||
| 103 | - <uni-list-item title="净重大写"> | ||
| 104 | - <template v-slot:footer> | ||
| 105 | - <uni-easyinput v-model="form.netWeightUpper" :inputBorder="false" placeholder="请输入净重大写" /> | ||
| 106 | - </template> | ||
| 107 | - </uni-list-item> | ||
| 108 | - | ||
| 109 | - <!-- 来料扣杂类型 --> | ||
| 110 | - <uni-list-item title="来料扣杂类型"> | ||
| 111 | - <template v-slot:footer> | ||
| 112 | - <uni-easyinput v-model="form.deductionTypes" :inputBorder="false" placeholder="请输入来料扣杂类型" /> | ||
| 113 | - </template> | ||
| 114 | - </uni-list-item> | ||
| 115 | - | ||
| 116 | - <!-- 供应存欠料 --> | ||
| 117 | - <uni-list-item title="供应存欠料"> | ||
| 118 | - <template v-slot:footer> | ||
| 119 | - <uni-easyinput v-model="form.supplierStockMaterial" type="digit" :inputBorder="false" placeholder="请输入供应存欠料" /> | ||
| 120 | - </template> | ||
| 121 | - </uni-list-item> | ||
| 122 | - | ||
| 123 | - <!-- 物流存欠料 --> | ||
| 124 | - <uni-list-item title="物流存欠料"> | ||
| 125 | - <template v-slot:footer> | ||
| 126 | - <uni-easyinput v-model="form.logisticsStockMaterial" type="digit" :inputBorder="false" placeholder="请输入物流存欠料" /> | ||
| 127 | - </template> | ||
| 128 | - </uni-list-item> | ||
| 129 | - | ||
| 130 | - <!-- 车牌号 --> | ||
| 131 | - <uni-list-item> | ||
| 132 | - <template v-slot:body> | ||
| 133 | - <view class="item-title"><text class="required">*</text><text>车牌号</text></view> | ||
| 134 | - </template> | ||
| 135 | - <template v-slot:footer> | ||
| 136 | - <uni-easyinput v-model="form.plateNumber" :inputBorder="false" placeholder="请输入车牌号" /> | 57 | + <uni-easyinput v-model="form.companyShortName" :inputBorder="false" disabled placeholder="选择计划后自动带出" /> |
| 137 | </template> | 58 | </template> |
| 138 | </uni-list-item> | 59 | </uni-list-item> |
| 139 | </uni-list> | 60 | </uni-list> |
| 140 | 61 | ||
| 141 | - <!-- 计划单明细 --> | 62 | + <!-- 计划单明细(只读) --> |
| 142 | <view class="sub-table"> | 63 | <view class="sub-table"> |
| 143 | <view class="header"> | 64 | <view class="header"> |
| 144 | <image class="opCollapse" src="/static/images/title.png" /> | 65 | <image class="opCollapse" src="/static/images/title.png" /> |
| 145 | <text class="title">计划单明细</text> | 66 | <text class="title">计划单明细</text> |
| 146 | - <view class="ops"> | ||
| 147 | - <image class="opAdd" @click="addPlan" src="/static/images/plus.png" /> | ||
| 148 | - </view> | ||
| 149 | </view> | 67 | </view> |
| 150 | <view class="add-list"> | 68 | <view class="add-list"> |
| 151 | - <view v-if="!planList.length" class="empty-tip">暂无明细,请添加</view> | ||
| 152 | - <view v-for="(item, idx) in planList" :key="'p-' + idx" class="block"> | 69 | + <view v-if="!planList.length" class="empty-tip">选择计划后自动带出</view> |
| 70 | + <view v-for="(item, idx) in planList" :key="'p-' + (item.id || idx)" class="block"> | ||
| 153 | <uni-list> | 71 | <uni-list> |
| 154 | <uni-list-item title="计划品种"> | 72 | <uni-list-item title="计划品种"> |
| 155 | <template v-slot:footer> | 73 | <template v-slot:footer> |
| 156 | - <uni-easyinput v-model="item.productName" :inputBorder="false" placeholder="请输入计划品种" /> | 74 | + <uni-easyinput :value="item.productName" :inputBorder="false" disabled /> |
| 157 | </template> | 75 | </template> |
| 158 | </uni-list-item> | 76 | </uni-list-item> |
| 159 | <uni-list-item title="计划数量"> | 77 | <uni-list-item title="计划数量"> |
| 160 | <template v-slot:footer> | 78 | <template v-slot:footer> |
| 161 | - <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入计划数量" /> | 79 | + <uni-easyinput :value="item.quantity" :inputBorder="false" disabled /> |
| 162 | </template> | 80 | </template> |
| 163 | </uni-list-item> | 81 | </uni-list-item> |
| 164 | <uni-list-item title="计划编号"> | 82 | <uni-list-item title="计划编号"> |
| 165 | <template v-slot:footer> | 83 | <template v-slot:footer> |
| 166 | - <uni-easyinput v-model="item.planCode" :inputBorder="false" placeholder="请输入计划编号" /> | 84 | + <uni-easyinput :value="item.planCode" :inputBorder="false" disabled /> |
| 167 | </template> | 85 | </template> |
| 168 | </uni-list-item> | 86 | </uni-list-item> |
| 169 | </uni-list> | 87 | </uni-list> |
| 170 | - <view class="block-ops"> | ||
| 171 | - <div class="del" @click="removeRow('plan', idx)"> | ||
| 172 | - <image src="/static/images/delete.png" class="icon" />删除 | ||
| 173 | - </div> | ||
| 174 | - </view> | ||
| 175 | </view> | 88 | </view> |
| 176 | </view> | 89 | </view> |
| 177 | </view> | 90 | </view> |
| 178 | 91 | ||
| 179 | - <!-- 过磅明细 --> | 92 | + <!-- 过磅明细(可编辑) --> |
| 180 | <view class="sub-table"> | 93 | <view class="sub-table"> |
| 181 | <view class="header"> | 94 | <view class="header"> |
| 182 | <image class="opCollapse" src="/static/images/title.png" /> | 95 | <image class="opCollapse" src="/static/images/title.png" /> |
| 183 | <text class="title">过磅明细</text> | 96 | <text class="title">过磅明细</text> |
| 184 | <view class="ops"> | 97 | <view class="ops"> |
| 185 | - <image class="opAdd" @click="addWeigh" src="/static/images/plus.png" /> | 98 | + <image class="opAdd" @click="addWeightRow" src="/static/images/plus.png" /> |
| 186 | </view> | 99 | </view> |
| 187 | </view> | 100 | </view> |
| 188 | <view class="add-list"> | 101 | <view class="add-list"> |
| 189 | <view v-if="!weighList.length" class="empty-tip">暂无明细,请添加</view> | 102 | <view v-if="!weighList.length" class="empty-tip">暂无明细,请添加</view> |
| 190 | - <view v-for="(item, idx) in weighList" :key="'w-' + idx" class="block"> | 103 | + <view v-for="(item, idx) in weighList" :key="'w-' + (item.id || idx)" class="block"> |
| 191 | <uni-list> | 104 | <uni-list> |
| 192 | - <uni-list-item title="过磅品种"> | 105 | + <uni-list-item class="select-item" :class="item.productId ? 'is-filled' : 'is-empty'"> |
| 106 | + <template v-slot:body> | ||
| 107 | + <view class="item-title"><text class="required">*</text><text>过磅品种</text></view> | ||
| 108 | + </template> | ||
| 193 | <template v-slot:footer> | 109 | <template v-slot:footer> |
| 194 | - <uni-easyinput v-model="item.productName" :inputBorder="false" placeholder="请输入过磅品种" /> | 110 | + <picker mode="selector" :range="weightProductLabels" |
| 111 | + @change="(e) => handleWeightProductChange(idx, Number(e.detail.value))"> | ||
| 112 | + <view class="picker-value" :class="{ placeholder: !item.productId }"> | ||
| 113 | + {{ getWeightProductLabel(item) || '请选择过磅品种' }} | ||
| 114 | + </view> | ||
| 115 | + </picker> | ||
| 195 | </template> | 116 | </template> |
| 196 | </uni-list-item> | 117 | </uni-list-item> |
| 197 | <uni-list-item title="开票品名"> | 118 | <uni-list-item title="开票品名"> |
| 198 | <template v-slot:footer> | 119 | <template v-slot:footer> |
| 199 | - <uni-easyinput v-model="item.invoiceProductName" :inputBorder="false" placeholder="请输入开票品名" /> | 120 | + <uni-easyinput v-model="item.invoiceProductName" :inputBorder="false" disabled /> |
| 200 | </template> | 121 | </template> |
| 201 | </uni-list-item> | 122 | </uni-list-item> |
| 202 | <uni-list-item title="过磅数量"> | 123 | <uni-list-item title="过磅数量"> |
| 124 | + <template v-slot:body> | ||
| 125 | + <view class="item-title"><text class="required">*</text><text>过磅数量</text></view> | ||
| 126 | + </template> | ||
| 203 | <template v-slot:footer> | 127 | <template v-slot:footer> |
| 204 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入过磅数量" /> | 128 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入过磅数量" /> |
| 205 | </template> | 129 | </template> |
| 206 | </uni-list-item> | 130 | </uni-list-item> |
| 207 | <uni-list-item title="计划编号"> | 131 | <uni-list-item title="计划编号"> |
| 208 | <template v-slot:footer> | 132 | <template v-slot:footer> |
| 209 | - <uni-easyinput v-model="item.planCode" :inputBorder="false" placeholder="请输入计划编号" /> | 133 | + <uni-easyinput v-model="item.planCode" :inputBorder="false" disabled /> |
| 210 | </template> | 134 | </template> |
| 211 | </uni-list-item> | 135 | </uni-list-item> |
| 212 | </uni-list> | 136 | </uni-list> |
| @@ -219,25 +143,36 @@ | @@ -219,25 +143,36 @@ | ||
| 219 | </view> | 143 | </view> |
| 220 | </view> | 144 | </view> |
| 221 | 145 | ||
| 222 | - <!-- 申请数量明细 --> | ||
| 223 | - <view class="sub-table"> | 146 | + <!-- 申请数量明细(仅买断展示) --> |
| 147 | + <view v-if="isBuyout" class="sub-table"> | ||
| 224 | <view class="header"> | 148 | <view class="header"> |
| 225 | <image class="opCollapse" src="/static/images/title.png" /> | 149 | <image class="opCollapse" src="/static/images/title.png" /> |
| 226 | <text class="title">申请数量明细</text> | 150 | <text class="title">申请数量明细</text> |
| 227 | <view class="ops"> | 151 | <view class="ops"> |
| 228 | - <image class="opAdd" @click="addApply" src="/static/images/plus.png" /> | 152 | + <image class="opAdd" @click="addApplyRow" src="/static/images/plus.png" /> |
| 229 | </view> | 153 | </view> |
| 230 | </view> | 154 | </view> |
| 231 | <view class="add-list"> | 155 | <view class="add-list"> |
| 232 | <view v-if="!applyList.length" class="empty-tip">暂无明细,请添加</view> | 156 | <view v-if="!applyList.length" class="empty-tip">暂无明细,请添加</view> |
| 233 | - <view v-for="(item, idx) in applyList" :key="'a-' + idx" class="block"> | 157 | + <view v-for="(item, idx) in applyList" :key="'a-' + (item.id || idx)" class="block"> |
| 234 | <uni-list> | 158 | <uni-list> |
| 235 | - <uni-list-item title="类别"> | 159 | + <uni-list-item class="select-item" :class="item.breedRelationshipId ? 'is-filled' : 'is-empty'"> |
| 160 | + <template v-slot:body> | ||
| 161 | + <view class="item-title"><text class="required">*</text><text>类别</text></view> | ||
| 162 | + </template> | ||
| 236 | <template v-slot:footer> | 163 | <template v-slot:footer> |
| 237 | - <uni-easyinput v-model="item.category" :inputBorder="false" placeholder="请输入类别" /> | 164 | + <picker mode="selector" :range="varietyLabels" |
| 165 | + @change="(e) => handleVarietyChange(idx, Number(e.detail.value))"> | ||
| 166 | + <view class="picker-value" :class="{ placeholder: !item.breedRelationshipId }"> | ||
| 167 | + {{ getVarietyLabel(item) || '请选择类别' }} | ||
| 168 | + </view> | ||
| 169 | + </picker> | ||
| 238 | </template> | 170 | </template> |
| 239 | </uni-list-item> | 171 | </uni-list-item> |
| 240 | <uni-list-item title="数量"> | 172 | <uni-list-item title="数量"> |
| 173 | + <template v-slot:body> | ||
| 174 | + <view class="item-title"><text class="required">*</text><text>数量</text></view> | ||
| 175 | + </template> | ||
| 241 | <template v-slot:footer> | 176 | <template v-slot:footer> |
| 242 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入数量" /> | 177 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入数量" /> |
| 243 | </template> | 178 | </template> |
| @@ -252,6 +187,88 @@ | @@ -252,6 +187,88 @@ | ||
| 252 | </view> | 187 | </view> |
| 253 | </view> | 188 | </view> |
| 254 | 189 | ||
| 190 | + <!-- 其他信息 --> | ||
| 191 | + <view class="remark-section"> | ||
| 192 | + <view class="header"> | ||
| 193 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 194 | + <text class="title">其他信息</text> | ||
| 195 | + </view> | ||
| 196 | + <view class="section-content"> | ||
| 197 | + <uni-list> | ||
| 198 | + <uni-list-item title="物料名称"> | ||
| 199 | + <template v-slot:footer> | ||
| 200 | + <uni-easyinput :value="materialName" :inputBorder="false" disabled /> | ||
| 201 | + </template> | ||
| 202 | + </uni-list-item> | ||
| 203 | + <uni-list-item> | ||
| 204 | + <template v-slot:body> | ||
| 205 | + <view class="item-title"><text class="required">*</text><text>过磅总重</text></view> | ||
| 206 | + </template> | ||
| 207 | + <template v-slot:footer> | ||
| 208 | + <uni-easyinput v-model="form.totalGrossWeight" type="digit" :inputBorder="false" placeholder="请输入过磅总重" /> | ||
| 209 | + </template> | ||
| 210 | + </uni-list-item> | ||
| 211 | + <uni-list-item> | ||
| 212 | + <template v-slot:body> | ||
| 213 | + <view class="item-title"><text class="required">*</text><text>实际伙重</text></view> | ||
| 214 | + </template> | ||
| 215 | + <template v-slot:footer> | ||
| 216 | + <uni-easyinput v-model="form.actualImpurityWeight" type="digit" :inputBorder="false" placeholder="请输入实际伙重" /> | ||
| 217 | + </template> | ||
| 218 | + </uni-list-item> | ||
| 219 | + <uni-list-item title="货物净重"> | ||
| 220 | + <template v-slot:footer> | ||
| 221 | + <uni-easyinput :value="computedNetWeight" :inputBorder="false" disabled /> | ||
| 222 | + </template> | ||
| 223 | + </uni-list-item> | ||
| 224 | + <uni-list-item title="净重大写"> | ||
| 225 | + <template v-slot:footer> | ||
| 226 | + <uni-easyinput :value="computedNetWeightUpper" :inputBorder="false" disabled /> | ||
| 227 | + </template> | ||
| 228 | + </uni-list-item> | ||
| 229 | + </uni-list> | ||
| 230 | + | ||
| 231 | + <view class="form-group"> | ||
| 232 | + <view class="item-title"><text class="required">*</text><text>来料扣杂类型</text></view> | ||
| 233 | + <uni-data-checkbox | ||
| 234 | + mode="tag" | ||
| 235 | + :multiple="true" | ||
| 236 | + :value-field="'value'" | ||
| 237 | + :text-field="'text'" | ||
| 238 | + v-model="form.deductionTypes" | ||
| 239 | + :localdata="deductionTypeOptions" | ||
| 240 | + /> | ||
| 241 | + </view> | ||
| 242 | + | ||
| 243 | + <uni-list> | ||
| 244 | + <uni-list-item> | ||
| 245 | + <template v-slot:body> | ||
| 246 | + <view class="item-title"><text class="required">*</text><text>供应存欠料</text></view> | ||
| 247 | + </template> | ||
| 248 | + <template v-slot:footer> | ||
| 249 | + <uni-easyinput v-model="form.supplierStockMaterial" :inputBorder="false" placeholder="请输入供应存欠料" /> | ||
| 250 | + </template> | ||
| 251 | + </uni-list-item> | ||
| 252 | + <uni-list-item> | ||
| 253 | + <template v-slot:body> | ||
| 254 | + <view class="item-title"><text class="required">*</text><text>物流存欠料</text></view> | ||
| 255 | + </template> | ||
| 256 | + <template v-slot:footer> | ||
| 257 | + <uni-easyinput v-model="form.logisticsStockMaterial" :inputBorder="false" placeholder="请输入物流存欠料" /> | ||
| 258 | + </template> | ||
| 259 | + </uni-list-item> | ||
| 260 | + <uni-list-item> | ||
| 261 | + <template v-slot:body> | ||
| 262 | + <view class="item-title"><text class="required">*</text><text>车牌号</text></view> | ||
| 263 | + </template> | ||
| 264 | + <template v-slot:footer> | ||
| 265 | + <uni-easyinput v-model="form.plateNumber" :inputBorder="false" placeholder="请输入车牌号" /> | ||
| 266 | + </template> | ||
| 267 | + </uni-list-item> | ||
| 268 | + </uni-list> | ||
| 269 | + </view> | ||
| 270 | + </view> | ||
| 271 | + | ||
| 255 | <!-- 备注模块 --> | 272 | <!-- 备注模块 --> |
| 256 | <view class="remark-section"> | 273 | <view class="remark-section"> |
| 257 | <view class="header"> | 274 | <view class="header"> |
| @@ -260,8 +277,8 @@ | @@ -260,8 +277,8 @@ | ||
| 260 | </view> | 277 | </view> |
| 261 | <view class="section-content"> | 278 | <view class="section-content"> |
| 262 | <view class="remark-group"> | 279 | <view class="remark-group"> |
| 263 | - <view class="remark-label"><text class="required">*</text><text>业务摘要</text></view> | ||
| 264 | - <uni-easyinput v-model="form.businessSummary" type="textarea" :inputBorder="false" placeholder="请输入业务摘要" maxlength="2000" /> | 280 | + <view class="remark-label">业务摘要</view> |
| 281 | + <uni-easyinput :value="computedBusinessSummary" type="textarea" :inputBorder="false" disabled autoHeight /> | ||
| 265 | </view> | 282 | </view> |
| 266 | <view class="remark-group"> | 283 | <view class="remark-group"> |
| 267 | <view class="remark-label">特别说明</view> | 284 | <view class="remark-label">特别说明</view> |
| @@ -269,134 +286,450 @@ | @@ -269,134 +286,450 @@ | ||
| 269 | </view> | 286 | </view> |
| 270 | <view class="remark-group"> | 287 | <view class="remark-group"> |
| 271 | <view class="remark-label">单据备注</view> | 288 | <view class="remark-label">单据备注</view> |
| 272 | - <uni-easyinput v-model="form.remark" type="textarea" :inputBorder="false" placeholder="请输入单据备注" maxlength="2000" /> | 289 | + <uni-easyinput :value="computedDocumentRemark" type="textarea" :inputBorder="false" disabled autoHeight /> |
| 273 | </view> | 290 | </view> |
| 274 | </view> | 291 | </view> |
| 275 | </view> | 292 | </view> |
| 276 | 293 | ||
| 277 | <view class="footer"> | 294 | <view class="footer"> |
| 278 | - <button class="btn submit" type="primary" @click="onSubmit">提交</button> | 295 | + <button class="btn submit" type="primary" @click="onSubmit">保存</button> |
| 279 | </view> | 296 | </view> |
| 280 | </scroll-view> | 297 | </scroll-view> |
| 298 | + | ||
| 299 | + <RelateSelectSheet :visible.sync="planSheet.visible" title="选择计划" :multiple="true" | ||
| 300 | + :fetchFn="planSheet.fetchFn" :display-fields="planSheet.displayFields" | ||
| 301 | + row-key="id" :selectedKeys.sync="planSheet.selectedKeys" @confirm="onPlanConfirm" /> | ||
| 281 | </view> | 302 | </view> |
| 282 | </template> | 303 | </template> |
| 283 | 304 | ||
| 284 | <script> | 305 | <script> |
| 285 | -import { weighTicketSaveApi } from '@/api/procure-manage/weighTicket.js' | 306 | +import RelateSelectSheet from '@/components/relate-select/index.vue' |
| 307 | +import { | ||
| 308 | + weighTicketGenerateCodeApi, | ||
| 309 | + weighingTicketPlansApi, | ||
| 310 | + weighTicketPlanLinesApi, | ||
| 311 | + weighTicketCreateApi | ||
| 312 | +} from '@/api/procure-manage/weighTicket.js' | ||
| 313 | +import { breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 314 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | ||
| 286 | 315 | ||
| 287 | export default { | 316 | export default { |
| 288 | name: 'AddWeightTicket', | 317 | name: 'AddWeightTicket', |
| 318 | + components: { RelateSelectSheet }, | ||
| 289 | data() { | 319 | data() { |
| 290 | return { | 320 | return { |
| 291 | form: { | 321 | form: { |
| 292 | code: '', | 322 | code: '', |
| 293 | type: '', | 323 | type: '', |
| 294 | - unit: '', | ||
| 295 | - firstGrossWeightTime: '', | 324 | + planCode: '', |
| 325 | + unit: '公斤', | ||
| 296 | supplierName: '', | 326 | supplierName: '', |
| 297 | companyShortName: '', | 327 | companyShortName: '', |
| 298 | - materialName: '', | ||
| 299 | totalGrossWeight: '', | 328 | totalGrossWeight: '', |
| 300 | actualImpurityWeight: '', | 329 | actualImpurityWeight: '', |
| 301 | - netWeight: '', | ||
| 302 | - netWeightUpper: '', | ||
| 303 | - deductionTypes: '', | 330 | + deductionTypes: [], |
| 304 | supplierStockMaterial: '', | 331 | supplierStockMaterial: '', |
| 305 | logisticsStockMaterial: '', | 332 | logisticsStockMaterial: '', |
| 306 | plateNumber: '', | 333 | plateNumber: '', |
| 307 | - businessSummary: '', | ||
| 308 | - specialNote: '', | ||
| 309 | - remark: '' | 334 | + specialNote: '' |
| 310 | }, | 335 | }, |
| 336 | + dicOptions: { TYPE: [], DEDUCTION_TYPE: [] }, | ||
| 337 | + // 选中计划行(多选) | ||
| 338 | + selectedPlanRows: [], | ||
| 339 | + // 计划单明细(只读) | ||
| 311 | planList: [], | 340 | planList: [], |
| 341 | + // 过磅明细(可编辑) | ||
| 312 | weighList: [], | 342 | weighList: [], |
| 313 | - applyList: [] | 343 | + // 申请数量明细(买断时) |
| 344 | + applyList: [], | ||
| 345 | + varietyOptions: [], | ||
| 346 | + planSheet: { | ||
| 347 | + visible: false, | ||
| 348 | + fetchFn: null, | ||
| 349 | + displayFields: [ | ||
| 350 | + { label: '计划编号', field: 'code' }, | ||
| 351 | + { label: '是否买断', field: 'buyout', format: v => (v ? '是' : '否') }, | ||
| 352 | + { label: '收料单位', field: 'companyName' }, | ||
| 353 | + { label: '供料单位', field: 'supplierName' }, | ||
| 354 | + { label: '总数量', field: 'totalQuantity' }, | ||
| 355 | + { label: '创建人', field: 'createBy' } | ||
| 356 | + ], | ||
| 357 | + selectedKeys: [] | ||
| 358 | + } | ||
| 359 | + } | ||
| 360 | + }, | ||
| 361 | + computed: { | ||
| 362 | + typeLabels() { | ||
| 363 | + return (this.dicOptions.TYPE || []).map(it => it.name) | ||
| 364 | + }, | ||
| 365 | + deductionTypeOptions() { | ||
| 366 | + return (this.dicOptions.DEDUCTION_TYPE || []).map(it => ({ | ||
| 367 | + value: it.code != null ? String(it.code) : '', | ||
| 368 | + text: it.name || '' | ||
| 369 | + })).filter(it => it.value) | ||
| 370 | + }, | ||
| 371 | + isBuyout() { | ||
| 372 | + const first = (this.selectedPlanRows || [])[0] | ||
| 373 | + return !!(first && first.buyout) | ||
| 374 | + }, | ||
| 375 | + // 过磅品种下拉:数据来自计划单明细 | ||
| 376 | + weightProductLabels() { | ||
| 377 | + return (this.planList || []).map(item => | ||
| 378 | + [item.productName, item.planCode].filter(Boolean).join(' ') | ||
| 379 | + ) | ||
| 380 | + }, | ||
| 381 | + varietyLabels() { | ||
| 382 | + return (this.varietyOptions || []).map(item => | ||
| 383 | + [item.productName, item.code].filter(Boolean).join(' ') | ||
| 384 | + ) | ||
| 385 | + }, | ||
| 386 | + // 物料名称:过磅明细开票品名去重顿号拼接 | ||
| 387 | + materialName() { | ||
| 388 | + const names = (this.weighList || []) | ||
| 389 | + .map(item => item.invoiceProductName) | ||
| 390 | + .filter(name => !!name) | ||
| 391 | + return Array.from(new Set(names)).join('、') | ||
| 392 | + }, | ||
| 393 | + // 货物净重 = 过磅总重 - 实际伙重(保留两位) | ||
| 394 | + computedNetWeight() { | ||
| 395 | + const gross = this.form.totalGrossWeight | ||
| 396 | + if (gross === undefined || gross === null || gross === '') return '' | ||
| 397 | + const num = Number(gross) - Number(this.form.actualImpurityWeight || 0) | ||
| 398 | + return String(Math.round(num * 100) / 100) | ||
| 399 | + }, | ||
| 400 | + // 净重大写:中文大写 | ||
| 401 | + computedNetWeightUpper() { | ||
| 402 | + const net = this.computedNetWeight | ||
| 403 | + if (net === '' || net === null || net === undefined) return '' | ||
| 404 | + return numberToChineseUpper(net) | ||
| 405 | + }, | ||
| 406 | + // 业务摘要 | ||
| 407 | + computedBusinessSummary() { | ||
| 408 | + const parts = [] | ||
| 409 | + const weightItems = (this.weighList || []) | ||
| 410 | + .map(item => { | ||
| 411 | + const name = item.productName || '' | ||
| 412 | + const qty = item.quantity === null || item.quantity === undefined ? '' : item.quantity | ||
| 413 | + if (!name && qty === '') return '' | ||
| 414 | + return `${name}${qty}公斤` | ||
| 415 | + }) | ||
| 416 | + .filter(text => !!text) | ||
| 417 | + if (weightItems.length) parts.push(weightItems.join('、')) | ||
| 418 | + const deductionNames = (this.form.deductionTypes || []) | ||
| 419 | + .map(code => getDicName('DEDUCTION_TYPE', code, this.dicOptions.DEDUCTION_TYPE)) | ||
| 420 | + .filter(name => !!name) | ||
| 421 | + if (deductionNames.length) parts.push(deductionNames.join('、')) | ||
| 422 | + if (this.form.supplierStockMaterial) parts.push(`供应存欠料:${this.form.supplierStockMaterial}`) | ||
| 423 | + if (this.form.logisticsStockMaterial) parts.push(`物流存欠料:${this.form.logisticsStockMaterial}`) | ||
| 424 | + if (this.form.plateNumber) parts.push(`车牌号:${this.form.plateNumber}`) | ||
| 425 | + return parts.join(',') | ||
| 426 | + }, | ||
| 427 | + // 单据备注 = 业务摘要 + 特别说明 | ||
| 428 | + computedDocumentRemark() { | ||
| 429 | + const summary = this.computedBusinessSummary || '' | ||
| 430 | + const note = this.form.specialNote || '' | ||
| 431 | + return [summary, note].filter(text => !!text).join('\n') | ||
| 314 | } | 432 | } |
| 315 | }, | 433 | }, |
| 316 | - onLoad() { | ||
| 317 | - this.initCode() | 434 | + created() { |
| 435 | + this.planSheet.fetchFn = this.fetchPlans.bind(this) | ||
| 436 | + this.loadDicData() | ||
| 437 | + this.loadVarietyOptions() | ||
| 438 | + this.onGenerateCode() | ||
| 318 | }, | 439 | }, |
| 319 | methods: { | 440 | methods: { |
| 320 | - initCode() { | ||
| 321 | - // 编号生成接口待后端提供,先占位 | ||
| 322 | - this.form.code = this.form.code || '' | 441 | + async loadDicData() { |
| 442 | + try { | ||
| 443 | + const results = await getDicByCodes(['TYPE', 'DEDUCTION_TYPE']) | ||
| 444 | + this.dicOptions.TYPE = (results.TYPE && results.TYPE.data) || [] | ||
| 445 | + this.dicOptions.DEDUCTION_TYPE = (results.DEDUCTION_TYPE && results.DEDUCTION_TYPE.data) || [] | ||
| 446 | + // 类型默认选择「常规」 | ||
| 447 | + const defaultType = (this.dicOptions.TYPE || []).find(item => item.name === '常规') | ||
| 448 | + if (defaultType) { | ||
| 449 | + this.form.type = defaultType.code != null ? String(defaultType.code) : '' | ||
| 450 | + } | ||
| 451 | + } catch (e) { | ||
| 452 | + this.dicOptions = { TYPE: [], DEDUCTION_TYPE: [] } | ||
| 453 | + } | ||
| 323 | }, | 454 | }, |
| 324 | - calcNetWeight() { | ||
| 325 | - const g = Number(this.form.totalGrossWeight) | ||
| 326 | - const i = Number(this.form.actualImpurityWeight || 0) | ||
| 327 | - if (!isNaN(g) && g > 0) { | ||
| 328 | - const net = g - (isNaN(i) ? 0 : i) | ||
| 329 | - this.form.netWeight = String(Math.round(net * 10000) / 10000) | 455 | + async loadVarietyOptions() { |
| 456 | + try { | ||
| 457 | + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 458 | + const _data = (res && res.data) || {} | ||
| 459 | + this.varietyOptions = _data.datas || _data.list || _data.records || [] | ||
| 460 | + } catch (e) { | ||
| 461 | + this.varietyOptions = [] | ||
| 330 | } | 462 | } |
| 331 | }, | 463 | }, |
| 332 | - addPlan() { | ||
| 333 | - this.planList.push({ productName: '', quantity: '', planCode: '' }) | 464 | + getTypeLabel() { |
| 465 | + const found = (this.dicOptions.TYPE || []).find(it => String(it.code) === String(this.form.type)) | ||
| 466 | + return found ? found.name : '' | ||
| 467 | + }, | ||
| 468 | + onTypeChange(e) { | ||
| 469 | + const idx = Number(e.detail.value) | ||
| 470 | + const opt = (this.dicOptions.TYPE || [])[idx] | ||
| 471 | + this.form.type = opt && opt.code != null ? String(opt.code) : '' | ||
| 472 | + }, | ||
| 473 | + onGenerateCode() { | ||
| 474 | + weighTicketGenerateCodeApi() | ||
| 475 | + .then(res => { | ||
| 476 | + this.form.code = (res && res.data) ? res.data : '' | ||
| 477 | + }) | ||
| 478 | + .catch(() => {}) | ||
| 479 | + }, | ||
| 480 | + // 计划选择弹窗数据源 | ||
| 481 | + fetchPlans({ pageIndex, pageSize, extra }) { | ||
| 482 | + const keyword = (extra && extra.keyword) || '' | ||
| 483 | + const params = { | ||
| 484 | + pageIndex, | ||
| 485 | + pageSize, | ||
| 486 | + code: keyword || undefined | ||
| 487 | + } | ||
| 488 | + return weighingTicketPlansApi(params).then(res => { | ||
| 489 | + const _data = (res && res.data) || {} | ||
| 490 | + const records = _data.datas || _data.list || _data.records || [] | ||
| 491 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 492 | + const hasNext = _data.hasNext || false | ||
| 493 | + return { records, totalCount, hasNext } | ||
| 494 | + }).catch(() => ({ records: [], totalCount: 0, hasNext: false })) | ||
| 495 | + }, | ||
| 496 | + openPlanSheet() { | ||
| 497 | + this.planSheet.selectedKeys = this.selectedPlanRows.map(it => it.id) | ||
| 498 | + this.planSheet.visible = true | ||
| 499 | + }, | ||
| 500 | + onPlanConfirm({ items }) { | ||
| 501 | + const list = items || [] | ||
| 502 | + if (!list.length) { | ||
| 503 | + this.selectedPlanRows = [] | ||
| 504 | + this.form.planCode = '' | ||
| 505 | + this.form.supplierName = '' | ||
| 506 | + this.form.companyShortName = '' | ||
| 507 | + this.planList = [] | ||
| 508 | + this.weighList = [] | ||
| 509 | + return | ||
| 510 | + } | ||
| 511 | + // 校验:所选计划的「是否买断、供料单位、收料单位、车间」必须一致 | ||
| 512 | + const first = list[0] | ||
| 513 | + const isSame = list.every(item => | ||
| 514 | + item.buyout === first.buyout && | ||
| 515 | + item.supplierName === first.supplierName && | ||
| 516 | + item.companyName === first.companyName && | ||
| 517 | + item.workshopName === first.workshopName | ||
| 518 | + ) | ||
| 519 | + if (!isSame) { | ||
| 520 | + uni.showToast({ title: '是否买断,供料单位,收料单位应保持一致', icon: 'none' }) | ||
| 521 | + this.planSheet.selectedKeys = this.selectedPlanRows.map(it => it.id) | ||
| 522 | + return | ||
| 523 | + } | ||
| 524 | + this.selectedPlanRows = list.map(it => ({ ...it })) | ||
| 525 | + this.form.planCode = list.map(it => it.code).filter(Boolean).join(',') | ||
| 526 | + this.form.supplierName = first.supplierName || '' | ||
| 527 | + this.form.companyShortName = (first.companyName || '') + (first.workshopName || '') | ||
| 528 | + // 查询计划明细行,填充计划单明细;过磅明细初始化为计划明细拷贝 | ||
| 529 | + weighTicketPlanLinesApi(list.map(it => it.id)).then(res => { | ||
| 530 | + const lines = (res && res.data) || [] | ||
| 531 | + this.planList = lines.map(it => ({ ...it })) | ||
| 532 | + this.weighList = lines.map(it => ({ ...it, id: it.id || genRowId() })) | ||
| 533 | + }).catch(() => { | ||
| 534 | + this.planList = [] | ||
| 535 | + this.weighList = [] | ||
| 536 | + }) | ||
| 334 | }, | 537 | }, |
| 335 | - addWeigh() { | ||
| 336 | - this.weighList.push({ productName: '', invoiceProductName: '', quantity: '', planCode: '' }) | 538 | + getWeightProductLabel(item) { |
| 539 | + if (!item.productId) return '' | ||
| 540 | + const found = (this.planList || []).find(it => it.productId === item.productId) | ||
| 541 | + return found ? [found.productName, found.planCode].filter(Boolean).join(' ') : '' | ||
| 337 | }, | 542 | }, |
| 338 | - addApply() { | ||
| 339 | - this.applyList.push({ category: '', quantity: '' }) | 543 | + // 过磅品种改选:整行替换为选中计划明细数据 |
| 544 | + handleWeightProductChange(idx, optIdx) { | ||
| 545 | + const raw = (this.planList || [])[optIdx] | ||
| 546 | + if (!raw) return | ||
| 547 | + const rowId = this.weighList[idx].id | ||
| 548 | + this.weighList.splice(idx, 1, { ...raw, id: rowId }) | ||
| 549 | + }, | ||
| 550 | + getVarietyLabel(item) { | ||
| 551 | + if (!item.breedRelationshipId) return '' | ||
| 552 | + const found = (this.varietyOptions || []).find(it => it.id === item.breedRelationshipId) | ||
| 553 | + return found ? [found.productName, found.code].filter(Boolean).join(' ') : '' | ||
| 554 | + }, | ||
| 555 | + handleVarietyChange(idx, optIdx) { | ||
| 556 | + const raw = (this.varietyOptions || [])[optIdx] | ||
| 557 | + if (!raw) return | ||
| 558 | + const row = this.applyList[idx] | ||
| 559 | + row.category = raw.code || '' | ||
| 560 | + row.breedRelationshipId = raw.id || '' | ||
| 561 | + }, | ||
| 562 | + addWeightRow() { | ||
| 563 | + this.weighList.push({ | ||
| 564 | + id: genRowId(), | ||
| 565 | + procurementPlanId: '', | ||
| 566 | + planCode: '', | ||
| 567 | + productId: '', | ||
| 568 | + invoiceProductName: '', | ||
| 569 | + quantity: '' | ||
| 570 | + }) | ||
| 571 | + }, | ||
| 572 | + addApplyRow() { | ||
| 573 | + this.applyList.push({ | ||
| 574 | + id: genRowId(), | ||
| 575 | + category: '', | ||
| 576 | + breedRelationshipId: '', | ||
| 577 | + quantity: '' | ||
| 578 | + }) | ||
| 340 | }, | 579 | }, |
| 341 | removeRow(type, idx) { | 580 | removeRow(type, idx) { |
| 342 | - if (type === 'plan') this.planList.splice(idx, 1) | ||
| 343 | - else if (type === 'weigh') this.weighList.splice(idx, 1) | 581 | + if (type === 'weigh') this.weighList.splice(idx, 1) |
| 344 | else if (type === 'apply') this.applyList.splice(idx, 1) | 582 | else if (type === 'apply') this.applyList.splice(idx, 1) |
| 345 | }, | 583 | }, |
| 346 | validate() { | 584 | validate() { |
| 347 | const f = this.form | 585 | const f = this.form |
| 348 | - if (!f.type) return this.tip('请输入类型') | ||
| 349 | - if (!f.unit) return this.tip('请输入计划编号') | ||
| 350 | - if (!f.firstGrossWeightTime) return this.tip('请选择时间') | ||
| 351 | - if (!f.supplierName) return this.tip('请输入供料单位') | ||
| 352 | - if (!f.companyShortName) return this.tip('请输入收料单位') | ||
| 353 | - if (!f.materialName) return this.tip('请输入物料名称') | ||
| 354 | - if (!f.totalGrossWeight) return this.tip('请输入过磅总重') | 586 | + if (!f.code) return this.tip('请生成编号') |
| 587 | + if (!f.type) return this.tip('请选择类型') | ||
| 588 | + if (!this.selectedPlanRows.length) return this.tip('请选择计划编号') | ||
| 589 | + if (f.totalGrossWeight === '' || f.totalGrossWeight == null) return this.tip('请输入过磅总重') | ||
| 590 | + if (f.actualImpurityWeight === '' || f.actualImpurityWeight == null) return this.tip('请输入实际伙重') | ||
| 591 | + if (!f.deductionTypes || !f.deductionTypes.length) return this.tip('请选择来料扣杂类型') | ||
| 592 | + if (!f.supplierStockMaterial) return this.tip('请输入供应存欠料') | ||
| 593 | + if (!f.logisticsStockMaterial) return this.tip('请输入物流存欠料') | ||
| 355 | if (!f.plateNumber) return this.tip('请输入车牌号') | 594 | if (!f.plateNumber) return this.tip('请输入车牌号') |
| 356 | - if (!f.businessSummary) return this.tip('请输入业务摘要') | 595 | + // 过磅明细:品种、数量必填 |
| 596 | + const weightList = this.weighList || [] | ||
| 597 | + for (let i = 0; i < weightList.length; i++) { | ||
| 598 | + const row = weightList[i] | ||
| 599 | + if (!row.productId) return this.tip(`过磅明细第${i + 1}行:请选择过磅品种`) | ||
| 600 | + if (row.quantity === '' || row.quantity == null) return this.tip(`过磅明细第${i + 1}行:请输入过磅数量`) | ||
| 601 | + } | ||
| 602 | + // 申请数量明细:类别、数量必填(买断时) | ||
| 603 | + if (this.isBuyout) { | ||
| 604 | + const applyList = this.applyList || [] | ||
| 605 | + for (let i = 0; i < applyList.length; i++) { | ||
| 606 | + const row = applyList[i] | ||
| 607 | + if (!row.breedRelationshipId) return this.tip(`申请数量明细第${i + 1}行:请选择类别`) | ||
| 608 | + if (row.quantity === '' || row.quantity == null) return this.tip(`申请数量明细第${i + 1}行:请输入数量`) | ||
| 609 | + } | ||
| 610 | + } | ||
| 357 | return true | 611 | return true |
| 358 | }, | 612 | }, |
| 359 | tip(msg) { | 613 | tip(msg) { |
| 360 | uni.showToast({ title: msg, icon: 'none' }) | 614 | uni.showToast({ title: msg, icon: 'none' }) |
| 361 | return false | 615 | return false |
| 362 | }, | 616 | }, |
| 617 | + buildSubmitData() { | ||
| 618 | + return { | ||
| 619 | + code: this.form.code, | ||
| 620 | + type: this.form.type, | ||
| 621 | + planIds: this.selectedPlanRows.map(it => it.id), | ||
| 622 | + weighLines: (this.weighList || []).map(row => ({ | ||
| 623 | + procurementPlanId: row.procurementPlanId || '', | ||
| 624 | + planCode: row.planCode || '', | ||
| 625 | + productId: row.productId || '', | ||
| 626 | + invoiceProductName: row.invoiceProductName || '', | ||
| 627 | + quantity: row.quantity === null || row.quantity === undefined ? '' : String(row.quantity), | ||
| 628 | + itemId: row.id | ||
| 629 | + })), | ||
| 630 | + applyLines: (this.applyList || []).map(row => ({ | ||
| 631 | + category: row.category || '', | ||
| 632 | + breedRelationshipId: row.breedRelationshipId || '', | ||
| 633 | + quantity: row.quantity === null || row.quantity === undefined ? '' : String(row.quantity), | ||
| 634 | + itemId: row.breedRelationshipId | ||
| 635 | + })), | ||
| 636 | + unit: this.form.unit, | ||
| 637 | + materialName: this.materialName || null, | ||
| 638 | + totalGrossWeight: this.form.totalGrossWeight === '' ? null : Number(this.form.totalGrossWeight), | ||
| 639 | + actualImpurityWeight: this.form.actualImpurityWeight === '' ? null : Number(this.form.actualImpurityWeight), | ||
| 640 | + netWeight: this.computedNetWeight === '' ? null : Number(this.computedNetWeight), | ||
| 641 | + netWeightUpper: this.computedNetWeightUpper || null, | ||
| 642 | + deductionTypes: (this.form.deductionTypes || []).join(',') || null, | ||
| 643 | + supplierStockMaterial: this.form.supplierStockMaterial || null, | ||
| 644 | + logisticsStockMaterial: this.form.logisticsStockMaterial || null, | ||
| 645 | + plateNumber: this.form.plateNumber || null, | ||
| 646 | + businessSummary: this.computedBusinessSummary || null, | ||
| 647 | + specialNote: this.form.specialNote || null, | ||
| 648 | + documentRemark: this.computedDocumentRemark || null | ||
| 649 | + } | ||
| 650 | + }, | ||
| 363 | async onSubmit() { | 651 | async onSubmit() { |
| 364 | if (!this.validate()) return | 652 | if (!this.validate()) return |
| 365 | const confirmRes = await new Promise(resolve => { | 653 | const confirmRes = await new Promise(resolve => { |
| 366 | - uni.showModal({ title: '提示', content: '确定新增过磅码单吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | 654 | + uni.showModal({ title: '提示', content: '确定保存过磅单吗?', confirmText: '确定', cancelText: '取消', success: resolve }) |
| 367 | }) | 655 | }) |
| 368 | if (!(confirmRes && confirmRes.confirm)) return | 656 | if (!(confirmRes && confirmRes.confirm)) return |
| 369 | - const clean = (obj) => { | ||
| 370 | - const out = {} | ||
| 371 | - Object.keys(obj || {}).forEach(k => { | ||
| 372 | - const v = obj[k] | ||
| 373 | - const isEmptyString = typeof v === 'string' && v.trim() === '' | ||
| 374 | - const isUndef = v === undefined || v === null | ||
| 375 | - if (!(isEmptyString || isUndef)) out[k] = v | ||
| 376 | - }) | ||
| 377 | - return out | ||
| 378 | - } | ||
| 379 | - const payload = clean({ | ||
| 380 | - ...this.form, | ||
| 381 | - planDetailList: this.planList.map(it => clean(it)), | ||
| 382 | - weighDetailList: this.weighList.map(it => clean(it)), | ||
| 383 | - applyQuantityList: this.applyList.map(it => clean(it)) | ||
| 384 | - }) | ||
| 385 | uni.showLoading({ title: '提交中...', mask: true }) | 657 | uni.showLoading({ title: '提交中...', mask: true }) |
| 386 | - weighTicketSaveApi(payload) | 658 | + weighTicketCreateApi(this.buildSubmitData()) |
| 387 | .then(() => { | 659 | .then(() => { |
| 388 | uni.hideLoading() | 660 | uni.hideLoading() |
| 389 | - uni.showToast({ title: '新增成功', icon: 'none' }) | 661 | + uni.showToast({ title: '保存成功', icon: 'none' }) |
| 390 | try { uni.setStorageSync('WEIGHT_TICKET_LIST_NEED_REFRESH', '1') } catch (e) {} | 662 | try { uni.setStorageSync('WEIGHT_TICKET_LIST_NEED_REFRESH', '1') } catch (e) {} |
| 391 | setTimeout(() => { uni.navigateBack() }, 400) | 663 | setTimeout(() => { uni.navigateBack() }, 400) |
| 392 | }) | 664 | }) |
| 393 | .catch(e => { | 665 | .catch(e => { |
| 394 | uni.hideLoading() | 666 | uni.hideLoading() |
| 395 | - uni.showToast({ title: (e && (e.msg || e.message)) || '新增失败', icon: 'none' }) | 667 | + uni.showToast({ title: (e && (e.msg || e.message)) || '保存失败', icon: 'none' }) |
| 396 | }) | 668 | }) |
| 397 | } | 669 | } |
| 398 | } | 670 | } |
| 399 | } | 671 | } |
| 672 | + | ||
| 673 | +// 生成前端临时行 id | ||
| 674 | +function genRowId() { | ||
| 675 | + return 'row_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8) | ||
| 676 | +} | ||
| 677 | + | ||
| 678 | +// 数字转中文大写(对齐 PC 端 useWeightTicketForm.ts) | ||
| 679 | +function numberToChineseUpper(num) { | ||
| 680 | + if (num === null || num === undefined || num === '' || isNaN(Number(num))) return '零' | ||
| 681 | + const n = Number(num) | ||
| 682 | + if (!isFinite(n)) return '零' | ||
| 683 | + | ||
| 684 | + const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'] | ||
| 685 | + const smallUnits = ['', '拾', '佰', '仟'] | ||
| 686 | + const bigUnits = ['', '万', '亿', '兆'] | ||
| 687 | + | ||
| 688 | + const negative = n < 0 | ||
| 689 | + const abs = Math.abs(n) | ||
| 690 | + const parts = abs.toString().split('.') | ||
| 691 | + const intStrRaw = parts[0] | ||
| 692 | + const decStrRaw = parts[1] || '' | ||
| 693 | + const s = intStrRaw | ||
| 694 | + const len = s.length | ||
| 695 | + | ||
| 696 | + let intPart = '' | ||
| 697 | + let zeroFlag = false | ||
| 698 | + for (let i = 0; i < len; i++) { | ||
| 699 | + const d = parseInt(s[i], 10) | ||
| 700 | + const pos = len - 1 - i | ||
| 701 | + const unitIdx = pos % 4 | ||
| 702 | + const groupIdx = Math.floor(pos / 4) | ||
| 703 | + if (d !== 0) { | ||
| 704 | + if (zeroFlag) { | ||
| 705 | + intPart += digit[0] | ||
| 706 | + zeroFlag = false | ||
| 707 | + } | ||
| 708 | + intPart += digit[d] + smallUnits[unitIdx] | ||
| 709 | + } else { | ||
| 710 | + zeroFlag = true | ||
| 711 | + } | ||
| 712 | + if (unitIdx === 0) { | ||
| 713 | + const start = Math.max(0, len - (groupIdx + 1) * 4) | ||
| 714 | + const end = len - groupIdx * 4 | ||
| 715 | + const groupDigits = s.slice(start, end) | ||
| 716 | + if (!/^0+$/.test(groupDigits)) { | ||
| 717 | + intPart += bigUnits[groupIdx] || '' | ||
| 718 | + } | ||
| 719 | + } | ||
| 720 | + } | ||
| 721 | + if (intPart === '') intPart = digit[0] | ||
| 722 | + | ||
| 723 | + let result = intPart | ||
| 724 | + if (decStrRaw) { | ||
| 725 | + const decChars = decStrRaw | ||
| 726 | + .split('') | ||
| 727 | + .map(c => digit[parseInt(c, 10)]) | ||
| 728 | + .join('') | ||
| 729 | + result += '点' + decChars | ||
| 730 | + } | ||
| 731 | + return (negative ? '负' : '') + result | ||
| 732 | +} | ||
| 400 | </script> | 733 | </script> |
| 401 | 734 | ||
| 402 | <style lang="scss" scoped> | 735 | <style lang="scss" scoped> |
| @@ -557,6 +890,18 @@ export default { | @@ -557,6 +890,18 @@ export default { | ||
| 557 | text-align: left; | 890 | text-align: left; |
| 558 | } | 891 | } |
| 559 | 892 | ||
| 893 | +.picker-value { | ||
| 894 | + font-size: 32rpx; | ||
| 895 | + color: rgba(0, 0, 0, 0.9); | ||
| 896 | + line-height: 48rpx; | ||
| 897 | + text-align: right; | ||
| 898 | + min-height: 48rpx; | ||
| 899 | + | ||
| 900 | + &.placeholder { | ||
| 901 | + color: rgba(0, 0, 0, 0.4); | ||
| 902 | + } | ||
| 903 | +} | ||
| 904 | + | ||
| 560 | .sub-table, | 905 | .sub-table, |
| 561 | .remark-section { | 906 | .remark-section { |
| 562 | margin-top: 20rpx; | 907 | margin-top: 20rpx; |
| @@ -644,19 +989,15 @@ export default { | @@ -644,19 +989,15 @@ export default { | ||
| 644 | padding: 32rpx; | 989 | padding: 32rpx; |
| 645 | } | 990 | } |
| 646 | 991 | ||
| 647 | -.remark-group { | ||
| 648 | - margin-bottom: 32rpx; | ||
| 649 | - | ||
| 650 | - &:last-child { | ||
| 651 | - margin-bottom: 0; | ||
| 652 | - } | 992 | +.form-group { |
| 993 | + margin: 24rpx 0 32rpx; | ||
| 653 | 994 | ||
| 654 | - .remark-label { | 995 | + .item-title { |
| 655 | display: flex; | 996 | display: flex; |
| 656 | align-items: center; | 997 | align-items: center; |
| 657 | font-size: 32rpx; | 998 | font-size: 32rpx; |
| 658 | color: rgba(0, 0, 0, 0.9); | 999 | color: rgba(0, 0, 0, 0.9); |
| 659 | - margin-bottom: 16rpx; | 1000 | + margin-bottom: 20rpx; |
| 660 | position: relative; | 1001 | position: relative; |
| 661 | padding-left: 16rpx; | 1002 | padding-left: 16rpx; |
| 662 | 1003 | ||
| @@ -667,4 +1008,20 @@ export default { | @@ -667,4 +1008,20 @@ export default { | ||
| 667 | } | 1008 | } |
| 668 | } | 1009 | } |
| 669 | } | 1010 | } |
| 1011 | + | ||
| 1012 | +.remark-group { | ||
| 1013 | + margin-bottom: 32rpx; | ||
| 1014 | + | ||
| 1015 | + &:last-child { | ||
| 1016 | + margin-bottom: 0; | ||
| 1017 | + } | ||
| 1018 | + | ||
| 1019 | + .remark-label { | ||
| 1020 | + display: flex; | ||
| 1021 | + align-items: center; | ||
| 1022 | + font-size: 32rpx; | ||
| 1023 | + color: rgba(0, 0, 0, 0.9); | ||
| 1024 | + margin-bottom: 16rpx; | ||
| 1025 | + } | ||
| 1026 | +} | ||
| 670 | </style> | 1027 | </style> |
| @@ -5,47 +5,12 @@ | @@ -5,47 +5,12 @@ | ||
| 5 | <!-- 基础信息 --> | 5 | <!-- 基础信息 --> |
| 6 | <view class="section"> | 6 | <view class="section"> |
| 7 | <text class="row company">{{ safeText(form.code) }}</text> | 7 | <text class="row company">{{ safeText(form.code) }}</text> |
| 8 | - <view class="row"><text class="label">类型</text><text class="value">{{ safeText(form.type) }}</text></view> | ||
| 9 | - <view class="row"><text class="label">计划编号</text><text class="value">{{ safeText(form.unit) }}</text></view> | 8 | + <view class="row"><text class="label">类型</text><text class="value">{{ typeName }}</text></view> |
| 9 | + <view class="row"><text class="label">计划编号</text><text class="value">{{ safeText(planCodeText) }}</text></view> | ||
| 10 | + <view class="row"><text class="label">单位</text><text class="value">{{ safeText(form.unit) }}</text></view> | ||
| 10 | <view class="row"><text class="label">时间</text><text class="value">{{ formatDate(form.firstGrossWeightTime) }}</text></view> | 11 | <view class="row"><text class="label">时间</text><text class="value">{{ formatDate(form.firstGrossWeightTime) }}</text></view> |
| 11 | <view class="row"><text class="label">供料单位</text><text class="value">{{ safeText(form.supplierName) }}</text></view> | 12 | <view class="row"><text class="label">供料单位</text><text class="value">{{ safeText(form.supplierName) }}</text></view> |
| 12 | <view class="row"><text class="label">收料单位</text><text class="value">{{ safeText(form.companyShortName) }}</text></view> | 13 | <view class="row"><text class="label">收料单位</text><text class="value">{{ safeText(form.companyShortName) }}</text></view> |
| 13 | - <view class="row"><text class="label">物料名称</text><text class="value">{{ safeText(form.materialName) }}</text></view> | ||
| 14 | - <view class="row"><text class="label">过磅总重</text><text class="value">{{ formatNumber(form.totalGrossWeight) }}</text></view> | ||
| 15 | - <view class="row"><text class="label">实际伙重</text><text class="value">{{ formatNumber(form.actualImpurityWeight) }}</text></view> | ||
| 16 | - <view class="row"><text class="label">货物净重</text><text class="value">{{ formatNumber(form.netWeight) }}</text></view> | ||
| 17 | - <view class="row"><text class="label">净重大写</text><text class="value">{{ safeText(form.netWeightUpper) }}</text></view> | ||
| 18 | - <view class="row"><text class="label">来料扣杂类型</text><text class="value">{{ safeText(form.deductionTypes) }}</text></view> | ||
| 19 | - <view class="row"><text class="label">供应存欠料</text><text class="value">{{ safeText(form.supplierStockMaterial) }}</text></view> | ||
| 20 | - <view class="row"><text class="label">物流存欠料</text><text class="value">{{ safeText(form.logisticsStockMaterial) }}</text></view> | ||
| 21 | - <view class="row"><text class="label">车牌号</text><text class="value">{{ safeText(form.plateNumber) }}</text></view> | ||
| 22 | - </view> | ||
| 23 | - | ||
| 24 | - <!-- 业务摘要 --> | ||
| 25 | - <view class="title-header"> | ||
| 26 | - <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 27 | - <span>业务摘要</span> | ||
| 28 | - </view> | ||
| 29 | - <view class="section"> | ||
| 30 | - <text class="remark-text">{{ safeText(form.businessSummary) }}</text> | ||
| 31 | - </view> | ||
| 32 | - | ||
| 33 | - <!-- 特别说明 --> | ||
| 34 | - <view class="title-header"> | ||
| 35 | - <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 36 | - <span>特别说明</span> | ||
| 37 | - </view> | ||
| 38 | - <view class="section"> | ||
| 39 | - <text class="remark-text">{{ safeText(form.specialNote) }}</text> | ||
| 40 | - </view> | ||
| 41 | - | ||
| 42 | - <!-- 单据备注 --> | ||
| 43 | - <view class="title-header"> | ||
| 44 | - <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 45 | - <span>单据备注</span> | ||
| 46 | - </view> | ||
| 47 | - <view class="section"> | ||
| 48 | - <text class="remark-text">{{ safeText(form.specialNote) }}</text> | ||
| 49 | </view> | 14 | </view> |
| 50 | 15 | ||
| 51 | <!-- 计划单明细 --> | 16 | <!-- 计划单明细 --> |
| @@ -91,8 +56,8 @@ | @@ -91,8 +56,8 @@ | ||
| 91 | </view> | 56 | </view> |
| 92 | </view> | 57 | </view> |
| 93 | 58 | ||
| 94 | - <!-- 申请数量明细 --> | ||
| 95 | - <view class="sub-table"> | 59 | + <!-- 申请数量明细(仅买断或有数据时展示) --> |
| 60 | + <view v-if="isBuyout" class="sub-table"> | ||
| 96 | <view class="sub-header"> | 61 | <view class="sub-header"> |
| 97 | <image class="sub-bar" src="/static/images/title.png" /> | 62 | <image class="sub-bar" src="/static/images/title.png" /> |
| 98 | <text class="sub-title">申请数量明细</text> | 63 | <text class="sub-title">申请数量明细</text> |
| @@ -110,16 +75,65 @@ | @@ -110,16 +75,65 @@ | ||
| 110 | </view> | 75 | </view> |
| 111 | </view> | 76 | </view> |
| 112 | </view> | 77 | </view> |
| 78 | + | ||
| 79 | + <!-- 其他信息 --> | ||
| 80 | + <view class="title-header"> | ||
| 81 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 82 | + <span>其他信息</span> | ||
| 83 | + </view> | ||
| 84 | + <view class="section"> | ||
| 85 | + <view class="row"><text class="label">物料名称</text><text class="value">{{ safeText(form.materialName) }}</text></view> | ||
| 86 | + <view class="row"><text class="label">过磅总重</text><text class="value">{{ formatNumber(form.totalGrossWeight) }}</text></view> | ||
| 87 | + <view class="row"><text class="label">实际伙重</text><text class="value">{{ formatNumber(form.actualImpurityWeight) }}</text></view> | ||
| 88 | + <view class="row"><text class="label">货物净重</text><text class="value">{{ formatNumber(form.netWeight) }}</text></view> | ||
| 89 | + <view class="row"><text class="label">净重大写</text><text class="value">{{ safeText(form.netWeightUpper) }}</text></view> | ||
| 90 | + <view class="row"><text class="label">来料扣杂类型</text><text class="value">{{ deductionNames }}</text></view> | ||
| 91 | + <view class="row"><text class="label">供应存欠料</text><text class="value">{{ safeText(form.supplierStockMaterial) }}</text></view> | ||
| 92 | + <view class="row"><text class="label">物流存欠料</text><text class="value">{{ safeText(form.logisticsStockMaterial) }}</text></view> | ||
| 93 | + <view class="row"><text class="label">车牌号</text><text class="value">{{ safeText(form.plateNumber) }}</text></view> | ||
| 94 | + </view> | ||
| 95 | + | ||
| 96 | + <!-- 业务摘要 --> | ||
| 97 | + <view class="title-header"> | ||
| 98 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 99 | + <span>业务摘要</span> | ||
| 100 | + </view> | ||
| 101 | + <view class="section"> | ||
| 102 | + <text class="remark-text">{{ safeText(form.businessSummary) }}</text> | ||
| 103 | + </view> | ||
| 104 | + | ||
| 105 | + <!-- 特别说明 --> | ||
| 106 | + <view class="title-header"> | ||
| 107 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 108 | + <span>特别说明</span> | ||
| 109 | + </view> | ||
| 110 | + <view class="section"> | ||
| 111 | + <text class="remark-text">{{ safeText(form.specialNote) }}</text> | ||
| 112 | + </view> | ||
| 113 | + | ||
| 114 | + <!-- 单据备注 --> | ||
| 115 | + <view class="title-header"> | ||
| 116 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 117 | + <span>单据备注</span> | ||
| 118 | + </view> | ||
| 119 | + <view class="section"> | ||
| 120 | + <text class="remark-text">{{ safeText(form.documentRemark) }}</text> | ||
| 121 | + </view> | ||
| 113 | </view> | 122 | </view> |
| 114 | </scroll-view> | 123 | </scroll-view> |
| 124 | + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> | ||
| 115 | </view> | 125 | </view> |
| 116 | </template> | 126 | </template> |
| 117 | 127 | ||
| 118 | <script> | 128 | <script> |
| 119 | -import { weighTicketDetailApi } from '@/api/procure-manage/weighTicket.js' | 129 | +import DetailButtons from '@/components/detail-buttons/index.vue' |
| 130 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | ||
| 131 | +import { weighTicketDetailApi, weighTicketSubmitAuditApi, weighTicketCancelApi } from '@/api/procure-manage/weighTicket.js' | ||
| 132 | +import { getInfo } from '@/api/login.js' | ||
| 120 | 133 | ||
| 121 | export default { | 134 | export default { |
| 122 | name: 'WeightTicketDetail', | 135 | name: 'WeightTicketDetail', |
| 136 | + components: { DetailButtons }, | ||
| 123 | data() { | 137 | data() { |
| 124 | return { | 138 | return { |
| 125 | id: '', | 139 | id: '', |
| @@ -127,12 +141,79 @@ export default { | @@ -127,12 +141,79 @@ export default { | ||
| 127 | planList: [], | 141 | planList: [], |
| 128 | weighList: [], | 142 | weighList: [], |
| 129 | applyList: [], | 143 | applyList: [], |
| 130 | - collapse: { plan: false, weigh: false, apply: false } | 144 | + buyout: false, |
| 145 | + currentUserId: '', | ||
| 146 | + collapse: { plan: false, weigh: false, apply: false }, | ||
| 147 | + dicOptions: { | ||
| 148 | + TYPE: [], | ||
| 149 | + DEDUCTION_TYPE: [], | ||
| 150 | + AUDIT_STATUS: [] | ||
| 151 | + }, | ||
| 152 | + buttons: [ | ||
| 153 | + { text: '修改', visible: true, variant: 'outline', event: 'edit' }, | ||
| 154 | + { text: '提交审核', visible: true, variant: 'outline', event: 'submitAudit' }, | ||
| 155 | + { text: '作废', visible: true, variant: 'outline', event: 'cancel' }, | ||
| 156 | + { text: '上传签字凭证', visible: true, variant: 'outline', event: 'uploadSign' }, | ||
| 157 | + { text: '上传延期说明', visible: true, variant: 'outline', event: 'uploadDelay' }, | ||
| 158 | + { text: '复磅', visible: true, variant: 'primary', event: 'reweigh' } | ||
| 159 | + ] | ||
| 160 | + } | ||
| 161 | + }, | ||
| 162 | + computed: { | ||
| 163 | + typeName() { | ||
| 164 | + const v = this.form.type == null ? '' : String(this.form.type) | ||
| 165 | + if (!v) return '-' | ||
| 166 | + return getDicName('TYPE', v, this.dicOptions.TYPE) || v | ||
| 167 | + }, | ||
| 168 | + planCodeText() { | ||
| 169 | + const codes = Array.from(new Set((this.planList || []).map(it => it.planCode).filter(Boolean))) | ||
| 170 | + return codes.join(',') | ||
| 171 | + }, | ||
| 172 | + deductionNames() { | ||
| 173 | + const codes = (this.form.deductionTypes == null ? '' : String(this.form.deductionTypes)).split(',').filter(Boolean) | ||
| 174 | + const names = codes.map(code => getDicName('DEDUCTION_TYPE', code, this.dicOptions.DEDUCTION_TYPE)).filter(Boolean) | ||
| 175 | + return names.length ? names.join('、') : '-' | ||
| 176 | + }, | ||
| 177 | + isBuyout() { | ||
| 178 | + return this.buyout || (this.applyList || []).length > 0 | ||
| 179 | + }, | ||
| 180 | + displayButtons() { | ||
| 181 | + const status = this.form.approvalStatus || '' | ||
| 182 | + const isMine = this.form.createById === this.currentUserId | ||
| 183 | + const isPass = status === 'PASS' | ||
| 184 | + return [ | ||
| 185 | + { | ||
| 186 | + ...this.buttons[0], | ||
| 187 | + visible: (status === 'DRAFT' || status === 'REFUSE' || !status) && isMine && this.$auth.hasPermi('warehouse-manage:weight-ticket:modify') | ||
| 188 | + }, | ||
| 189 | + { | ||
| 190 | + ...this.buttons[1], | ||
| 191 | + visible: (status === 'DRAFT' || status === 'REFUSE' || !status) && isMine && this.$auth.hasPermi('warehouse-manage:weight-ticket:submit') | ||
| 192 | + }, | ||
| 193 | + { | ||
| 194 | + ...this.buttons[2], | ||
| 195 | + visible: isPass && this.$auth.hasPermi('warehouse-manage:weight-ticket:cancel') | ||
| 196 | + }, | ||
| 197 | + { | ||
| 198 | + ...this.buttons[3], | ||
| 199 | + visible: isPass && this.$auth.hasPermi('warehouse-manage:weight-ticket:uploadSigned') | ||
| 200 | + }, | ||
| 201 | + { | ||
| 202 | + ...this.buttons[4], | ||
| 203 | + visible: isPass && this.$auth.hasPermi('warehouse-manage:weight-ticket:uploadExtension') | ||
| 204 | + }, | ||
| 205 | + { | ||
| 206 | + ...this.buttons[5], | ||
| 207 | + visible: isPass && this.$auth.hasPermi('warehouse-manage:weight-ticket:reweigh') | ||
| 208 | + } | ||
| 209 | + ] | ||
| 131 | } | 210 | } |
| 132 | }, | 211 | }, |
| 133 | onLoad(query) { | 212 | onLoad(query) { |
| 134 | this.id = (query && query.id) || '' | 213 | this.id = (query && query.id) || '' |
| 214 | + this.loadDicData() | ||
| 135 | this.loadDetail() | 215 | this.loadDetail() |
| 216 | + this.getUserInfo() | ||
| 136 | }, | 217 | }, |
| 137 | onShow() { | 218 | onShow() { |
| 138 | let needRefresh = '' | 219 | let needRefresh = '' |
| @@ -145,6 +226,24 @@ export default { | @@ -145,6 +226,24 @@ export default { | ||
| 145 | toggle(key) { | 226 | toggle(key) { |
| 146 | this.collapse = { ...this.collapse, [key]: !this.collapse[key] } | 227 | this.collapse = { ...this.collapse, [key]: !this.collapse[key] } |
| 147 | }, | 228 | }, |
| 229 | + async loadDicData() { | ||
| 230 | + try { | ||
| 231 | + const results = await getDicByCodes(['TYPE', 'DEDUCTION_TYPE', 'AUDIT_STATUS']) | ||
| 232 | + this.dicOptions.TYPE = (results.TYPE && results.TYPE.data) || [] | ||
| 233 | + this.dicOptions.DEDUCTION_TYPE = (results.DEDUCTION_TYPE && results.DEDUCTION_TYPE.data) || [] | ||
| 234 | + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | ||
| 235 | + } catch (e) { | ||
| 236 | + this.dicOptions = { TYPE: [], DEDUCTION_TYPE: [], AUDIT_STATUS: [] } | ||
| 237 | + } | ||
| 238 | + }, | ||
| 239 | + async getUserInfo() { | ||
| 240 | + try { | ||
| 241 | + const res = await getInfo() | ||
| 242 | + this.currentUserId = (res && (res.id || (res.data && res.data.id))) || '' | ||
| 243 | + } catch (e) { | ||
| 244 | + this.currentUserId = '' | ||
| 245 | + } | ||
| 246 | + }, | ||
| 148 | loadDetail() { | 247 | loadDetail() { |
| 149 | if (!this.id) { | 248 | if (!this.id) { |
| 150 | uni.showToast({ title: '缺少单据ID', icon: 'none' }) | 249 | uni.showToast({ title: '缺少单据ID', icon: 'none' }) |
| @@ -155,9 +254,10 @@ export default { | @@ -155,9 +254,10 @@ export default { | ||
| 155 | .then(res => { | 254 | .then(res => { |
| 156 | const data = res && res.data ? (res.data.data || res.data) : {} | 255 | const data = res && res.data ? (res.data.data || res.data) : {} |
| 157 | this.form = Object.assign({}, data) | 256 | this.form = Object.assign({}, data) |
| 158 | - this.planList = this.pickList(data, ['planDetailList', 'planLineList', 'procurementPlanLineList']) | ||
| 159 | - this.weighList = this.pickList(data, ['weighDetailList', 'weighLineList', 'grossWeightList']) | ||
| 160 | - this.applyList = this.pickList(data, ['applyQuantityList', 'applyDetailList', 'applyLineList']) | 257 | + this.buyout = !!data.buyout |
| 258 | + this.planList = Array.isArray(data.planLines) ? data.planLines.map(x => ({ ...x })) : [] | ||
| 259 | + this.weighList = Array.isArray(data.weighLines) ? data.weighLines.map(x => ({ ...x })) : [] | ||
| 260 | + this.applyList = Array.isArray(data.applyLines) ? data.applyLines.map(x => ({ ...x })) : [] | ||
| 161 | }) | 261 | }) |
| 162 | .catch(() => { | 262 | .catch(() => { |
| 163 | uni.showToast({ title: '详情加载失败', icon: 'none' }) | 263 | uni.showToast({ title: '详情加载失败', icon: 'none' }) |
| @@ -166,12 +266,83 @@ export default { | @@ -166,12 +266,83 @@ export default { | ||
| 166 | uni.hideLoading && uni.hideLoading() | 266 | uni.hideLoading && uni.hideLoading() |
| 167 | }) | 267 | }) |
| 168 | }, | 268 | }, |
| 169 | - pickList(data, keys) { | ||
| 170 | - if (!data) return [] | ||
| 171 | - for (const k of keys) { | ||
| 172 | - if (Array.isArray(data[k])) return data[k].map(x => Object.assign({}, x)) | 269 | + handleButtonClick(btn) { |
| 270 | + if (!btn || btn.disabled || !btn.visible) return | ||
| 271 | + const e = btn.event || '' | ||
| 272 | + if (e === 'edit') return this.onEdit() | ||
| 273 | + if (e === 'submitAudit') return this.onSubmitAudit() | ||
| 274 | + if (e === 'cancel') return this.onCancel() | ||
| 275 | + if (e === 'uploadSign') return this.onUpload('sign') | ||
| 276 | + if (e === 'uploadDelay') return this.onUpload('delay') | ||
| 277 | + if (e === 'reweigh') return this.onReweigh() | ||
| 278 | + }, | ||
| 279 | + onEdit() { | ||
| 280 | + uni.navigateTo({ url: '/pages/weight-ticket/modify?id=' + this.id }) | ||
| 281 | + }, | ||
| 282 | + onUpload(mode) { | ||
| 283 | + uni.navigateTo({ url: '/pages/weight-ticket/upload?id=' + this.id + '&mode=' + mode }) | ||
| 284 | + }, | ||
| 285 | + onReweigh() { | ||
| 286 | + uni.navigateTo({ url: '/pages/weight-ticket/reweigh?id=' + this.id }) | ||
| 287 | + }, | ||
| 288 | + refreshListFlags() { | ||
| 289 | + try { | ||
| 290 | + uni.setStorageSync('WEIGHT_TICKET_LIST_NEED_REFRESH', '1') | ||
| 291 | + uni.setStorageSync('WEIGHT_TICKET_DETAIL_NEED_REFRESH', '1') | ||
| 292 | + } catch (e) {} | ||
| 293 | + }, | ||
| 294 | + runWithConfirm(opts) { | ||
| 295 | + const title = opts.title || '提示' | ||
| 296 | + const content = opts.content || '' | ||
| 297 | + const run = opts.run | ||
| 298 | + const loading = opts.loading || '处理中' | ||
| 299 | + const successText = opts.successText || '操作成功' | ||
| 300 | + const failText = opts.failText || '操作失败' | ||
| 301 | + if (!this.id) { | ||
| 302 | + uni.showToast({ title: '缺少单据ID', icon: 'none' }) | ||
| 303 | + return | ||
| 173 | } | 304 | } |
| 174 | - return [] | 305 | + uni.showModal({ |
| 306 | + title, | ||
| 307 | + content, | ||
| 308 | + confirmText: '确定', | ||
| 309 | + cancelText: '取消', | ||
| 310 | + success: res => { | ||
| 311 | + if (!res || !res.confirm) return | ||
| 312 | + uni.showLoading({ title: loading, mask: true }) | ||
| 313 | + Promise.resolve(run(this.id)) | ||
| 314 | + .then(() => { | ||
| 315 | + uni.hideLoading() | ||
| 316 | + uni.showToast({ title: successText, icon: 'none' }) | ||
| 317 | + this.refreshListFlags() | ||
| 318 | + this.loadDetail() | ||
| 319 | + }) | ||
| 320 | + .catch(e => { | ||
| 321 | + uni.hideLoading() | ||
| 322 | + uni.showToast({ title: (e && (e.msg || e.message)) || failText, icon: 'none' }) | ||
| 323 | + }) | ||
| 324 | + } | ||
| 325 | + }) | ||
| 326 | + }, | ||
| 327 | + onSubmitAudit() { | ||
| 328 | + this.runWithConfirm({ | ||
| 329 | + title: '提交审核', | ||
| 330 | + content: '确认提交审核吗?', | ||
| 331 | + loading: '提交中', | ||
| 332 | + successText: '提交审核成功', | ||
| 333 | + failText: '提交审核失败', | ||
| 334 | + run: id => weighTicketSubmitAuditApi(id) | ||
| 335 | + }) | ||
| 336 | + }, | ||
| 337 | + onCancel() { | ||
| 338 | + this.runWithConfirm({ | ||
| 339 | + title: '作废', | ||
| 340 | + content: '确认作废该过磅单吗?', | ||
| 341 | + loading: '处理中', | ||
| 342 | + successText: '作废成功', | ||
| 343 | + failText: '作废失败', | ||
| 344 | + run: id => weighTicketCancelApi(id) | ||
| 345 | + }) | ||
| 175 | }, | 346 | }, |
| 176 | safeText(v) { | 347 | safeText(v) { |
| 177 | const s = v == null ? '' : String(v) | 348 | const s = v == null ? '' : String(v) |
| @@ -200,7 +371,7 @@ export default { | @@ -200,7 +371,7 @@ export default { | ||
| 200 | } | 371 | } |
| 201 | .scroll { | 372 | .scroll { |
| 202 | flex: 1; | 373 | flex: 1; |
| 203 | - padding: 8rpx 0 32rpx; | 374 | + padding: 8rpx 0 144rpx; |
| 204 | } | 375 | } |
| 205 | .detail-page { | 376 | .detail-page { |
| 206 | background: #f3f3f3; | 377 | background: #f3f3f3; |
| @@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
| 5 | <uni-search-bar | 5 | <uni-search-bar |
| 6 | v-model="searchKeyword" | 6 | v-model="searchKeyword" |
| 7 | radius="6" | 7 | radius="6" |
| 8 | - placeholder="请输入编号/计划编号/供料单位" | 8 | + placeholder="请输入编号" |
| 9 | clearButton="auto" | 9 | clearButton="auto" |
| 10 | cancelButton="none" | 10 | cancelButton="none" |
| 11 | bgColor="#F3F3F3" | 11 | bgColor="#F3F3F3" |
| @@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
| 15 | /> | 15 | /> |
| 16 | <view class="tool-icons"> | 16 | <view class="tool-icons"> |
| 17 | <image | 17 | <image |
| 18 | - v-if="$auth.hasPermi('procure-manage:weigh-ticket:add')" | 18 | + v-if="$auth.hasPermi('warehouse-manage:weight-ticket:add')" |
| 19 | class="tool-icon" | 19 | class="tool-icon" |
| 20 | src="/static/images/dev_manage/add_icon.png" | 20 | src="/static/images/dev_manage/add_icon.png" |
| 21 | @click="onAdd" | 21 | @click="onAdd" |
| @@ -60,13 +60,17 @@ | @@ -60,13 +60,17 @@ | ||
| 60 | </view> | 60 | </view> |
| 61 | <view class="info-row"> | 61 | <view class="info-row"> |
| 62 | <text>计划编号</text> | 62 | <text>计划编号</text> |
| 63 | - <text>{{ item.planCode || '-' }}</text> | 63 | + <text>{{ item.planCodes || '-' }}</text> |
| 64 | </view> | 64 | </view> |
| 65 | <view class="info-row"> | 65 | <view class="info-row"> |
| 66 | <text>公司简称</text> | 66 | <text>公司简称</text> |
| 67 | <text>{{ item.companyShortName || '-' }}</text> | 67 | <text>{{ item.companyShortName || '-' }}</text> |
| 68 | </view> | 68 | </view> |
| 69 | <view class="info-row"> | 69 | <view class="info-row"> |
| 70 | + <text>创建人</text> | ||
| 71 | + <text>{{ item.createBy || '-' }}</text> | ||
| 72 | + </view> | ||
| 73 | + <view class="info-row"> | ||
| 70 | <text>时间</text> | 74 | <text>时间</text> |
| 71 | <text>{{ formatDateOnly(item.firstGrossWeightTime) }}</text> | 75 | <text>{{ formatDateOnly(item.firstGrossWeightTime) }}</text> |
| 72 | </view> | 76 | </view> |
| @@ -98,7 +102,12 @@ | @@ -98,7 +102,12 @@ | ||
| 98 | </view> | 102 | </view> |
| 99 | <view class="form-item"> | 103 | <view class="form-item"> |
| 100 | <view class="label">公司简称</view> | 104 | <view class="label">公司简称</view> |
| 101 | - <input class="input" v-model="model.companyShortName" placeholder="请输入公司简称" /> | 105 | + <picker mode="selector" :range="companyShortLabels" @change="onCompanyShortChange"> |
| 106 | + <view class="fake-select"> | ||
| 107 | + <text v-if="companyShortLabel" class="value">{{ companyShortLabel }}</text> | ||
| 108 | + <text v-else class="placeholder">请选择公司简称</text> | ||
| 109 | + </view> | ||
| 110 | + </picker> | ||
| 102 | </view> | 111 | </view> |
| 103 | <view class="form-item"> | 112 | <view class="form-item"> |
| 104 | <view class="label">审核状态</view> | 113 | <view class="label">审核状态</view> |
| @@ -108,11 +117,14 @@ | @@ -108,11 +117,14 @@ | ||
| 108 | :value-field="'value'" | 117 | :value-field="'value'" |
| 109 | :text-field="'text'" | 118 | :text-field="'text'" |
| 110 | v-model="model.approvalStatus" | 119 | v-model="model.approvalStatus" |
| 111 | - @change="onApprovalStatusChange" | ||
| 112 | :localdata="approvalStatusOptions" | 120 | :localdata="approvalStatusOptions" |
| 113 | /> | 121 | /> |
| 114 | </view> | 122 | </view> |
| 115 | <view class="form-item"> | 123 | <view class="form-item"> |
| 124 | + <view class="label">创建人</view> | ||
| 125 | + <input class="input" v-model="model.createBy" placeholder="请输入创建人" /> | ||
| 126 | + </view> | ||
| 127 | + <view class="form-item"> | ||
| 116 | <view class="label">时间</view> | 128 | <view class="label">时间</view> |
| 117 | <uni-datetime-picker type="daterange" v-model="model.timeRange" start="2023-01-01" /> | 129 | <uni-datetime-picker type="daterange" v-model="model.timeRange" start="2023-01-01" /> |
| 118 | </view> | 130 | </view> |
| @@ -126,7 +138,7 @@ | @@ -126,7 +138,7 @@ | ||
| 126 | import CardList from '@/components/card/index.vue' | 138 | import CardList from '@/components/card/index.vue' |
| 127 | import FilterModal from '@/components/filter/index.vue' | 139 | import FilterModal from '@/components/filter/index.vue' |
| 128 | import { getDicByCodes, getDicName } from '@/utils/dic.js' | 140 | import { getDicByCodes, getDicName } from '@/utils/dic.js' |
| 129 | -import { weighTicketQueryApi } from '@/api/procure-manage/weighTicket.js' | 141 | +import { weighTicketQueryApi, companyShortQueryApi } from '@/api/procure-manage/weighTicket.js' |
| 130 | 142 | ||
| 131 | export default { | 143 | export default { |
| 132 | name: 'WeightTicketList', | 144 | name: 'WeightTicketList', |
| @@ -136,17 +148,18 @@ export default { | @@ -136,17 +148,18 @@ export default { | ||
| 136 | searchKeyword: '', | 148 | searchKeyword: '', |
| 137 | searchKeywordDebounced: '', | 149 | searchKeywordDebounced: '', |
| 138 | searchDebounceTimer: null, | 150 | searchDebounceTimer: null, |
| 139 | - deleted: 0, | 151 | + deleted: false, |
| 140 | tabs: [ | 152 | tabs: [ |
| 141 | - { label: '有效', value: 0 }, | ||
| 142 | - { label: '作废', value: 1 } | 153 | + { label: '有效', value: false }, |
| 154 | + { label: '作废', value: true } | ||
| 143 | ], | 155 | ], |
| 144 | query: { | 156 | query: { |
| 145 | code: '', | 157 | code: '', |
| 146 | planCode: '', | 158 | planCode: '', |
| 147 | supplierName: '', | 159 | supplierName: '', |
| 148 | - companyShortName: '', | 160 | + companyShortId: '', |
| 149 | approvalStatus: '', | 161 | approvalStatus: '', |
| 162 | + createBy: '', | ||
| 150 | timeRange: [] | 163 | timeRange: [] |
| 151 | }, | 164 | }, |
| 152 | extraParams: {}, | 165 | extraParams: {}, |
| @@ -156,21 +169,33 @@ export default { | @@ -156,21 +169,33 @@ export default { | ||
| 156 | code: '', | 169 | code: '', |
| 157 | planCode: '', | 170 | planCode: '', |
| 158 | supplierName: '', | 171 | supplierName: '', |
| 159 | - companyShortName: '', | 172 | + companyShortId: '', |
| 160 | approvalStatus: '', | 173 | approvalStatus: '', |
| 174 | + createBy: '', | ||
| 161 | timeRange: [] | 175 | timeRange: [] |
| 162 | }, | 176 | }, |
| 163 | - approvalStatusOptions: [{ value: '', text: '全部' }], | 177 | + approvalStatusOptions: [ |
| 178 | + { value: '', text: '全部' }, | ||
| 179 | + { value: 'DRAFT', text: '草稿' }, | ||
| 180 | + { value: 'AUDIT', text: '审核中' }, | ||
| 181 | + { value: 'PASS', text: '审核通过' }, | ||
| 182 | + { value: 'REFUSE', text: '已驳回' }, | ||
| 183 | + { value: 'CANCEL', text: '已取消' } | ||
| 184 | + ], | ||
| 185 | + companyShortOptions: [], | ||
| 186 | + companyShortLabel: '', | ||
| 164 | dicOptions: { | 187 | dicOptions: { |
| 165 | AUDIT_STATUS: [] | 188 | AUDIT_STATUS: [] |
| 166 | } | 189 | } |
| 167 | } | 190 | } |
| 168 | }, | 191 | }, |
| 169 | computed: { | 192 | computed: { |
| 193 | + companyShortLabels() { | ||
| 194 | + return ['全部'].concat(this.companyShortOptions.map(it => it.label)) | ||
| 195 | + }, | ||
| 170 | extraCombined() { | 196 | extraCombined() { |
| 171 | - const keyword = this.searchKeywordDebounced || '' | ||
| 172 | return { | 197 | return { |
| 173 | - keyword: keyword || undefined, | 198 | + keyword: this.searchKeywordDebounced || undefined, |
| 174 | deleted: this.deleted | 199 | deleted: this.deleted |
| 175 | } | 200 | } |
| 176 | } | 201 | } |
| @@ -186,6 +211,7 @@ export default { | @@ -186,6 +211,7 @@ export default { | ||
| 186 | }, | 211 | }, |
| 187 | created() { | 212 | created() { |
| 188 | this.loadDicData() | 213 | this.loadDicData() |
| 214 | + this.loadCompanyShortOptions() | ||
| 189 | }, | 215 | }, |
| 190 | onShow() { | 216 | onShow() { |
| 191 | let needRefresh = '' | 217 | let needRefresh = '' |
| @@ -212,18 +238,20 @@ export default { | @@ -212,18 +238,20 @@ export default { | ||
| 212 | try { | 238 | try { |
| 213 | const results = await getDicByCodes(['AUDIT_STATUS']) | 239 | const results = await getDicByCodes(['AUDIT_STATUS']) |
| 214 | this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | 240 | this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] |
| 215 | - const list = Array.isArray(this.dicOptions.AUDIT_STATUS) ? this.dicOptions.AUDIT_STATUS : [] | ||
| 216 | - this.approvalStatusOptions = [{ value: '', text: '全部' }].concat( | ||
| 217 | - list | ||
| 218 | - .map(it => ({ | ||
| 219 | - value: it && it.code != null ? String(it.code) : '', | ||
| 220 | - text: it && it.name != null ? String(it.name) : '' | ||
| 221 | - })) | ||
| 222 | - .filter(it => it.value) | ||
| 223 | - ) | ||
| 224 | } catch (e) { | 241 | } catch (e) { |
| 225 | this.dicOptions.AUDIT_STATUS = [] | 242 | this.dicOptions.AUDIT_STATUS = [] |
| 226 | - this.approvalStatusOptions = [{ value: '', text: '全部' }] | 243 | + } |
| 244 | + }, | ||
| 245 | + async loadCompanyShortOptions() { | ||
| 246 | + try { | ||
| 247 | + const res = await companyShortQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 248 | + const datas = (res && res.data && res.data.datas) || [] | ||
| 249 | + this.companyShortOptions = datas.map(item => ({ | ||
| 250 | + label: item.shortName || '', | ||
| 251 | + value: item.id || '' | ||
| 252 | + })).filter(it => it.value) | ||
| 253 | + } catch (e) { | ||
| 254 | + this.companyShortOptions = [] | ||
| 227 | } | 255 | } |
| 228 | }, | 256 | }, |
| 229 | getAuditStatusText(status) { | 257 | getAuditStatusText(status) { |
| @@ -261,39 +289,46 @@ export default { | @@ -261,39 +289,46 @@ export default { | ||
| 261 | switchTab(t) { | 289 | switchTab(t) { |
| 262 | this.deleted = t.value | 290 | this.deleted = t.value |
| 263 | }, | 291 | }, |
| 292 | + onCompanyShortChange(e) { | ||
| 293 | + const idx = Number(e.detail.value) | ||
| 294 | + if (idx <= 0) { | ||
| 295 | + this.filterForm.companyShortId = '' | ||
| 296 | + this.companyShortLabel = '' | ||
| 297 | + } else { | ||
| 298 | + const opt = this.companyShortOptions[idx - 1] | ||
| 299 | + this.filterForm.companyShortId = opt ? opt.value : '' | ||
| 300 | + this.companyShortLabel = opt ? opt.label : '' | ||
| 301 | + } | ||
| 302 | + }, | ||
| 264 | openFilter() { | 303 | openFilter() { |
| 265 | this.filterForm = { | 304 | this.filterForm = { |
| 266 | code: this.query.code || '', | 305 | code: this.query.code || '', |
| 267 | planCode: this.query.planCode || '', | 306 | planCode: this.query.planCode || '', |
| 268 | supplierName: this.query.supplierName || '', | 307 | supplierName: this.query.supplierName || '', |
| 269 | - companyShortName: this.query.companyShortName || '', | 308 | + companyShortId: this.query.companyShortId || '', |
| 270 | approvalStatus: this.query.approvalStatus || '', | 309 | approvalStatus: this.query.approvalStatus || '', |
| 310 | + createBy: this.query.createBy || '', | ||
| 271 | timeRange: Array.isArray(this.query.timeRange) ? this.query.timeRange.slice(0) : [] | 311 | timeRange: Array.isArray(this.query.timeRange) ? this.query.timeRange.slice(0) : [] |
| 272 | } | 312 | } |
| 313 | + const found = this.companyShortOptions.find(it => it.value === this.filterForm.companyShortId) | ||
| 314 | + this.companyShortLabel = found ? found.label : '' | ||
| 273 | this.filterVisible = true | 315 | this.filterVisible = true |
| 274 | }, | 316 | }, |
| 275 | onFilterReset(payload) { | 317 | onFilterReset(payload) { |
| 276 | this.filterForm = payload | 318 | this.filterForm = payload |
| 319 | + this.companyShortLabel = '' | ||
| 277 | }, | 320 | }, |
| 278 | onFilterConfirm(payload) { | 321 | onFilterConfirm(payload) { |
| 279 | this.query = { | 322 | this.query = { |
| 280 | code: payload.code || '', | 323 | code: payload.code || '', |
| 281 | planCode: payload.planCode || '', | 324 | planCode: payload.planCode || '', |
| 282 | supplierName: payload.supplierName || '', | 325 | supplierName: payload.supplierName || '', |
| 283 | - companyShortName: payload.companyShortName || '', | 326 | + companyShortId: payload.companyShortId || '', |
| 284 | approvalStatus: payload.approvalStatus || '', | 327 | approvalStatus: payload.approvalStatus || '', |
| 328 | + createBy: payload.createBy || '', | ||
| 285 | timeRange: Array.isArray(payload.timeRange) ? payload.timeRange : [] | 329 | timeRange: Array.isArray(payload.timeRange) ? payload.timeRange : [] |
| 286 | } | 330 | } |
| 287 | }, | 331 | }, |
| 288 | - onApprovalStatusChange(e) { | ||
| 289 | - const raw = | ||
| 290 | - e && e.detail && e.detail.value !== undefined | ||
| 291 | - ? e.detail.value | ||
| 292 | - : e && e.value !== undefined | ||
| 293 | - ? e.value | ||
| 294 | - : '' | ||
| 295 | - this.filterForm.approvalStatus = raw | ||
| 296 | - }, | ||
| 297 | fetchList({ pageIndex, pageSize, query, extra }) { | 332 | fetchList({ pageIndex, pageSize, query, extra }) { |
| 298 | const q = query || {} | 333 | const q = query || {} |
| 299 | const e = extra || {} | 334 | const e = extra || {} |
| @@ -302,19 +337,15 @@ export default { | @@ -302,19 +337,15 @@ export default { | ||
| 302 | const params = { | 337 | const params = { |
| 303 | pageIndex, | 338 | pageIndex, |
| 304 | pageSize, | 339 | pageSize, |
| 305 | - deleted: e.deleted != null ? e.deleted : 0, | ||
| 306 | - code: q.code || '', | 340 | + deleted: e.deleted === true, |
| 341 | + code: q.code || keyword || '', | ||
| 307 | planCode: q.planCode || '', | 342 | planCode: q.planCode || '', |
| 308 | supplierName: q.supplierName || '', | 343 | supplierName: q.supplierName || '', |
| 309 | - companyShortName: q.companyShortName || '', | 344 | + companyShortId: q.companyShortId || '', |
| 310 | approvalStatus: q.approvalStatus || '', | 345 | approvalStatus: q.approvalStatus || '', |
| 311 | - startFirstGrossWeightTime: range && range.length === 2 ? range[0] : '', | ||
| 312 | - endFirstGrossWeightTime: range && range.length === 2 ? range[1] : '' | ||
| 313 | - } | ||
| 314 | - if (keyword) { | ||
| 315 | - if (!params.code) params.code = keyword | ||
| 316 | - if (!params.planCode) params.planCode = keyword | ||
| 317 | - if (!params.supplierName) params.supplierName = keyword | 346 | + createBy: q.createBy || '', |
| 347 | + startTime: range && range.length === 2 ? range[0] : '', | ||
| 348 | + endTime: range && range.length === 2 ? range[1] : '' | ||
| 318 | } | 349 | } |
| 319 | return weighTicketQueryApi(params) | 350 | return weighTicketQueryApi(params) |
| 320 | .then(res => { | 351 | .then(res => { |
| @@ -331,7 +362,7 @@ export default { | @@ -331,7 +362,7 @@ export default { | ||
| 331 | }) | 362 | }) |
| 332 | }, | 363 | }, |
| 333 | onCardClick(item) { | 364 | onCardClick(item) { |
| 334 | - const id = item && (item.id || item.weighTicketId) | 365 | + const id = item && item.id |
| 335 | if (!id) { | 366 | if (!id) { |
| 336 | uni.showToast({ title: '缺少ID', icon: 'none' }) | 367 | uni.showToast({ title: '缺少ID', icon: 'none' }) |
| 337 | return | 368 | return |
| @@ -415,6 +446,7 @@ export default { | @@ -415,6 +446,7 @@ export default { | ||
| 415 | &.status_AUDIT { background: $theme-primary; } | 446 | &.status_AUDIT { background: $theme-primary; } |
| 416 | &.status_PASS { background: #2ba471; } | 447 | &.status_PASS { background: #2ba471; } |
| 417 | &.status_REFUSE { background: #d54941; } | 448 | &.status_REFUSE { background: #d54941; } |
| 449 | + &.status_DRAFT { background: #e7e7e7; color: rgba(0, 0, 0, 0.9); } | ||
| 418 | &.status_CANCEL { background: #e7e7e7; color: rgba(0, 0, 0, 0.9); } | 450 | &.status_CANCEL { background: #e7e7e7; color: rgba(0, 0, 0, 0.9); } |
| 419 | } | 451 | } |
| 420 | } | 452 | } |
| @@ -453,5 +485,15 @@ export default { | @@ -453,5 +485,15 @@ export default { | ||
| 453 | background: #fff; | 485 | background: #fff; |
| 454 | box-sizing: border-box; | 486 | box-sizing: border-box; |
| 455 | } | 487 | } |
| 488 | + .fake-select { | ||
| 489 | + height: 72rpx; | ||
| 490 | + line-height: 72rpx; | ||
| 491 | + padding: 0 24rpx; | ||
| 492 | + border: 1rpx solid #e7e7e7; | ||
| 493 | + border-radius: 8rpx; | ||
| 494 | + font-size: 28rpx; | ||
| 495 | + .placeholder { color: #999; } | ||
| 496 | + .value { color: rgba(0, 0, 0, 0.9); } | ||
| 497 | + } | ||
| 456 | } | 498 | } |
| 457 | </style> | 499 | </style> |
| @@ -2,10 +2,10 @@ | @@ -2,10 +2,10 @@ | ||
| 2 | <view class="page"> | 2 | <view class="page"> |
| 3 | <scroll-view class="scroll" scroll-y> | 3 | <scroll-view class="scroll" scroll-y> |
| 4 | <uni-list> | 4 | <uni-list> |
| 5 | - <!-- 编号 --> | 5 | + <!-- 编号(只读) --> |
| 6 | <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> | 6 | <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> |
| 7 | <template v-slot:body> | 7 | <template v-slot:body> |
| 8 | - <view class="item-title"><text>编号</text></view> | 8 | + <view class="item-title"><text class="required">*</text><text>编号</text></view> |
| 9 | </template> | 9 | </template> |
| 10 | <template v-slot:footer> | 10 | <template v-slot:footer> |
| 11 | <text class="readonly-text value-code">{{ form.code || '-' }}</text> | 11 | <text class="readonly-text value-code">{{ form.code || '-' }}</text> |
| @@ -13,197 +13,121 @@ | @@ -13,197 +13,121 @@ | ||
| 13 | </uni-list-item> | 13 | </uni-list-item> |
| 14 | 14 | ||
| 15 | <!-- 类型 --> | 15 | <!-- 类型 --> |
| 16 | - <uni-list-item> | 16 | + <uni-list-item class="select-item" :class="form.type ? 'is-filled' : 'is-empty'"> |
| 17 | <template v-slot:body> | 17 | <template v-slot:body> |
| 18 | <view class="item-title"><text class="required">*</text><text>类型</text></view> | 18 | <view class="item-title"><text class="required">*</text><text>类型</text></view> |
| 19 | </template> | 19 | </template> |
| 20 | <template v-slot:footer> | 20 | <template v-slot:footer> |
| 21 | - <uni-easyinput v-model="form.type" :inputBorder="false" placeholder="请输入类型" /> | 21 | + <picker mode="selector" :range="typeLabels" @change="onTypeChange"> |
| 22 | + <view class="picker-value" :class="{ placeholder: !form.type }"> | ||
| 23 | + {{ getTypeLabel() || '请选择类型' }} | ||
| 24 | + </view> | ||
| 25 | + </picker> | ||
| 22 | </template> | 26 | </template> |
| 23 | </uni-list-item> | 27 | </uni-list-item> |
| 24 | 28 | ||
| 25 | - <!-- 计划编号 --> | ||
| 26 | - <uni-list-item> | 29 | + <!-- 计划编号(弹窗多选计划) --> |
| 30 | + <uni-list-item class="select-item" :class="form.planCode ? 'is-filled' : 'is-empty'" clickable | ||
| 31 | + @click="openPlanSheet" :rightText="form.planCode || '请选择计划'" showArrow> | ||
| 27 | <template v-slot:body> | 32 | <template v-slot:body> |
| 28 | <view class="item-title"><text class="required">*</text><text>计划编号</text></view> | 33 | <view class="item-title"><text class="required">*</text><text>计划编号</text></view> |
| 29 | </template> | 34 | </template> |
| 30 | - <template v-slot:footer> | ||
| 31 | - <uni-easyinput v-model="form.unit" :inputBorder="false" placeholder="请输入计划编号" /> | ||
| 32 | - </template> | ||
| 33 | - </uni-list-item> | ||
| 34 | - | ||
| 35 | - <!-- 时间 --> | ||
| 36 | - <uni-list-item class="select-item" :class="form.firstGrossWeightTime ? 'is-filled' : 'is-empty'"> | ||
| 37 | - <template v-slot:body> | ||
| 38 | - <view class="item-title"><text class="required">*</text><text>时间</text></view> | ||
| 39 | - </template> | ||
| 40 | - <template v-slot:footer> | ||
| 41 | - <uni-datetime-picker type="date" v-model="form.firstGrossWeightTime" /> | ||
| 42 | - </template> | ||
| 43 | - </uni-list-item> | ||
| 44 | - | ||
| 45 | - <!-- 供料单位 --> | ||
| 46 | - <uni-list-item> | ||
| 47 | - <template v-slot:body> | ||
| 48 | - <view class="item-title"><text class="required">*</text><text>供料单位</text></view> | ||
| 49 | - </template> | ||
| 50 | - <template v-slot:footer> | ||
| 51 | - <uni-easyinput v-model="form.supplierName" :inputBorder="false" placeholder="请输入供料单位" /> | ||
| 52 | - </template> | ||
| 53 | - </uni-list-item> | ||
| 54 | - | ||
| 55 | - <!-- 收料单位 --> | ||
| 56 | - <uni-list-item> | ||
| 57 | - <template v-slot:body> | ||
| 58 | - <view class="item-title"><text class="required">*</text><text>收料单位</text></view> | ||
| 59 | - </template> | ||
| 60 | - <template v-slot:footer> | ||
| 61 | - <uni-easyinput v-model="form.companyShortName" :inputBorder="false" placeholder="请输入收料单位" /> | ||
| 62 | - </template> | ||
| 63 | - </uni-list-item> | ||
| 64 | - | ||
| 65 | - <!-- 物料名称 --> | ||
| 66 | - <uni-list-item> | ||
| 67 | - <template v-slot:body> | ||
| 68 | - <view class="item-title"><text class="required">*</text><text>物料名称</text></view> | ||
| 69 | - </template> | ||
| 70 | - <template v-slot:footer> | ||
| 71 | - <uni-easyinput v-model="form.materialName" :inputBorder="false" placeholder="请输入物料名称" /> | ||
| 72 | - </template> | ||
| 73 | - </uni-list-item> | ||
| 74 | - | ||
| 75 | - <!-- 过磅总重 --> | ||
| 76 | - <uni-list-item> | ||
| 77 | - <template v-slot:body> | ||
| 78 | - <view class="item-title"><text class="required">*</text><text>过磅总重</text></view> | ||
| 79 | - </template> | ||
| 80 | - <template v-slot:footer> | ||
| 81 | - <uni-easyinput v-model="form.totalGrossWeight" type="digit" :inputBorder="false" placeholder="请输入过磅总重" @input="calcNetWeight" /> | ||
| 82 | - </template> | ||
| 83 | - </uni-list-item> | ||
| 84 | - | ||
| 85 | - <!-- 实际伙重 --> | ||
| 86 | - <uni-list-item title="实际伙重"> | ||
| 87 | - <template v-slot:footer> | ||
| 88 | - <uni-easyinput v-model="form.actualImpurityWeight" type="digit" :inputBorder="false" placeholder="请输入实际伙重" @input="calcNetWeight" /> | ||
| 89 | - </template> | ||
| 90 | - </uni-list-item> | ||
| 91 | - | ||
| 92 | - <!-- 货物净重 --> | ||
| 93 | - <uni-list-item title="货物净重"> | ||
| 94 | - <template v-slot:footer> | ||
| 95 | - <uni-easyinput v-model="form.netWeight" type="digit" :inputBorder="false" placeholder="请输入货物净重" /> | ||
| 96 | - </template> | ||
| 97 | - </uni-list-item> | ||
| 98 | - | ||
| 99 | - <!-- 净重大写 --> | ||
| 100 | - <uni-list-item title="净重大写"> | ||
| 101 | - <template v-slot:footer> | ||
| 102 | - <uni-easyinput v-model="form.netWeightUpper" :inputBorder="false" placeholder="请输入净重大写" /> | ||
| 103 | - </template> | ||
| 104 | </uni-list-item> | 35 | </uni-list-item> |
| 105 | 36 | ||
| 106 | - <!-- 来料扣杂类型 --> | ||
| 107 | - <uni-list-item title="来料扣杂类型"> | 37 | + <!-- 单位(禁用) --> |
| 38 | + <uni-list-item title="单位"> | ||
| 108 | <template v-slot:footer> | 39 | <template v-slot:footer> |
| 109 | - <uni-easyinput v-model="form.deductionTypes" :inputBorder="false" placeholder="请输入来料扣杂类型" /> | 40 | + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled /> |
| 110 | </template> | 41 | </template> |
| 111 | </uni-list-item> | 42 | </uni-list-item> |
| 112 | 43 | ||
| 113 | - <!-- 供应存欠料 --> | ||
| 114 | - <uni-list-item title="供应存欠料"> | 44 | + <!-- 供料单位(带出,禁用) --> |
| 45 | + <uni-list-item title="供料单位"> | ||
| 115 | <template v-slot:footer> | 46 | <template v-slot:footer> |
| 116 | - <uni-easyinput v-model="form.supplierStockMaterial" type="digit" :inputBorder="false" placeholder="请输入供应存欠料" /> | 47 | + <uni-easyinput v-model="form.supplierName" :inputBorder="false" disabled placeholder="选择计划后自动带出" /> |
| 117 | </template> | 48 | </template> |
| 118 | </uni-list-item> | 49 | </uni-list-item> |
| 119 | 50 | ||
| 120 | - <!-- 物流存欠料 --> | ||
| 121 | - <uni-list-item title="物流存欠料"> | ||
| 122 | - <template v-slot:footer> | ||
| 123 | - <uni-easyinput v-model="form.logisticsStockMaterial" type="digit" :inputBorder="false" placeholder="请输入物流存欠料" /> | ||
| 124 | - </template> | ||
| 125 | - </uni-list-item> | ||
| 126 | - | ||
| 127 | - <!-- 车牌号 --> | ||
| 128 | - <uni-list-item> | ||
| 129 | - <template v-slot:body> | ||
| 130 | - <view class="item-title"><text class="required">*</text><text>车牌号</text></view> | ||
| 131 | - </template> | 51 | + <!-- 收料单位(带出,禁用) --> |
| 52 | + <uni-list-item title="收料单位"> | ||
| 132 | <template v-slot:footer> | 53 | <template v-slot:footer> |
| 133 | - <uni-easyinput v-model="form.plateNumber" :inputBorder="false" placeholder="请输入车牌号" /> | 54 | + <uni-easyinput v-model="form.companyShortName" :inputBorder="false" disabled placeholder="选择计划后自动带出" /> |
| 134 | </template> | 55 | </template> |
| 135 | </uni-list-item> | 56 | </uni-list-item> |
| 136 | </uni-list> | 57 | </uni-list> |
| 137 | 58 | ||
| 138 | - <!-- 计划单明细 --> | 59 | + <!-- 计划单明细(只读) --> |
| 139 | <view class="sub-table"> | 60 | <view class="sub-table"> |
| 140 | <view class="header"> | 61 | <view class="header"> |
| 141 | <image class="opCollapse" src="/static/images/title.png" /> | 62 | <image class="opCollapse" src="/static/images/title.png" /> |
| 142 | <text class="title">计划单明细</text> | 63 | <text class="title">计划单明细</text> |
| 143 | - <view class="ops"> | ||
| 144 | - <image class="opAdd" @click="addPlan" src="/static/images/plus.png" /> | ||
| 145 | - </view> | ||
| 146 | </view> | 64 | </view> |
| 147 | <view class="add-list"> | 65 | <view class="add-list"> |
| 148 | - <view v-if="!planList.length" class="empty-tip">暂无明细,请添加</view> | ||
| 149 | - <view v-for="(item, idx) in planList" :key="'p-' + idx" class="block"> | 66 | + <view v-if="!planList.length" class="empty-tip">选择计划后自动带出</view> |
| 67 | + <view v-for="(item, idx) in planList" :key="'p-' + (item.id || idx)" class="block"> | ||
| 150 | <uni-list> | 68 | <uni-list> |
| 151 | <uni-list-item title="计划品种"> | 69 | <uni-list-item title="计划品种"> |
| 152 | <template v-slot:footer> | 70 | <template v-slot:footer> |
| 153 | - <uni-easyinput v-model="item.productName" :inputBorder="false" placeholder="请输入计划品种" /> | 71 | + <uni-easyinput :value="item.productName" :inputBorder="false" disabled /> |
| 154 | </template> | 72 | </template> |
| 155 | </uni-list-item> | 73 | </uni-list-item> |
| 156 | <uni-list-item title="计划数量"> | 74 | <uni-list-item title="计划数量"> |
| 157 | <template v-slot:footer> | 75 | <template v-slot:footer> |
| 158 | - <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入计划数量" /> | 76 | + <uni-easyinput :value="item.quantity" :inputBorder="false" disabled /> |
| 159 | </template> | 77 | </template> |
| 160 | </uni-list-item> | 78 | </uni-list-item> |
| 161 | <uni-list-item title="计划编号"> | 79 | <uni-list-item title="计划编号"> |
| 162 | <template v-slot:footer> | 80 | <template v-slot:footer> |
| 163 | - <uni-easyinput v-model="item.planCode" :inputBorder="false" placeholder="请输入计划编号" /> | 81 | + <uni-easyinput :value="item.planCode" :inputBorder="false" disabled /> |
| 164 | </template> | 82 | </template> |
| 165 | </uni-list-item> | 83 | </uni-list-item> |
| 166 | </uni-list> | 84 | </uni-list> |
| 167 | - <view class="block-ops"> | ||
| 168 | - <div class="del" @click="removeRow('plan', idx)"> | ||
| 169 | - <image src="/static/images/delete.png" class="icon" />删除 | ||
| 170 | - </div> | ||
| 171 | - </view> | ||
| 172 | </view> | 85 | </view> |
| 173 | </view> | 86 | </view> |
| 174 | </view> | 87 | </view> |
| 175 | 88 | ||
| 176 | - <!-- 过磅明细 --> | 89 | + <!-- 过磅明细(可编辑) --> |
| 177 | <view class="sub-table"> | 90 | <view class="sub-table"> |
| 178 | <view class="header"> | 91 | <view class="header"> |
| 179 | <image class="opCollapse" src="/static/images/title.png" /> | 92 | <image class="opCollapse" src="/static/images/title.png" /> |
| 180 | <text class="title">过磅明细</text> | 93 | <text class="title">过磅明细</text> |
| 181 | <view class="ops"> | 94 | <view class="ops"> |
| 182 | - <image class="opAdd" @click="addWeigh" src="/static/images/plus.png" /> | 95 | + <image class="opAdd" @click="addWeightRow" src="/static/images/plus.png" /> |
| 183 | </view> | 96 | </view> |
| 184 | </view> | 97 | </view> |
| 185 | <view class="add-list"> | 98 | <view class="add-list"> |
| 186 | <view v-if="!weighList.length" class="empty-tip">暂无明细,请添加</view> | 99 | <view v-if="!weighList.length" class="empty-tip">暂无明细,请添加</view> |
| 187 | - <view v-for="(item, idx) in weighList" :key="'w-' + idx" class="block"> | 100 | + <view v-for="(item, idx) in weighList" :key="'w-' + (item.id || idx)" class="block"> |
| 188 | <uni-list> | 101 | <uni-list> |
| 189 | - <uni-list-item title="过磅品种"> | 102 | + <uni-list-item class="select-item" :class="item.productId ? 'is-filled' : 'is-empty'"> |
| 103 | + <template v-slot:body> | ||
| 104 | + <view class="item-title"><text class="required">*</text><text>过磅品种</text></view> | ||
| 105 | + </template> | ||
| 190 | <template v-slot:footer> | 106 | <template v-slot:footer> |
| 191 | - <uni-easyinput v-model="item.productName" :inputBorder="false" placeholder="请输入过磅品种" /> | 107 | + <picker mode="selector" :range="weightProductLabels" |
| 108 | + @change="(e) => handleWeightProductChange(idx, Number(e.detail.value))"> | ||
| 109 | + <view class="picker-value" :class="{ placeholder: !item.productId }"> | ||
| 110 | + {{ getWeightProductLabel(item) || '请选择过磅品种' }} | ||
| 111 | + </view> | ||
| 112 | + </picker> | ||
| 192 | </template> | 113 | </template> |
| 193 | </uni-list-item> | 114 | </uni-list-item> |
| 194 | <uni-list-item title="开票品名"> | 115 | <uni-list-item title="开票品名"> |
| 195 | <template v-slot:footer> | 116 | <template v-slot:footer> |
| 196 | - <uni-easyinput v-model="item.invoiceProductName" :inputBorder="false" placeholder="请输入开票品名" /> | 117 | + <uni-easyinput v-model="item.invoiceProductName" :inputBorder="false" disabled /> |
| 197 | </template> | 118 | </template> |
| 198 | </uni-list-item> | 119 | </uni-list-item> |
| 199 | <uni-list-item title="过磅数量"> | 120 | <uni-list-item title="过磅数量"> |
| 121 | + <template v-slot:body> | ||
| 122 | + <view class="item-title"><text class="required">*</text><text>过磅数量</text></view> | ||
| 123 | + </template> | ||
| 200 | <template v-slot:footer> | 124 | <template v-slot:footer> |
| 201 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入过磅数量" /> | 125 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入过磅数量" /> |
| 202 | </template> | 126 | </template> |
| 203 | </uni-list-item> | 127 | </uni-list-item> |
| 204 | <uni-list-item title="计划编号"> | 128 | <uni-list-item title="计划编号"> |
| 205 | <template v-slot:footer> | 129 | <template v-slot:footer> |
| 206 | - <uni-easyinput v-model="item.planCode" :inputBorder="false" placeholder="请输入计划编号" /> | 130 | + <uni-easyinput v-model="item.planCode" :inputBorder="false" disabled /> |
| 207 | </template> | 131 | </template> |
| 208 | </uni-list-item> | 132 | </uni-list-item> |
| 209 | </uni-list> | 133 | </uni-list> |
| @@ -216,25 +140,36 @@ | @@ -216,25 +140,36 @@ | ||
| 216 | </view> | 140 | </view> |
| 217 | </view> | 141 | </view> |
| 218 | 142 | ||
| 219 | - <!-- 申请数量明细 --> | ||
| 220 | - <view class="sub-table"> | 143 | + <!-- 申请数量明细(仅买断展示) --> |
| 144 | + <view v-if="isBuyout" class="sub-table"> | ||
| 221 | <view class="header"> | 145 | <view class="header"> |
| 222 | <image class="opCollapse" src="/static/images/title.png" /> | 146 | <image class="opCollapse" src="/static/images/title.png" /> |
| 223 | <text class="title">申请数量明细</text> | 147 | <text class="title">申请数量明细</text> |
| 224 | <view class="ops"> | 148 | <view class="ops"> |
| 225 | - <image class="opAdd" @click="addApply" src="/static/images/plus.png" /> | 149 | + <image class="opAdd" @click="addApplyRow" src="/static/images/plus.png" /> |
| 226 | </view> | 150 | </view> |
| 227 | </view> | 151 | </view> |
| 228 | <view class="add-list"> | 152 | <view class="add-list"> |
| 229 | <view v-if="!applyList.length" class="empty-tip">暂无明细,请添加</view> | 153 | <view v-if="!applyList.length" class="empty-tip">暂无明细,请添加</view> |
| 230 | - <view v-for="(item, idx) in applyList" :key="'a-' + idx" class="block"> | 154 | + <view v-for="(item, idx) in applyList" :key="'a-' + (item.id || idx)" class="block"> |
| 231 | <uni-list> | 155 | <uni-list> |
| 232 | - <uni-list-item title="类别"> | 156 | + <uni-list-item class="select-item" :class="item.breedRelationshipId ? 'is-filled' : 'is-empty'"> |
| 157 | + <template v-slot:body> | ||
| 158 | + <view class="item-title"><text class="required">*</text><text>类别</text></view> | ||
| 159 | + </template> | ||
| 233 | <template v-slot:footer> | 160 | <template v-slot:footer> |
| 234 | - <uni-easyinput v-model="item.category" :inputBorder="false" placeholder="请输入类别" /> | 161 | + <picker mode="selector" :range="varietyLabels" |
| 162 | + @change="(e) => handleVarietyChange(idx, Number(e.detail.value))"> | ||
| 163 | + <view class="picker-value" :class="{ placeholder: !item.breedRelationshipId }"> | ||
| 164 | + {{ getVarietyLabel(item) || '请选择类别' }} | ||
| 165 | + </view> | ||
| 166 | + </picker> | ||
| 235 | </template> | 167 | </template> |
| 236 | </uni-list-item> | 168 | </uni-list-item> |
| 237 | <uni-list-item title="数量"> | 169 | <uni-list-item title="数量"> |
| 170 | + <template v-slot:body> | ||
| 171 | + <view class="item-title"><text class="required">*</text><text>数量</text></view> | ||
| 172 | + </template> | ||
| 238 | <template v-slot:footer> | 173 | <template v-slot:footer> |
| 239 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入数量" /> | 174 | <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入数量" /> |
| 240 | </template> | 175 | </template> |
| @@ -249,6 +184,88 @@ | @@ -249,6 +184,88 @@ | ||
| 249 | </view> | 184 | </view> |
| 250 | </view> | 185 | </view> |
| 251 | 186 | ||
| 187 | + <!-- 其他信息 --> | ||
| 188 | + <view class="remark-section"> | ||
| 189 | + <view class="header"> | ||
| 190 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 191 | + <text class="title">其他信息</text> | ||
| 192 | + </view> | ||
| 193 | + <view class="section-content"> | ||
| 194 | + <uni-list> | ||
| 195 | + <uni-list-item title="物料名称"> | ||
| 196 | + <template v-slot:footer> | ||
| 197 | + <uni-easyinput :value="materialName" :inputBorder="false" disabled /> | ||
| 198 | + </template> | ||
| 199 | + </uni-list-item> | ||
| 200 | + <uni-list-item> | ||
| 201 | + <template v-slot:body> | ||
| 202 | + <view class="item-title"><text class="required">*</text><text>过磅总重</text></view> | ||
| 203 | + </template> | ||
| 204 | + <template v-slot:footer> | ||
| 205 | + <uni-easyinput v-model="form.totalGrossWeight" type="digit" :inputBorder="false" placeholder="请输入过磅总重" /> | ||
| 206 | + </template> | ||
| 207 | + </uni-list-item> | ||
| 208 | + <uni-list-item> | ||
| 209 | + <template v-slot:body> | ||
| 210 | + <view class="item-title"><text class="required">*</text><text>实际伙重</text></view> | ||
| 211 | + </template> | ||
| 212 | + <template v-slot:footer> | ||
| 213 | + <uni-easyinput v-model="form.actualImpurityWeight" type="digit" :inputBorder="false" placeholder="请输入实际伙重" /> | ||
| 214 | + </template> | ||
| 215 | + </uni-list-item> | ||
| 216 | + <uni-list-item title="货物净重"> | ||
| 217 | + <template v-slot:footer> | ||
| 218 | + <uni-easyinput :value="computedNetWeight" :inputBorder="false" disabled /> | ||
| 219 | + </template> | ||
| 220 | + </uni-list-item> | ||
| 221 | + <uni-list-item title="净重大写"> | ||
| 222 | + <template v-slot:footer> | ||
| 223 | + <uni-easyinput :value="computedNetWeightUpper" :inputBorder="false" disabled /> | ||
| 224 | + </template> | ||
| 225 | + </uni-list-item> | ||
| 226 | + </uni-list> | ||
| 227 | + | ||
| 228 | + <view class="form-group"> | ||
| 229 | + <view class="item-title"><text class="required">*</text><text>来料扣杂类型</text></view> | ||
| 230 | + <uni-data-checkbox | ||
| 231 | + mode="tag" | ||
| 232 | + :multiple="true" | ||
| 233 | + :value-field="'value'" | ||
| 234 | + :text-field="'text'" | ||
| 235 | + v-model="form.deductionTypes" | ||
| 236 | + :localdata="deductionTypeOptions" | ||
| 237 | + /> | ||
| 238 | + </view> | ||
| 239 | + | ||
| 240 | + <uni-list> | ||
| 241 | + <uni-list-item> | ||
| 242 | + <template v-slot:body> | ||
| 243 | + <view class="item-title"><text class="required">*</text><text>供应存欠料</text></view> | ||
| 244 | + </template> | ||
| 245 | + <template v-slot:footer> | ||
| 246 | + <uni-easyinput v-model="form.supplierStockMaterial" :inputBorder="false" placeholder="请输入供应存欠料" /> | ||
| 247 | + </template> | ||
| 248 | + </uni-list-item> | ||
| 249 | + <uni-list-item> | ||
| 250 | + <template v-slot:body> | ||
| 251 | + <view class="item-title"><text class="required">*</text><text>物流存欠料</text></view> | ||
| 252 | + </template> | ||
| 253 | + <template v-slot:footer> | ||
| 254 | + <uni-easyinput v-model="form.logisticsStockMaterial" :inputBorder="false" placeholder="请输入物流存欠料" /> | ||
| 255 | + </template> | ||
| 256 | + </uni-list-item> | ||
| 257 | + <uni-list-item> | ||
| 258 | + <template v-slot:body> | ||
| 259 | + <view class="item-title"><text class="required">*</text><text>车牌号</text></view> | ||
| 260 | + </template> | ||
| 261 | + <template v-slot:footer> | ||
| 262 | + <uni-easyinput v-model="form.plateNumber" :inputBorder="false" placeholder="请输入车牌号" /> | ||
| 263 | + </template> | ||
| 264 | + </uni-list-item> | ||
| 265 | + </uni-list> | ||
| 266 | + </view> | ||
| 267 | + </view> | ||
| 268 | + | ||
| 252 | <!-- 备注模块 --> | 269 | <!-- 备注模块 --> |
| 253 | <view class="remark-section"> | 270 | <view class="remark-section"> |
| 254 | <view class="header"> | 271 | <view class="header"> |
| @@ -257,8 +274,8 @@ | @@ -257,8 +274,8 @@ | ||
| 257 | </view> | 274 | </view> |
| 258 | <view class="section-content"> | 275 | <view class="section-content"> |
| 259 | <view class="remark-group"> | 276 | <view class="remark-group"> |
| 260 | - <view class="remark-label"><text class="required">*</text><text>业务摘要</text></view> | ||
| 261 | - <uni-easyinput v-model="form.businessSummary" type="textarea" :inputBorder="false" placeholder="请输入业务摘要" maxlength="2000" /> | 277 | + <view class="remark-label">业务摘要</view> |
| 278 | + <uni-easyinput :value="computedBusinessSummary" type="textarea" :inputBorder="false" disabled autoHeight /> | ||
| 262 | </view> | 279 | </view> |
| 263 | <view class="remark-group"> | 280 | <view class="remark-group"> |
| 264 | <view class="remark-label">特别说明</view> | 281 | <view class="remark-label">特别说明</view> |
| @@ -266,7 +283,7 @@ | @@ -266,7 +283,7 @@ | ||
| 266 | </view> | 283 | </view> |
| 267 | <view class="remark-group"> | 284 | <view class="remark-group"> |
| 268 | <view class="remark-label">单据备注</view> | 285 | <view class="remark-label">单据备注</view> |
| 269 | - <uni-easyinput v-model="form.remark" type="textarea" :inputBorder="false" placeholder="请输入单据备注" maxlength="2000" /> | 286 | + <uni-easyinput :value="computedDocumentRemark" type="textarea" :inputBorder="false" disabled autoHeight /> |
| 270 | </view> | 287 | </view> |
| 271 | </view> | 288 | </view> |
| 272 | </view> | 289 | </view> |
| @@ -275,47 +292,171 @@ | @@ -275,47 +292,171 @@ | ||
| 275 | <button class="btn submit" type="primary" @click="onSubmit">保存</button> | 292 | <button class="btn submit" type="primary" @click="onSubmit">保存</button> |
| 276 | </view> | 293 | </view> |
| 277 | </scroll-view> | 294 | </scroll-view> |
| 295 | + | ||
| 296 | + <RelateSelectSheet :visible.sync="planSheet.visible" title="选择计划" :multiple="true" | ||
| 297 | + :fetchFn="planSheet.fetchFn" :display-fields="planSheet.displayFields" | ||
| 298 | + row-key="id" :selectedKeys.sync="planSheet.selectedKeys" @confirm="onPlanConfirm" /> | ||
| 278 | </view> | 299 | </view> |
| 279 | </template> | 300 | </template> |
| 280 | 301 | ||
| 281 | <script> | 302 | <script> |
| 282 | -import { weighTicketDetailApi, weighTicketUpdateApi } from '@/api/procure-manage/weighTicket.js' | 303 | +import RelateSelectSheet from '@/components/relate-select/index.vue' |
| 304 | +import { | ||
| 305 | + weighingTicketPlansApi, | ||
| 306 | + weighTicketPlanLinesApi, | ||
| 307 | + weighTicketDetailApi, | ||
| 308 | + weighTicketUpdateApi | ||
| 309 | +} from '@/api/procure-manage/weighTicket.js' | ||
| 310 | +import { breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 311 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | ||
| 283 | 312 | ||
| 284 | export default { | 313 | export default { |
| 285 | name: 'ModifyWeightTicket', | 314 | name: 'ModifyWeightTicket', |
| 315 | + components: { RelateSelectSheet }, | ||
| 286 | data() { | 316 | data() { |
| 287 | return { | 317 | return { |
| 288 | id: '', | 318 | id: '', |
| 289 | form: { | 319 | form: { |
| 290 | code: '', | 320 | code: '', |
| 291 | type: '', | 321 | type: '', |
| 292 | - unit: '', | ||
| 293 | - firstGrossWeightTime: '', | 322 | + planCode: '', |
| 323 | + unit: '公斤', | ||
| 294 | supplierName: '', | 324 | supplierName: '', |
| 295 | companyShortName: '', | 325 | companyShortName: '', |
| 296 | - materialName: '', | ||
| 297 | totalGrossWeight: '', | 326 | totalGrossWeight: '', |
| 298 | actualImpurityWeight: '', | 327 | actualImpurityWeight: '', |
| 299 | - netWeight: '', | ||
| 300 | - netWeightUpper: '', | ||
| 301 | - deductionTypes: '', | 328 | + deductionTypes: [], |
| 302 | supplierStockMaterial: '', | 329 | supplierStockMaterial: '', |
| 303 | logisticsStockMaterial: '', | 330 | logisticsStockMaterial: '', |
| 304 | plateNumber: '', | 331 | plateNumber: '', |
| 305 | - businessSummary: '', | ||
| 306 | - specialNote: '', | ||
| 307 | - remark: '' | 332 | + specialNote: '' |
| 308 | }, | 333 | }, |
| 334 | + dicOptions: { TYPE: [], DEDUCTION_TYPE: [] }, | ||
| 335 | + // 选中计划行(多选) | ||
| 336 | + selectedPlanRows: [], | ||
| 337 | + // 计划单明细(只读) | ||
| 309 | planList: [], | 338 | planList: [], |
| 339 | + // 过磅明细(可编辑) | ||
| 310 | weighList: [], | 340 | weighList: [], |
| 311 | - applyList: [] | 341 | + // 申请数量明细(买断时) |
| 342 | + applyList: [], | ||
| 343 | + varietyOptions: [], | ||
| 344 | + planSheet: { | ||
| 345 | + visible: false, | ||
| 346 | + fetchFn: null, | ||
| 347 | + displayFields: [ | ||
| 348 | + { label: '计划编号', field: 'code' }, | ||
| 349 | + { label: '是否买断', field: 'buyout', format: v => (v ? '是' : '否') }, | ||
| 350 | + { label: '收料单位', field: 'companyName' }, | ||
| 351 | + { label: '供料单位', field: 'supplierName' }, | ||
| 352 | + { label: '总数量', field: 'totalQuantity' }, | ||
| 353 | + { label: '创建人', field: 'createBy' } | ||
| 354 | + ], | ||
| 355 | + selectedKeys: [] | ||
| 356 | + } | ||
| 357 | + } | ||
| 358 | + }, | ||
| 359 | + computed: { | ||
| 360 | + typeLabels() { | ||
| 361 | + return (this.dicOptions.TYPE || []).map(it => it.name) | ||
| 362 | + }, | ||
| 363 | + deductionTypeOptions() { | ||
| 364 | + return (this.dicOptions.DEDUCTION_TYPE || []).map(it => ({ | ||
| 365 | + value: it.code != null ? String(it.code) : '', | ||
| 366 | + text: it.name || '' | ||
| 367 | + })).filter(it => it.value) | ||
| 368 | + }, | ||
| 369 | + isBuyout() { | ||
| 370 | + const first = (this.selectedPlanRows || [])[0] | ||
| 371 | + return !!(first && first.buyout) | ||
| 372 | + }, | ||
| 373 | + // 过磅品种下拉:数据来自计划单明细 | ||
| 374 | + weightProductLabels() { | ||
| 375 | + return (this.planList || []).map(item => | ||
| 376 | + [item.productName, item.planCode].filter(Boolean).join(' ') | ||
| 377 | + ) | ||
| 378 | + }, | ||
| 379 | + varietyLabels() { | ||
| 380 | + return (this.varietyOptions || []).map(item => | ||
| 381 | + [item.productName, item.code].filter(Boolean).join(' ') | ||
| 382 | + ) | ||
| 383 | + }, | ||
| 384 | + // 物料名称:过磅明细开票品名去重顿号拼接 | ||
| 385 | + materialName() { | ||
| 386 | + const names = (this.weighList || []) | ||
| 387 | + .map(item => item.invoiceProductName) | ||
| 388 | + .filter(name => !!name) | ||
| 389 | + return Array.from(new Set(names)).join('、') | ||
| 390 | + }, | ||
| 391 | + // 货物净重 = 过磅总重 - 实际伙重(保留两位) | ||
| 392 | + computedNetWeight() { | ||
| 393 | + const gross = this.form.totalGrossWeight | ||
| 394 | + if (gross === undefined || gross === null || gross === '') return '' | ||
| 395 | + const num = Number(gross) - Number(this.form.actualImpurityWeight || 0) | ||
| 396 | + return String(Math.round(num * 100) / 100) | ||
| 397 | + }, | ||
| 398 | + // 净重大写:中文大写 | ||
| 399 | + computedNetWeightUpper() { | ||
| 400 | + const net = this.computedNetWeight | ||
| 401 | + if (net === '' || net === null || net === undefined) return '' | ||
| 402 | + return numberToChineseUpper(net) | ||
| 403 | + }, | ||
| 404 | + // 业务摘要 | ||
| 405 | + computedBusinessSummary() { | ||
| 406 | + const parts = [] | ||
| 407 | + const weightItems = (this.weighList || []) | ||
| 408 | + .map(item => { | ||
| 409 | + const name = item.productName || '' | ||
| 410 | + const qty = item.quantity === null || item.quantity === undefined ? '' : item.quantity | ||
| 411 | + if (!name && qty === '') return '' | ||
| 412 | + return `${name}${qty}公斤` | ||
| 413 | + }) | ||
| 414 | + .filter(text => !!text) | ||
| 415 | + if (weightItems.length) parts.push(weightItems.join('、')) | ||
| 416 | + const deductionNames = (this.form.deductionTypes || []) | ||
| 417 | + .map(code => getDicName('DEDUCTION_TYPE', code, this.dicOptions.DEDUCTION_TYPE)) | ||
| 418 | + .filter(name => !!name) | ||
| 419 | + if (deductionNames.length) parts.push(deductionNames.join('、')) | ||
| 420 | + if (this.form.supplierStockMaterial) parts.push(`供应存欠料:${this.form.supplierStockMaterial}`) | ||
| 421 | + if (this.form.logisticsStockMaterial) parts.push(`物流存欠料:${this.form.logisticsStockMaterial}`) | ||
| 422 | + if (this.form.plateNumber) parts.push(`车牌号:${this.form.plateNumber}`) | ||
| 423 | + return parts.join(',') | ||
| 424 | + }, | ||
| 425 | + // 单据备注 = 业务摘要 + 特别说明 | ||
| 426 | + computedDocumentRemark() { | ||
| 427 | + const summary = this.computedBusinessSummary || '' | ||
| 428 | + const note = this.form.specialNote || '' | ||
| 429 | + return [summary, note].filter(text => !!text).join('\n') | ||
| 312 | } | 430 | } |
| 313 | }, | 431 | }, |
| 314 | onLoad(query) { | 432 | onLoad(query) { |
| 315 | this.id = (query && query.id) || '' | 433 | this.id = (query && query.id) || '' |
| 434 | + }, | ||
| 435 | + created() { | ||
| 436 | + this.planSheet.fetchFn = this.fetchPlans.bind(this) | ||
| 437 | + this.loadDicData() | ||
| 438 | + this.loadVarietyOptions() | ||
| 316 | this.loadDetail() | 439 | this.loadDetail() |
| 317 | }, | 440 | }, |
| 318 | methods: { | 441 | methods: { |
| 442 | + async loadDicData() { | ||
| 443 | + try { | ||
| 444 | + const results = await getDicByCodes(['TYPE', 'DEDUCTION_TYPE']) | ||
| 445 | + this.dicOptions.TYPE = (results.TYPE && results.TYPE.data) || [] | ||
| 446 | + this.dicOptions.DEDUCTION_TYPE = (results.DEDUCTION_TYPE && results.DEDUCTION_TYPE.data) || [] | ||
| 447 | + } catch (e) { | ||
| 448 | + this.dicOptions = { TYPE: [], DEDUCTION_TYPE: [] } | ||
| 449 | + } | ||
| 450 | + }, | ||
| 451 | + async loadVarietyOptions() { | ||
| 452 | + try { | ||
| 453 | + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 454 | + const _data = (res && res.data) || {} | ||
| 455 | + this.varietyOptions = _data.datas || _data.list || _data.records || [] | ||
| 456 | + } catch (e) { | ||
| 457 | + this.varietyOptions = [] | ||
| 458 | + } | ||
| 459 | + }, | ||
| 319 | loadDetail() { | 460 | loadDetail() { |
| 320 | if (!this.id) { | 461 | if (!this.id) { |
| 321 | uni.showToast({ title: '缺少单据ID', icon: 'none' }) | 462 | uni.showToast({ title: '缺少单据ID', icon: 'none' }) |
| @@ -325,10 +466,34 @@ export default { | @@ -325,10 +466,34 @@ export default { | ||
| 325 | weighTicketDetailApi({ id: this.id }) | 466 | weighTicketDetailApi({ id: this.id }) |
| 326 | .then(res => { | 467 | .then(res => { |
| 327 | const data = res && res.data ? (res.data.data || res.data) : {} | 468 | const data = res && res.data ? (res.data.data || res.data) : {} |
| 328 | - this.form = Object.assign({}, this.form, data) | ||
| 329 | - this.planList = this.pickList(data, ['planDetailList', 'planLineList', 'procurementPlanLineList']) | ||
| 330 | - this.weighList = this.pickList(data, ['weighDetailList', 'weighLineList', 'grossWeightList']) | ||
| 331 | - this.applyList = this.pickList(data, ['applyQuantityList', 'applyDetailList', 'applyLineList']) | 469 | + const buyout = !!data.buyout |
| 470 | + this.form = { | ||
| 471 | + code: data.code || '', | ||
| 472 | + type: data.type != null ? String(data.type) : '', | ||
| 473 | + planCode: data.planCode || data.planCodes || '', | ||
| 474 | + unit: data.unit || '', | ||
| 475 | + supplierName: data.supplierName || '', | ||
| 476 | + companyShortName: data.companyShortName || '', | ||
| 477 | + totalGrossWeight: data.totalGrossWeight == null ? '' : String(data.totalGrossWeight), | ||
| 478 | + actualImpurityWeight: data.actualImpurityWeight == null ? '' : String(data.actualImpurityWeight), | ||
| 479 | + deductionTypes: data.deductionTypes ? String(data.deductionTypes).split(',').filter(Boolean) : [], | ||
| 480 | + supplierStockMaterial: data.supplierStockMaterial || '', | ||
| 481 | + logisticsStockMaterial: data.logisticsStockMaterial || '', | ||
| 482 | + plateNumber: data.plateNumber || '', | ||
| 483 | + specialNote: data.specialNote || '' | ||
| 484 | + } | ||
| 485 | + // 计划选择回显:行对象缓存供提交 planIds 使用(id 取计划明细行上的计划 id) | ||
| 486 | + this.planList = (Array.isArray(data.planLines) ? data.planLines : []).map(it => ({ ...it })) | ||
| 487 | + this.selectedPlanRows = this.planList.map(item => ({ | ||
| 488 | + id: item.procurementPlanId || item.id, | ||
| 489 | + code: item.planCode || '', | ||
| 490 | + buyout: buyout, | ||
| 491 | + supplierName: data.supplierName || '', | ||
| 492 | + companyName: data.companyShortName || '', | ||
| 493 | + workshopName: '' | ||
| 494 | + })) | ||
| 495 | + this.weighList = (Array.isArray(data.weighLines) ? data.weighLines : []).map(it => ({ ...it, id: it.id || genRowId() })) | ||
| 496 | + this.applyList = (Array.isArray(data.applyLines) ? data.applyLines : []).map(it => ({ ...it, id: it.id || genRowId() })) | ||
| 332 | }) | 497 | }) |
| 333 | .catch(() => { | 498 | .catch(() => { |
| 334 | uni.showToast({ title: '加载详情失败', icon: 'none' }) | 499 | uni.showToast({ title: '加载详情失败', icon: 'none' }) |
| @@ -337,77 +502,195 @@ export default { | @@ -337,77 +502,195 @@ export default { | ||
| 337 | uni.hideLoading() | 502 | uni.hideLoading() |
| 338 | }) | 503 | }) |
| 339 | }, | 504 | }, |
| 340 | - pickList(data, keys) { | ||
| 341 | - if (!data) return [] | ||
| 342 | - for (const k of keys) { | ||
| 343 | - if (Array.isArray(data[k])) return data[k].map(x => Object.assign({}, x)) | 505 | + getTypeLabel() { |
| 506 | + const found = (this.dicOptions.TYPE || []).find(it => String(it.code) === String(this.form.type)) | ||
| 507 | + return found ? found.name : '' | ||
| 508 | + }, | ||
| 509 | + onTypeChange(e) { | ||
| 510 | + const idx = Number(e.detail.value) | ||
| 511 | + const opt = (this.dicOptions.TYPE || [])[idx] | ||
| 512 | + this.form.type = opt && opt.code != null ? String(opt.code) : '' | ||
| 513 | + }, | ||
| 514 | + // 计划选择弹窗数据源 | ||
| 515 | + fetchPlans({ pageIndex, pageSize, extra }) { | ||
| 516 | + const keyword = (extra && extra.keyword) || '' | ||
| 517 | + const params = { | ||
| 518 | + pageIndex, | ||
| 519 | + pageSize, | ||
| 520 | + code: keyword || undefined | ||
| 344 | } | 521 | } |
| 345 | - return [] | 522 | + return weighingTicketPlansApi(params).then(res => { |
| 523 | + const _data = (res && res.data) || {} | ||
| 524 | + const records = _data.datas || _data.list || _data.records || [] | ||
| 525 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 526 | + const hasNext = _data.hasNext || false | ||
| 527 | + return { records, totalCount, hasNext } | ||
| 528 | + }).catch(() => ({ records: [], totalCount: 0, hasNext: false })) | ||
| 346 | }, | 529 | }, |
| 347 | - calcNetWeight() { | ||
| 348 | - const g = Number(this.form.totalGrossWeight) | ||
| 349 | - const i = Number(this.form.actualImpurityWeight || 0) | ||
| 350 | - if (!isNaN(g) && g > 0) { | ||
| 351 | - const net = g - (isNaN(i) ? 0 : i) | ||
| 352 | - this.form.netWeight = String(Math.round(net * 10000) / 10000) | 530 | + openPlanSheet() { |
| 531 | + this.planSheet.selectedKeys = this.selectedPlanRows.map(it => it.id) | ||
| 532 | + this.planSheet.visible = true | ||
| 533 | + }, | ||
| 534 | + onPlanConfirm({ items }) { | ||
| 535 | + const list = items || [] | ||
| 536 | + if (!list.length) { | ||
| 537 | + this.selectedPlanRows = [] | ||
| 538 | + this.form.planCode = '' | ||
| 539 | + this.form.supplierName = '' | ||
| 540 | + this.form.companyShortName = '' | ||
| 541 | + this.planList = [] | ||
| 542 | + this.weighList = [] | ||
| 543 | + return | ||
| 353 | } | 544 | } |
| 545 | + // 校验:所选计划的「是否买断、供料单位、收料单位、车间」必须一致 | ||
| 546 | + const first = list[0] | ||
| 547 | + const isSame = list.every(item => | ||
| 548 | + item.buyout === first.buyout && | ||
| 549 | + item.supplierName === first.supplierName && | ||
| 550 | + item.companyName === first.companyName && | ||
| 551 | + item.workshopName === first.workshopName | ||
| 552 | + ) | ||
| 553 | + if (!isSame) { | ||
| 554 | + uni.showToast({ title: '是否买断,供料单位,收料单位应保持一致', icon: 'none' }) | ||
| 555 | + this.planSheet.selectedKeys = this.selectedPlanRows.map(it => it.id) | ||
| 556 | + return | ||
| 557 | + } | ||
| 558 | + this.selectedPlanRows = list.map(it => ({ ...it })) | ||
| 559 | + this.form.planCode = list.map(it => it.code).filter(Boolean).join(',') | ||
| 560 | + this.form.supplierName = first.supplierName || '' | ||
| 561 | + this.form.companyShortName = (first.companyName || '') + (first.workshopName || '') | ||
| 562 | + // 查询计划明细行,填充计划单明细;过磅明细初始化为计划明细拷贝 | ||
| 563 | + weighTicketPlanLinesApi(list.map(it => it.id)).then(res => { | ||
| 564 | + const lines = (res && res.data) || [] | ||
| 565 | + this.planList = lines.map(it => ({ ...it })) | ||
| 566 | + this.weighList = lines.map(it => ({ ...it, id: it.id || genRowId() })) | ||
| 567 | + }).catch(() => { | ||
| 568 | + this.planList = [] | ||
| 569 | + this.weighList = [] | ||
| 570 | + }) | ||
| 354 | }, | 571 | }, |
| 355 | - addPlan() { | ||
| 356 | - this.planList.push({ productName: '', quantity: '', planCode: '' }) | 572 | + getWeightProductLabel(item) { |
| 573 | + if (!item.productId) return '' | ||
| 574 | + const found = (this.planList || []).find(it => it.productId === item.productId) | ||
| 575 | + return found ? [found.productName, found.planCode].filter(Boolean).join(' ') : '' | ||
| 357 | }, | 576 | }, |
| 358 | - addWeigh() { | ||
| 359 | - this.weighList.push({ productName: '', invoiceProductName: '', quantity: '', planCode: '' }) | 577 | + // 过磅品种改选:整行替换为选中计划明细数据 |
| 578 | + handleWeightProductChange(idx, optIdx) { | ||
| 579 | + const raw = (this.planList || [])[optIdx] | ||
| 580 | + if (!raw) return | ||
| 581 | + const rowId = this.weighList[idx].id | ||
| 582 | + this.weighList.splice(idx, 1, { ...raw, id: rowId }) | ||
| 360 | }, | 583 | }, |
| 361 | - addApply() { | ||
| 362 | - this.applyList.push({ category: '', quantity: '' }) | 584 | + getVarietyLabel(item) { |
| 585 | + if (!item.breedRelationshipId) return '' | ||
| 586 | + const found = (this.varietyOptions || []).find(it => it.id === item.breedRelationshipId) | ||
| 587 | + return found ? [found.productName, found.code].filter(Boolean).join(' ') : '' | ||
| 588 | + }, | ||
| 589 | + handleVarietyChange(idx, optIdx) { | ||
| 590 | + const raw = (this.varietyOptions || [])[optIdx] | ||
| 591 | + if (!raw) return | ||
| 592 | + const row = this.applyList[idx] | ||
| 593 | + row.category = raw.code || '' | ||
| 594 | + row.breedRelationshipId = raw.id || '' | ||
| 595 | + }, | ||
| 596 | + addWeightRow() { | ||
| 597 | + this.weighList.push({ | ||
| 598 | + id: genRowId(), | ||
| 599 | + procurementPlanId: '', | ||
| 600 | + planCode: '', | ||
| 601 | + productId: '', | ||
| 602 | + invoiceProductName: '', | ||
| 603 | + quantity: '' | ||
| 604 | + }) | ||
| 605 | + }, | ||
| 606 | + addApplyRow() { | ||
| 607 | + this.applyList.push({ | ||
| 608 | + id: genRowId(), | ||
| 609 | + category: '', | ||
| 610 | + breedRelationshipId: '', | ||
| 611 | + quantity: '' | ||
| 612 | + }) | ||
| 363 | }, | 613 | }, |
| 364 | removeRow(type, idx) { | 614 | removeRow(type, idx) { |
| 365 | - if (type === 'plan') this.planList.splice(idx, 1) | ||
| 366 | - else if (type === 'weigh') this.weighList.splice(idx, 1) | 615 | + if (type === 'weigh') this.weighList.splice(idx, 1) |
| 367 | else if (type === 'apply') this.applyList.splice(idx, 1) | 616 | else if (type === 'apply') this.applyList.splice(idx, 1) |
| 368 | }, | 617 | }, |
| 369 | validate() { | 618 | validate() { |
| 370 | const f = this.form | 619 | const f = this.form |
| 371 | - if (!f.type) return this.tip('请输入类型') | ||
| 372 | - if (!f.unit) return this.tip('请输入计划编号') | ||
| 373 | - if (!f.firstGrossWeightTime) return this.tip('请选择时间') | ||
| 374 | - if (!f.supplierName) return this.tip('请输入供料单位') | ||
| 375 | - if (!f.companyShortName) return this.tip('请输入收料单位') | ||
| 376 | - if (!f.materialName) return this.tip('请输入物料名称') | ||
| 377 | - if (!f.totalGrossWeight) return this.tip('请输入过磅总重') | 620 | + if (!f.code) return this.tip('缺少编号') |
| 621 | + if (!f.type) return this.tip('请选择类型') | ||
| 622 | + if (!this.selectedPlanRows.length) return this.tip('请选择计划编号') | ||
| 623 | + if (f.totalGrossWeight === '' || f.totalGrossWeight == null) return this.tip('请输入过磅总重') | ||
| 624 | + if (f.actualImpurityWeight === '' || f.actualImpurityWeight == null) return this.tip('请输入实际伙重') | ||
| 625 | + if (!f.deductionTypes || !f.deductionTypes.length) return this.tip('请选择来料扣杂类型') | ||
| 626 | + if (!f.supplierStockMaterial) return this.tip('请输入供应存欠料') | ||
| 627 | + if (!f.logisticsStockMaterial) return this.tip('请输入物流存欠料') | ||
| 378 | if (!f.plateNumber) return this.tip('请输入车牌号') | 628 | if (!f.plateNumber) return this.tip('请输入车牌号') |
| 379 | - if (!f.businessSummary) return this.tip('请输入业务摘要') | 629 | + // 过磅明细:品种、数量必填 |
| 630 | + const weightList = this.weighList || [] | ||
| 631 | + for (let i = 0; i < weightList.length; i++) { | ||
| 632 | + const row = weightList[i] | ||
| 633 | + if (!row.productId) return this.tip(`过磅明细第${i + 1}行:请选择过磅品种`) | ||
| 634 | + if (row.quantity === '' || row.quantity == null) return this.tip(`过磅明细第${i + 1}行:请输入过磅数量`) | ||
| 635 | + } | ||
| 636 | + // 申请数量明细:类别、数量必填(买断时) | ||
| 637 | + if (this.isBuyout) { | ||
| 638 | + const applyList = this.applyList || [] | ||
| 639 | + for (let i = 0; i < applyList.length; i++) { | ||
| 640 | + const row = applyList[i] | ||
| 641 | + if (!row.breedRelationshipId) return this.tip(`申请数量明细第${i + 1}行:请选择类别`) | ||
| 642 | + if (row.quantity === '' || row.quantity == null) return this.tip(`申请数量明细第${i + 1}行:请输入数量`) | ||
| 643 | + } | ||
| 644 | + } | ||
| 380 | return true | 645 | return true |
| 381 | }, | 646 | }, |
| 382 | tip(msg) { | 647 | tip(msg) { |
| 383 | uni.showToast({ title: msg, icon: 'none' }) | 648 | uni.showToast({ title: msg, icon: 'none' }) |
| 384 | return false | 649 | return false |
| 385 | }, | 650 | }, |
| 651 | + buildSubmitData() { | ||
| 652 | + return { | ||
| 653 | + id: this.id, | ||
| 654 | + code: this.form.code, | ||
| 655 | + type: this.form.type, | ||
| 656 | + planIds: this.selectedPlanRows.map(it => it.id), | ||
| 657 | + weighLines: (this.weighList || []).map(row => ({ | ||
| 658 | + procurementPlanId: row.procurementPlanId || '', | ||
| 659 | + planCode: row.planCode || '', | ||
| 660 | + productId: row.productId || '', | ||
| 661 | + invoiceProductName: row.invoiceProductName || '', | ||
| 662 | + quantity: row.quantity === null || row.quantity === undefined ? '' : String(row.quantity), | ||
| 663 | + itemId: row.id | ||
| 664 | + })), | ||
| 665 | + applyLines: (this.applyList || []).map(row => ({ | ||
| 666 | + category: row.category || '', | ||
| 667 | + breedRelationshipId: row.breedRelationshipId || '', | ||
| 668 | + quantity: row.quantity === null || row.quantity === undefined ? '' : String(row.quantity), | ||
| 669 | + itemId: row.breedRelationshipId | ||
| 670 | + })), | ||
| 671 | + unit: this.form.unit, | ||
| 672 | + materialName: this.materialName || null, | ||
| 673 | + totalGrossWeight: this.form.totalGrossWeight === '' ? null : Number(this.form.totalGrossWeight), | ||
| 674 | + actualImpurityWeight: this.form.actualImpurityWeight === '' ? null : Number(this.form.actualImpurityWeight), | ||
| 675 | + netWeight: this.computedNetWeight === '' ? null : Number(this.computedNetWeight), | ||
| 676 | + netWeightUpper: this.computedNetWeightUpper || null, | ||
| 677 | + deductionTypes: (this.form.deductionTypes || []).join(',') || null, | ||
| 678 | + supplierStockMaterial: this.form.supplierStockMaterial || null, | ||
| 679 | + logisticsStockMaterial: this.form.logisticsStockMaterial || null, | ||
| 680 | + plateNumber: this.form.plateNumber || null, | ||
| 681 | + businessSummary: this.computedBusinessSummary || null, | ||
| 682 | + specialNote: this.form.specialNote || null, | ||
| 683 | + documentRemark: this.computedDocumentRemark || null | ||
| 684 | + } | ||
| 685 | + }, | ||
| 386 | async onSubmit() { | 686 | async onSubmit() { |
| 387 | if (!this.validate()) return | 687 | if (!this.validate()) return |
| 388 | const confirmRes = await new Promise(resolve => { | 688 | const confirmRes = await new Promise(resolve => { |
| 389 | uni.showModal({ title: '提示', content: '确定保存修改吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | 689 | uni.showModal({ title: '提示', content: '确定保存修改吗?', confirmText: '确定', cancelText: '取消', success: resolve }) |
| 390 | }) | 690 | }) |
| 391 | if (!(confirmRes && confirmRes.confirm)) return | 691 | if (!(confirmRes && confirmRes.confirm)) return |
| 392 | - const clean = (obj) => { | ||
| 393 | - const out = {} | ||
| 394 | - Object.keys(obj || {}).forEach(k => { | ||
| 395 | - const v = obj[k] | ||
| 396 | - const isEmptyString = typeof v === 'string' && v.trim() === '' | ||
| 397 | - const isUndef = v === undefined || v === null | ||
| 398 | - if (!(isEmptyString || isUndef)) out[k] = v | ||
| 399 | - }) | ||
| 400 | - return out | ||
| 401 | - } | ||
| 402 | - const payload = clean({ | ||
| 403 | - ...this.form, | ||
| 404 | - id: this.id, | ||
| 405 | - planDetailList: this.planList.map(it => clean(it)), | ||
| 406 | - weighDetailList: this.weighList.map(it => clean(it)), | ||
| 407 | - applyQuantityList: this.applyList.map(it => clean(it)) | ||
| 408 | - }) | ||
| 409 | uni.showLoading({ title: '保存中...', mask: true }) | 692 | uni.showLoading({ title: '保存中...', mask: true }) |
| 410 | - weighTicketUpdateApi(payload) | 693 | + weighTicketUpdateApi(this.buildSubmitData()) |
| 411 | .then(() => { | 694 | .then(() => { |
| 412 | uni.hideLoading() | 695 | uni.hideLoading() |
| 413 | uni.showToast({ title: '保存成功', icon: 'none' }) | 696 | uni.showToast({ title: '保存成功', icon: 'none' }) |
| @@ -424,6 +707,67 @@ export default { | @@ -424,6 +707,67 @@ export default { | ||
| 424 | } | 707 | } |
| 425 | } | 708 | } |
| 426 | } | 709 | } |
| 710 | + | ||
| 711 | +// 生成前端临时行 id | ||
| 712 | +function genRowId() { | ||
| 713 | + return 'row_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8) | ||
| 714 | +} | ||
| 715 | + | ||
| 716 | +// 数字转中文大写(对齐 PC 端 useWeightTicketForm.ts) | ||
| 717 | +function numberToChineseUpper(num) { | ||
| 718 | + if (num === null || num === undefined || num === '' || isNaN(Number(num))) return '零' | ||
| 719 | + const n = Number(num) | ||
| 720 | + if (!isFinite(n)) return '零' | ||
| 721 | + | ||
| 722 | + const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'] | ||
| 723 | + const smallUnits = ['', '拾', '佰', '仟'] | ||
| 724 | + const bigUnits = ['', '万', '亿', '兆'] | ||
| 725 | + | ||
| 726 | + const negative = n < 0 | ||
| 727 | + const abs = Math.abs(n) | ||
| 728 | + const parts = abs.toString().split('.') | ||
| 729 | + const intStrRaw = parts[0] | ||
| 730 | + const decStrRaw = parts[1] || '' | ||
| 731 | + const s = intStrRaw | ||
| 732 | + const len = s.length | ||
| 733 | + | ||
| 734 | + let intPart = '' | ||
| 735 | + let zeroFlag = false | ||
| 736 | + for (let i = 0; i < len; i++) { | ||
| 737 | + const d = parseInt(s[i], 10) | ||
| 738 | + const pos = len - 1 - i | ||
| 739 | + const unitIdx = pos % 4 | ||
| 740 | + const groupIdx = Math.floor(pos / 4) | ||
| 741 | + if (d !== 0) { | ||
| 742 | + if (zeroFlag) { | ||
| 743 | + intPart += digit[0] | ||
| 744 | + zeroFlag = false | ||
| 745 | + } | ||
| 746 | + intPart += digit[d] + smallUnits[unitIdx] | ||
| 747 | + } else { | ||
| 748 | + zeroFlag = true | ||
| 749 | + } | ||
| 750 | + if (unitIdx === 0) { | ||
| 751 | + const start = Math.max(0, len - (groupIdx + 1) * 4) | ||
| 752 | + const end = len - groupIdx * 4 | ||
| 753 | + const groupDigits = s.slice(start, end) | ||
| 754 | + if (!/^0+$/.test(groupDigits)) { | ||
| 755 | + intPart += bigUnits[groupIdx] || '' | ||
| 756 | + } | ||
| 757 | + } | ||
| 758 | + } | ||
| 759 | + if (intPart === '') intPart = digit[0] | ||
| 760 | + | ||
| 761 | + let result = intPart | ||
| 762 | + if (decStrRaw) { | ||
| 763 | + const decChars = decStrRaw | ||
| 764 | + .split('') | ||
| 765 | + .map(c => digit[parseInt(c, 10)]) | ||
| 766 | + .join('') | ||
| 767 | + result += '点' + decChars | ||
| 768 | + } | ||
| 769 | + return (negative ? '负' : '') + result | ||
| 770 | +} | ||
| 427 | </script> | 771 | </script> |
| 428 | 772 | ||
| 429 | <style lang="scss" scoped> | 773 | <style lang="scss" scoped> |
| @@ -584,6 +928,18 @@ export default { | @@ -584,6 +928,18 @@ export default { | ||
| 584 | text-align: left; | 928 | text-align: left; |
| 585 | } | 929 | } |
| 586 | 930 | ||
| 931 | +.picker-value { | ||
| 932 | + font-size: 32rpx; | ||
| 933 | + color: rgba(0, 0, 0, 0.9); | ||
| 934 | + line-height: 48rpx; | ||
| 935 | + text-align: right; | ||
| 936 | + min-height: 48rpx; | ||
| 937 | + | ||
| 938 | + &.placeholder { | ||
| 939 | + color: rgba(0, 0, 0, 0.4); | ||
| 940 | + } | ||
| 941 | +} | ||
| 942 | + | ||
| 587 | .sub-table, | 943 | .sub-table, |
| 588 | .remark-section { | 944 | .remark-section { |
| 589 | margin-top: 20rpx; | 945 | margin-top: 20rpx; |
| @@ -671,19 +1027,15 @@ export default { | @@ -671,19 +1027,15 @@ export default { | ||
| 671 | padding: 32rpx; | 1027 | padding: 32rpx; |
| 672 | } | 1028 | } |
| 673 | 1029 | ||
| 674 | -.remark-group { | ||
| 675 | - margin-bottom: 32rpx; | 1030 | +.form-group { |
| 1031 | + margin: 24rpx 0 32rpx; | ||
| 676 | 1032 | ||
| 677 | - &:last-child { | ||
| 678 | - margin-bottom: 0; | ||
| 679 | - } | ||
| 680 | - | ||
| 681 | - .remark-label { | 1033 | + .item-title { |
| 682 | display: flex; | 1034 | display: flex; |
| 683 | align-items: center; | 1035 | align-items: center; |
| 684 | font-size: 32rpx; | 1036 | font-size: 32rpx; |
| 685 | color: rgba(0, 0, 0, 0.9); | 1037 | color: rgba(0, 0, 0, 0.9); |
| 686 | - margin-bottom: 16rpx; | 1038 | + margin-bottom: 20rpx; |
| 687 | position: relative; | 1039 | position: relative; |
| 688 | padding-left: 16rpx; | 1040 | padding-left: 16rpx; |
| 689 | 1041 | ||
| @@ -694,4 +1046,20 @@ export default { | @@ -694,4 +1046,20 @@ export default { | ||
| 694 | } | 1046 | } |
| 695 | } | 1047 | } |
| 696 | } | 1048 | } |
| 1049 | + | ||
| 1050 | +.remark-group { | ||
| 1051 | + margin-bottom: 32rpx; | ||
| 1052 | + | ||
| 1053 | + &:last-child { | ||
| 1054 | + margin-bottom: 0; | ||
| 1055 | + } | ||
| 1056 | + | ||
| 1057 | + .remark-label { | ||
| 1058 | + display: flex; | ||
| 1059 | + align-items: center; | ||
| 1060 | + font-size: 32rpx; | ||
| 1061 | + color: rgba(0, 0, 0, 0.9); | ||
| 1062 | + margin-bottom: 16rpx; | ||
| 1063 | + } | ||
| 1064 | +} | ||
| 697 | </style> | 1065 | </style> |
pages/weight-ticket/reweigh.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <uni-list> | ||
| 5 | + <!-- 编号(F+原编号,只读) --> | ||
| 6 | + <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> | ||
| 7 | + <template v-slot:body> | ||
| 8 | + <view class="item-title"><text class="required">*</text><text>编号</text></view> | ||
| 9 | + </template> | ||
| 10 | + <template v-slot:footer> | ||
| 11 | + <text class="readonly-text value-code">{{ form.code || '-' }}</text> | ||
| 12 | + </template> | ||
| 13 | + </uni-list-item> | ||
| 14 | + | ||
| 15 | + <!-- 类型(只读) --> | ||
| 16 | + <uni-list-item title="类型"> | ||
| 17 | + <template v-slot:footer> | ||
| 18 | + <uni-easyinput :value="getTypeLabel() || form.type" :inputBorder="false" disabled /> | ||
| 19 | + </template> | ||
| 20 | + </uni-list-item> | ||
| 21 | + | ||
| 22 | + <!-- 计划编号(只读) --> | ||
| 23 | + <uni-list-item title="计划编号"> | ||
| 24 | + <template v-slot:footer> | ||
| 25 | + <uni-easyinput :value="planCodeText" :inputBorder="false" disabled /> | ||
| 26 | + </template> | ||
| 27 | + </uni-list-item> | ||
| 28 | + | ||
| 29 | + <!-- 单位(只读) --> | ||
| 30 | + <uni-list-item title="单位"> | ||
| 31 | + <template v-slot:footer> | ||
| 32 | + <uni-easyinput :value="form.unit" :inputBorder="false" disabled /> | ||
| 33 | + </template> | ||
| 34 | + </uni-list-item> | ||
| 35 | + | ||
| 36 | + <!-- 供料单位(只读) --> | ||
| 37 | + <uni-list-item title="供料单位"> | ||
| 38 | + <template v-slot:footer> | ||
| 39 | + <uni-easyinput :value="form.supplierName" :inputBorder="false" disabled /> | ||
| 40 | + </template> | ||
| 41 | + </uni-list-item> | ||
| 42 | + | ||
| 43 | + <!-- 收料单位(只读) --> | ||
| 44 | + <uni-list-item title="收料单位"> | ||
| 45 | + <template v-slot:footer> | ||
| 46 | + <uni-easyinput :value="form.companyShortName" :inputBorder="false" disabled /> | ||
| 47 | + </template> | ||
| 48 | + </uni-list-item> | ||
| 49 | + </uni-list> | ||
| 50 | + | ||
| 51 | + <!-- 计划单明细(只读) --> | ||
| 52 | + <view class="sub-table"> | ||
| 53 | + <view class="header"> | ||
| 54 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 55 | + <text class="title">计划单明细</text> | ||
| 56 | + </view> | ||
| 57 | + <view class="add-list"> | ||
| 58 | + <view v-if="!planList.length" class="empty-tip">暂无明细</view> | ||
| 59 | + <view v-for="(item, idx) in planList" :key="'p-' + (item.id || idx)" class="block"> | ||
| 60 | + <uni-list> | ||
| 61 | + <uni-list-item title="计划品种"> | ||
| 62 | + <template v-slot:footer> | ||
| 63 | + <uni-easyinput :value="item.productName" :inputBorder="false" disabled /> | ||
| 64 | + </template> | ||
| 65 | + </uni-list-item> | ||
| 66 | + <uni-list-item title="计划数量"> | ||
| 67 | + <template v-slot:footer> | ||
| 68 | + <uni-easyinput :value="item.quantity" :inputBorder="false" disabled /> | ||
| 69 | + </template> | ||
| 70 | + </uni-list-item> | ||
| 71 | + <uni-list-item title="计划编号"> | ||
| 72 | + <template v-slot:footer> | ||
| 73 | + <uni-easyinput :value="item.planCode" :inputBorder="false" disabled /> | ||
| 74 | + </template> | ||
| 75 | + </uni-list-item> | ||
| 76 | + </uni-list> | ||
| 77 | + </view> | ||
| 78 | + </view> | ||
| 79 | + </view> | ||
| 80 | + | ||
| 81 | + <!-- 过磅明细(仅过磅数量可编辑) --> | ||
| 82 | + <view class="sub-table"> | ||
| 83 | + <view class="header"> | ||
| 84 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 85 | + <text class="title">过磅明细</text> | ||
| 86 | + </view> | ||
| 87 | + <view class="add-list"> | ||
| 88 | + <view v-if="!weighList.length" class="empty-tip">暂无明细</view> | ||
| 89 | + <view v-for="(item, idx) in weighList" :key="'w-' + (item.id || idx)" class="block"> | ||
| 90 | + <uni-list> | ||
| 91 | + <uni-list-item title="过磅品种"> | ||
| 92 | + <template v-slot:footer> | ||
| 93 | + <uni-easyinput :value="item.productName" :inputBorder="false" disabled /> | ||
| 94 | + </template> | ||
| 95 | + </uni-list-item> | ||
| 96 | + <uni-list-item title="开票品名"> | ||
| 97 | + <template v-slot:footer> | ||
| 98 | + <uni-easyinput :value="item.invoiceProductName" :inputBorder="false" disabled /> | ||
| 99 | + </template> | ||
| 100 | + </uni-list-item> | ||
| 101 | + <uni-list-item title="过磅数量"> | ||
| 102 | + <template v-slot:body> | ||
| 103 | + <view class="item-title"><text class="required">*</text><text>过磅数量</text></view> | ||
| 104 | + </template> | ||
| 105 | + <template v-slot:footer> | ||
| 106 | + <uni-easyinput v-model="item.quantity" type="digit" :inputBorder="false" placeholder="请输入过磅数量" /> | ||
| 107 | + </template> | ||
| 108 | + </uni-list-item> | ||
| 109 | + <uni-list-item title="计划编号"> | ||
| 110 | + <template v-slot:footer> | ||
| 111 | + <uni-easyinput :value="item.planCode" :inputBorder="false" disabled /> | ||
| 112 | + </template> | ||
| 113 | + </uni-list-item> | ||
| 114 | + </uni-list> | ||
| 115 | + </view> | ||
| 116 | + </view> | ||
| 117 | + </view> | ||
| 118 | + | ||
| 119 | + <!-- 申请数量明细(仅买断展示,只读) --> | ||
| 120 | + <view v-if="isBuyout" class="sub-table"> | ||
| 121 | + <view class="header"> | ||
| 122 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 123 | + <text class="title">申请数量明细</text> | ||
| 124 | + </view> | ||
| 125 | + <view class="add-list"> | ||
| 126 | + <view v-if="!applyList.length" class="empty-tip">暂无明细</view> | ||
| 127 | + <view v-for="(item, idx) in applyList" :key="'a-' + (item.id || idx)" class="block"> | ||
| 128 | + <uni-list> | ||
| 129 | + <uni-list-item title="类别"> | ||
| 130 | + <template v-slot:footer> | ||
| 131 | + <uni-easyinput :value="item.category" :inputBorder="false" disabled /> | ||
| 132 | + </template> | ||
| 133 | + </uni-list-item> | ||
| 134 | + <uni-list-item title="数量"> | ||
| 135 | + <template v-slot:footer> | ||
| 136 | + <uni-easyinput :value="item.quantity" :inputBorder="false" disabled /> | ||
| 137 | + </template> | ||
| 138 | + </uni-list-item> | ||
| 139 | + </uni-list> | ||
| 140 | + </view> | ||
| 141 | + </view> | ||
| 142 | + </view> | ||
| 143 | + | ||
| 144 | + <!-- 其他信息 --> | ||
| 145 | + <view class="remark-section"> | ||
| 146 | + <view class="header"> | ||
| 147 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 148 | + <text class="title">其他信息</text> | ||
| 149 | + </view> | ||
| 150 | + <view class="section-content"> | ||
| 151 | + <uni-list> | ||
| 152 | + <uni-list-item title="物料名称"> | ||
| 153 | + <template v-slot:footer> | ||
| 154 | + <uni-easyinput :value="materialName" :inputBorder="false" disabled /> | ||
| 155 | + </template> | ||
| 156 | + </uni-list-item> | ||
| 157 | + <uni-list-item> | ||
| 158 | + <template v-slot:body> | ||
| 159 | + <view class="item-title"><text class="required">*</text><text>过磅总重</text></view> | ||
| 160 | + </template> | ||
| 161 | + <template v-slot:footer> | ||
| 162 | + <uni-easyinput v-model="form.totalGrossWeight" type="digit" :inputBorder="false" placeholder="请输入过磅总重" /> | ||
| 163 | + </template> | ||
| 164 | + </uni-list-item> | ||
| 165 | + <uni-list-item> | ||
| 166 | + <template v-slot:body> | ||
| 167 | + <view class="item-title"><text class="required">*</text><text>实际伙重</text></view> | ||
| 168 | + </template> | ||
| 169 | + <template v-slot:footer> | ||
| 170 | + <uni-easyinput v-model="form.actualImpurityWeight" type="digit" :inputBorder="false" placeholder="请输入实际伙重" /> | ||
| 171 | + </template> | ||
| 172 | + </uni-list-item> | ||
| 173 | + <uni-list-item title="货物净重"> | ||
| 174 | + <template v-slot:footer> | ||
| 175 | + <uni-easyinput :value="computedNetWeight" :inputBorder="false" disabled /> | ||
| 176 | + </template> | ||
| 177 | + </uni-list-item> | ||
| 178 | + <uni-list-item title="净重大写"> | ||
| 179 | + <template v-slot:footer> | ||
| 180 | + <uni-easyinput :value="computedNetWeightUpper" :inputBorder="false" disabled /> | ||
| 181 | + </template> | ||
| 182 | + </uni-list-item> | ||
| 183 | + </uni-list> | ||
| 184 | + | ||
| 185 | + <view class="form-group"> | ||
| 186 | + <view class="item-title"><text class="required">*</text><text>来料扣杂类型</text></view> | ||
| 187 | + <uni-data-checkbox | ||
| 188 | + mode="tag" | ||
| 189 | + :multiple="true" | ||
| 190 | + :value-field="'value'" | ||
| 191 | + :text-field="'text'" | ||
| 192 | + v-model="form.deductionTypes" | ||
| 193 | + :localdata="deductionTypeOptions" | ||
| 194 | + /> | ||
| 195 | + </view> | ||
| 196 | + | ||
| 197 | + <uni-list> | ||
| 198 | + <uni-list-item> | ||
| 199 | + <template v-slot:body> | ||
| 200 | + <view class="item-title"><text class="required">*</text><text>供应存欠料</text></view> | ||
| 201 | + </template> | ||
| 202 | + <template v-slot:footer> | ||
| 203 | + <uni-easyinput v-model="form.supplierStockMaterial" :inputBorder="false" placeholder="请输入供应存欠料" /> | ||
| 204 | + </template> | ||
| 205 | + </uni-list-item> | ||
| 206 | + <uni-list-item> | ||
| 207 | + <template v-slot:body> | ||
| 208 | + <view class="item-title"><text class="required">*</text><text>物流存欠料</text></view> | ||
| 209 | + </template> | ||
| 210 | + <template v-slot:footer> | ||
| 211 | + <uni-easyinput v-model="form.logisticsStockMaterial" :inputBorder="false" placeholder="请输入物流存欠料" /> | ||
| 212 | + </template> | ||
| 213 | + </uni-list-item> | ||
| 214 | + <uni-list-item> | ||
| 215 | + <template v-slot:body> | ||
| 216 | + <view class="item-title"><text class="required">*</text><text>车牌号</text></view> | ||
| 217 | + </template> | ||
| 218 | + <template v-slot:footer> | ||
| 219 | + <uni-easyinput v-model="form.plateNumber" :inputBorder="false" placeholder="请输入车牌号" /> | ||
| 220 | + </template> | ||
| 221 | + </uni-list-item> | ||
| 222 | + </uni-list> | ||
| 223 | + </view> | ||
| 224 | + </view> | ||
| 225 | + | ||
| 226 | + <!-- 备注模块 --> | ||
| 227 | + <view class="remark-section"> | ||
| 228 | + <view class="header"> | ||
| 229 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 230 | + <text class="title">备注</text> | ||
| 231 | + </view> | ||
| 232 | + <view class="section-content"> | ||
| 233 | + <view class="remark-group"> | ||
| 234 | + <view class="remark-label">业务摘要</view> | ||
| 235 | + <uni-easyinput :value="computedBusinessSummary" type="textarea" :inputBorder="false" disabled autoHeight /> | ||
| 236 | + </view> | ||
| 237 | + <view class="remark-group"> | ||
| 238 | + <view class="remark-label">特别说明</view> | ||
| 239 | + <uni-easyinput v-model="form.specialNote" type="textarea" :inputBorder="false" placeholder="请输入特别说明" maxlength="2000" /> | ||
| 240 | + </view> | ||
| 241 | + <view class="remark-group"> | ||
| 242 | + <view class="remark-label">单据备注</view> | ||
| 243 | + <uni-easyinput :value="computedDocumentRemark" type="textarea" :inputBorder="false" disabled autoHeight /> | ||
| 244 | + </view> | ||
| 245 | + </view> | ||
| 246 | + </view> | ||
| 247 | + | ||
| 248 | + <!-- 附件信息 --> | ||
| 249 | + <view class="remark-section"> | ||
| 250 | + <view class="header"> | ||
| 251 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 252 | + <text class="title">复磅附件</text> | ||
| 253 | + <view class="ops"> | ||
| 254 | + <view class="upload-btn" @click="selectFile">上传文件</view> | ||
| 255 | + </view> | ||
| 256 | + </view> | ||
| 257 | + <view class="section-content"> | ||
| 258 | + <view v-if="!fileList.length" class="empty-tip">暂无附件,请上传</view> | ||
| 259 | + <view v-for="(file, idx) in fileList" :key="file.id || idx" class="file-item"> | ||
| 260 | + <text class="file-name">{{ file.name || '未命名文件' }}</text> | ||
| 261 | + <text class="file-del" @click="removeFile(idx)">删除</text> | ||
| 262 | + </view> | ||
| 263 | + </view> | ||
| 264 | + </view> | ||
| 265 | + | ||
| 266 | + <view class="footer"> | ||
| 267 | + <button class="btn submit" type="primary" @click="onSubmit">保存</button> | ||
| 268 | + </view> | ||
| 269 | + </scroll-view> | ||
| 270 | + </view> | ||
| 271 | +</template> | ||
| 272 | + | ||
| 273 | +<script> | ||
| 274 | +import { weighTicketDetailApi, weighTicketCreateApi } from '@/api/procure-manage/weighTicket.js' | ||
| 275 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | ||
| 276 | +import upload from '@/utils/upload' | ||
| 277 | +import { uploadFileApi } from '@/api/base.js' | ||
| 278 | + | ||
| 279 | +export default { | ||
| 280 | + name: 'ReweighWeightTicket', | ||
| 281 | + data() { | ||
| 282 | + return { | ||
| 283 | + // 原过磅单ID | ||
| 284 | + id: '', | ||
| 285 | + form: { | ||
| 286 | + code: '', | ||
| 287 | + type: '', | ||
| 288 | + planCode: '', | ||
| 289 | + unit: '', | ||
| 290 | + supplierName: '', | ||
| 291 | + companyShortName: '', | ||
| 292 | + totalGrossWeight: '', | ||
| 293 | + actualImpurityWeight: '', | ||
| 294 | + deductionTypes: [], | ||
| 295 | + supplierStockMaterial: '', | ||
| 296 | + logisticsStockMaterial: '', | ||
| 297 | + plateNumber: '', | ||
| 298 | + specialNote: '' | ||
| 299 | + }, | ||
| 300 | + dicOptions: { TYPE: [], DEDUCTION_TYPE: [] }, | ||
| 301 | + // 选中计划行(供 planIds 提交与 isBuyout 判断) | ||
| 302 | + selectedPlanRows: [], | ||
| 303 | + buyout: false, | ||
| 304 | + // 计划单明细(只读) | ||
| 305 | + planList: [], | ||
| 306 | + // 过磅明细(仅数量可编辑) | ||
| 307 | + weighList: [], | ||
| 308 | + // 申请数量明细(只读) | ||
| 309 | + applyList: [], | ||
| 310 | + // 复磅附件 [{ id, name }] | ||
| 311 | + fileList: [] | ||
| 312 | + } | ||
| 313 | + }, | ||
| 314 | + computed: { | ||
| 315 | + deductionTypeOptions() { | ||
| 316 | + return (this.dicOptions.DEDUCTION_TYPE || []).map(it => ({ | ||
| 317 | + value: it.code != null ? String(it.code) : '', | ||
| 318 | + text: it.name || '' | ||
| 319 | + })).filter(it => it.value) | ||
| 320 | + }, | ||
| 321 | + isBuyout() { | ||
| 322 | + return this.buyout || (this.applyList || []).length > 0 | ||
| 323 | + }, | ||
| 324 | + planCodeText() { | ||
| 325 | + const codes = Array.from(new Set((this.planList || []).map(it => it.planCode).filter(Boolean))) | ||
| 326 | + return codes.join(',') | ||
| 327 | + }, | ||
| 328 | + // 物料名称:过磅明细开票品名去重顿号拼接 | ||
| 329 | + materialName() { | ||
| 330 | + const names = (this.weighList || []) | ||
| 331 | + .map(item => item.invoiceProductName) | ||
| 332 | + .filter(name => !!name) | ||
| 333 | + return Array.from(new Set(names)).join('、') | ||
| 334 | + }, | ||
| 335 | + // 货物净重 = 过磅总重 - 实际伙重(保留两位) | ||
| 336 | + computedNetWeight() { | ||
| 337 | + const gross = this.form.totalGrossWeight | ||
| 338 | + if (gross === undefined || gross === null || gross === '') return '' | ||
| 339 | + const num = Number(gross) - Number(this.form.actualImpurityWeight || 0) | ||
| 340 | + return String(Math.round(num * 100) / 100) | ||
| 341 | + }, | ||
| 342 | + // 净重大写:中文大写 | ||
| 343 | + computedNetWeightUpper() { | ||
| 344 | + const net = this.computedNetWeight | ||
| 345 | + if (net === '' || net === null || net === undefined) return '' | ||
| 346 | + return numberToChineseUpper(net) | ||
| 347 | + }, | ||
| 348 | + // 业务摘要 | ||
| 349 | + computedBusinessSummary() { | ||
| 350 | + const parts = [] | ||
| 351 | + const weightItems = (this.weighList || []) | ||
| 352 | + .map(item => { | ||
| 353 | + const name = item.productName || '' | ||
| 354 | + const qty = item.quantity === null || item.quantity === undefined ? '' : item.quantity | ||
| 355 | + if (!name && qty === '') return '' | ||
| 356 | + return `${name}${qty}公斤` | ||
| 357 | + }) | ||
| 358 | + .filter(text => !!text) | ||
| 359 | + if (weightItems.length) parts.push(weightItems.join('、')) | ||
| 360 | + const deductionNames = (this.form.deductionTypes || []) | ||
| 361 | + .map(code => getDicName('DEDUCTION_TYPE', code, this.dicOptions.DEDUCTION_TYPE)) | ||
| 362 | + .filter(name => !!name) | ||
| 363 | + if (deductionNames.length) parts.push(deductionNames.join('、')) | ||
| 364 | + if (this.form.supplierStockMaterial) parts.push(`供应存欠料:${this.form.supplierStockMaterial}`) | ||
| 365 | + if (this.form.logisticsStockMaterial) parts.push(`物流存欠料:${this.form.logisticsStockMaterial}`) | ||
| 366 | + if (this.form.plateNumber) parts.push(`车牌号:${this.form.plateNumber}`) | ||
| 367 | + return parts.join(',') | ||
| 368 | + }, | ||
| 369 | + // 单据备注 = 业务摘要 + 特别说明 | ||
| 370 | + computedDocumentRemark() { | ||
| 371 | + const summary = this.computedBusinessSummary || '' | ||
| 372 | + const note = this.form.specialNote || '' | ||
| 373 | + return [summary, note].filter(text => !!text).join('\n') | ||
| 374 | + } | ||
| 375 | + }, | ||
| 376 | + onLoad(query) { | ||
| 377 | + this.id = (query && query.id) || '' | ||
| 378 | + }, | ||
| 379 | + created() { | ||
| 380 | + this.loadDicData() | ||
| 381 | + this.loadDetail() | ||
| 382 | + }, | ||
| 383 | + methods: { | ||
| 384 | + async loadDicData() { | ||
| 385 | + try { | ||
| 386 | + const results = await getDicByCodes(['TYPE', 'DEDUCTION_TYPE']) | ||
| 387 | + this.dicOptions.TYPE = (results.TYPE && results.TYPE.data) || [] | ||
| 388 | + this.dicOptions.DEDUCTION_TYPE = (results.DEDUCTION_TYPE && results.DEDUCTION_TYPE.data) || [] | ||
| 389 | + } catch (e) { | ||
| 390 | + this.dicOptions = { TYPE: [], DEDUCTION_TYPE: [] } | ||
| 391 | + } | ||
| 392 | + }, | ||
| 393 | + getTypeLabel() { | ||
| 394 | + const found = (this.dicOptions.TYPE || []).find(it => String(it.code) === String(this.form.type)) | ||
| 395 | + return found ? found.name : '' | ||
| 396 | + }, | ||
| 397 | + loadDetail() { | ||
| 398 | + if (!this.id) { | ||
| 399 | + uni.showToast({ title: '缺少单据ID', icon: 'none' }) | ||
| 400 | + return | ||
| 401 | + } | ||
| 402 | + uni.showLoading({ title: '加载中...', mask: true }) | ||
| 403 | + weighTicketDetailApi({ id: this.id }) | ||
| 404 | + .then(res => { | ||
| 405 | + const data = res && res.data ? (res.data.data || res.data) : {} | ||
| 406 | + this.buyout = !!data.buyout | ||
| 407 | + this.form = { | ||
| 408 | + // 复磅编号 = F + 原编号 | ||
| 409 | + code: 'F' + (data.code || ''), | ||
| 410 | + type: data.type != null ? String(data.type) : '', | ||
| 411 | + planCode: data.planCode || data.planCodes || '', | ||
| 412 | + unit: data.unit || '', | ||
| 413 | + supplierName: data.supplierName || '', | ||
| 414 | + companyShortName: data.companyShortName || '', | ||
| 415 | + totalGrossWeight: data.totalGrossWeight == null ? '' : String(data.totalGrossWeight), | ||
| 416 | + actualImpurityWeight: data.actualImpurityWeight == null ? '' : String(data.actualImpurityWeight), | ||
| 417 | + deductionTypes: data.deductionTypes ? String(data.deductionTypes).split(',').filter(Boolean) : [], | ||
| 418 | + supplierStockMaterial: data.supplierStockMaterial || '', | ||
| 419 | + logisticsStockMaterial: data.logisticsStockMaterial || '', | ||
| 420 | + plateNumber: data.plateNumber || '', | ||
| 421 | + specialNote: data.specialNote || '' | ||
| 422 | + } | ||
| 423 | + this.planList = (Array.isArray(data.planLines) ? data.planLines : []).map(it => ({ ...it })) | ||
| 424 | + // 选中计划行对象(buyout 供 isBuyout 判断,id 供 planIds 提交使用) | ||
| 425 | + this.selectedPlanRows = this.planList.map(item => ({ | ||
| 426 | + id: item.procurementPlanId || item.id, | ||
| 427 | + buyout: this.buyout | ||
| 428 | + })) | ||
| 429 | + this.weighList = (Array.isArray(data.weighLines) ? data.weighLines : []).map(it => ({ ...it, id: it.id || genRowId() })) | ||
| 430 | + this.applyList = (Array.isArray(data.applyLines) ? data.applyLines : []).map(it => ({ ...it, id: it.id || genRowId() })) | ||
| 431 | + // 已传复磅附件回显(多文件逗号分隔) | ||
| 432 | + const ids = String(data.reweighAttachmentFileIds || '').split(',').filter(Boolean) | ||
| 433 | + const names = String(data.reweighAttachmentFileNames || '').split(',').filter(Boolean) | ||
| 434 | + this.fileList = ids.map((fid, i) => ({ id: fid, name: names[i] || '' })) | ||
| 435 | + }) | ||
| 436 | + .catch(() => { | ||
| 437 | + uni.showToast({ title: '加载详情失败', icon: 'none' }) | ||
| 438 | + }) | ||
| 439 | + .finally(() => { | ||
| 440 | + uni.hideLoading() | ||
| 441 | + }) | ||
| 442 | + }, | ||
| 443 | + // 选择并上传复磅附件(多文件逐个追加) | ||
| 444 | + selectFile() { | ||
| 445 | + if (typeof uni !== 'undefined' && typeof uni.chooseMessageFile === 'function') { | ||
| 446 | + uni.chooseMessageFile({ | ||
| 447 | + count: 9, | ||
| 448 | + type: 'all', | ||
| 449 | + success: async res => { | ||
| 450 | + const files = (res && res.tempFiles) || [] | ||
| 451 | + if (!files.length) return | ||
| 452 | + uni.showLoading({ title: '上传中...', mask: true }) | ||
| 453 | + try { | ||
| 454 | + for (const f of files) { | ||
| 455 | + const name = f.name || 'file' | ||
| 456 | + const r = await upload({ url: '/sw/filebox/uploadFile', filePath: f.path, name: 'file' }) | ||
| 457 | + const d = r && r.data ? r.data : r | ||
| 458 | + const fid = (d && (d.id || d.fileId || (d.data && (d.data.id || d.data.fileId)))) | ||
| 459 | + ? String(d.id || d.fileId || d.data.id || d.data.fileId) | ||
| 460 | + : '' | ||
| 461 | + if (fid) this.fileList.push({ id: fid, name }) | ||
| 462 | + } | ||
| 463 | + } catch (e) { | ||
| 464 | + uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 465 | + } finally { | ||
| 466 | + uni.hideLoading() | ||
| 467 | + } | ||
| 468 | + }, | ||
| 469 | + fail: () => { | ||
| 470 | + uni.showToast({ title: '未选择文件', icon: 'none' }) | ||
| 471 | + } | ||
| 472 | + }) | ||
| 473 | + return | ||
| 474 | + } | ||
| 475 | + // H5 兜底:动态创建原生 input | ||
| 476 | + try { | ||
| 477 | + const self = this | ||
| 478 | + const input = document.createElement('input') | ||
| 479 | + input.type = 'file' | ||
| 480 | + input.multiple = true | ||
| 481 | + input.style.position = 'fixed' | ||
| 482 | + input.style.left = '-9999px' | ||
| 483 | + document.body.appendChild(input) | ||
| 484 | + input.addEventListener('change', self.onFileChange) | ||
| 485 | + input.click() | ||
| 486 | + setTimeout(() => { document.body.removeChild(input) }, 1000) | ||
| 487 | + } catch (e) { | ||
| 488 | + uni.showToast({ title: '无法打开文件选择', icon: 'none' }) | ||
| 489 | + } | ||
| 490 | + }, | ||
| 491 | + async onFileChange(e) { | ||
| 492 | + const files = (e && e.target && e.target.files) || [] | ||
| 493 | + if (!files.length) return | ||
| 494 | + uni.showLoading({ title: '上传中...', mask: true }) | ||
| 495 | + try { | ||
| 496 | + for (const file of files) { | ||
| 497 | + const name = file.name || '' | ||
| 498 | + const fd = new FormData() | ||
| 499 | + fd.append('file', file, name) | ||
| 500 | + const d = await uploadFileApi(fd) | ||
| 501 | + const data = d && d.data ? d.data : d | ||
| 502 | + const fid = (data && (data.id || data.fileId || (data.data && (data.data.id || data.data.fileId)))) | ||
| 503 | + ? String(data.id || data.fileId || data.data.id || data.data.fileId) | ||
| 504 | + : '' | ||
| 505 | + if (fid) this.fileList.push({ id: fid, name }) | ||
| 506 | + } | ||
| 507 | + } catch (e2) { | ||
| 508 | + uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 509 | + } finally { | ||
| 510 | + uni.hideLoading() | ||
| 511 | + if (e && e.target) e.target.value = '' | ||
| 512 | + } | ||
| 513 | + }, | ||
| 514 | + removeFile(idx) { | ||
| 515 | + this.fileList.splice(idx, 1) | ||
| 516 | + }, | ||
| 517 | + validate() { | ||
| 518 | + const f = this.form | ||
| 519 | + if (f.totalGrossWeight === '' || f.totalGrossWeight == null) return this.tip('请输入过磅总重') | ||
| 520 | + if (f.actualImpurityWeight === '' || f.actualImpurityWeight == null) return this.tip('请输入实际伙重') | ||
| 521 | + if (!f.deductionTypes || !f.deductionTypes.length) return this.tip('请选择来料扣杂类型') | ||
| 522 | + if (!f.supplierStockMaterial) return this.tip('请输入供应存欠料') | ||
| 523 | + if (!f.logisticsStockMaterial) return this.tip('请输入物流存欠料') | ||
| 524 | + if (!f.plateNumber) return this.tip('请输入车牌号') | ||
| 525 | + // 过磅明细:过磅数量必填 | ||
| 526 | + const weightList = this.weighList || [] | ||
| 527 | + for (let i = 0; i < weightList.length; i++) { | ||
| 528 | + const row = weightList[i] | ||
| 529 | + if (row.quantity === '' || row.quantity == null) return this.tip(`过磅明细第${i + 1}行:请输入过磅数量`) | ||
| 530 | + } | ||
| 531 | + // 复磅附件必传 | ||
| 532 | + if (!this.fileList.length) return this.tip('请上传复磅附件') | ||
| 533 | + return true | ||
| 534 | + }, | ||
| 535 | + tip(msg) { | ||
| 536 | + uni.showToast({ title: msg, icon: 'none' }) | ||
| 537 | + return false | ||
| 538 | + }, | ||
| 539 | + async onSubmit() { | ||
| 540 | + if (!this.validate()) return | ||
| 541 | + const confirmRes = await new Promise(resolve => { | ||
| 542 | + uni.showModal({ title: '提示', content: '确定保存复磅单吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | ||
| 543 | + }) | ||
| 544 | + if (!(confirmRes && confirmRes.confirm)) return | ||
| 545 | + const ids = this.fileList.map(it => it.id).filter(Boolean) | ||
| 546 | + const names = this.fileList.map(it => it.name).filter(Boolean) | ||
| 547 | + const payload = { | ||
| 548 | + originWeighingTicketId: this.id, | ||
| 549 | + code: this.form.code, | ||
| 550 | + type: this.form.type, | ||
| 551 | + planIds: (this.selectedPlanRows || []).map(it => it.id), | ||
| 552 | + weighLines: (this.weighList || []).map(row => ({ | ||
| 553 | + procurementPlanId: row.procurementPlanId || '', | ||
| 554 | + planCode: row.planCode || '', | ||
| 555 | + productId: row.productId || '', | ||
| 556 | + invoiceProductName: row.invoiceProductName || '', | ||
| 557 | + quantity: row.quantity === null || row.quantity === undefined ? '' : String(row.quantity), | ||
| 558 | + itemId: row.id | ||
| 559 | + })), | ||
| 560 | + applyLines: (this.applyList || []).map(row => ({ | ||
| 561 | + category: row.category || '', | ||
| 562 | + breedRelationshipId: row.breedRelationshipId || '', | ||
| 563 | + quantity: row.quantity === null || row.quantity === undefined ? '' : String(row.quantity), | ||
| 564 | + itemId: row.breedRelationshipId | ||
| 565 | + })), | ||
| 566 | + unit: this.form.unit, | ||
| 567 | + materialName: this.materialName || null, | ||
| 568 | + totalGrossWeight: this.form.totalGrossWeight === '' ? null : Number(this.form.totalGrossWeight), | ||
| 569 | + actualImpurityWeight: this.form.actualImpurityWeight === '' ? null : Number(this.form.actualImpurityWeight), | ||
| 570 | + netWeight: this.computedNetWeight === '' ? null : Number(this.computedNetWeight), | ||
| 571 | + netWeightUpper: this.computedNetWeightUpper || null, | ||
| 572 | + deductionTypes: (this.form.deductionTypes || []).join(',') || null, | ||
| 573 | + supplierStockMaterial: this.form.supplierStockMaterial || null, | ||
| 574 | + logisticsStockMaterial: this.form.logisticsStockMaterial || null, | ||
| 575 | + plateNumber: this.form.plateNumber || null, | ||
| 576 | + businessSummary: this.computedBusinessSummary || null, | ||
| 577 | + specialNote: this.form.specialNote || null, | ||
| 578 | + documentRemark: this.computedDocumentRemark || null, | ||
| 579 | + reweighAttachmentFileIds: ids.join(','), | ||
| 580 | + reweighAttachmentFileNames: names.join(',') | ||
| 581 | + } | ||
| 582 | + uni.showLoading({ title: '保存中...', mask: true }) | ||
| 583 | + weighTicketCreateApi(payload) | ||
| 584 | + .then(() => { | ||
| 585 | + uni.hideLoading() | ||
| 586 | + uni.showToast({ title: '保存成功', icon: 'none' }) | ||
| 587 | + try { | ||
| 588 | + uni.setStorageSync('WEIGHT_TICKET_LIST_NEED_REFRESH', '1') | ||
| 589 | + uni.setStorageSync('WEIGHT_TICKET_DETAIL_NEED_REFRESH', '1') | ||
| 590 | + } catch (e) {} | ||
| 591 | + setTimeout(() => { uni.navigateBack() }, 400) | ||
| 592 | + }) | ||
| 593 | + .catch(e => { | ||
| 594 | + uni.hideLoading() | ||
| 595 | + uni.showToast({ title: (e && (e.msg || e.message)) || '保存失败', icon: 'none' }) | ||
| 596 | + }) | ||
| 597 | + } | ||
| 598 | + } | ||
| 599 | +} | ||
| 600 | + | ||
| 601 | +// 生成前端临时行 id | ||
| 602 | +function genRowId() { | ||
| 603 | + return 'row_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8) | ||
| 604 | +} | ||
| 605 | + | ||
| 606 | +// 数字转中文大写(对齐 PC 端 useWeightTicketForm.ts) | ||
| 607 | +function numberToChineseUpper(num) { | ||
| 608 | + if (num === null || num === undefined || num === '' || isNaN(Number(num))) return '零' | ||
| 609 | + const n = Number(num) | ||
| 610 | + if (!isFinite(n)) return '零' | ||
| 611 | + | ||
| 612 | + const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'] | ||
| 613 | + const smallUnits = ['', '拾', '佰', '仟'] | ||
| 614 | + const bigUnits = ['', '万', '亿', '兆'] | ||
| 615 | + | ||
| 616 | + const negative = n < 0 | ||
| 617 | + const abs = Math.abs(n) | ||
| 618 | + const parts = abs.toString().split('.') | ||
| 619 | + const intStrRaw = parts[0] | ||
| 620 | + const decStrRaw = parts[1] || '' | ||
| 621 | + const s = intStrRaw | ||
| 622 | + const len = s.length | ||
| 623 | + | ||
| 624 | + let intPart = '' | ||
| 625 | + let zeroFlag = false | ||
| 626 | + for (let i = 0; i < len; i++) { | ||
| 627 | + const d = parseInt(s[i], 10) | ||
| 628 | + const pos = len - 1 - i | ||
| 629 | + const unitIdx = pos % 4 | ||
| 630 | + const groupIdx = Math.floor(pos / 4) | ||
| 631 | + if (d !== 0) { | ||
| 632 | + if (zeroFlag) { | ||
| 633 | + intPart += digit[0] | ||
| 634 | + zeroFlag = false | ||
| 635 | + } | ||
| 636 | + intPart += digit[d] + smallUnits[unitIdx] | ||
| 637 | + } else { | ||
| 638 | + zeroFlag = true | ||
| 639 | + } | ||
| 640 | + if (unitIdx === 0) { | ||
| 641 | + const start = Math.max(0, len - (groupIdx + 1) * 4) | ||
| 642 | + const end = len - groupIdx * 4 | ||
| 643 | + const groupDigits = s.slice(start, end) | ||
| 644 | + if (!/^0+$/.test(groupDigits)) { | ||
| 645 | + intPart += bigUnits[groupIdx] || '' | ||
| 646 | + } | ||
| 647 | + } | ||
| 648 | + } | ||
| 649 | + if (intPart === '') intPart = digit[0] | ||
| 650 | + | ||
| 651 | + let result = intPart | ||
| 652 | + if (decStrRaw) { | ||
| 653 | + const decChars = decStrRaw | ||
| 654 | + .split('') | ||
| 655 | + .map(c => digit[parseInt(c, 10)]) | ||
| 656 | + .join('') | ||
| 657 | + result += '点' + decChars | ||
| 658 | + } | ||
| 659 | + return (negative ? '负' : '') + result | ||
| 660 | +} | ||
| 661 | +</script> | ||
| 662 | + | ||
| 663 | +<style lang="scss" scoped> | ||
| 664 | +.page { | ||
| 665 | + display: flex; | ||
| 666 | + flex-direction: column; | ||
| 667 | + height: 100%; | ||
| 668 | +} | ||
| 669 | + | ||
| 670 | +.scroll { | ||
| 671 | + flex: 1; | ||
| 672 | + padding: 12rpx 0 200rpx !important; | ||
| 673 | +} | ||
| 674 | + | ||
| 675 | +.footer { | ||
| 676 | + z-index: 2; | ||
| 677 | + position: fixed; | ||
| 678 | + left: 0; | ||
| 679 | + right: 0; | ||
| 680 | + bottom: 0; | ||
| 681 | + padding: 32rpx; | ||
| 682 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 683 | + background: #fff; | ||
| 684 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 685 | + | ||
| 686 | + .btn { | ||
| 687 | + height: 80rpx; | ||
| 688 | + line-height: 80rpx; | ||
| 689 | + border-radius: 12rpx; | ||
| 690 | + font-size: 32rpx; | ||
| 691 | + } | ||
| 692 | + | ||
| 693 | + .submit { | ||
| 694 | + background: $theme-primary; | ||
| 695 | + color: #fff; | ||
| 696 | + } | ||
| 697 | +} | ||
| 698 | + | ||
| 699 | +::v-deep .uni-list { | ||
| 700 | + .uni-easyinput { | ||
| 701 | + display: flex; | ||
| 702 | + | ||
| 703 | + .uni-input-input { | ||
| 704 | + color: rgba(0, 0, 0, 0.9); | ||
| 705 | + } | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + .uni-input-placeholder { | ||
| 709 | + z-index: 1; | ||
| 710 | + } | ||
| 711 | + | ||
| 712 | + .uni-input-input { | ||
| 713 | + background-color: #ffffff; | ||
| 714 | + } | ||
| 715 | + | ||
| 716 | + background: transparent; | ||
| 717 | + | ||
| 718 | + &-item { | ||
| 719 | + &__extra-text { | ||
| 720 | + font-size: 32rpx; | ||
| 721 | + } | ||
| 722 | + | ||
| 723 | + &__content-title { | ||
| 724 | + font-size: 32rpx; | ||
| 725 | + color: rgba(0, 0, 0, 0.9); | ||
| 726 | + } | ||
| 727 | + | ||
| 728 | + &__container { | ||
| 729 | + padding: 32rpx; | ||
| 730 | + | ||
| 731 | + .uni-easyinput { | ||
| 732 | + &__placeholder-class { | ||
| 733 | + font-size: 32rpx; | ||
| 734 | + color: rgba(0, 0, 0, 0.4); | ||
| 735 | + } | ||
| 736 | + | ||
| 737 | + &__content { | ||
| 738 | + border: none; | ||
| 739 | + background-color: #ffffff !important; | ||
| 740 | + | ||
| 741 | + &-input { | ||
| 742 | + padding-left: 0 !important; | ||
| 743 | + height: 48rpx; | ||
| 744 | + line-height: 48rpx; | ||
| 745 | + font-size: 32rpx; | ||
| 746 | + } | ||
| 747 | + } | ||
| 748 | + } | ||
| 749 | + | ||
| 750 | + .item-title, | ||
| 751 | + .uni-list-item__content { | ||
| 752 | + flex: none; | ||
| 753 | + min-height: 48rpx; | ||
| 754 | + line-height: 48rpx; | ||
| 755 | + font-size: 32rpx; | ||
| 756 | + position: relative; | ||
| 757 | + width: 240rpx; | ||
| 758 | + margin-right: 32rpx; | ||
| 759 | + color: rgba(0, 0, 0, 0.9); | ||
| 760 | + | ||
| 761 | + .required { | ||
| 762 | + color: red; | ||
| 763 | + position: absolute; | ||
| 764 | + top: 50%; | ||
| 765 | + transform: translateY(-50%); | ||
| 766 | + left: -16rpx; | ||
| 767 | + } | ||
| 768 | + } | ||
| 769 | + } | ||
| 770 | + } | ||
| 771 | +} | ||
| 772 | + | ||
| 773 | +.readonly-text { | ||
| 774 | + color: rgba(0, 0, 0, 0.9); | ||
| 775 | + font-size: 32rpx; | ||
| 776 | + line-height: 48rpx; | ||
| 777 | + text-align: right; | ||
| 778 | + white-space: pre-wrap; | ||
| 779 | + word-break: break-all; | ||
| 780 | +} | ||
| 781 | + | ||
| 782 | +.value-code { | ||
| 783 | + width: 260rpx; | ||
| 784 | + text-align: left; | ||
| 785 | +} | ||
| 786 | + | ||
| 787 | +.sub-table, | ||
| 788 | +.remark-section { | ||
| 789 | + margin-top: 20rpx; | ||
| 790 | + background: #fff; | ||
| 791 | +} | ||
| 792 | + | ||
| 793 | +.header { | ||
| 794 | + display: flex; | ||
| 795 | + align-items: center; | ||
| 796 | + padding: 24rpx 32rpx; | ||
| 797 | + border-bottom: 1rpx solid #f0f0f0; | ||
| 798 | + | ||
| 799 | + .opCollapse { | ||
| 800 | + width: 32rpx; | ||
| 801 | + height: 28rpx; | ||
| 802 | + margin-right: 16rpx; | ||
| 803 | + margin-top: 8rpx; | ||
| 804 | + } | ||
| 805 | + | ||
| 806 | + .title { | ||
| 807 | + font-size: 32rpx; | ||
| 808 | + color: rgba(0, 0, 0, 0.9); | ||
| 809 | + font-weight: 600; | ||
| 810 | + flex: 1; | ||
| 811 | + } | ||
| 812 | + | ||
| 813 | + .ops { | ||
| 814 | + display: flex; | ||
| 815 | + align-items: center; | ||
| 816 | + | ||
| 817 | + .upload-btn { | ||
| 818 | + height: 56rpx; | ||
| 819 | + line-height: 56rpx; | ||
| 820 | + padding: 0 24rpx; | ||
| 821 | + font-size: 26rpx; | ||
| 822 | + border-radius: 8rpx; | ||
| 823 | + background: $theme-primary; | ||
| 824 | + color: #fff; | ||
| 825 | + } | ||
| 826 | + } | ||
| 827 | +} | ||
| 828 | + | ||
| 829 | +.add-list { | ||
| 830 | + padding: 0 0 16rpx; | ||
| 831 | + | ||
| 832 | + .empty-tip { | ||
| 833 | + text-align: center; | ||
| 834 | + padding: 60rpx 0; | ||
| 835 | + color: rgba(0, 0, 0, 0.4); | ||
| 836 | + font-size: 28rpx; | ||
| 837 | + } | ||
| 838 | + | ||
| 839 | + .block { | ||
| 840 | + border-bottom: 1rpx solid #f0f0f0; | ||
| 841 | + | ||
| 842 | + &:last-child { | ||
| 843 | + border-bottom: none; | ||
| 844 | + } | ||
| 845 | + } | ||
| 846 | +} | ||
| 847 | + | ||
| 848 | +.section-content { | ||
| 849 | + padding: 32rpx; | ||
| 850 | + | ||
| 851 | + .empty-tip { | ||
| 852 | + text-align: center; | ||
| 853 | + padding: 40rpx 0; | ||
| 854 | + color: rgba(0, 0, 0, 0.4); | ||
| 855 | + font-size: 28rpx; | ||
| 856 | + } | ||
| 857 | + | ||
| 858 | + .file-item { | ||
| 859 | + display: flex; | ||
| 860 | + align-items: center; | ||
| 861 | + justify-content: space-between; | ||
| 862 | + padding: 20rpx 24rpx; | ||
| 863 | + margin-bottom: 16rpx; | ||
| 864 | + background: #fafafa; | ||
| 865 | + border-radius: 8rpx; | ||
| 866 | + | ||
| 867 | + &:last-child { | ||
| 868 | + margin-bottom: 0; | ||
| 869 | + } | ||
| 870 | + | ||
| 871 | + .file-name { | ||
| 872 | + flex: 1; | ||
| 873 | + font-size: 28rpx; | ||
| 874 | + color: rgba(0, 0, 0, 0.9); | ||
| 875 | + word-break: break-all; | ||
| 876 | + margin-right: 20rpx; | ||
| 877 | + } | ||
| 878 | + | ||
| 879 | + .file-del { | ||
| 880 | + flex-shrink: 0; | ||
| 881 | + font-size: 26rpx; | ||
| 882 | + color: #d54941; | ||
| 883 | + } | ||
| 884 | + } | ||
| 885 | +} | ||
| 886 | + | ||
| 887 | +.form-group { | ||
| 888 | + margin: 24rpx 0 32rpx; | ||
| 889 | + | ||
| 890 | + .item-title { | ||
| 891 | + display: flex; | ||
| 892 | + align-items: center; | ||
| 893 | + font-size: 32rpx; | ||
| 894 | + color: rgba(0, 0, 0, 0.9); | ||
| 895 | + margin-bottom: 20rpx; | ||
| 896 | + position: relative; | ||
| 897 | + padding-left: 16rpx; | ||
| 898 | + | ||
| 899 | + .required { | ||
| 900 | + color: red; | ||
| 901 | + position: absolute; | ||
| 902 | + left: 0; | ||
| 903 | + } | ||
| 904 | + } | ||
| 905 | +} | ||
| 906 | + | ||
| 907 | +.remark-group { | ||
| 908 | + margin-bottom: 32rpx; | ||
| 909 | + | ||
| 910 | + &:last-child { | ||
| 911 | + margin-bottom: 0; | ||
| 912 | + } | ||
| 913 | + | ||
| 914 | + .remark-label { | ||
| 915 | + display: flex; | ||
| 916 | + align-items: center; | ||
| 917 | + font-size: 32rpx; | ||
| 918 | + color: rgba(0, 0, 0, 0.9); | ||
| 919 | + margin-bottom: 16rpx; | ||
| 920 | + } | ||
| 921 | +} | ||
| 922 | +</style> |
pages/weight-ticket/upload.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <view class="detail-page"> | ||
| 5 | + <!-- 基础信息 --> | ||
| 6 | + <view class="section"> | ||
| 7 | + <text class="row company">{{ form.code || '-' }}</text> | ||
| 8 | + <view class="row"><text class="label">类型</text><text class="value">{{ typeName }}</text></view> | ||
| 9 | + <view class="row"><text class="label">计划编号</text><text class="value">{{ planCodeText || '-' }}</text></view> | ||
| 10 | + <view class="row"><text class="label">单位</text><text class="value">{{ form.unit || '-' }}</text></view> | ||
| 11 | + <view class="row"><text class="label">供料单位</text><text class="value">{{ form.supplierName || '-' }}</text></view> | ||
| 12 | + <view class="row"><text class="label">收料单位</text><text class="value">{{ form.companyShortName || '-' }}</text></view> | ||
| 13 | + </view> | ||
| 14 | + | ||
| 15 | + <!-- 计划单明细 --> | ||
| 16 | + <view class="sub-table"> | ||
| 17 | + <view class="sub-header"> | ||
| 18 | + <image class="sub-bar" src="/static/images/title.png" /> | ||
| 19 | + <text class="sub-title">计划单明细</text> | ||
| 20 | + </view> | ||
| 21 | + <view class="sub-body"> | ||
| 22 | + <view v-if="!planList.length" class="empty-tip">暂无明细</view> | ||
| 23 | + <view v-for="(item, idx) in planList" :key="'p-' + (item.id || idx)" class="card"> | ||
| 24 | + <view class="card-index">第 {{ idx + 1 }} 行</view> | ||
| 25 | + <view class="row"><text class="label">计划品种</text><text class="value">{{ item.productName || '-' }}</text></view> | ||
| 26 | + <view class="row"><text class="label">计划数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view> | ||
| 27 | + <view class="row"><text class="label">计划编号</text><text class="value">{{ item.planCode || '-' }}</text></view> | ||
| 28 | + </view> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | + | ||
| 32 | + <!-- 过磅明细 --> | ||
| 33 | + <view class="sub-table"> | ||
| 34 | + <view class="sub-header"> | ||
| 35 | + <image class="sub-bar" src="/static/images/title.png" /> | ||
| 36 | + <text class="sub-title">过磅明细</text> | ||
| 37 | + </view> | ||
| 38 | + <view class="sub-body"> | ||
| 39 | + <view v-if="!weighList.length" class="empty-tip">暂无明细</view> | ||
| 40 | + <view v-for="(item, idx) in weighList" :key="'w-' + (item.id || idx)" class="card"> | ||
| 41 | + <view class="card-index">第 {{ idx + 1 }} 行</view> | ||
| 42 | + <view class="row"><text class="label">过磅品种</text><text class="value">{{ item.productName || '-' }}</text></view> | ||
| 43 | + <view class="row"><text class="label">开票品名</text><text class="value">{{ item.invoiceProductName || '-' }}</text></view> | ||
| 44 | + <view class="row"><text class="label">过磅数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view> | ||
| 45 | + <view class="row"><text class="label">计划编号</text><text class="value">{{ item.planCode || '-' }}</text></view> | ||
| 46 | + </view> | ||
| 47 | + </view> | ||
| 48 | + </view> | ||
| 49 | + | ||
| 50 | + <!-- 申请数量明细(仅买断展示) --> | ||
| 51 | + <view v-if="isBuyout" class="sub-table"> | ||
| 52 | + <view class="sub-header"> | ||
| 53 | + <image class="sub-bar" src="/static/images/title.png" /> | ||
| 54 | + <text class="sub-title">申请数量明细</text> | ||
| 55 | + </view> | ||
| 56 | + <view class="sub-body"> | ||
| 57 | + <view v-if="!applyList.length" class="empty-tip">暂无明细</view> | ||
| 58 | + <view v-for="(item, idx) in applyList" :key="'a-' + (item.id || idx)" class="card"> | ||
| 59 | + <view class="card-index">第 {{ idx + 1 }} 行</view> | ||
| 60 | + <view class="row"><text class="label">类别</text><text class="value">{{ item.category || '-' }}</text></view> | ||
| 61 | + <view class="row"><text class="label">数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view> | ||
| 62 | + </view> | ||
| 63 | + </view> | ||
| 64 | + </view> | ||
| 65 | + | ||
| 66 | + <!-- 其他信息 --> | ||
| 67 | + <view class="title-header"> | ||
| 68 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 69 | + <span>其他信息</span> | ||
| 70 | + </view> | ||
| 71 | + <view class="section"> | ||
| 72 | + <view class="row"><text class="label">物料名称</text><text class="value">{{ form.materialName || '-' }}</text></view> | ||
| 73 | + <view class="row"><text class="label">过磅总重</text><text class="value">{{ formatNumber(form.totalGrossWeight) }}</text></view> | ||
| 74 | + <view class="row"><text class="label">实际伙重</text><text class="value">{{ formatNumber(form.actualImpurityWeight) }}</text></view> | ||
| 75 | + <view class="row"><text class="label">货物净重</text><text class="value">{{ formatNumber(form.netWeight) }}</text></view> | ||
| 76 | + <view class="row"><text class="label">净重大写</text><text class="value">{{ form.netWeightUpper || '-' }}</text></view> | ||
| 77 | + <view class="row"><text class="label">来料扣杂类型</text><text class="value">{{ deductionNames }}</text></view> | ||
| 78 | + <view class="row"><text class="label">供应存欠料</text><text class="value">{{ form.supplierStockMaterial || '-' }}</text></view> | ||
| 79 | + <view class="row"><text class="label">物流存欠料</text><text class="value">{{ form.logisticsStockMaterial || '-' }}</text></view> | ||
| 80 | + <view class="row"><text class="label">车牌号</text><text class="value">{{ form.plateNumber || '-' }}</text></view> | ||
| 81 | + </view> | ||
| 82 | + | ||
| 83 | + <!-- 业务摘要 --> | ||
| 84 | + <view class="title-header"> | ||
| 85 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 86 | + <span>业务摘要</span> | ||
| 87 | + </view> | ||
| 88 | + <view class="section"> | ||
| 89 | + <text class="remark-text">{{ form.businessSummary || '-' }}</text> | ||
| 90 | + </view> | ||
| 91 | + | ||
| 92 | + <!-- 特别说明 --> | ||
| 93 | + <view class="title-header"> | ||
| 94 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 95 | + <span>特别说明</span> | ||
| 96 | + </view> | ||
| 97 | + <view class="section"> | ||
| 98 | + <text class="remark-text">{{ form.specialNote || '-' }}</text> | ||
| 99 | + </view> | ||
| 100 | + | ||
| 101 | + <!-- 单据备注 --> | ||
| 102 | + <view class="title-header"> | ||
| 103 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 104 | + <span>单据备注</span> | ||
| 105 | + </view> | ||
| 106 | + <view class="section"> | ||
| 107 | + <text class="remark-text">{{ form.documentRemark || '-' }}</text> | ||
| 108 | + </view> | ||
| 109 | + | ||
| 110 | + <!-- 附件信息 --> | ||
| 111 | + <view class="sub-table"> | ||
| 112 | + <view class="sub-header"> | ||
| 113 | + <image class="sub-bar" src="/static/images/title.png" /> | ||
| 114 | + <text class="sub-title">{{ mode === 'delay' ? '延期说明' : '签字凭证' }}</text> | ||
| 115 | + <view class="upload-btn" @click="selectFile">上传文件</view> | ||
| 116 | + </view> | ||
| 117 | + <view class="sub-body"> | ||
| 118 | + <view v-if="mode === 'sign'" class="driver-row"> | ||
| 119 | + <view class="driver-label"><text class="required">*</text><text>驾驶员姓名</text></view> | ||
| 120 | + <input | ||
| 121 | + class="driver-input" | ||
| 122 | + v-model="driver" | ||
| 123 | + placeholder="请输入驾驶员姓名" | ||
| 124 | + placeholder-style="color: rgba(0,0,0,0.4); font-size: 28rpx;" | ||
| 125 | + /> | ||
| 126 | + </view> | ||
| 127 | + <view v-if="!fileList.length" class="empty-tip">暂无附件,请上传</view> | ||
| 128 | + <view v-for="(file, idx) in fileList" :key="file.id || idx" class="file-item"> | ||
| 129 | + <text class="file-name">{{ file.name || '未命名文件' }}</text> | ||
| 130 | + <text class="file-del" @click="removeFile(idx)">删除</text> | ||
| 131 | + </view> | ||
| 132 | + </view> | ||
| 133 | + </view> | ||
| 134 | + </view> | ||
| 135 | + </scroll-view> | ||
| 136 | + <view class="footer"> | ||
| 137 | + <button class="btn submit" type="primary" @click="onSubmit">保存</button> | ||
| 138 | + </view> | ||
| 139 | + </view> | ||
| 140 | +</template> | ||
| 141 | + | ||
| 142 | +<script> | ||
| 143 | +import { | ||
| 144 | + weighTicketDetailApi, | ||
| 145 | + weighTicketUploadSignApi, | ||
| 146 | + weighTicketUploadDelayApi | ||
| 147 | +} from '@/api/procure-manage/weighTicket.js' | ||
| 148 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | ||
| 149 | +import upload from '@/utils/upload' | ||
| 150 | +import { uploadFileApi } from '@/api/base.js' | ||
| 151 | + | ||
| 152 | +export default { | ||
| 153 | + name: 'WeightTicketUpload', | ||
| 154 | + data() { | ||
| 155 | + return { | ||
| 156 | + id: '', | ||
| 157 | + // 上传类型:sign-签字凭证;delay-延期说明 | ||
| 158 | + mode: 'sign', | ||
| 159 | + form: { | ||
| 160 | + code: '', | ||
| 161 | + type: '', | ||
| 162 | + unit: '', | ||
| 163 | + supplierName: '', | ||
| 164 | + companyShortName: '', | ||
| 165 | + materialName: '', | ||
| 166 | + totalGrossWeight: '', | ||
| 167 | + actualImpurityWeight: '', | ||
| 168 | + netWeight: '', | ||
| 169 | + netWeightUpper: '', | ||
| 170 | + deductionTypes: '', | ||
| 171 | + supplierStockMaterial: '', | ||
| 172 | + logisticsStockMaterial: '', | ||
| 173 | + plateNumber: '', | ||
| 174 | + businessSummary: '', | ||
| 175 | + specialNote: '', | ||
| 176 | + documentRemark: '' | ||
| 177 | + }, | ||
| 178 | + planList: [], | ||
| 179 | + weighList: [], | ||
| 180 | + applyList: [], | ||
| 181 | + buyout: false, | ||
| 182 | + // 附件列表 [{ id, name }] | ||
| 183 | + fileList: [], | ||
| 184 | + // 驾驶员姓名(仅签字凭证必填) | ||
| 185 | + driver: '', | ||
| 186 | + dicOptions: { TYPE: [], DEDUCTION_TYPE: [] } | ||
| 187 | + } | ||
| 188 | + }, | ||
| 189 | + computed: { | ||
| 190 | + typeName() { | ||
| 191 | + const v = this.form.type == null ? '' : String(this.form.type) | ||
| 192 | + if (!v) return '-' | ||
| 193 | + return getDicName('TYPE', v, this.dicOptions.TYPE) || v | ||
| 194 | + }, | ||
| 195 | + planCodeText() { | ||
| 196 | + const codes = Array.from(new Set((this.planList || []).map(it => it.planCode).filter(Boolean))) | ||
| 197 | + return codes.join(',') | ||
| 198 | + }, | ||
| 199 | + deductionNames() { | ||
| 200 | + const codes = (this.form.deductionTypes == null ? '' : String(this.form.deductionTypes)).split(',').filter(Boolean) | ||
| 201 | + const names = codes.map(code => getDicName('DEDUCTION_TYPE', code, this.dicOptions.DEDUCTION_TYPE)).filter(Boolean) | ||
| 202 | + return names.length ? names.join('、') : '-' | ||
| 203 | + }, | ||
| 204 | + isBuyout() { | ||
| 205 | + return this.buyout || (this.applyList || []).length > 0 | ||
| 206 | + } | ||
| 207 | + }, | ||
| 208 | + onLoad(query) { | ||
| 209 | + this.id = (query && query.id) || '' | ||
| 210 | + this.mode = query && query.mode === 'delay' ? 'delay' : 'sign' | ||
| 211 | + uni.setNavigationBarTitle({ | ||
| 212 | + title: this.mode === 'delay' ? '上传延期说明' : '上传签字凭证' | ||
| 213 | + }) | ||
| 214 | + }, | ||
| 215 | + created() { | ||
| 216 | + this.loadDicData() | ||
| 217 | + this.loadDetail() | ||
| 218 | + }, | ||
| 219 | + methods: { | ||
| 220 | + async loadDicData() { | ||
| 221 | + try { | ||
| 222 | + const results = await getDicByCodes(['TYPE', 'DEDUCTION_TYPE']) | ||
| 223 | + this.dicOptions.TYPE = (results.TYPE && results.TYPE.data) || [] | ||
| 224 | + this.dicOptions.DEDUCTION_TYPE = (results.DEDUCTION_TYPE && results.DEDUCTION_TYPE.data) || [] | ||
| 225 | + } catch (e) { | ||
| 226 | + this.dicOptions = { TYPE: [], DEDUCTION_TYPE: [] } | ||
| 227 | + } | ||
| 228 | + }, | ||
| 229 | + loadDetail() { | ||
| 230 | + if (!this.id) { | ||
| 231 | + uni.showToast({ title: '缺少单据ID', icon: 'none' }) | ||
| 232 | + return | ||
| 233 | + } | ||
| 234 | + uni.showLoading({ title: '加载中...', mask: true }) | ||
| 235 | + weighTicketDetailApi({ id: this.id }) | ||
| 236 | + .then(res => { | ||
| 237 | + const data = res && res.data ? (res.data.data || res.data) : {} | ||
| 238 | + this.form = { | ||
| 239 | + code: data.code || '', | ||
| 240 | + type: data.type != null ? String(data.type) : '', | ||
| 241 | + unit: data.unit || '', | ||
| 242 | + supplierName: data.supplierName || '', | ||
| 243 | + companyShortName: data.companyShortName || '', | ||
| 244 | + materialName: data.materialName || '', | ||
| 245 | + totalGrossWeight: data.totalGrossWeight == null ? '' : String(data.totalGrossWeight), | ||
| 246 | + actualImpurityWeight: data.actualImpurityWeight == null ? '' : String(data.actualImpurityWeight), | ||
| 247 | + netWeight: data.netWeight == null ? '' : String(data.netWeight), | ||
| 248 | + netWeightUpper: data.netWeightUpper || '', | ||
| 249 | + deductionTypes: data.deductionTypes || '', | ||
| 250 | + supplierStockMaterial: data.supplierStockMaterial || '', | ||
| 251 | + logisticsStockMaterial: data.logisticsStockMaterial || '', | ||
| 252 | + plateNumber: data.plateNumber || '', | ||
| 253 | + businessSummary: data.businessSummary || '', | ||
| 254 | + specialNote: data.specialNote || '', | ||
| 255 | + documentRemark: data.documentRemark || '' | ||
| 256 | + } | ||
| 257 | + // 驾驶员姓名回显(仅签字凭证) | ||
| 258 | + this.driver = data.driver || '' | ||
| 259 | + this.buyout = !!data.buyout | ||
| 260 | + this.planList = Array.isArray(data.planLines) ? data.planLines.map(x => ({ ...x })) : [] | ||
| 261 | + this.weighList = Array.isArray(data.weighLines) ? data.weighLines.map(x => ({ ...x })) : [] | ||
| 262 | + this.applyList = Array.isArray(data.applyLines) ? data.applyLines.map(x => ({ ...x })) : [] | ||
| 263 | + // 已传附件回显(多文件逗号分隔) | ||
| 264 | + const key = this.mode === 'delay' ? 'delayFile' : 'signFile' | ||
| 265 | + const ids = String(data[key + 'Id'] || '').split(',').filter(Boolean) | ||
| 266 | + const names = String(data[key + 'Name'] || '').split(',').filter(Boolean) | ||
| 267 | + this.fileList = ids.map((id, i) => ({ id, name: names[i] || '' })) | ||
| 268 | + }) | ||
| 269 | + .catch(() => { | ||
| 270 | + uni.showToast({ title: '加载详情失败', icon: 'none' }) | ||
| 271 | + }) | ||
| 272 | + .finally(() => { | ||
| 273 | + uni.hideLoading() | ||
| 274 | + }) | ||
| 275 | + }, | ||
| 276 | + // 选择并上传文件(多文件逐个追加) | ||
| 277 | + selectFile() { | ||
| 278 | + if (typeof uni !== 'undefined' && typeof uni.chooseMessageFile === 'function') { | ||
| 279 | + uni.chooseMessageFile({ | ||
| 280 | + count: 9, | ||
| 281 | + type: 'all', | ||
| 282 | + success: async res => { | ||
| 283 | + const files = (res && res.tempFiles) || [] | ||
| 284 | + if (!files.length) return | ||
| 285 | + uni.showLoading({ title: '上传中...', mask: true }) | ||
| 286 | + try { | ||
| 287 | + for (const f of files) { | ||
| 288 | + const name = f.name || 'file' | ||
| 289 | + const r = await upload({ url: '/sw/filebox/uploadFile', filePath: f.path, name: 'file' }) | ||
| 290 | + const d = r && r.data ? r.data : r | ||
| 291 | + const id = (d && (d.id || d.fileId || (d.data && (d.data.id || d.data.fileId)))) | ||
| 292 | + ? String(d.id || d.fileId || d.data.id || d.data.fileId) | ||
| 293 | + : '' | ||
| 294 | + if (id) this.fileList.push({ id, name }) | ||
| 295 | + } | ||
| 296 | + } catch (e) { | ||
| 297 | + uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 298 | + } finally { | ||
| 299 | + uni.hideLoading() | ||
| 300 | + } | ||
| 301 | + }, | ||
| 302 | + fail: () => { | ||
| 303 | + uni.showToast({ title: '未选择文件', icon: 'none' }) | ||
| 304 | + } | ||
| 305 | + }) | ||
| 306 | + return | ||
| 307 | + } | ||
| 308 | + // H5 兜底:动态创建原生 input | ||
| 309 | + try { | ||
| 310 | + const self = this | ||
| 311 | + const input = document.createElement('input') | ||
| 312 | + input.type = 'file' | ||
| 313 | + input.multiple = true | ||
| 314 | + input.style.position = 'fixed' | ||
| 315 | + input.style.left = '-9999px' | ||
| 316 | + document.body.appendChild(input) | ||
| 317 | + input.addEventListener('change', self.onFileChange) | ||
| 318 | + input.click() | ||
| 319 | + setTimeout(() => { document.body.removeChild(input) }, 1000) | ||
| 320 | + } catch (e) { | ||
| 321 | + uni.showToast({ title: '无法打开文件选择', icon: 'none' }) | ||
| 322 | + } | ||
| 323 | + }, | ||
| 324 | + async onFileChange(e) { | ||
| 325 | + const files = (e && e.target && e.target.files) || [] | ||
| 326 | + if (!files.length) return | ||
| 327 | + uni.showLoading({ title: '上传中...', mask: true }) | ||
| 328 | + try { | ||
| 329 | + for (const file of files) { | ||
| 330 | + const name = file.name || '' | ||
| 331 | + const fd = new FormData() | ||
| 332 | + fd.append('file', file, name) | ||
| 333 | + const d = await uploadFileApi(fd) | ||
| 334 | + const data = d && d.data ? d.data : d | ||
| 335 | + const id = (data && (data.id || data.fileId || (data.data && (data.data.id || data.data.fileId)))) | ||
| 336 | + ? String(data.id || data.fileId || data.data.id || data.data.fileId) | ||
| 337 | + : '' | ||
| 338 | + if (id) this.fileList.push({ id, name }) | ||
| 339 | + } | ||
| 340 | + } catch (e2) { | ||
| 341 | + uni.showToast({ title: '上传失败', icon: 'none' }) | ||
| 342 | + } finally { | ||
| 343 | + uni.hideLoading() | ||
| 344 | + if (e && e.target) e.target.value = '' | ||
| 345 | + } | ||
| 346 | + }, | ||
| 347 | + removeFile(idx) { | ||
| 348 | + this.fileList.splice(idx, 1) | ||
| 349 | + }, | ||
| 350 | + formatNumber(v) { | ||
| 351 | + if (v === null || v === undefined || v === '') return '-' | ||
| 352 | + const n = Number(v) | ||
| 353 | + if (isNaN(n)) return String(v) | ||
| 354 | + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 }) | ||
| 355 | + }, | ||
| 356 | + async onSubmit() { | ||
| 357 | + const ids = this.fileList.map(it => it.id).filter(Boolean) | ||
| 358 | + const names = this.fileList.map(it => it.name).filter(Boolean) | ||
| 359 | + if (!ids.length || !names.length) { | ||
| 360 | + uni.showToast({ title: this.mode === 'delay' ? '请上传延期说明附件' : '请上传签字凭证', icon: 'none' }) | ||
| 361 | + return | ||
| 362 | + } | ||
| 363 | + // 签字凭证:驾驶员姓名必填 | ||
| 364 | + const driver = (this.driver || '').trim() | ||
| 365 | + if (this.mode === 'sign' && !driver) { | ||
| 366 | + uni.showToast({ title: '请输入驾驶员姓名', icon: 'none' }) | ||
| 367 | + return | ||
| 368 | + } | ||
| 369 | + const confirmRes = await new Promise(resolve => { | ||
| 370 | + uni.showModal({ title: '提示', content: '确定保存附件吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | ||
| 371 | + }) | ||
| 372 | + if (!(confirmRes && confirmRes.confirm)) return | ||
| 373 | + const data = { | ||
| 374 | + id: this.id, | ||
| 375 | + fileIds: ids.join(','), | ||
| 376 | + fileNames: names.join(',') | ||
| 377 | + } | ||
| 378 | + if (this.mode === 'sign') { | ||
| 379 | + data.driver = driver | ||
| 380 | + } | ||
| 381 | + uni.showLoading({ title: '保存中...', mask: true }) | ||
| 382 | + const api = this.mode === 'delay' ? weighTicketUploadDelayApi : weighTicketUploadSignApi | ||
| 383 | + api(data) | ||
| 384 | + .then(() => { | ||
| 385 | + uni.hideLoading() | ||
| 386 | + uni.showToast({ title: '保存成功', icon: 'none' }) | ||
| 387 | + try { | ||
| 388 | + uni.setStorageSync('WEIGHT_TICKET_LIST_NEED_REFRESH', '1') | ||
| 389 | + uni.setStorageSync('WEIGHT_TICKET_DETAIL_NEED_REFRESH', '1') | ||
| 390 | + } catch (e) {} | ||
| 391 | + setTimeout(() => { uni.navigateBack() }, 400) | ||
| 392 | + }) | ||
| 393 | + .catch(e => { | ||
| 394 | + uni.hideLoading() | ||
| 395 | + uni.showToast({ title: (e && (e.msg || e.message)) || '保存失败', icon: 'none' }) | ||
| 396 | + }) | ||
| 397 | + } | ||
| 398 | + } | ||
| 399 | +} | ||
| 400 | +</script> | ||
| 401 | + | ||
| 402 | +<style lang="scss" scoped> | ||
| 403 | +.page { | ||
| 404 | + display: flex; | ||
| 405 | + flex-direction: column; | ||
| 406 | + height: 100%; | ||
| 407 | +} | ||
| 408 | + | ||
| 409 | +.scroll { | ||
| 410 | + flex: 1; | ||
| 411 | + padding: 8rpx 0 176rpx; | ||
| 412 | +} | ||
| 413 | + | ||
| 414 | +.detail-page { | ||
| 415 | + background: #f3f3f3; | ||
| 416 | +} | ||
| 417 | + | ||
| 418 | +.footer { | ||
| 419 | + z-index: 2; | ||
| 420 | + position: fixed; | ||
| 421 | + left: 0; | ||
| 422 | + right: 0; | ||
| 423 | + bottom: 0; | ||
| 424 | + padding: 32rpx; | ||
| 425 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 426 | + background: #fff; | ||
| 427 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 428 | + | ||
| 429 | + .btn { | ||
| 430 | + height: 80rpx; | ||
| 431 | + line-height: 80rpx; | ||
| 432 | + border-radius: 12rpx; | ||
| 433 | + font-size: 32rpx; | ||
| 434 | + } | ||
| 435 | + | ||
| 436 | + .submit { | ||
| 437 | + background: $theme-primary; | ||
| 438 | + color: #fff; | ||
| 439 | + } | ||
| 440 | +} | ||
| 441 | + | ||
| 442 | +.section { | ||
| 443 | + padding: 32rpx; | ||
| 444 | + background: #fff; | ||
| 445 | + margin-bottom: 20rpx; | ||
| 446 | +} | ||
| 447 | + | ||
| 448 | +.title-header { | ||
| 449 | + display: flex; | ||
| 450 | + align-items: center; | ||
| 451 | + padding: 24rpx 32rpx 12rpx; | ||
| 452 | + background-color: #ffffff; | ||
| 453 | + | ||
| 454 | + .title-header_icon { | ||
| 455 | + width: 36rpx; | ||
| 456 | + height: 36rpx; | ||
| 457 | + margin-right: 12rpx; | ||
| 458 | + } | ||
| 459 | + | ||
| 460 | + span { | ||
| 461 | + font-size: 34rpx; | ||
| 462 | + font-weight: 600; | ||
| 463 | + color: rgba(0, 0, 0, 0.9); | ||
| 464 | + } | ||
| 465 | +} | ||
| 466 | + | ||
| 467 | +.row { | ||
| 468 | + display: flex; | ||
| 469 | + margin-bottom: 28rpx; | ||
| 470 | + | ||
| 471 | + &:last-child { | ||
| 472 | + margin-bottom: 0; | ||
| 473 | + } | ||
| 474 | + | ||
| 475 | + &.company { | ||
| 476 | + font-size: 36rpx; | ||
| 477 | + font-weight: 600; | ||
| 478 | + color: rgba(0, 0, 0, 0.9); | ||
| 479 | + padding-top: 8rpx; | ||
| 480 | + line-height: 50rpx; | ||
| 481 | + } | ||
| 482 | + | ||
| 483 | + .label { | ||
| 484 | + max-width: 420rpx; | ||
| 485 | + margin-right: 20rpx; | ||
| 486 | + line-height: 32rpx; | ||
| 487 | + font-size: 28rpx; | ||
| 488 | + color: rgba(0, 0, 0, 0.6); | ||
| 489 | + } | ||
| 490 | + | ||
| 491 | + .value { | ||
| 492 | + flex: 1; | ||
| 493 | + line-height: 32rpx; | ||
| 494 | + font-size: 28rpx; | ||
| 495 | + color: rgba(0, 0, 0, 0.9); | ||
| 496 | + text-align: right; | ||
| 497 | + word-break: break-all; | ||
| 498 | + } | ||
| 499 | +} | ||
| 500 | + | ||
| 501 | +.remark-text { | ||
| 502 | + font-size: 28rpx; | ||
| 503 | + color: rgba(0, 0, 0, 0.9); | ||
| 504 | + line-height: 1.6; | ||
| 505 | + white-space: pre-wrap; | ||
| 506 | +} | ||
| 507 | + | ||
| 508 | +.sub-table { | ||
| 509 | + background: #fff; | ||
| 510 | + margin-bottom: 20rpx; | ||
| 511 | +} | ||
| 512 | + | ||
| 513 | +.sub-header { | ||
| 514 | + display: flex; | ||
| 515 | + align-items: center; | ||
| 516 | + padding: 16rpx 0 16rpx 32rpx; | ||
| 517 | + | ||
| 518 | + .sub-bar { | ||
| 519 | + width: 6rpx; | ||
| 520 | + height: 32rpx; | ||
| 521 | + margin-right: 14rpx; | ||
| 522 | + } | ||
| 523 | + | ||
| 524 | + .sub-title { | ||
| 525 | + font-size: 30rpx; | ||
| 526 | + font-weight: 600; | ||
| 527 | + color: rgba(0, 0, 0, 0.9); | ||
| 528 | + flex: 1; | ||
| 529 | + line-height: 42rpx; | ||
| 530 | + } | ||
| 531 | + | ||
| 532 | + .upload-btn { | ||
| 533 | + margin-right: 32rpx; | ||
| 534 | + height: 56rpx; | ||
| 535 | + line-height: 56rpx; | ||
| 536 | + padding: 0 24rpx; | ||
| 537 | + font-size: 26rpx; | ||
| 538 | + border-radius: 8rpx; | ||
| 539 | + background: $theme-primary; | ||
| 540 | + color: #fff; | ||
| 541 | + } | ||
| 542 | +} | ||
| 543 | + | ||
| 544 | +.sub-body { | ||
| 545 | + padding: 0 32rpx 24rpx; | ||
| 546 | + | ||
| 547 | + .empty-tip { | ||
| 548 | + text-align: center; | ||
| 549 | + padding: 40rpx 0; | ||
| 550 | + color: rgba(0, 0, 0, 0.4); | ||
| 551 | + font-size: 28rpx; | ||
| 552 | + } | ||
| 553 | + | ||
| 554 | + .driver-row { | ||
| 555 | + display: flex; | ||
| 556 | + align-items: center; | ||
| 557 | + justify-content: space-between; | ||
| 558 | + min-height: 88rpx; | ||
| 559 | + padding: 8rpx 0; | ||
| 560 | + margin-bottom: 8rpx; | ||
| 561 | + border-bottom: 1rpx dashed #f2f2f2; | ||
| 562 | + | ||
| 563 | + .driver-label { | ||
| 564 | + display: flex; | ||
| 565 | + align-items: center; | ||
| 566 | + flex-shrink: 0; | ||
| 567 | + width: 220rpx; | ||
| 568 | + font-size: 28rpx; | ||
| 569 | + color: rgba(0, 0, 0, 0.6); | ||
| 570 | + line-height: 40rpx; | ||
| 571 | + | ||
| 572 | + .required { | ||
| 573 | + color: #d54941; | ||
| 574 | + margin-right: 6rpx; | ||
| 575 | + } | ||
| 576 | + } | ||
| 577 | + | ||
| 578 | + .driver-input { | ||
| 579 | + flex: 1; | ||
| 580 | + height: 56rpx; | ||
| 581 | + line-height: 56rpx; | ||
| 582 | + font-size: 28rpx; | ||
| 583 | + color: rgba(0, 0, 0, 0.9); | ||
| 584 | + text-align: right; | ||
| 585 | + } | ||
| 586 | + } | ||
| 587 | + | ||
| 588 | + .card { | ||
| 589 | + position: relative; | ||
| 590 | + background: #fafafa; | ||
| 591 | + border-radius: 12rpx; | ||
| 592 | + padding: 32rpx 28rpx 20rpx; | ||
| 593 | + margin-bottom: 24rpx; | ||
| 594 | + | ||
| 595 | + .card-index { | ||
| 596 | + position: absolute; | ||
| 597 | + top: 0; | ||
| 598 | + right: 0; | ||
| 599 | + background: rgba(24, 144, 255, 0.08); | ||
| 600 | + color: $theme-primary; | ||
| 601 | + font-size: 22rpx; | ||
| 602 | + line-height: 36rpx; | ||
| 603 | + padding: 0 16rpx; | ||
| 604 | + border-bottom-left-radius: 12rpx; | ||
| 605 | + border-top-right-radius: 12rpx; | ||
| 606 | + } | ||
| 607 | + | ||
| 608 | + .row { | ||
| 609 | + align-items: center; | ||
| 610 | + justify-content: space-between; | ||
| 611 | + padding: 14rpx 0; | ||
| 612 | + margin-bottom: 0; | ||
| 613 | + border-bottom: 1rpx dashed #f2f2f2; | ||
| 614 | + | ||
| 615 | + &:last-child { | ||
| 616 | + border-bottom: none; | ||
| 617 | + } | ||
| 618 | + | ||
| 619 | + .label { | ||
| 620 | + flex-shrink: 0; | ||
| 621 | + width: 220rpx; | ||
| 622 | + max-width: none; | ||
| 623 | + margin-right: 0; | ||
| 624 | + font-size: 28rpx; | ||
| 625 | + color: rgba(0, 0, 0, 0.6); | ||
| 626 | + line-height: 40rpx; | ||
| 627 | + } | ||
| 628 | + | ||
| 629 | + .value { | ||
| 630 | + flex: 1; | ||
| 631 | + text-align: right; | ||
| 632 | + font-size: 28rpx; | ||
| 633 | + color: rgba(0, 0, 0, 0.9); | ||
| 634 | + line-height: 40rpx; | ||
| 635 | + overflow: hidden; | ||
| 636 | + text-overflow: ellipsis; | ||
| 637 | + white-space: nowrap; | ||
| 638 | + } | ||
| 639 | + } | ||
| 640 | + } | ||
| 641 | + | ||
| 642 | + .file-item { | ||
| 643 | + display: flex; | ||
| 644 | + align-items: center; | ||
| 645 | + justify-content: space-between; | ||
| 646 | + padding: 20rpx 24rpx; | ||
| 647 | + margin-bottom: 16rpx; | ||
| 648 | + background: #fafafa; | ||
| 649 | + border-radius: 8rpx; | ||
| 650 | + | ||
| 651 | + &:last-child { | ||
| 652 | + margin-bottom: 0; | ||
| 653 | + } | ||
| 654 | + | ||
| 655 | + .file-name { | ||
| 656 | + flex: 1; | ||
| 657 | + font-size: 28rpx; | ||
| 658 | + color: rgba(0, 0, 0, 0.9); | ||
| 659 | + word-break: break-all; | ||
| 660 | + margin-right: 20rpx; | ||
| 661 | + } | ||
| 662 | + | ||
| 663 | + .file-del { | ||
| 664 | + flex-shrink: 0; | ||
| 665 | + font-size: 26rpx; | ||
| 666 | + color: #d54941; | ||
| 667 | + } | ||
| 668 | + } | ||
| 669 | +} | ||
| 670 | +</style> |