|
|
@@ -0,0 +1,2188 @@
|
|
|
+<template>
|
|
|
+ <div class="container">
|
|
|
+ <van-nav-bar
|
|
|
+ title="退货登记"
|
|
|
+ left-arrow
|
|
|
+ @click-left="goBack"
|
|
|
+ @click-right="init"
|
|
|
+ >
|
|
|
+ <template #left>
|
|
|
+ <van-icon name="arrow-left" size="25" />
|
|
|
+ <div class="left-btn">返回</div>
|
|
|
+ </template>
|
|
|
+ <template #right>
|
|
|
+ <div class="nav-right right-btn">重置</div>
|
|
|
+ </template>
|
|
|
+ </van-nav-bar>
|
|
|
+
|
|
|
+ <div class="content">
|
|
|
+ <div v-if="showInitialPage" class="init-container">
|
|
|
+ <div class="content-tips">
|
|
|
+ <div style="flex: 1">
|
|
|
+ <van-notice-bar left-icon="volume-o">请扫描退回单号</van-notice-bar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="scan-returned-content">
|
|
|
+ <div class="input-group">
|
|
|
+ <van-field
|
|
|
+ ref="scan-express-no-input"
|
|
|
+ autofocus
|
|
|
+ v-model="expressNo"
|
|
|
+ autocomplete="off"
|
|
|
+ placeholder="输入快递单号"
|
|
|
+ clearable
|
|
|
+ @keydown.enter="inputExpressNo"
|
|
|
+ >
|
|
|
+ </van-field>
|
|
|
+ </div>
|
|
|
+ <div class="button-group">
|
|
|
+ <van-button
|
|
|
+ @click="inputExpressNo"
|
|
|
+ style="width: 100%"
|
|
|
+ type="primary"
|
|
|
+ class="confirm-btn"
|
|
|
+ >确认
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else>
|
|
|
+ <van-tabs>
|
|
|
+ <van-tab title="退货信息">
|
|
|
+ <div>
|
|
|
+ <div class="content-tips">
|
|
|
+ <div style="flex: 1">
|
|
|
+ <van-notice-bar color="#1989fa" background="#ecf9ff"
|
|
|
+ >{{ ownerQualityInspection }}
|
|
|
+ </van-notice-bar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <van-cell-group inset style="margin-top: 10px">
|
|
|
+ <van-field
|
|
|
+ v-model="params.returnNo"
|
|
|
+ label="快递单号"
|
|
|
+ readonly
|
|
|
+ placeholder="请输入快递单号"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ readonly
|
|
|
+ clickable
|
|
|
+ label="承运商"
|
|
|
+ placeholder="选择承运商"
|
|
|
+ :model-value="getLogisticName()"
|
|
|
+ @click="logisticPickerShow = true"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model:show="logisticPickerShow"
|
|
|
+ position="bottom"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <van-picker
|
|
|
+ :columns="logistics"
|
|
|
+ @cancel="logisticPickerShow = false"
|
|
|
+ @confirm="selectedLogistic"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ readonly
|
|
|
+ clickable
|
|
|
+ label="仓库"
|
|
|
+ placeholder="选择仓库"
|
|
|
+ :model-value="getWarehouseName()"
|
|
|
+ @click="warehousePickerShow = true"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model:show="warehousePickerShow"
|
|
|
+ position="bottom"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <van-picker
|
|
|
+ :columns="warehouses"
|
|
|
+ @cancel="warehousePickerShow = false"
|
|
|
+ @confirm="selectedWarehouse"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ readonly
|
|
|
+ clickable
|
|
|
+ label="货主"
|
|
|
+ placeholder="选择货主"
|
|
|
+ :model-value="getOwnerName(params.ownerCode)"
|
|
|
+ @click="showOwnerSelectFunc"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ readonly
|
|
|
+ clickable
|
|
|
+ label="店铺"
|
|
|
+ placeholder="选择店铺"
|
|
|
+ v-model="params.storeName"
|
|
|
+ @click="storePickerShow = true"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model:show="storePickerShow"
|
|
|
+ position="bottom"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <van-picker
|
|
|
+ :columns="storeOptions"
|
|
|
+ @cancel="storePickerShow = false"
|
|
|
+ @confirm="selectedStore"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="params.orderUpstream"
|
|
|
+ label="上游平台"
|
|
|
+ placeholder="上游平台"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ v-model="params.arrivalPayment"
|
|
|
+ label="到付费用"
|
|
|
+ placeholder="到付费用"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="params.remark"
|
|
|
+ rows="1"
|
|
|
+ autosize
|
|
|
+ label="备注"
|
|
|
+ type="textarea"
|
|
|
+ placeholder="备注"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+
|
|
|
+ <van-cell-group inset style="margin-top: 10px">
|
|
|
+ <van-field
|
|
|
+ :model-value="params.originalNo"
|
|
|
+ label="是否原单"
|
|
|
+ readonly
|
|
|
+ placeholder="是否原单"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ v-model="params.upstreamNo"
|
|
|
+ label="客户订单号"
|
|
|
+ placeholder="客户订单号"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="params.asnNo"
|
|
|
+ label="ASN单号"
|
|
|
+ readonly
|
|
|
+ placeholder="ASN单号"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="params.buyerName"
|
|
|
+ label="客户姓名"
|
|
|
+ readonly
|
|
|
+ placeholder="客户姓名"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="params.buyerPhone"
|
|
|
+ label="电话号码"
|
|
|
+ readonly
|
|
|
+ placeholder="电话号码"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+
|
|
|
+ <van-cell-group inset style="margin-top: 20px; margin-bottom: 50px">
|
|
|
+ <van-button type="primary" block @click="submit">提交</van-button>
|
|
|
+ </van-cell-group>
|
|
|
+ </van-tab>
|
|
|
+ <van-tab title="商品信息" class="returned-detail-list">
|
|
|
+ <div>
|
|
|
+ <div class="content-tips">
|
|
|
+ <div style="flex: 1">
|
|
|
+ <van-notice-bar color="#1989fa" background="#ecf9ff"
|
|
|
+ >{{ ownerQualityInspection }}
|
|
|
+ </van-notice-bar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template v-if="!params.details || params.details.length === 0">
|
|
|
+ <van-empty description="暂无信息请进行录入" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-for="(item, index) in params.details">
|
|
|
+ <div class="card-div">
|
|
|
+ <div class="card-div-content">
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">sku</div>
|
|
|
+ <div class="info-value">{{ item.sku }}</div>
|
|
|
+ <div class="info-label">质量状态</div>
|
|
|
+ <div class="info-value">
|
|
|
+ <van-tag :color="getTagColor(item.qualityStatus)">
|
|
|
+ {{ item.qualityStatus }}
|
|
|
+ </van-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">商品编号</div>
|
|
|
+ <div class="info-value">{{ item.barCode }}</div>
|
|
|
+ <div class="info-label">商品名称</div>
|
|
|
+ <div class="info-value">
|
|
|
+ <van-text-ellipsis
|
|
|
+ :content="item.tradeName"
|
|
|
+ rows="1"
|
|
|
+ expand-text="展开"
|
|
|
+ collapse-text="收起"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">生产日期</div>
|
|
|
+ <div class="info-value">
|
|
|
+ {{ item.manufactureTime }}
|
|
|
+ </div>
|
|
|
+ <div class="info-label">失效日期</div>
|
|
|
+ <div class="info-value">{{ item.validityTime }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="info-row">
|
|
|
+ <div class="info-label">批次号</div>
|
|
|
+ <div class="info-value">{{ item.batchNumber }}</div>
|
|
|
+ <div class="info-label">数量</div>
|
|
|
+ <div class="info-value">{{ item.number }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card-div-footer">
|
|
|
+ <div class="product-description">
|
|
|
+ {{ item.remark }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template v-if="hasBoxItems(item)">
|
|
|
+ <div>
|
|
|
+ <van-divider content-position="left">外箱图</van-divider>
|
|
|
+ <van-row>
|
|
|
+ <template v-for="(i, imgIndex) in getBoxItems(item)">
|
|
|
+ <van-col span="4">
|
|
|
+ <van-image
|
|
|
+ :key="`box-photos-${index}-${imgIndex}`"
|
|
|
+ @click="
|
|
|
+ previewImages(item.boxPhotos, imgIndex, '外箱图')
|
|
|
+ "
|
|
|
+ width="100%"
|
|
|
+ height="50"
|
|
|
+ :src="i.src"
|
|
|
+ />
|
|
|
+ </van-col>
|
|
|
+ </template>
|
|
|
+ </van-row>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="hasProductItems(item)">
|
|
|
+ <div>
|
|
|
+ <van-divider content-position="left">内物图</van-divider>
|
|
|
+ <van-row>
|
|
|
+ <template v-for="(i, imgIndex) in getProductItems(item)">
|
|
|
+ <van-col span="4">
|
|
|
+ <van-image
|
|
|
+ :key="`product-photos-${index}-${imgIndex}`"
|
|
|
+ @click="
|
|
|
+ previewImages(
|
|
|
+ item.productPhotos,
|
|
|
+ imgIndex,
|
|
|
+ '内物图',
|
|
|
+ )
|
|
|
+ "
|
|
|
+ width="100%"
|
|
|
+ height="60"
|
|
|
+ :src="i.src"
|
|
|
+ />
|
|
|
+ </van-col>
|
|
|
+ </template>
|
|
|
+ </van-row>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="card-div-footer-options">
|
|
|
+ <div class="options-row">
|
|
|
+ <div class="info-value">
|
|
|
+ <van-button
|
|
|
+ size="mini"
|
|
|
+ type="danger"
|
|
|
+ block
|
|
|
+ plain
|
|
|
+ @click="removeDetails(index)"
|
|
|
+ >删除
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ <div class="info-value">
|
|
|
+ <van-button
|
|
|
+ size="mini"
|
|
|
+ type="default"
|
|
|
+ block
|
|
|
+ plain
|
|
|
+ @click="editDetails(index)"
|
|
|
+ >编辑
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <van-floating-bubble
|
|
|
+ axis="xy"
|
|
|
+ icon="add"
|
|
|
+ magnetic="x"
|
|
|
+ @click="showScancode"
|
|
|
+ />
|
|
|
+ </van-tab>
|
|
|
+ </van-tabs>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <van-dialog
|
|
|
+ v-model:show="scancodeDialog"
|
|
|
+ title="扫描条码"
|
|
|
+ @open="openScanCode"
|
|
|
+ @confirm="showQualityStatus"
|
|
|
+ show-cancel-button
|
|
|
+ >
|
|
|
+ <van-field
|
|
|
+ ref="scancodeInputRef"
|
|
|
+ v-model="scancode"
|
|
|
+ label="商品条码"
|
|
|
+ autocomplete="off"
|
|
|
+ @keyup.enter="showQualityStatus"
|
|
|
+ placeholder="商品条码"
|
|
|
+ />
|
|
|
+ </van-dialog>
|
|
|
+
|
|
|
+ <van-dialog
|
|
|
+ v-model:show="qualityStatusDialog"
|
|
|
+ title="质量状态"
|
|
|
+ @confirm="queryBarcode"
|
|
|
+ show-cancel-button
|
|
|
+ >
|
|
|
+ <van-radio-group v-model="qualityStatus">
|
|
|
+ <template v-for="(item, index) in qualityStatusOptions">
|
|
|
+ <van-cell
|
|
|
+ :title="item.text"
|
|
|
+ clickable
|
|
|
+ @click="qualityStatus = item.value"
|
|
|
+ >
|
|
|
+ <template #right-icon>
|
|
|
+ <van-radio :name="item.value" />
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ </template>
|
|
|
+ </van-radio-group>
|
|
|
+ </van-dialog>
|
|
|
+
|
|
|
+ <van-dialog
|
|
|
+ v-model:show="returnedDetailDialog"
|
|
|
+ title="商品详情"
|
|
|
+ show-cancel-button
|
|
|
+ :lazy-render="true"
|
|
|
+ :show-confirm-button="checkUploadImages()"
|
|
|
+ @confirm="addDetails"
|
|
|
+ @cancel="cancelReturnedDetailDialog"
|
|
|
+ >
|
|
|
+ <div style="max-height: 70vh; overflow-y: auto">
|
|
|
+ <van-field
|
|
|
+ v-model="selectDetail.sku"
|
|
|
+ label="SKU"
|
|
|
+ placeholder="SKU"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ readonly
|
|
|
+ v-model="selectDetail.barCode"
|
|
|
+ label="商品条码"
|
|
|
+ placeholder="商品条码"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ v-model="selectDetail.tradeName"
|
|
|
+ label="商品名称"
|
|
|
+ placeholder="商品名称"
|
|
|
+ readonly
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ readonly
|
|
|
+ clickable
|
|
|
+ label="质量状态"
|
|
|
+ placeholder="质量状态"
|
|
|
+ v-model="selectDetail.qualityStatus"
|
|
|
+ @click="selectedDetailQualityStatus = true"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model:show="selectedDetailQualityStatus"
|
|
|
+ position="bottom"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <van-picker
|
|
|
+ :columns="qualityStatusOptions"
|
|
|
+ @cancel="selectedDetailQualityStatus = false"
|
|
|
+ @confirm="selectedDetailQualityStatusFunc"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="datePicker"
|
|
|
+ label="生产日期"
|
|
|
+ :placeholder="selectDetail.manufactureTime ? '' : '请选择生产日期'"
|
|
|
+ :model-value="formatDateDisplay(selectDetail.manufactureTime)"
|
|
|
+ @click="showManufactureTime = true"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showManufactureTime"
|
|
|
+ destroy-on-close
|
|
|
+ position="bottom"
|
|
|
+ >
|
|
|
+ <van-date-picker
|
|
|
+ :max-date="maxDate"
|
|
|
+ :min-date="minDate"
|
|
|
+ :model-value="parseDateValue(selectDetail.manufactureTime)"
|
|
|
+ @confirm="manufactureTimeConfirm"
|
|
|
+ @cancel="showManufactureTime = false"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ :model-value="formatDateDisplay(selectDetail.validityTime)"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="datePicker"
|
|
|
+ label="失效日期"
|
|
|
+ :placeholder="selectDetail.validityTime ? '' : '请选择失效日期'"
|
|
|
+ @click="showValidityTime = true"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showValidityTime"
|
|
|
+ destroy-on-close
|
|
|
+ position="bottom"
|
|
|
+ >
|
|
|
+ <van-date-picker
|
|
|
+ :max-date="maxDate"
|
|
|
+ :min-date="minDate"
|
|
|
+ :model-value="parseDateValue(selectDetail.validityTime)"
|
|
|
+ @confirm="validityTimeConfirm"
|
|
|
+ @cancel="showValidityTime = false"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ autocomplete="off"
|
|
|
+ v-model="selectDetail.batchNumber"
|
|
|
+ label="批次号"
|
|
|
+ placeholder="批次号"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="selectDetail.number"
|
|
|
+ label="数量"
|
|
|
+ type="digit"
|
|
|
+ placeholder="数量"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-field
|
|
|
+ v-model="selectDetail.remark"
|
|
|
+ label="备注"
|
|
|
+ placeholder="备注"
|
|
|
+ label-align="top"
|
|
|
+ />
|
|
|
+
|
|
|
+ <van-row v-if="showAccessories">
|
|
|
+ <div style="font-size: 12px">
|
|
|
+ <template v-for="(item, index) in accessories">
|
|
|
+ <p>
|
|
|
+ 配件条码: [<span style="color: #2ca547">{{
|
|
|
+ item.accessory
|
|
|
+ }}</span
|
|
|
+ >] [<span style="color: #277b39">{{ item.descrC }}</span
|
|
|
+ >] 数量: [<span style="color: #2ca547">{{ item.qty }}</span
|
|
|
+ >]件
|
|
|
+ </p>
|
|
|
+ </template>
|
|
|
+ <p style="font-size: 12px">
|
|
|
+ 请检查商品: 【<span style="color: #ff2020">{{
|
|
|
+ selectDetail.sku
|
|
|
+ }}</span
|
|
|
+ >】 {{ selectDetail.tradeName }} 配件
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </van-row>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="selectDetail.boxPhotos && selectDetail.boxPhotos.length > 0"
|
|
|
+ >
|
|
|
+ <van-divider content-position="left" style="margin: 0px"
|
|
|
+ >外箱图
|
|
|
+ </van-divider>
|
|
|
+ <van-row>
|
|
|
+ <template
|
|
|
+ v-if="selectDetail.boxPhotos && selectDetail.boxPhotos.length > 0"
|
|
|
+ >
|
|
|
+ <template v-for="(item, index) in selectDetail.boxPhotos">
|
|
|
+ <van-col span="4">
|
|
|
+ <van-image
|
|
|
+ :key="`box-photos-${index}`"
|
|
|
+ width="100%"
|
|
|
+ height="50"
|
|
|
+ :src="getImageUrl(item, '外箱图')"
|
|
|
+ @click="showBoxImagePreview(index)"
|
|
|
+ />
|
|
|
+ </van-col>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <van-image-preview
|
|
|
+ v-model:show="showBoxPreview"
|
|
|
+ :images="detailBoxImages"
|
|
|
+ :start-position="startBoxPosition"
|
|
|
+ @change="onBoxPreviewChange"
|
|
|
+ closeable
|
|
|
+ >
|
|
|
+ <template #index>
|
|
|
+ <div class="custom-toolbar">
|
|
|
+ <span
|
|
|
+ >{{ startPhotosPosition + 1 }}/{{
|
|
|
+ selectDetail.boxPhotos.length
|
|
|
+ }}</span
|
|
|
+ >
|
|
|
+ <van-button
|
|
|
+ icon="delete"
|
|
|
+ type="danger"
|
|
|
+ @click.stop="handleBoxDelete"
|
|
|
+ size="mini"
|
|
|
+ >删除
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-image-preview>
|
|
|
+ </template>
|
|
|
+ </van-row>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template
|
|
|
+ v-if="
|
|
|
+ selectDetail.productPhotos && selectDetail.productPhotos.length > 0
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <van-divider content-position="left" style="margin: 0px"
|
|
|
+ >内物图
|
|
|
+ </van-divider>
|
|
|
+ <van-row>
|
|
|
+ <template v-for="(item, index) in selectDetail.productPhotos">
|
|
|
+ <van-col span="4">
|
|
|
+ <van-image
|
|
|
+ :key="`product-photos-${index}`"
|
|
|
+ width="100%"
|
|
|
+ height="50"
|
|
|
+ :src="getImageUrl(item, '内物图')"
|
|
|
+ @click="showPhotosImagePreview(index)"
|
|
|
+ />
|
|
|
+ </van-col>
|
|
|
+ </template>
|
|
|
+ </van-row>
|
|
|
+
|
|
|
+ <van-image-preview
|
|
|
+ v-model:show="showPhotosPreview"
|
|
|
+ :images="detailProductImages"
|
|
|
+ :start-position="startPhotosPosition"
|
|
|
+ @change="onPhotosPreviewChange"
|
|
|
+ closeable
|
|
|
+ >
|
|
|
+ <template #index>
|
|
|
+ <div class="custom-toolbar">
|
|
|
+ <span>
|
|
|
+ {{ startPhotosPosition + 1 }}/{{
|
|
|
+ selectDetail.productPhotos.length
|
|
|
+ }}
|
|
|
+ </span>
|
|
|
+ <van-button
|
|
|
+ icon="delete"
|
|
|
+ type="danger"
|
|
|
+ @click.stop="handlePhotosDelete"
|
|
|
+ size="mini"
|
|
|
+ >删除
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-image-preview>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <van-row>
|
|
|
+ <van-col span="12">
|
|
|
+ <van-button
|
|
|
+ type="primary"
|
|
|
+ block
|
|
|
+ @click="invokeCameraToCapture('外箱图')"
|
|
|
+ >外箱图录入
|
|
|
+ </van-button>
|
|
|
+ </van-col>
|
|
|
+ <van-col span="12">
|
|
|
+ <van-button
|
|
|
+ type="primary"
|
|
|
+ block
|
|
|
+ @click="invokeCameraToCapture('内物图')"
|
|
|
+ >内物图录入
|
|
|
+ </van-button>
|
|
|
+ </van-col>
|
|
|
+ </van-row>
|
|
|
+
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ id="outer-carton-box-input"
|
|
|
+ capture="user"
|
|
|
+ accept="image/*"
|
|
|
+ hidden
|
|
|
+ @change="outerCartonInput"
|
|
|
+ />
|
|
|
+
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ id="inner-contents-input"
|
|
|
+ capture="user"
|
|
|
+ accept="image/*"
|
|
|
+ hidden
|
|
|
+ @change="innerContentsInput"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </van-dialog>
|
|
|
+
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showOwnerSelect"
|
|
|
+ destroy-on-close
|
|
|
+ round
|
|
|
+ position="bottom"
|
|
|
+ >
|
|
|
+ <van-picker
|
|
|
+ :model-value="getOwnerName(params.ownerCode)"
|
|
|
+ :columns="ownerSelectedOptions"
|
|
|
+ @cancel="showOwnerSelect = false"
|
|
|
+ @confirm="selectOwner"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+ <owner ref="ownerRef" @onOwner="onOwner" />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, nextTick, onMounted } from 'vue'
|
|
|
+import {
|
|
|
+ showFailToast,
|
|
|
+ showNotify,
|
|
|
+ showLoadingToast,
|
|
|
+ closeToast,
|
|
|
+ showConfirmDialog,
|
|
|
+ showImagePreview
|
|
|
+} from 'vant'
|
|
|
+import { getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
|
|
|
+import {
|
|
|
+ deleteDetails,
|
|
|
+ getQualityInspection,
|
|
|
+ getQualityInspectionBy,
|
|
|
+ getQualityStatus,
|
|
|
+ getReturnedByExpress,
|
|
|
+ getTagColorBy,
|
|
|
+ listAsn,
|
|
|
+ matchAsnBy,
|
|
|
+ matchCarrierCode,
|
|
|
+ matchOrderBy,
|
|
|
+ register,
|
|
|
+ searchBarcode,
|
|
|
+ searchOwnerBarcode,
|
|
|
+ shops,
|
|
|
+ validateDate
|
|
|
+} from '@/api/returned/index.ts'
|
|
|
+import { carrierOptions, getOwner, getWarehouse } from '@/api/basic/index.ts'
|
|
|
+import { useStore } from '@/store/modules/user'
|
|
|
+import { getStatus } from '@/utils/returned.ts'
|
|
|
+import Owner from '@/components/Owner.vue'
|
|
|
+
|
|
|
+try {
|
|
|
+ getHeader()
|
|
|
+} catch (error) {
|
|
|
+ console.log(error)
|
|
|
+}
|
|
|
+
|
|
|
+const minDate = ref(new Date(new Date().getFullYear() - 5, 0, 1))
|
|
|
+const maxDate = ref(new Date((new Date().getFullYear() + 50, 0, 1)))
|
|
|
+
|
|
|
+const showInitialPage = ref(true)
|
|
|
+const expressNo = ref(null)
|
|
|
+const store = useStore()
|
|
|
+const warehouse = store.warehouse
|
|
|
+// 当前选择的货主
|
|
|
+
|
|
|
+const title = computed(() => {
|
|
|
+ if (expressNo.value && showInitialPage.value === false) {
|
|
|
+ return '退货登记:' + params.value.returnNo
|
|
|
+ }
|
|
|
+ return '退货登记'
|
|
|
+})
|
|
|
+
|
|
|
+const qualityStatusOptions = ref([])
|
|
|
+// 货主
|
|
|
+const owners = ref([])
|
|
|
+// 仓库
|
|
|
+const warehouses = ref([])
|
|
|
+// 承运商
|
|
|
+const logistics = ref([])
|
|
|
+// 店铺
|
|
|
+const storeOptions = ref([])
|
|
|
+// 选中相关信息的下标
|
|
|
+const selectDetailIndex = ref(-1)
|
|
|
+
|
|
|
+const ownerMap = ref({})
|
|
|
+
|
|
|
+const warehousesMap = ref({})
|
|
|
+const logisticsMap = ref({})
|
|
|
+
|
|
|
+const asnList = ref({})
|
|
|
+// 外箱图
|
|
|
+const boxFiles = ref([])
|
|
|
+// 内物图
|
|
|
+const productFiles = ref([])
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const now = new Date()
|
|
|
+ const currentYear = now.getFullYear()
|
|
|
+ const currentCentury = Math.floor(currentYear / 100) * 100
|
|
|
+ const endOfCenturyYear = currentCentury + 99
|
|
|
+
|
|
|
+ maxDate.value = new Date(endOfCenturyYear, 0, 1)
|
|
|
+ minDate.value = new Date(currentCentury, 0, 1)
|
|
|
+
|
|
|
+ console.log(warehouse)
|
|
|
+
|
|
|
+ getOwner().then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ owners.value = data.map((item) => {
|
|
|
+ return { value: item.code, text: item.name }
|
|
|
+ })
|
|
|
+ const map = {}
|
|
|
+ data.forEach((item) => {
|
|
|
+ map[item.code] = item.name
|
|
|
+ })
|
|
|
+ ownerMap.value = map
|
|
|
+ })
|
|
|
+ getQualityStatus().then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ qualityStatusOptions.value = data
|
|
|
+ .filter((item) => {
|
|
|
+ return item !== '机损'
|
|
|
+ })
|
|
|
+ .map((item) => {
|
|
|
+ return { value: item, text: item }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ getWarehouse().then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ warehouses.value = data.map((item) => {
|
|
|
+ return { value: item.code, text: item.name }
|
|
|
+ })
|
|
|
+ const map = {}
|
|
|
+ data.forEach((item) => {
|
|
|
+ map[item.code] = item.name
|
|
|
+ })
|
|
|
+ warehousesMap.value = map
|
|
|
+ })
|
|
|
+
|
|
|
+ carrierOptions().then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ logistics.value = data.map((item) => {
|
|
|
+ return { value: item.name, text: item.name }
|
|
|
+ })
|
|
|
+ const map = {}
|
|
|
+ data.forEach((item) => {
|
|
|
+ map[item.name] = item.name
|
|
|
+ })
|
|
|
+ logisticsMap.value = map
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+// 商品外箱图
|
|
|
+function hasBoxItems(detail) {
|
|
|
+ const { boxPhotos } = detail
|
|
|
+ if (!boxPhotos || boxPhotos.length === 0) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return boxFiles.value.some((item) => {
|
|
|
+ return boxPhotos.includes(item.fileName)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 商品外箱图
|
|
|
+function getBoxItems(detail) {
|
|
|
+ const { boxPhotos } = detail
|
|
|
+ if (!boxPhotos || boxPhotos.length === 0) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ return boxFiles.value.filter((item) => boxPhotos.includes(item.fileName))
|
|
|
+}
|
|
|
+
|
|
|
+// 商品外箱图
|
|
|
+function hasProductItems(detail) {
|
|
|
+ const { productPhotos } = detail
|
|
|
+ if (!productPhotos || productPhotos.length === 0) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return productFiles.value.some((item) => {
|
|
|
+ return productPhotos.includes(item.fileName)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 商品内物图
|
|
|
+function getProductItems(detail) {
|
|
|
+ const { productPhotos } = detail
|
|
|
+ if (!productPhotos || productPhotos.length === 0) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ return productFiles.value.filter((item) => {
|
|
|
+ return productPhotos.includes(item.fileName)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 获取对应的店铺信息
|
|
|
+async function getStoreOptionsBy(owner) {
|
|
|
+ const results = await shops(owner)
|
|
|
+ const { data } = results
|
|
|
+ if (!data || data.length === 0) {
|
|
|
+ storeOptions.value = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+ storeOptions.value = data.map((item) => {
|
|
|
+ return { value: item.name, text: item.name }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const qualityInspection = ref(null)
|
|
|
+
|
|
|
+// 初始化质检状态
|
|
|
+function initQualityInspection(owner) {
|
|
|
+ getQualityInspection(owner).then((res) => {
|
|
|
+ qualityInspection.value = res.data
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const ownerQualityInspection = computed(() => {
|
|
|
+ return getQualityInspectionBy(qualityInspection.value)
|
|
|
+})
|
|
|
+
|
|
|
+// 扫描商品条码
|
|
|
+const scancode = ref('')
|
|
|
+// 商品质量状态
|
|
|
+const qualityStatus = ref('')
|
|
|
+// 提交的商品信息
|
|
|
+const params = ref({
|
|
|
+ id: null,
|
|
|
+ returnNo: null,
|
|
|
+ warehouseCode: warehouse,
|
|
|
+ logisticsName: null,
|
|
|
+ storeName: null,
|
|
|
+ upstreamNo: null,
|
|
|
+ ownerCode: null,
|
|
|
+ orderUpstream: null,
|
|
|
+ orderUpSteam: null,
|
|
|
+ arrivalPayment: null,
|
|
|
+ buyerName: null,
|
|
|
+ asnNo: null,
|
|
|
+ buyerPhone: null,
|
|
|
+ originalNo: null,
|
|
|
+ remark: null,
|
|
|
+ details: []
|
|
|
+})
|
|
|
+
|
|
|
+// 商品信息
|
|
|
+const selectDetail = ref({
|
|
|
+ id: null,
|
|
|
+ rejectHeadId: null,
|
|
|
+ rejectPushTaskNo: null,
|
|
|
+ status: null,
|
|
|
+ detailStatus: null,
|
|
|
+ isGenuine: null,
|
|
|
+ qualityMark: null,
|
|
|
+ sku: '',
|
|
|
+ barCode: '',
|
|
|
+ tradeName: '',
|
|
|
+ qualityStatus: '',
|
|
|
+ manufactureTime: '',
|
|
|
+ validityTime: '',
|
|
|
+ batchNumber: '',
|
|
|
+ remark: '',
|
|
|
+ asnNo: null,
|
|
|
+ number: 0,
|
|
|
+ warehouse: null,
|
|
|
+ warehouseBin: null,
|
|
|
+ boxPhotos: [],
|
|
|
+ productPhotos: [],
|
|
|
+ files: null,
|
|
|
+ pieceTag: null,
|
|
|
+ createTime: null,
|
|
|
+ creatorId: null,
|
|
|
+ updateTime: null,
|
|
|
+ updaterId: null,
|
|
|
+ deleteTime: null,
|
|
|
+ version: null,
|
|
|
+ repairableType: null,
|
|
|
+ repairableTypes: null,
|
|
|
+ operatorId: null,
|
|
|
+ operatorName: null,
|
|
|
+ operatorTime: null,
|
|
|
+ skuImage: null,
|
|
|
+ orginSkuImage: null
|
|
|
+})
|
|
|
+
|
|
|
+function initDetail() {
|
|
|
+ selectDetail.value = {
|
|
|
+ id: null,
|
|
|
+ rejectHeadId: null,
|
|
|
+ rejectPushTaskNo: null,
|
|
|
+ status: null,
|
|
|
+ detailStatus: null,
|
|
|
+ isGenuine: null,
|
|
|
+ qualityMark: null,
|
|
|
+ sku: '',
|
|
|
+ barCode: '',
|
|
|
+ tradeName: '',
|
|
|
+ qualityStatus: '',
|
|
|
+ manufactureTime: '',
|
|
|
+ validityTime: '',
|
|
|
+ batchNumber: '',
|
|
|
+ remark: '',
|
|
|
+ asnNo: null,
|
|
|
+ number: null,
|
|
|
+ warehouse: null,
|
|
|
+ warehouseBin: null,
|
|
|
+ boxPhotos: [],
|
|
|
+ productPhotos: [],
|
|
|
+ files: null,
|
|
|
+ pieceTag: null,
|
|
|
+ createTime: null,
|
|
|
+ creatorId: null,
|
|
|
+ updateTime: null,
|
|
|
+ updaterId: null,
|
|
|
+ deleteTime: null,
|
|
|
+ version: null,
|
|
|
+ repairableType: null,
|
|
|
+ repairableTypes: null,
|
|
|
+ operatorId: null,
|
|
|
+ operatorName: null,
|
|
|
+ operatorTime: null,
|
|
|
+ skuImage: null,
|
|
|
+ orginSkuImage: null
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 承运商选择
|
|
|
+const logisticPickerShow = ref(false)
|
|
|
+const selectedLogistic = (row) => {
|
|
|
+ const { selectedOptions } = row
|
|
|
+ logisticPickerShow.value = false
|
|
|
+ params.value.logisticsName = selectedOptions[0].text
|
|
|
+}
|
|
|
+
|
|
|
+// 货主选择
|
|
|
+const ownerPickerShow = ref(false)
|
|
|
+const ownerName = ref('')
|
|
|
+const selectedOwner = (row) => {
|
|
|
+ const { selectedValues, selectedOptions } = row
|
|
|
+ ownerPickerShow.value = false
|
|
|
+ params.value.ownerCode = selectedOptions[0].value
|
|
|
+ ownerName.value = selectedOptions[0].text
|
|
|
+ initQualityInspection(params.value.ownerCode)
|
|
|
+}
|
|
|
+
|
|
|
+// 仓库选择
|
|
|
+const warehousePickerShow = ref(false)
|
|
|
+const selectedWarehouse = (row) => {
|
|
|
+ const { selectedOptions } = row
|
|
|
+ warehousePickerShow.value = false
|
|
|
+ params.value.warehouseCode = selectedOptions[0].value
|
|
|
+}
|
|
|
+
|
|
|
+// 店铺选择
|
|
|
+const storePickerShow = ref(false)
|
|
|
+const selectedStore = (row) => {
|
|
|
+ const { selectedOptions } = row
|
|
|
+ storePickerShow.value = false
|
|
|
+ params.value.storeName = selectedOptions[0].text
|
|
|
+}
|
|
|
+
|
|
|
+// 承运商名称
|
|
|
+function getLogisticName() {
|
|
|
+ return params.value.logisticsName
|
|
|
+}
|
|
|
+
|
|
|
+// 货主名
|
|
|
+function getOwnerName(owner) {
|
|
|
+ return ownerMap.value[owner]
|
|
|
+}
|
|
|
+
|
|
|
+// 仓库名
|
|
|
+function getWarehouseName() {
|
|
|
+ console.log(params.value.warehouseCode)
|
|
|
+ return warehousesMap.value[params.value.warehouseCode]
|
|
|
+}
|
|
|
+
|
|
|
+// 输入快递单号
|
|
|
+function inputExpressNo() {
|
|
|
+ const no = expressNo.value
|
|
|
+ const isSuccess = checkExpressNo(no)
|
|
|
+ if (!isSuccess) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const express_no = initExpressNo(no)
|
|
|
+ if (!express_no || express_no.length === 0) {
|
|
|
+ showFailToast('快递单号异常')
|
|
|
+ scanError()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ params.value.returnNo = express_no
|
|
|
+ params.value.warehouseCode = warehouse
|
|
|
+ listAsn(express_no).then((res) => {
|
|
|
+ if (res.data) {
|
|
|
+ asnList.value = res.data
|
|
|
+ }
|
|
|
+ })
|
|
|
+ matchReturned(express_no)
|
|
|
+}
|
|
|
+
|
|
|
+function matchReturned(express_no) {
|
|
|
+ getReturnedByExpress(express_no).then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ if (!data) {
|
|
|
+ matchOrder(express_no)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const { id, headStatus, returnNo, warehouseCode } = data
|
|
|
+ if (!id) {
|
|
|
+ matchOrder(express_no)
|
|
|
+ expressNo.value = null
|
|
|
+ showInitialPage.value = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (id) {
|
|
|
+ if (['已入仓', '已拆包'].includes(headStatus)) {
|
|
|
+ showNotify({
|
|
|
+ type: 'primary',
|
|
|
+ message: `当前退回单号${returnNo}--${headStatus}`
|
|
|
+ })
|
|
|
+ init(false)
|
|
|
+ params.value.id = id
|
|
|
+ params.value.returnNo = returnNo
|
|
|
+ params.value.warehouseCode = warehouseCode
|
|
|
+ params.value.warehousingStatus = null
|
|
|
+ selectDetailIndex.value = -1
|
|
|
+ matchOrder(express_no)
|
|
|
+ expressNo.value = null
|
|
|
+ showInitialPage.value = false
|
|
|
+ scanSuccess()
|
|
|
+ } else {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: '当前退回单号已进行过登记 如需修改请前往PC端进行'
|
|
|
+ })
|
|
|
+ scanSuccess()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 匹配原单信息
|
|
|
+function matchOrder(expressNo) {
|
|
|
+ matchOrderBy(expressNo).then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ if (!data) {
|
|
|
+ console.log('未匹配到订单信息')
|
|
|
+ matchAsn(expressNo)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ console.log('匹配到订单信息')
|
|
|
+ if (data) {
|
|
|
+ const {
|
|
|
+ upstreamNo,
|
|
|
+ shopName,
|
|
|
+ ownerCode,
|
|
|
+ recipientName,
|
|
|
+ phone,
|
|
|
+ logisticName,
|
|
|
+ details
|
|
|
+ } = data
|
|
|
+ showNotify({ type: 'success', message: '匹配到原单信息' })
|
|
|
+ params.value.upstreamNo = upstreamNo
|
|
|
+ params.value.ownerCode = ownerCode
|
|
|
+ params.value.warehouseCode = warehouse
|
|
|
+ params.value.storeName = shopName
|
|
|
+ params.value.logisticsName = logisticName
|
|
|
+ params.value.buyerName = handlerLongText(recipientName)
|
|
|
+ params.value.buyerPhone = handlerLongText(phone)
|
|
|
+ params.value.originalNo = '原单退回'
|
|
|
+ params.value.sendNo = null
|
|
|
+ initQualityInspection(params.value.ownerCode)
|
|
|
+ getStoreOptionsBy(ownerCode)
|
|
|
+ if (!details || details.length === 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const list = []
|
|
|
+ details.forEach((item) => {
|
|
|
+ const {
|
|
|
+ sku,
|
|
|
+ barCode,
|
|
|
+ detailAmount,
|
|
|
+ name,
|
|
|
+ productionDate,
|
|
|
+ expirationDate,
|
|
|
+ batchNumber,
|
|
|
+ quality,
|
|
|
+ attributeBin
|
|
|
+ } = item
|
|
|
+ let qualityStatus
|
|
|
+ if (quality) {
|
|
|
+ if (quality === 'ZP') {
|
|
|
+ qualityStatus = '正品'
|
|
|
+ qualityStatus = '正品'
|
|
|
+ } else if (quality === 'CP') {
|
|
|
+ qualityStatus = '次品'
|
|
|
+ } else {
|
|
|
+ qualityStatus = '正品'
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ qualityStatus = '正品'
|
|
|
+ }
|
|
|
+ list.push({
|
|
|
+ sku: sku,
|
|
|
+ tradeName: name,
|
|
|
+ barCode: barCode,
|
|
|
+ number: detailAmount,
|
|
|
+ manufactureTime: productionDate,
|
|
|
+ validityTime: expirationDate,
|
|
|
+ batchNumber: batchNumber,
|
|
|
+ warehouse: attributeBin,
|
|
|
+ qualityStatus: qualityStatus,
|
|
|
+ isOriginal: true
|
|
|
+ })
|
|
|
+ params.value.details = list
|
|
|
+ matchCarrier(expressNo)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ matchAsn(expressNo)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function matchCarrier(expressNo) {
|
|
|
+ matchCarrierCode(expressNo).then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ if (!data || data.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'primary',
|
|
|
+ message: '请手动选择承运商'
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ params.value.logisticsName = data
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 转化加密
|
|
|
+function handlerLongText(text) {
|
|
|
+ return text && text.length > 15 ? '加密' : text ? text : null
|
|
|
+}
|
|
|
+
|
|
|
+// 匹配对应的ASN
|
|
|
+function matchAsn(expressNo) {
|
|
|
+ matchAsnBy(expressNo).then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ if (!data) {
|
|
|
+ console.log('未匹配asn单信息')
|
|
|
+ matchCarrier(expressNo)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const {
|
|
|
+ ownerCode,
|
|
|
+ phone,
|
|
|
+ shopName,
|
|
|
+ recipientName,
|
|
|
+ logisticName,
|
|
|
+ upstreamNo
|
|
|
+ } = data
|
|
|
+ params.value.returnNo = expressNo
|
|
|
+ params.value.upstreamNo = upstreamNo
|
|
|
+ params.value.ownerCode = ownerCode
|
|
|
+ params.value.warehouseCode = warehouse
|
|
|
+ params.value.storeName = shopName
|
|
|
+ params.value.logisticsName = logisticName
|
|
|
+ params.value.buyerName = handlerLongText(recipientName)
|
|
|
+ params.value.buyerPhone = handlerLongText(phone)
|
|
|
+ params.value.originalNo = null
|
|
|
+ params.value.sendNo = null
|
|
|
+ params.value.details = []
|
|
|
+ matchCarrier(expressNo)
|
|
|
+ getStoreOptionsBy(ownerCode)
|
|
|
+ initQualityInspection(params.value.ownerCode)
|
|
|
+ initDetail()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 校验快递单号格式
|
|
|
+function checkExpressNo(no) {
|
|
|
+ if (!no || no.length === 0) {
|
|
|
+ showFailToast('单号长度异常')
|
|
|
+ scanError()
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (no.startsWith('http')) {
|
|
|
+ showFailToast('扫描到了错误的条码')
|
|
|
+ scanError()
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (no.endsWith('.com')) {
|
|
|
+ showFailToast('扫描到了错误的条码')
|
|
|
+ scanError()
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ const length = no.length
|
|
|
+ if (length > 30 || length < 5) {
|
|
|
+ showFailToast('单号长度异常')
|
|
|
+ scanError()
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+// 处理快递单号相关问题
|
|
|
+function initExpressNo(no) {
|
|
|
+ // 处理扫描快递单号
|
|
|
+ if (!no) {
|
|
|
+ return no
|
|
|
+ }
|
|
|
+ if (no.includes('-')) {
|
|
|
+ no = no.substring(0, no.indexOf('-')) // 京东快递异常
|
|
|
+ }
|
|
|
+ return no
|
|
|
+ .replaceAll('-', '')
|
|
|
+ .replaceAll(' ', '')
|
|
|
+ .replaceAll('R02Z', '')
|
|
|
+ .replaceAll('R02T', '') // 圆通退回单号异常
|
|
|
+}
|
|
|
+
|
|
|
+// 重置提交 恢复到扫描快递单号页面
|
|
|
+function init(showInputPage = true) {
|
|
|
+ ownerName.value = null
|
|
|
+ clearImageFileCache()
|
|
|
+ params.value = {
|
|
|
+ orderUpstream: null,
|
|
|
+ returnNo: null,
|
|
|
+ warehouseCode: warehouse,
|
|
|
+ logisticsName: null,
|
|
|
+ storeName: null,
|
|
|
+ orderUpSteam: null,
|
|
|
+ arrivalPayment: null,
|
|
|
+ buyerName: null,
|
|
|
+ asnNo: null,
|
|
|
+ upstreamNo: null,
|
|
|
+ buyerPhone: null,
|
|
|
+ originalNo: null,
|
|
|
+ remark: null,
|
|
|
+ details: []
|
|
|
+ }
|
|
|
+ storeOptions.value = []
|
|
|
+ expressNo.value = null
|
|
|
+ showInitialPage.value = showInputPage
|
|
|
+ initDetail()
|
|
|
+}
|
|
|
+
|
|
|
+// 扫码弹框
|
|
|
+const scancodeDialog = ref(false)
|
|
|
+const scancodeInputRef = ref(false)
|
|
|
+
|
|
|
+const qualityStatusDialog = ref(false)
|
|
|
+
|
|
|
+// 扫描条码dialog
|
|
|
+function showScancode() {
|
|
|
+ scancodeDialog.value = true
|
|
|
+}
|
|
|
+
|
|
|
+function openScanCode() {
|
|
|
+ nextTick(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ const input = scancodeInputRef.value?.$el?.querySelector('input')
|
|
|
+ input?.focus()
|
|
|
+ input?.setSelectionRange(0, input.value.length)
|
|
|
+ }, 150)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 选择质量状态
|
|
|
+function showQualityStatus() {
|
|
|
+ const barcode = scancode.value
|
|
|
+ if (!barcode) {
|
|
|
+ showFailToast('商品条码异常')
|
|
|
+ scancodeDialog.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+ scanSuccess()
|
|
|
+ qualityStatusDialog.value = true
|
|
|
+ qualityStatus.value = '正品'
|
|
|
+}
|
|
|
+
|
|
|
+// 查询商品
|
|
|
+async function queryBarcode() {
|
|
|
+ showLoadingToast({
|
|
|
+ duration: 0,
|
|
|
+ forbidClick: true,
|
|
|
+ message: '查询商品信息中.....'
|
|
|
+ })
|
|
|
+ const barcode = scancode.value
|
|
|
+ const { ownerCode, details } = params.value
|
|
|
+ if (ownerCode) {
|
|
|
+ const result = await queryOwnerBarcode(ownerCode, barcode)
|
|
|
+ if (result) {
|
|
|
+ scanSuccess()
|
|
|
+ scancodeDialog.value = false
|
|
|
+ qualityStatusDialog.value = false
|
|
|
+ closeToast()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!details || details.length === 0) {
|
|
|
+ await queryBarcodeBy(barcode)
|
|
|
+ scancodeDialog.value = false
|
|
|
+ qualityStatusDialog.value = false
|
|
|
+ closeToast()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 根据获取查询信息
|
|
|
+async function queryOwnerBarcode(ownerCode, barcode) {
|
|
|
+ try {
|
|
|
+ const results = await searchOwnerBarcode({ ownerCode, barcode })
|
|
|
+ const {
|
|
|
+ data: { basSku }
|
|
|
+ } = results
|
|
|
+ if (!basSku) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ addDetailByBasSku(basSku)
|
|
|
+ return true
|
|
|
+ } catch (err) {
|
|
|
+ closeToast()
|
|
|
+ console.log(err.message)
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+async function queryBarcodeBy(barcode) {
|
|
|
+ try {
|
|
|
+ const results = await searchBarcode({ barcode })
|
|
|
+ const { data } = results
|
|
|
+ const { basSku, ownerCodes } = data
|
|
|
+ if (ownerCodes && ownerCodes.length > 1) {
|
|
|
+ showOwnerSelectDialog(ownerCodes)
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ if (!basSku) {
|
|
|
+ scanError()
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ addDetailByBasSku(basSku)
|
|
|
+ scanSuccess()
|
|
|
+ return null
|
|
|
+ } catch (err) {
|
|
|
+ closeToast()
|
|
|
+ scanError()
|
|
|
+ console.log(err.message)
|
|
|
+ }
|
|
|
+ scanError()
|
|
|
+ return null
|
|
|
+}
|
|
|
+
|
|
|
+// 添加详情
|
|
|
+function addDetailByBasSku(basSku) {
|
|
|
+ const { sku, barCode, ownerCode, tradeName, accessories } = basSku
|
|
|
+ selectDetailIndex.value = -1
|
|
|
+ selectDetail.value.sku = sku
|
|
|
+ if (
|
|
|
+ !params.value.ownerCode ||
|
|
|
+ !params.value.details ||
|
|
|
+ params.value.details.length === 0
|
|
|
+ ) {
|
|
|
+ params.value.ownerCode = ownerCode
|
|
|
+ initQualityInspection(params.value.ownerCode)
|
|
|
+ getStoreOptionsBy(params.value.ownerCode)
|
|
|
+ }
|
|
|
+ selectDetail.value.barCode = barCode
|
|
|
+ selectDetail.value.qualityStatus = qualityStatus.value
|
|
|
+ selectDetail.value.tradeName = tradeName
|
|
|
+ selectDetail.value.number = 1
|
|
|
+ scancodeDialog.value = false
|
|
|
+ qualityStatusDialog.value = false
|
|
|
+ returnedDetailDialog.value = true
|
|
|
+ // 显示
|
|
|
+ showAccessoriesItems(accessories)
|
|
|
+}
|
|
|
+
|
|
|
+const accessories = ref([])
|
|
|
+const showAccessories = ref(false)
|
|
|
+
|
|
|
+function showAccessoriesItems(items) {
|
|
|
+ if (!items || items.length === 0) {
|
|
|
+ accessories.value = []
|
|
|
+ showAccessories.value = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ accessories.value = items
|
|
|
+ showAccessories.value = true
|
|
|
+}
|
|
|
+
|
|
|
+// 质量状态
|
|
|
+const returnedDetailDialog = ref(false)
|
|
|
+const selectedDetailQualityStatus = ref(false)
|
|
|
+const selectedDetailQualityStatusFunc = (row) => {
|
|
|
+ const { selectedOptions } = row
|
|
|
+ selectedDetailQualityStatus.value = false
|
|
|
+ selectDetail.value.qualityStatus = selectedOptions[0].text
|
|
|
+}
|
|
|
+
|
|
|
+// 辅助函数:格式化日期显示(可选)
|
|
|
+const formatDateDisplay = (dateString) => {
|
|
|
+ if (!dateString) return ''
|
|
|
+ return dateString.replace(/-/g, '/') // 将 2023-05-01 显示为 2023/05/01
|
|
|
+}
|
|
|
+// 辅助函数:将日期字符串转换为数组格式 [年, 月, 日]
|
|
|
+const parseDateValue = (dateString) => {
|
|
|
+ if (!dateString) return []
|
|
|
+ const [year, month, day] = dateString.split('-')
|
|
|
+ return [year, month, day]
|
|
|
+}
|
|
|
+
|
|
|
+// 生产日期
|
|
|
+const showManufactureTime = ref(false)
|
|
|
+const manufactureTimeConfirm = async (result) => {
|
|
|
+ if (!result.selectedValues) {
|
|
|
+ showManufactureTime.value = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 正确解构参数
|
|
|
+ const { selectedValues } = result
|
|
|
+ const [year, month, day] = selectedValues
|
|
|
+ const formatted_month = month.padStart(2, '0')
|
|
|
+ const formatted_day = day.padStart(2, '0')
|
|
|
+ const manufactureTime = `${year}-${formatted_month}-${formatted_day}`
|
|
|
+ const { sku } = selectDetail.value
|
|
|
+ const { ownerCode } = params.value
|
|
|
+ const check_validate_date = await checkValidateDate(
|
|
|
+ ownerCode,
|
|
|
+ sku,
|
|
|
+ manufactureTime,
|
|
|
+ 'manufactureTime'
|
|
|
+ )
|
|
|
+ if (!check_validate_date) {
|
|
|
+ console.log('检验出现异常')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ selectDetail.value.manufactureTime = manufactureTime
|
|
|
+ showManufactureTime.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 失效日期
|
|
|
+const showValidityTime = ref(false)
|
|
|
+const validityTimeConfirm = async (result) => {
|
|
|
+ if (!result.selectedValues) {
|
|
|
+ showValidityTime.value = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 正确解构参数
|
|
|
+ const { selectedValues } = result
|
|
|
+ const [year, month, day] = selectedValues
|
|
|
+ const formatted_month = month.padStart(2, '0')
|
|
|
+ const formatted_day = day.padStart(2, '0')
|
|
|
+ const validityTime = `${year}-${formatted_month}-${formatted_day}`
|
|
|
+ const { sku } = selectDetail.value
|
|
|
+ const { ownerCode } = params.value
|
|
|
+ const check_validate_date = await checkValidateDate(
|
|
|
+ ownerCode,
|
|
|
+ sku,
|
|
|
+ validityTime,
|
|
|
+ 'validityTime'
|
|
|
+ )
|
|
|
+ if (!check_validate_date) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ selectDetail.value.validityTime = `${year}-${formatted_month}-${formatted_day}`
|
|
|
+ showValidityTime.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 质量状态标签
|
|
|
+function getTagColor(qualityStatus) {
|
|
|
+ return getTagColorBy(qualityStatus)
|
|
|
+}
|
|
|
+
|
|
|
+const cancelReturnedDetailDialog = async () => {
|
|
|
+ returnedDetailDialog.value = false
|
|
|
+ initDetail()
|
|
|
+}
|
|
|
+
|
|
|
+const addDetails = async () => {
|
|
|
+ const isCheck = checkUploadImages()
|
|
|
+ if (!isCheck) {
|
|
|
+ returnedDetailDialog.value = true
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ const index = selectDetailIndex.value
|
|
|
+ const detail = JSON.parse(JSON.stringify(selectDetail.value))
|
|
|
+ if (index > -1) {
|
|
|
+ params.value.details[index] = detail
|
|
|
+ initDetail()
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ const {
|
|
|
+ sku: detail_sku,
|
|
|
+ batchNumber: detail_batch_number,
|
|
|
+ validityTime: detail_validity_time,
|
|
|
+ manufactureTime: detail_manufacture_time,
|
|
|
+ qualityStatus: detail_quality_status,
|
|
|
+ number: detailNumber
|
|
|
+ } = selectDetail.value
|
|
|
+ if (['次品', '待修复'].includes(detail_quality_status)) {
|
|
|
+ params.value.details.push(detail)
|
|
|
+ initDetail()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const searchIndex = params.value.details.findIndex((item) => {
|
|
|
+ const { sku, batchNumber, qualityStatus, validityTime, manufactureTime } =
|
|
|
+ item
|
|
|
+ return (
|
|
|
+ sku === detail_sku &&
|
|
|
+ batchNumber === detail_batch_number &&
|
|
|
+ detail_validity_time === validityTime &&
|
|
|
+ detail_manufacture_time === manufactureTime &&
|
|
|
+ detail_quality_status === qualityStatus
|
|
|
+ )
|
|
|
+ })
|
|
|
+ if (searchIndex > -1) {
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '系统提示',
|
|
|
+ message: '查询到有对应的商品详情是否进行合并'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ const { number } = params.value.details[searchIndex]
|
|
|
+ params.value.details[searchIndex].number =
|
|
|
+ Number(detailNumber) + Number(number)
|
|
|
+ showNotify({ type: 'success', message: '合并成功' })
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ params.value.details.push(detail)
|
|
|
+ showNotify({ type: 'success', message: '添加成功' })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ params.value.details.push(detail)
|
|
|
+ }
|
|
|
+ initDetail()
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+// 删除对应的详情
|
|
|
+function removeDetails(index) {
|
|
|
+ if (null === index) {
|
|
|
+ showFailToast('未找到对应的详情')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '系统提示',
|
|
|
+ message: '是否删除当前登记信息'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ const { id } = params.value.details[index]
|
|
|
+ if (!id) {
|
|
|
+ params.value.details.splice(index, 1)
|
|
|
+ showNotify({ type: 'success', message: '删除成功' })
|
|
|
+ } else {
|
|
|
+ deleteDetails(id).then((res) => {
|
|
|
+ if (res.data) {
|
|
|
+ params.value.details.splice(index, 1)
|
|
|
+ showNotify({ type: 'success', message: '删除成功' })
|
|
|
+ } else {
|
|
|
+ showNotify({ type: 'danger', message: '删除失败' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ showNotify({ type: 'primary', message: '取消删除' })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function selectOwner({ selectedValues }) {
|
|
|
+ const ownerCode = selectedValues[0]
|
|
|
+ params.value.ownerCode = ownerCode
|
|
|
+ showOwnerSelect.value = false
|
|
|
+ ownerSelectedOptions.value = []
|
|
|
+ getStoreOptionsBy(ownerCode)
|
|
|
+ queryOwnerBarcode(params.value.ownerCode, scancode.value)
|
|
|
+}
|
|
|
+
|
|
|
+const ownerRef = ref(null)
|
|
|
+
|
|
|
+function showOwnerSelectFunc() {
|
|
|
+ ownerRef.value?.show(1)
|
|
|
+}
|
|
|
+
|
|
|
+// 指定货主
|
|
|
+const onOwner = (item, type) => {
|
|
|
+ params.value.ownerCode = item.code
|
|
|
+ getStoreOptionsBy(item.code)
|
|
|
+}
|
|
|
+
|
|
|
+const showOwnerSelect = ref(false)
|
|
|
+const ownerSelectedOptions = ref([])
|
|
|
+
|
|
|
+// 多货主选择
|
|
|
+function showOwnerSelectDialog(items) {
|
|
|
+ if (!items || items.length === 0) {
|
|
|
+ ownerSelectedOptions.value = owners.value.map((item) => {
|
|
|
+ JSON.parse(JSON.stringify(item))
|
|
|
+ })
|
|
|
+ showOwnerSelect.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ownerSelectedOptions.value = owners.value
|
|
|
+ .filter((item) => {
|
|
|
+ const { value } = item
|
|
|
+ return items.includes(value)
|
|
|
+ })
|
|
|
+ .map((item) => JSON.parse(JSON.stringify(item)))
|
|
|
+ showOwnerSelect.value = true
|
|
|
+}
|
|
|
+
|
|
|
+// 校验日期
|
|
|
+async function checkValidateDate(ownerCode, sku, newDate, fieldName) {
|
|
|
+ if (['NOSKU', 'NOBARCODE'].includes(sku)) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ const type = fieldName === 'manufactureTime' ? '生产日期' : '失效日期'
|
|
|
+ try {
|
|
|
+ await validateDate({
|
|
|
+ newDate: newDate,
|
|
|
+ fieldName: fieldName,
|
|
|
+ ownerCode: ownerCode,
|
|
|
+ sku: sku
|
|
|
+ })
|
|
|
+ showNotify({
|
|
|
+ type: 'success',
|
|
|
+ message: `${type} 状态校验成功 `
|
|
|
+ })
|
|
|
+ return true
|
|
|
+ } catch (error) {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: `校验${type}出现异常`
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function blobToBase64(blob) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const fileReader = new FileReader()
|
|
|
+ fileReader.onload = (e) => {
|
|
|
+ resolve(e.target.result)
|
|
|
+ }
|
|
|
+ fileReader.readAsDataURL(blob)
|
|
|
+ fileReader.onerror = () => {
|
|
|
+ reject(new Error('blobToBase64 error'))
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 编辑等级详情
|
|
|
+function editDetails(index) {
|
|
|
+ selectDetailIndex.value = index
|
|
|
+ const { details } = params.value
|
|
|
+ selectDetail.value = JSON.parse(JSON.stringify(details[index]))
|
|
|
+ returnedDetailDialog.value = true
|
|
|
+}
|
|
|
+
|
|
|
+// 写入当前商品详情
|
|
|
+function pushImageItem(event, type) {
|
|
|
+ const file = event.target.files[0]
|
|
|
+ if (!file) return
|
|
|
+
|
|
|
+ if (!file.type.startsWith('image/')) {
|
|
|
+ alert('请选择图片文件!')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const filename = file.name
|
|
|
+ const item = {
|
|
|
+ src: URL.createObjectURL(file),
|
|
|
+ file: file,
|
|
|
+ fileName: filename,
|
|
|
+ type
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === '外箱图') {
|
|
|
+ if (!selectDetail.value.boxPhotos) {
|
|
|
+ selectDetail.value.boxPhotos = []
|
|
|
+ }
|
|
|
+
|
|
|
+ blobToBase64(file).then((_) => {
|
|
|
+ const some = boxFiles.value.some((item) => {
|
|
|
+ return filename === item.fileName
|
|
|
+ })
|
|
|
+ if (some) {
|
|
|
+ showFailToast('录入重复图片')
|
|
|
+ } else {
|
|
|
+ boxFiles.value.push(item)
|
|
|
+ selectDetail.value.boxPhotos.push(filename)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else if (type === '内物图') {
|
|
|
+ if (!selectDetail.value.productPhotos) {
|
|
|
+ selectDetail.value.productPhotos = []
|
|
|
+ }
|
|
|
+ blobToBase64(file).then((_) => {
|
|
|
+ const some = productFiles.value.some((item) => {
|
|
|
+ return filename === item.fileName
|
|
|
+ })
|
|
|
+ if (some) {
|
|
|
+ showFailToast('录入重复图片')
|
|
|
+ } else {
|
|
|
+ productFiles.value.push(item)
|
|
|
+ selectDetail.value.productPhotos.push(filename)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 触发拍照
|
|
|
+function invokeCameraToCapture(type) {
|
|
|
+ const { sku } = selectDetail.value
|
|
|
+ if (!sku) {
|
|
|
+ showFailToast('当前没有可录入的商品信息')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (type === '外箱图') {
|
|
|
+ document.getElementById('outer-carton-box-input').click()
|
|
|
+ } else if (type === '内物图') {
|
|
|
+ document.getElementById('inner-contents-input').click()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function getImageUrl(file_name, type) {
|
|
|
+ let list = []
|
|
|
+ if (type === '外箱图') {
|
|
|
+ list = boxFiles.value
|
|
|
+ } else if (type === '内物图') {
|
|
|
+ list = productFiles.value
|
|
|
+ }
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ const item = list[i]
|
|
|
+ const { src, fileName } = item
|
|
|
+ if (file_name === fileName) {
|
|
|
+ return src
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null
|
|
|
+}
|
|
|
+
|
|
|
+// 外箱图事件
|
|
|
+function outerCartonInput(event) {
|
|
|
+ pushImageItem(event, '外箱图')
|
|
|
+}
|
|
|
+
|
|
|
+// 内物图异常
|
|
|
+function innerContentsInput(event) {
|
|
|
+ pushImageItem(event, '内物图')
|
|
|
+}
|
|
|
+
|
|
|
+function submit() {
|
|
|
+ const { ownerCode, logisticsName, returnNo, warehouseCode } = params.value
|
|
|
+ if (!ownerCode || ownerCode.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '没有对应的退件详情!请录入对应的退件详情'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ } else if (!logisticsName || logisticsName.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请录入承运商'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ } else if (!returnNo || ownerCode.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请录入退件单号'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ } else if (!warehouseCode || warehouseCode.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请选择登记仓库'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ console.log('checkDetailNumber')
|
|
|
+ if (checkDetailNumber()) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const formData = new FormData()
|
|
|
+ const boxItems = boxFiles && boxFiles.value ? boxFiles.value : []
|
|
|
+ const productItems =
|
|
|
+ productFiles && productFiles.value ? productFiles.value : []
|
|
|
+ const files = [...boxItems, ...productItems]
|
|
|
+ const filenames = []
|
|
|
+
|
|
|
+ if (files && files.length > 0) {
|
|
|
+ files.forEach((item) => {
|
|
|
+ const { file, fileName } = item
|
|
|
+ if (!filenames.includes(fileName)) {
|
|
|
+ formData.append('files', file)
|
|
|
+ filenames.push(fileName)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ handleDetails(params.value.details)
|
|
|
+ formData.append('body', JSON.stringify(JSON.parse(JSON.stringify(params.value))))
|
|
|
+ console.log(formData)
|
|
|
+ showLoadingToast({
|
|
|
+ duration: 0,
|
|
|
+ forbidClick: true,
|
|
|
+ message: '提交登记中.....'
|
|
|
+ })
|
|
|
+
|
|
|
+ register(formData)
|
|
|
+ .then((res) => {
|
|
|
+ const { data } = res
|
|
|
+ const { accumulateTaskMap } = data
|
|
|
+ closeToast()
|
|
|
+ if (data) {
|
|
|
+ if (accumulateTaskMap && accumulateTaskMap.length > 0) {
|
|
|
+ let messages = []
|
|
|
+ const ownerName = getOwnerName(params.value.ownerCode)
|
|
|
+ for (let i = 0; i < accumulateTaskMap.length; i++) {
|
|
|
+ const { quality, taskCode } = accumulateTaskMap[i]
|
|
|
+ messages.push(`进入${ownerName}新的${quality}攒单任务号${taskCode}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '提交成功',
|
|
|
+ message: messages.join('\r\n'),
|
|
|
+ theme: 'round-button'
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ showNotify({
|
|
|
+ type: 'success',
|
|
|
+ message: '成功提交'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ init()
|
|
|
+ params.value.ownerCode = ownerCode
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ closeToast()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function checkDetailNumber() {
|
|
|
+ const { details } = params.value
|
|
|
+ if (!details || details.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '登记详情不能为空'
|
|
|
+ })
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ const check = details.some((item) => {
|
|
|
+ const { number } = item
|
|
|
+ return Number.isNaN(number) || Number(number) <= 0
|
|
|
+ })
|
|
|
+ if (check) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '登记数量不能为 0 和 空 '
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return check
|
|
|
+}
|
|
|
+
|
|
|
+function handleDetails(details) {
|
|
|
+ for (let i = 0; i < details.length; i++) {
|
|
|
+ const { qualityStatus } = details[i]
|
|
|
+ const { isGenuineValue, qualityMark } = getStatus(qualityStatus)
|
|
|
+ details[i].isGenuine = isGenuineValue
|
|
|
+ details[i].qualityMark = qualityMark
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const showPhotosPreview = ref(false)
|
|
|
+const startPhotosPosition = ref(0)
|
|
|
+
|
|
|
+const showPhotosImagePreview = (index) => {
|
|
|
+ startPhotosPosition.value = index
|
|
|
+ showPhotosPreview.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const onPhotosPreviewChange = (index) => {
|
|
|
+ startPhotosPosition.value = index
|
|
|
+}
|
|
|
+const handlePhotosDelete = () => {
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '提示',
|
|
|
+ message: '确定要删除这张图片吗?'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ selectDetail.value.productPhotos.splice(startPhotosPosition.value, 1)
|
|
|
+ showNotify({ type: 'success', message: '删除成功' })
|
|
|
+ if (selectDetail.value.productPhotos.length === 0) {
|
|
|
+ showPhotosPreview.value = false
|
|
|
+ } else if (
|
|
|
+ startPhotosPosition.value >= selectDetail.value.productPhotos.length
|
|
|
+ ) {
|
|
|
+ startPhotosPosition.value = selectDetail.value.productPhotos.length - 1
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ showNotify({ type: 'primary', message: '取消删除' })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const showBoxPreview = ref(false)
|
|
|
+const startBoxPosition = ref(0)
|
|
|
+
|
|
|
+const showBoxImagePreview = (index) => {
|
|
|
+ startBoxPosition.value = index
|
|
|
+ showBoxPreview.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const onBoxPreviewChange = (index) => {
|
|
|
+ startBoxPosition.value = index
|
|
|
+}
|
|
|
+const handleBoxDelete = () => {
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '提示',
|
|
|
+ message: '确定要删除这张图片吗?'
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ selectDetail.value.boxPhotos.splice(startBoxPosition.value, 1)
|
|
|
+ showNotify({ type: 'success', message: '删除成功' })
|
|
|
+ if (selectDetail.value.boxPhotos.length === 0) {
|
|
|
+ showBoxPreview.value = false
|
|
|
+ } else if (
|
|
|
+ startBoxPosition.value >= selectDetail.value.boxPhotos.length
|
|
|
+ ) {
|
|
|
+ startBoxPosition.value = selectDetail.value.boxPhotos.length - 1
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ showNotify({ type: 'primary', message: '取消删除' })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const detailBoxImages = computed(() => {
|
|
|
+ const items = selectDetail.value.boxPhotos
|
|
|
+ if (!items || items.length === 0) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ return boxFiles.value
|
|
|
+ .filter((item) => {
|
|
|
+ return items.includes(item.fileName)
|
|
|
+ })
|
|
|
+ .map((item) => item.src)
|
|
|
+})
|
|
|
+
|
|
|
+const detailProductImages = computed(() => {
|
|
|
+ const items = selectDetail.value.productPhotos
|
|
|
+ if (!items || items.length === 0) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ return productFiles.value
|
|
|
+ .filter((item) => {
|
|
|
+ return items.includes(item.fileName)
|
|
|
+ })
|
|
|
+ .map((item) => item.src)
|
|
|
+})
|
|
|
+
|
|
|
+// 校验是否上次图片
|
|
|
+function checkUploadImages() {
|
|
|
+ const status = ['次品', '待修复']
|
|
|
+ const { productPhotos, boxPhotos, qualityStatus } = selectDetail.value
|
|
|
+ if (!status.includes(qualityStatus)) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!qualityStatus) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ const boxPhotoIsNull = !boxPhotos || boxPhotos.length === 0
|
|
|
+ const productPhotoIsNull = !productPhotos || productPhotos.length === 0
|
|
|
+
|
|
|
+ if (boxPhotoIsNull) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请传入对应的外箱图'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if (productPhotoIsNull) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请传入对应的内物图'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+window.onRefresh = async () => {
|
|
|
+ console.log('window.onRefresh')
|
|
|
+}
|
|
|
+
|
|
|
+function clearImageFileCache() {
|
|
|
+ if (productFiles.value && productFiles.value.length > 0) {
|
|
|
+ productFiles.value
|
|
|
+ .map((item) => item.src)
|
|
|
+ .forEach((item) => URL.revokeObjectURL(item))
|
|
|
+ }
|
|
|
+ if (boxFiles.value && boxFiles.value.length > 0) {
|
|
|
+ boxFiles.value
|
|
|
+ .map((item) => item.src)
|
|
|
+ .forEach((item) => URL.revokeObjectURL(item))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function previewImages(filenames, index, type) {
|
|
|
+ let list = []
|
|
|
+ if (type === '外箱图') {
|
|
|
+ list = boxFiles.value
|
|
|
+ } else if (type === '内物图') {
|
|
|
+ list = productFiles.value
|
|
|
+ }
|
|
|
+ const images = []
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ const item = list[i]
|
|
|
+ const { src, fileName } = item
|
|
|
+ if (filenames.includes(fileName)) {
|
|
|
+ images.push(src)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!images || images.length === 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ showImagePreview({
|
|
|
+ images: images,
|
|
|
+ startPosition: index
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="sass">
|
|
|
+.van-nav-bar
|
|
|
+ .left-btn
|
|
|
+ color: #fff
|
|
|
+ height: 46px
|
|
|
+ padding-right: 20px
|
|
|
+ line-height: 46px
|
|
|
+
|
|
|
+ .right-btn
|
|
|
+ color: #fff
|
|
|
+
|
|
|
+.container
|
|
|
+ .init-container
|
|
|
+ width: 100%
|
|
|
+
|
|
|
+ .scan-returned-content
|
|
|
+ padding: 10px
|
|
|
+
|
|
|
+ .input-group
|
|
|
+ padding: 5px
|
|
|
+
|
|
|
+ .button-group
|
|
|
+ padding: 5px
|
|
|
+
|
|
|
+ .content
|
|
|
+ width: 100%
|
|
|
+
|
|
|
+ .scan-returned-no
|
|
|
+ align-items: center
|
|
|
+ padding: 15px
|
|
|
+
|
|
|
+ .returned-detail-list
|
|
|
+ .card-div
|
|
|
+ background: #fff
|
|
|
+ border-radius: 12px
|
|
|
+ overflow: hidden
|
|
|
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05)
|
|
|
+ margin: 5px 0
|
|
|
+ padding: 5px 0
|
|
|
+
|
|
|
+ .card-div-content
|
|
|
+ padding: 3px
|
|
|
+
|
|
|
+ .info-row
|
|
|
+ display: flex
|
|
|
+ margin-bottom: 12px
|
|
|
+ font-size: 12px
|
|
|
+
|
|
|
+ .info-label
|
|
|
+ width: 100px
|
|
|
+ color: #969799
|
|
|
+
|
|
|
+ .info-value
|
|
|
+ flex: 1
|
|
|
+ color: #333333
|
|
|
+ font-weight: 500
|
|
|
+
|
|
|
+ .card-div-footer
|
|
|
+ padding: 5px
|
|
|
+ background: #fafafa
|
|
|
+ border-top: 1px solid #f5f5f5
|
|
|
+ color: #646566
|
|
|
+ font-size: 14px
|
|
|
+ line-height: 1.5
|
|
|
+
|
|
|
+ .card-div-footer-images
|
|
|
+ padding: 5px
|
|
|
+ background: #fafafa
|
|
|
+ border-top: 1px solid #f5f5f5
|
|
|
+ color: #646566
|
|
|
+ font-size: 14px
|
|
|
+ line-height: 1.5
|
|
|
+
|
|
|
+ .card-div-footer-options
|
|
|
+ background: #fafafa
|
|
|
+ border-top: 1px solid #f5f5f5
|
|
|
+ color: #646566
|
|
|
+ font-size: 14px
|
|
|
+
|
|
|
+ .options-row
|
|
|
+ display: flex
|
|
|
+ font-size: 12px
|
|
|
+
|
|
|
+ .info-label
|
|
|
+ width: 100px
|
|
|
+ color: #969799
|
|
|
+
|
|
|
+ .info-value
|
|
|
+ flex: 1
|
|
|
+ color: #333333
|
|
|
+ font-weight: 500
|
|
|
+
|
|
|
+ .returned-details
|
|
|
+ .van-field
|
|
|
+ padding: 0
|
|
|
+</style>
|