daShangDao_miniProgram/pkgUpload/photo-upload/index.vue
2026-06-15 16:37:57 +08:00

3699 lines
104 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container" @click="closeAllDropdowns" :style="pageContainerStyle">
<!-- 顶部Tab切换 -->
<view v-if="!showBcodeCamera" class="upload-tab-header">
<view
class="upload-tab-item"
@click="switchToIsbn">
<text>ISBN上传</text>
</view>
<view
class="upload-tab-item"
:class="{ 'active': true }"
@click="stayOnPhoto">
<text>无ISBN上传</text>
</view>
</view>
<view v-if="currentTab === 'photo' && !showBcodeCamera" class="form-container">
<!-- <view class="result-content"> -->
<text v-if="isLoading">正在识别中...</text>
<text v-else-if="errorMsg">{{errorMsg}}</text>
<view v-else class="book-info">
<!-- 货区和ISBN同一行 -->
<view class="info-item info-item-row">
<warehouse-selector v-if="selectedWarehouse" :initialStorage="selectedStorage" :initialWarehouse="selectedWarehouse"
@label-click="navigateBack" @storage-selected="handleStorageSelected" ref="warehouseSelector"
style="flex: 0.4"></warehouse-selector>
<view class="half-item" style="flex: 0.6">
<text class="label">印刷时间</text>
<view class="input-field time-input-view" @tap="showPrintTimeKeyboard">
<text>{{ bookInfo.printTime || '请输入印刷时间' }}</text>
</view>
<button class="upload-btn" @click="chooseImage" type="default" size="mini">
识图上传
</button>
</view>
</view>
<!-- 书名单独一行 -->
<view class="info-item">
<view class="half-item">
<text class="label">书名</text>
<input type="text" v-model="bookInfo.bookName" class="input-field" placeholder="请输入书名"
:disabled="hasNormalImages" />
<button class="upload-btn" @click="getBookName" type="default" size="mini"
:disabled="hasNormalImages" :class="{'scan-btn-disabled': hasNormalImages}">
书名查询
</button>
</view>
</view>
<!-- 作者单独一行 -->
<view class="info-item">
<view class="half-item">
<text class="label">作者</text>
<input type="text" v-model="bookInfo.author" class="input-field" placeholder="请输入作者" />
<button class="dropdown-btn"
@click.stop="authorDropdownVisible = !authorDropdownVisible">▼</button>
<view v-if="authorDropdownVisible" class="dropdown-list">
<view v-for="(item, idx) in authorOptions" :key="idx">
<view class="dropdown-item" @click="selectAuthor(item)">{{ item }}</view>
<view v-if="idx < authorOptions.length - 1" class="dropdown-divider"></view>
</view>
</view>
</view>
</view>
<!-- 出版社单独一行 -->
<view class="info-item" style="position:relative;">
<text class="label">出版社</text>
<input type="text" v-model="bookInfo.publisher" class="input-field" placeholder="请输入出版社" />
<button class="dropdown-btn"
@click.stop="publisherDropdownVisible = !publisherDropdownVisible">▼</button>
<view v-if="publisherDropdownVisible" class="dropdown-list" style="top:70rpx;left:0;">
<view v-for="(item, idx) in publisherOptions" :key="idx">
<view class="dropdown-item" @click="selectPublisher(item)">{{ item }}</view>
<view v-if="idx < publisherOptions.length - 1" class="dropdown-divider"></view>
</view>
</view>
</view>
<!-- 图书分类多级联动 -->
<view class="info-item category-container">
<view class="half-item">
<text class="label">图书分类</text>
<picker mode="multiSelector" :range="categoryColumns" range-key="name"
@columnchange="onCategoryColumnChange" @change="onCategoryChange" :value="categoryIndexes">
<view class="picker-single">
{{ categoryPathText || '请选择分类' }}
</view>
</picker>
</view>
</view>
<!-- 开本与书号同一行 -->
<view class="info-item info-item-row">
<view class="half-item format-item" style="position:relative;">
<text class="label">开本</text>
<input type="text" v-model="bookInfo.format" class="input-field" placeholder="请输入开本" />
<button class="dropdown-btn"
@click.stop="formatDropdownVisible = !formatDropdownVisible">▼</button>
<view v-if="formatDropdownVisible" class="dropdown-list"
style="top:70rpx;left:0;max-height:300rpx;">
<view v-for="(item, idx) in formatOptions" :key="idx">
<view class="dropdown-item" @click="selectFormat(item)">{{ item }}</view>
<view v-if="idx < formatOptions.length - 1" class="dropdown-divider"></view>
</view>
</view>
</view>
<view class="half-item isbn-item">
<text class="label">书号</text>
<input type="text" v-model="bookInfo.unifyIsbn" class="input-field" placeholder="请输入统一书号" />
</view>
</view>
<!-- 字数和定价同一行 -->
<view class="info-item info-item-row">
<view class="half-item format-item">
<text class="label">定价</text>
<input type="digit" v-model="bookInfo.price" class="input-field" placeholder="请输入定价" />
</view>
<view class="half-item isbn-item">
<text class="label">字数</text>
<input type="number" v-model="bookInfo.wordage" class="input-field" placeholder="请输入字数" />
</view>
</view>
<view class="info-item">
<view class="half-item">
<text class="label">ISBN</text>
<input type="text" v-model="bookInfo.isbn" class="input-field" placeholder="请输入ISBN"
:disabled="hasNormalImages" />
</view>
</view>
<!-- </view> -->
</view>
<!-- 品相选择组件 -->
<book-condition-select ref="conditionSelect" @change="onConditionChange"></book-condition-select>
<!-- 价格库存控制组件 -->
<price-stock-control :price.sync="value4" :stock.sync="value3" @priceChange="onPriceChange"
@stockChange="onStockChange" />
<!-- 拍照组件 -->
<camera-upload v-model="fileList1" :maxCount="9" :isbn="bookInfo.isbn" :bookName="bookInfo.bookName"
@input="handleFileChange" @camera-status-change="handleCameraStatusChange"
@upload-status-change="handleUploadStatusChange"></camera-upload>
<!-- 在售商品列组件 -->
<on-sale-products :initialOnSaleProducts="onSaleProducts"
:initialDisplayOnSaleProducts="displayOnSaleProducts" :initialCompareType="compareType"
:isbn="bookInfo.isbn" :bookName="bookInfo.bookName" :showCompareButton="false"
:showCopyrightButton="true" :publisher="bookInfo.publisher" :author="bookInfo.author"
@compare-type-change="handleCompareTypeChange" :showFilterButton="false"
@copyright-compare="handleCopyrightCompare" @filters-applied="handleFiltersApplied"
@filters-reset="handleFiltersReset" @products-updated="handleProductsUpdated"
ref="onSaleProductsComponent" />
<view class="view-container" style="margin-top: 40rpx;">
<view class="view-item" @click="getBookRecords" style="display: flex; align-items: center;">
<view class="blue-block"></view>
<text class="general-label" style="background: none; padding: 0;">上书记录</text>
</view>
</view>
<!-- 提交按钮 -->
<view class="form-item fixed-bottom" v-show="showSubmitButton && !showBcodeCamera">
<button type="primary" @click="submitForm" class="submit-btn"
:disabled="isSubmitting || isUploading">{{ isSubmitting ? '正在提交...' : (isUploading ? '图片上传中...' : '提交') }}</button>
<u-popup class="form-popup" :show="popupDialog.show" mode="center">
<!-- 标题 -->
<view class="popupContentBox">{{ popupDialog.title }}</view>
<view class="popupContentBox">{{ popupDialog.content }}</view>
<!-- 图片容器(保持正方形) -->
<view class="c_box_">
<image :src="popupDialog.imgSrc" mode="aspectFill" class="popup-image"></image>
</view>
<!-- 字母选择下拉框 -->
<view class="select-container">
<view class="custom-select" @click="popupDialog.showPicker = true">
<text>{{ popupDialog.selectedSeries || '请选择' }}</text>
</view>
</view>
<u-picker :show="popupDialog.showPicker" :columns="[popupDialog.seriesOptions]"
@confirm="onSeriesConfirm" @cancel="popupDialog.showPicker = false"></u-picker>
<!-- 按钮容器 -->
<view class="button-group">
<view class="btn cancel-btn" @click="onPopupCancel">
<text>{{ popupDialog.cancelText }}</text>
</view>
<view class="btn confirm-btn" @click="onPopupConfirm">
<text>{{ popupDialog.confirmText }}</text>
</view>
</view>
</u-popup>
</view>
</view>
<!-- 添加bcode-camera组件 -->
<bcode-camera v-if="showBcodeCamera" tipsText="请将书籍对准取景框" @onConfirm="handleBcodeCameraResult"
@onCancel="handleBcodeCameraCancel" @onUpload="handleBcodeCameraResult" :color="'rgba(0, 122, 255, 0.8)'"
:showScanEffect="true" :scanMode="true" :customStyle="{
scanBox: {
borderColor: '#007AFF',
backgroundColor: 'rgba(0,0,0,0.1)'
}
}" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999;">
<view class="scan-container">
<view class="grid-background"></view>
<view class="scan-line"></view>
</view>
</bcode-camera>
<!-- 自定义识别中动画 -->
<!-- <view v-if="showRecognizing" class="recognizing-overlay">
<view class="recognizing-container">
<view class="grid-background"></view>
<view class="scan-animation"></view>
<view class="recognizing-text">正在识别中...</view>
</view>
</view> -->
<!-- 新增:识别动画覆盖在图片预览上 -->
<view v-if="showRecognizing && previewImageUrl" class="recognizing-preview-box">
<image :src="previewImageUrl" class="recognizing-preview-img" mode="aspectFit" />
<view class="recognizing-overlay-on-image">
<view class="scan-line"></view>
<view class="recognizing-text">正在识别中...</view>
</view>
</view>
<!-- 添加印刷时间键盘弹窗 -->
<view class="print-time-popup" v-if="printTimePopupVisible">
<view class="print-time-container">
<view class="print-time-header">
<text>出版时间</text>
<text class="close-btn" @click="closePrintTimePopup">×</text>
</view>
<view class="print-time-tabs">
<view class="tab-item" :class="{ active: printTimeTab === 'input' }"
@click="printTimeTab = 'input'">
<text>填写时间</text>
<view class="tab-line" v-if="printTimeTab === 'input'"></view>
</view>
<view class="tab-item" :class="{ active: printTimeTab === 'year' }" @click="printTimeTab = 'year'">
<text>选择年代</text>
<view class="tab-line" v-if="printTimeTab === 'year'"></view>
</view>
</view>
<view class="print-time-content" v-if="printTimeTab === 'input'">
<!-- 注释掉自动填充按钮
<view class="auto-fill-row" @click="useCurrentDate">
<view class="auto-fill-circle">
<view class="auto-fill-dot" v-if="autoFillSelected"></view>
</view>
<view class="auto-fill-text">自动填充</view>
</view>
-->
<view class="time-input-fields">
<view class="input-group">
<input type="text" v-model="printTimeYear" class="time-input year-input" placeholder="年"
:focus="printTimeActiveInput === 'year'" @focus="printTimeActiveInput = 'year'"
readonly />
</view>
<view class="input-group">
<input type="text" v-model="printTimeMonth" class="time-input month-input" placeholder="月"
:focus="printTimeActiveInput === 'month'" @focus="printTimeActiveInput = 'month'"
readonly />
</view>
</view>
</view>
<view class="print-time-content year-selection" v-if="printTimeTab === 'year'">
<view class="year-grid">
<view v-for="decade in decades" :key="decade.label" class="decade-item"
@click="selectDecade(decade.value)">
{{ decade.label }}
</view>
</view>
</view>
<view class="numeric-keyboard">
<view class="keyboard-row">
<view class="key-item" @click="inputPrintTimeDigit('1')">1</view>
<view class="key-item" @click="inputPrintTimeDigit('2')">2</view>
<view class="key-item" @click="inputPrintTimeDigit('3')">3</view>
<view class="key-item delete-key" @click="deletePrintTimeDigit">×</view>
</view>
<view class="keyboard-row">
<view class="key-item" @click="inputPrintTimeDigit('4')">4</view>
<view class="key-item" @click="inputPrintTimeDigit('5')">5</view>
<view class="key-item" @click="inputPrintTimeDigit('6')">6</view>
</view>
<view class="keyboard-row">
<view class="key-item" @click="inputPrintTimeDigit('7')">7</view>
<view class="key-item" @click="inputPrintTimeDigit('8')">8</view>
<view class="key-item" @click="inputPrintTimeDigit('9')">9</view>
</view>
<view class="keyboard-row">
<view class="key-item zero-key" @click="inputPrintTimeDigit('0')">0</view>
<view class="key-item keyboard-btn" @click="confirmPrintTime">确定</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from 'vuex'
// Vuex 模块拆分后使用命名空间访问
import BookConditionSelect from '@/components/BookConditionSelect.vue';
import PriceStockControl from '@/components/PriceStockControl.vue';
import BookProductList from '@/components/BookProductList.vue';
import * as selectBookImage from '@/service/selectBookImage.js';
import WarehouseSelector from '@/components/WarehouserSelector.vue';
import CameraUpload from '@/components/CameraUpload.vue';
// 导入上书记录获取方法
import * as bookRecords from '@/service/bookRecords.js';
import {
getAuthorAndPublisher
} from '@/service/getAuthorAndPublisher.js';
// 导入bcode-camera组件
import bcodeCamera from '@/uni_modules/bcode-camera/components/bcode-camera/bcode-camera.vue';
// 导入会员书籍数量检查工具
import {
checkMemberBooksCount
} from '@/components/MemberBookCheck.js';
export default {
name: 'PhotoUpload',
components: {
'book-condition-select': BookConditionSelect,
'price-stock-control': PriceStockControl,
'on-sale-products': BookProductList,
"warehouse-selector": WarehouseSelector,
"camera-upload": CameraUpload,
"bcode-camera": bcodeCamera, // 注册bcode-camera组件
},
computed: {
...mapState('price', ['priceMode', 'priceType', 'averageRange', 'freight', 'minValue']),
...mapState('warehouse', ['selectedPosition']),
// 根据相机状态动态设置页面容器样式
pageContainerStyle() {
if (this.showBcodeCamera) {
return {
overflow: 'hidden',
height: '100vh'
};
}
return {};
},
hasNormalImages() {
return this.fileList1.some(file => !file.name || !file.name.startsWith('识图-'));
}
},
watch: {
displayOnSaleProducts: {
handler(newProducts) {
if (newProducts && newProducts.length > 0) {
// 更新最低价格
this.lowestBookPrice = Math.min(...newProducts.map(p => parseFloat(p.bookPrice) || 0));
this.lowestTotalPrice = Math.min(...newProducts.map(p => parseFloat(p.totalPrice) || 0));
// 调用计算参考价格的方法
this.calculateReferencePrice();
}
},
immediate: true
},
// 监听价格模式和类型变化,重新计算价格
priceMode: {
handler() {
this.calculateReferencePrice();
}
},
priceType: {
handler() {
this.calculateReferencePrice();
}
},
averageRange: {
handler() {
this.calculateReferencePrice();
}
},
freight: {
handler() {
this.calculateReferencePrice();
}
},
minValue: {
handler() {
this.calculateReferencePrice();
}
},
selectedPosition: {
handler() {
this.calculateReferencePrice();
}
}
},
data() {
return {
currentTab: 'photo',
imageUrl: '',
isLoading: false,
errorMsg: '',
selectedWarehouse: null, // 添加 selectedWarehouse
selectedStorage: '',
warehouse: '',
shelf: '',
location: '',
shelves: [], // 货架列表
locations: [], // 货位列表
selectedSheId: null,
selectedFreId: null,
goodUnifyIsbn: '',
uploadedImages: [], // 存储上传成功的图片信息,用于提交表单时一并传递
bookInfo: {
bookName: '',
author: '',
publisher: '',
format: '',
printTime: '',
isbn: '',
price: '',
wordage: '',
unifyIsbn: '',
},
value4: 1.00, // 价格
value3: 1, // 库存
showSubmitButton: true,
isSubmitting: false,
isUploading: false, // 新增:用于跟踪图片是否正在上传
fileList: [],
fileList1: [],
compareType: 'isbn',
onSaleProducts: [], // 存储所有在售商品信息
LocalWarehouse: this.selectedWarehouse,
displayOnSaleProducts: [], // 存储按总价排序后的前十条在售商品信息
marketTags: [{
label: '在售:',
value: 0
}, {
label: '旧:',
value: 0
}, {
label: '新:',
value: 0
}, {
label: '已售:',
value: 0
}],
columns: [
[],
[],
[]
], // 新增,仓库/货架/货位选择
popupDialog: {
show: false,
title: '',
content: '',
confirmText: '',
cancelText: '',
imgSrc: '',
count: 0,
subFormData: null,
showPicker: false,
selectedSeries: '',
seriesOptions: ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']
},
authorDropdownVisible: false,
publisherDropdownVisible: false,
authorOptions: [],
publisherOptions: [],
formatDropdownVisible: false,
formatOptions: [
'16', '32', '24', '36', '40', '42', '48', '50', '60', '64', '72',
'2', '4', '6', '8', '12', '18', '20', '大16', '大32', '其他'
],
showBcodeCamera: false, // 添加控制bcode-camera显示的状态
showRecognizing: false, // 控制自定义识别中动画的显示
previewImageUrl: '', // 新增:识别时的图片预览
hasShownUploadMessage: false, // 用于控制是否显示上传图片的提示
printTimePopupVisible: false,
printTimeTab: 'input',
printTimeYear: '',
printTimeMonth: '',
printTimeActiveInput: 'year',
autoFillSelected: false, // 已禁用自动填充功能
decades: [{
label: '1950年代',
value: '195'
},
{
label: '1960年代',
value: '196'
},
{
label: '1970年代',
value: '197'
},
{
label: '1980年代',
value: '198'
},
{
label: '1990年代',
value: '199'
},
{
label: '2000年代',
value: '200'
},
{
label: '2010年代',
value: '201'
},
{
label: '2020年代',
value: '202'
}
],
isScanning: false, // 新增:扫码状态
// 分类相关数据
categoryList: [], // 原始分类数据
categoryOptions2: [], // 二级分类
categoryOptions3: [], // 三级分类
categoryLevel1: null, // 选中的一级
categoryLevel2: null, // 选中的二级
categoryLevel3: null, // 选中的三级
selectedCategoryId: '', // 选中的分类id最终叶子节点的id
categoryIndexes: [], // 用于存储分类选择的索引(可变长度数组)
maxCategoryLevel: 6, // 支持的最大分类级别数
categoryPathText: '', // 用于显示分类路径
categoryColumns: [], // 多级分类选择器的所有列数据
categoryLevels: [], // 存储每个级别选中的分类对象
}
},
created() {
this.$selectBookImage = selectBookImage;
},
async onLoad() {
const phoneNumber = uni.getStorageSync('phoneNumber');
const warehouse = uni.getStorageSync("selectedWarehouse");
console.log('选择仓库11111:', warehouse);
// 先设置 selectedWarehouse触发 warehouse-selector 组件渲染
if (warehouse) {
this.selectedWarehouse = warehouse;
this.columns[0] = [warehouse.name]; // 假设仓库对象有name字段
}
// 使用 setTimeout 等待 warehouse-selector 组件渲染完成后再加载货区选择状态
setTimeout(() => {
this.loadStorageSelection();
}, 100);
// 获取图书分类数据
await this.fetchCategoryData();
console.log("分类数据获取成功:", this.categoryList);
},
// 添加Vue的mounted生命周期钩子确保组件切换时能正确加载状态
mounted() {
// 不在这里调用 loadStorageSelection因为 v-if 导致组件渲染延迟
// 使用 setTimeout 等待组件渲染完成后再调用
setTimeout(() => {
this.loadStorageSelection();
}, 100);
},
onReady() {
console.log('=== onReady 方法被调用 ===');
// 在uni-app中我们可以使用页面级别的点击事件
// 这里不需要添加全局事件监听器,我们将在模板中使用@click事件
// 手动触发分类数据获取
console.log('onReady: 手动触发fetchCategoryData');
this.fetchCategoryData().then(() => {
console.log('onReady: fetchCategoryData执行完成');
}).catch(error => {
console.error('onReady: fetchCategoryData执行失败:', error);
});
},
onShow() {
// 检查本地存储中是否有更新的仓库信息
const warehouse = uni.getStorageSync("selectedWarehouse");
if (warehouse) {
console.log('从存储获取仓库信息:', warehouse);
// 设置仓库对象以便传递给组件
this.selectedWarehouse = warehouse;
}
// 使用 setTimeout 等待组件渲染后再加载货区选择状态
setTimeout(() => {
this.loadStorageSelection();
}, 100);
// 每次页面显示都拉取分类数据
console.log('onShow: 开始调用fetchCategoryData');
this.fetchCategoryData().then(() => {
console.log('onShow: fetchCategoryData执行完成');
}).catch(error => {
console.error('onShow: fetchCategoryData执行失败:', error);
});
},
methods: {
// 停留在无ISBN上传页面
stayOnPhoto() {
// 已在当前页面,不做任何操作
},
// 切换到ISBN上传页面
switchToIsbn() {
uni.redirectTo({
url: '/pkgUpload/isbn-upload/index'
});
},
// 从本地存储加载货区选择状态
loadStorageSelection() {
try {
// 只有在选择了仓库的情况下才加载货区状态
if (!this.selectedWarehouse || !this.selectedWarehouse.id) {
console.log('Photo页面未选择仓库不加载货区状态');
return;
}
// 根据仓库ID加载对应的货区状态
const storageKey = `selectedStorageData_${this.selectedWarehouse.id}`;
const storageData = uni.getStorageSync(storageKey);
if (storageData) {
console.log(`Photo页面加载仓库${this.selectedWarehouse.id}的货区选择状态:`, storageData);
this.selectedStorage = storageData.selectedStorage || '';
this.warehouse = storageData.warehouse || '';
this.shelf = storageData.shelf || '';
this.location = storageData.location || '';
this.selectedSheId = storageData.selectedSheId || null;
this.selectedFreId = storageData.selectedFreId || null;
// 如果有完整的货区信息,通知仓库选择器组件更新
if (this.selectedStorage && this.$refs.warehouseSelector) {
this.$nextTick(() => {
this.$refs.warehouseSelector.updateSelectedStorage({
storage: this.selectedStorage,
warehouse: this.warehouse,
shelf: this.shelf,
location: this.location,
shelfId: this.selectedSheId,
locationId: this.selectedFreId
});
});
}
} else {
console.log(`Photo页面仓库${this.selectedWarehouse.id}没有保存的货区状态`);
}
} catch (error) {
console.error('Photo页面加载货区选择状态失败:', error);
}
},
// 选择图片
async chooseImage() {
// 检查用户是否可以上传书籍
const canUpload = await checkMemberBooksCount();
if (!canUpload) {
// 如果不能上传,则直接返回,不继续执行
return;
}
const warehouse = this.warehouse
console.log("warehouse", warehouse)
const shelf = this.shelf
console.log("shelf", shelf)
const location = this.location
console.log("location", location)
// 验证仓库/货架/货位 - 确保三个值都必须存在
if (!warehouse || !shelf || !location) {
uni.showToast({
title: '请完整选择仓库、货架和货位',
icon: 'none',
duration: 2500
});
return;
}
// 保存当前的货区和品相数据
const currentStorage = this.selectedStorage;
const currentWarehouse = this.warehouse;
const currentShelf = this.shelf;
const currentLocation = this.location;
const currentSelectedSheId = this.selectedSheId;
const currentSelectedFreId = this.selectedFreId;
// 保存当前的品相选择
let currentCondition = null;
if (this.$refs.conditionSelect) {
currentCondition = this.$refs.conditionSelect.getSelectedCondition();
}
// 清空表单数据
this.bookInfo = {
bookName: '',
author: '',
publisher: '',
format: '',
printTime: '',
isbn: '',
price: '',
wordage: '',
unifyIsbn: ''
};
// 清空图片列表和已上传图片
this.fileList1 = [];
this.uploadedImages = [];
this.hasShownUploadMessage = false;
// 重置在售商品列表
this.onSaleProducts = [];
this.displayOnSaleProducts = [];
// 重置下拉选项
this.authorOptions = [];
this.publisherOptions = [];
this.authorDropdownVisible = false;
this.publisherDropdownVisible = false;
this.formatDropdownVisible = false;
// 重置分类选择
this.categoryIndexes = [];
this.categoryPathText = '';
this.selectedCategoryId = '';
this.categoryLevels = [];
this.initCategoryPicker(); // 重新初始化选择器
// 恢复货区数据
this.selectedStorage = currentStorage;
this.warehouse = currentWarehouse;
this.shelf = currentShelf;
this.location = currentLocation;
this.selectedSheId = currentSelectedSheId;
this.selectedFreId = currentSelectedFreId;
// 恢复品相选择
if (this.$refs.conditionSelect && currentCondition) {
this.$refs.conditionSelect.setSelection(currentCondition.name);
}
// 显示bcode-camera组件
this.showBcodeCamera = true;
// 隐藏提交按钮
this.showSubmitButton = false;
this.$emit('camera-status-change', true);
},
// 新增:更新作者和出版社信息的方法
async updateAuthorAndPublisher() {
try {
const cookies = uni.getStorageSync('cookies');
if (!cookies || !this.bookInfo.bookName) {
return;
}
const result = await getAuthorAndPublisher(this.bookInfo.bookName, cookies);
this.authorOptions = result.authors || [];
this.publisherOptions = result.publishers || [];
// 如果OCR识别的作者在列表中保持选中
if (this.bookInfo.author && result.authors && result.authors.includes(this.bookInfo.author)) {
this.bookInfo.author = this.bookInfo.author;
}
} catch (error) {
console.error('获取作者和出版社信息失败:', error);
}
},
handleFileChange(newFileList) {
// 过滤出普通上传的图片(不包含识图上传的图片)
const normalImages = newFileList.filter(file => !file.name || !file.name.startsWith('识图-'));
// 过滤出识图上传的图片
const ocrImages = this.fileList1.filter(file => file.name && file.name.startsWith('识图-'));
// 合并两个数组
this.fileList1 = [...normalImages, ...ocrImages];
// 只有当有普通上传的图片时才显示提示并禁用输入框
if (normalImages.length > 0 && (!this.hasShownUploadMessage)) {
uni.showToast({
title: '已上传图片ISBN和书名不可修改',
icon: 'none',
duration: 2000
});
this.hasShownUploadMessage = true;
} else if (normalImages.length === 0) {
this.hasShownUploadMessage = false;
}
// 检查是否有文件正在上传
this.isUploading = newFileList.some(file => file.status === 'uploading');
console.log("普通上传图片数量:", normalImages.length);
console.log("识图上传图片数量:", ocrImages.length);
console.log("fileList1", this.fileList1);
console.log("文件上传状态:", this.isUploading ? "上传中" : "未上传");
},
// 删除图片
deleteImage() {
this.imageUrl = '';
this.bookInfo = {
title: '',
author: '',
publisher: '',
format: '',
printTime: '',
isbn: '',
price: '',
wordage: ''
};
this.errorMsg = '';
},
// 返回上一页并清除缓存
navigateBack() {
// 清除相关缓存数据
uni.removeStorageSync('lastSelectedStorage');
uni.removeStorageSync('selectedWarehouse');
uni.removeStorageSync('lastSelectedShelf');
uni.removeStorageSync('lastSelectedLocation');
// 清除三级货区选择状态
uni.removeStorageSync('selectedStorageData');
// 重置相关数据
this.selectedStorage = '';
this.warehouse = '';
this.shelf = '';
this.location = '';
uni.navigateTo({
url: '/pages/warehouse/warehouse-select'
});
},
// 相机按钮
handleCameraStatusChange(isCameraOpen) {
// 当相机打开时隐藏提交按钮,关闭时显示
this.showSubmitButton = !isCameraOpen;
},
// 处理上传状态变化
handleUploadStatusChange(isUploading) {
console.log('文件上传状态变化:', isUploading ? '上传中' : '未上传');
this.isUploading = isUploading;
},
handleStorageSelected(data) {
console.log('选择的货区数据:', data);
this.selectedStorage = data.storage;
this.warehouse = data.warehouse;
this.shelf = data.shelf;
this.location = data.location;
this.selectedSheId = data.shelfId;
this.selectedFreId = data.locationId;
// 将ID存储到本地
uni.setStorageSync('warehouseId', this.selectedWarehouse.id); // 仓库ID
uni.setStorageSync('shelfId', data.shelfId); // 货架ID
uni.setStorageSync('locationId', data.locationId); // 货位ID
},
// 品相选择变化
onConditionChange(index, conditionName) {
console.log('品相已选择:', index);
console.log('选中的品相名称:', conditionName);
},
// 价格变化
onPriceChange(value) {
this.value4 = value;
},
// 库存变化
onStockChange(value) {
this.value3 = value;
},
// 获取在售商品信息
async fetchOnSaleProducts(keyword) {
try {
const conditionValue = uni.getStorageSync("conditionValue");
const sortType = 7;
const cookies = uni.getStorageSync('UserInfoCookies');
const mockData = await this.$selectBookImage.fetchOnSaleProducts(keyword, sortType, conditionValue,
cookies);
const blockedShopsStr = uni.getStorageSync('blockedShops') || '';
const blockedShops = blockedShopsStr.split(';').filter(shop => shop.trim() !== '');
const filteredData = mockData.filter(product => {
return !blockedShops.some(shop => product.shopName && product.shopName.includes(shop
.trim()));
});
this.onSaleProducts = [...filteredData];
this.extractAuthorsAndPublishers();
if (this.$refs.onSaleProductsComponent) {
this.$refs.onSaleProductsComponent.updateProducts(this.onSaleProducts);
}
this.calculateReferencePrice();
} catch (error) {
console.error('获取在售商品信息失败:', error);
uni.showToast({
title: '获取在售商品信息失败',
icon: 'none',
duration: 2500
});
}
},
// 计算参考价格
calculateReferencePrice() {
if (!this.displayOnSaleProducts || this.displayOnSaleProducts.length === 0) {
this.value4 = 1.00;
return;
}
let products = [...this.displayOnSaleProducts];
// 永远使用总价
let priceField = 'totalPrice';
// 按总价排序
products.sort((a, b) => parseFloat(a[priceField]) - parseFloat(b[priceField]));
// 从Vuex store获取运费和最低值
const shippingFee = this.freight;
const minValue = this.minValue;
console.log("priceMode111", this.priceMode)
const priceMode = uni.getStorageSync("current1")
console.log("priceMode", priceMode)
const selectedPositionIndex = uni.getStorageSync("selectedPositionIndex")
console.log("selectedPositionIndex", selectedPositionIndex)
switch (priceMode) {
case 0: // 最低价
// 获取选择的位置索引从store中获取
const positionIndex = this.selectedPosition || selectedPositionIndex || 0;
console.log("索引", positionIndex)
// 确保索引在有效范围内
const validIndex = Math.min(positionIndex, products.length - 1);
console.log("索引1", positionIndex)
console.log('使用第' + (validIndex + 1) + '条数据的价格');
// 获取选中位置的总价
const selectedTotal = parseFloat(products[validIndex].totalPrice);
this.lowestTotalPrice = parseFloat(products[0].totalPrice);
// 计算新价格:选中位置的总价 - 运费 - 最低值
const lowestPrice = selectedTotal - shippingFee - 0.01;
// 如果总价减去运费后的价格小于0则使用最低值设置的值
if (lowestPrice <= minValue) {
this.value4 = minValue;
} else {
this.value4 = parseFloat(lowestPrice.toFixed(2));
}
break;
case 1: // 均价
// 获取最低的N个价格并计算平均值
let count = Math.min(this.averageRange, products.length);
console.log("count", count)
let sum = 0;
for (let i = 0; i < count; i++) {
sum += parseFloat(products[i][priceField]);
console.log("sum+", sum)
}
// 计算平均总价后减去运费
const averagePrice = (sum / count) - shippingFee - 0.01;
console.log("averagePrice", averagePrice)
// 如果计算结果小于等于0则使用最低值
if (averagePrice <= minValue) {
this.value4 = minValue;
} else {
this.value4 = parseFloat(averagePrice.toFixed(2));
}
break;
case 2: // 最新已售价
// 使用最低总价
this.value4 = parseFloat(products[0].totalPrice);
break;
}
},
// 处理比价类型变化
async handleCompareTypeChange(payload) {
this.compareType = payload.type;
if (payload.type === 'isbn') {
await this.fetchOnSaleProducts(this.bookInfo.isbn);
} else {
await this.fetchOnSaleProducts(this.bookInfo.bookName);
}
},
// 处理筛选结果
handleFiltersApplied(filteredProducts) {
this.filteredOnSaleProducts = filteredProducts;
this.isFiltered = true;
},
// 处理筛选重置
handleFiltersReset() {
this.isFiltered = false;
},
// 处理产品数据更新
handleProductsUpdated(products) {
this.displayOnSaleProducts = products;
// 如果需要,可以在这里更新最低价格并重新计算参考价格
this.calculateReferencePrice();
},
// 提交表单
async submitForm() {
// 检查提交时间间隔
const lastSubmitTime = uni.getStorageSync('lastSubmitTime');
const currentTime = Date.now();
if (lastSubmitTime) {
const timeDiff = currentTime - lastSubmitTime;
const twoHours = 2 * 60 * 60 * 1000; // 2小时的毫秒数
if (timeDiff > twoHours) {
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none',
duration: 2000
});
setTimeout(() => {
uni.navigateTo({
url: '/pages/login/index'
});
}, 2000);
return;
}
}
// 更新最后提交时间
uni.setStorageSync('lastSubmitTime', currentTime);
// 检查用户是否可以上传书籍
const canUpload = await checkMemberBooksCount();
if (!canUpload) {
// 如果不能上传,则直接返回,不继续执行
return;
}
if (this.isSubmitting) return;
this.isSubmitting = true;
const warehouse = this.warehouse;
const shelf = this.shelf;
const location = this.location;
const userId = uni.getStorageSync("userId")
try {
// 验证必填字段
if (!this.bookInfo.bookName) {
uni.showToast({
title: '请输入书名',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
return;
}
if (!this.bookInfo.publisher) {
uni.showToast({
title: '请输入出版社',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
return;
}
if (!this.bookInfo.author) {
uni.showToast({
title: '请输入作者',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
return;
}
if (!this.bookInfo.printTime) {
uni.showToast({
title: '请输入印刷时间',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
return;
}
// 获取选中的品相
const selectedCondition = this.$refs.conditionSelect.getSelectedCondition();
if (!selectedCondition) {
uni.showToast({
title: '请选择品相',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
return;
}
// 验证仓库/货架/货位
if (!warehouse || !shelf || !location) {
uni.showToast({
title: '请选择仓库/货架/货位',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
return;
}
// 检查用户是否可以上传书籍
const canUpload = await checkMemberBooksCount();
if (!canUpload) {
// 如果不能上传,则直接返回,不继续执行
this.isSubmitting = false;
return;
}
// 检查是否选择了分类
// if (!this.selectedCategoryId) {
// uni.showToast({
// title: '请选择图书分类',
// icon: 'none',
// duration: 2500
// });
// this.isSubmitting = false;
// return;
// }
// 上传所有待上传的图片
if (this.fileList1.length > 0) {
if (this.fileList1.length > 0) {
// 检查是否有上传失败或者临时路径的图片
const temporaryImages = [];
console.log("当前图片数据fileList1", this.fileList1)
this.fileList1.forEach((file, index) => {
// 跳过识图照片(本地状态)
if (file.isOCR || file.status === 'local') {
return;
}
// 检查图片状态是否为error或者路径是临时路径
if (file.status === 'error' ||
(file.url && (file.url.startsWith('file://') ||
file.url.startsWith('blob:') ||
file.url.startsWith('wxfile://') ||
file.url.indexOf('tmp') !== -1))) {
temporaryImages.push(index + 1); // 索引从0开始所以+1表示第几张
}
});
if (temporaryImages.length > 0) {
uni.showToast({
title: `${temporaryImages.join('、')}张图片上传失败,请重新拍照,若仍然失败请联系管理员!`,
icon: 'none',
duration: 4000
});
this.isSubmitting = false; // 重置提交状态
return;
}
}
try {
// 显示上传中提示
uni.showLoading({
title: '正在上传图片...'
});
// 设置上传状态为true
this.isUploading = true;
// 过滤出需要上传的普通照片(排除识图照片)
const normalPhotos = this.fileList1.filter(file => !file.isOCR && file.status === "ready");
console.log('准备上传的普通照片:', normalPhotos);
// 按顺序上传所有普通照片
for (let i = 0; i < this.fileList1.length; i++) {
const file = this.fileList1[i];
// 只上传状态为ready且非识图的图片
if (file.status === "ready" && !file.isOCR) {
// 更新状态为上传中
this.fileList1.splice(i, 1, {
...file,
status: "uploading",
message: "上传中"
});
try {
// 上传图片
const result = await this.uploadFilePromise(file.url, i);
// 更新状态为上传成功
this.fileList1.splice(i, 1, {
...file,
status: "success",
message: "",
url: result,
num: file.num || (i + 1).toString()
});
} catch (error) {
console.error('图片上传失败:', error);
// 更新状态为上传失败
this.fileList1.splice(i, 1, {
...file,
status: "error",
message: "上传失败"
});
// 显示错误提示
uni.showToast({
title: '图片上传失败',
icon: 'none',
duration: 2500
});
// 重置提交状态
this.isSubmitting = false;
this.isUploading = false;
uni.hideLoading();
return;
}
}
}
// 所有图片上传完成后设置上传状态为false
this.isUploading = false;
uni.hideLoading();
} catch (error) {
console.error('图片上传过程出错:', error);
uni.hideLoading();
uni.showToast({
title: '图片上传失败',
icon: 'none',
duration: 2500
});
this.isSubmitting = false;
this.isUploading = false;
return;
}
}
// 构建提交数据
const formData = {
userId: userId,
barcode: this.bookInfo.isbn,
name: this.bookInfo.bookName,
conditionCode: selectedCondition.name,
price: this.value4 * 100,
inventory: this.value3 || 1,
marketTags: this.marketTags,
// files: this.uploadedImages.length > 0 ? this.uploadedImages : this.fileList1.map(file => ({
// ...file,
// num: file.num || '1'
// })),
files: this.fileList1,
author: this.bookInfo.author,
publisher: this.bookInfo.publisher,
format: this.bookInfo.format,
printTime: this.bookInfo.printTime,
wordage: this.bookInfo.wordage,
priceText: this.bookInfo.price,
goodUnifyIsbn: this.bookInfo.unifyIsbn,
selectedStorage: this.selectedStorage, // 仓库ID
depotName: this.warehouse, // 仓库名称(需与后端字段名一致)
shelvesName: this.shelf, // 货架名称
freightName: this.location, // 自由区名称
phoneNumber: uni.getStorageSync('phoneNumber'), // 从本地存储获取用户
passWord: uni.getStorageSync('password'), // 从本地存储获取用户
tenantId: uni.getStorageSync('tenantId'), // 从本地存储获取租户ID
userName: uni.getStorageSync('userName'), // 从本地存储获取手机号
categoryId: this.selectedCategoryId || '' // 添加分类ID
};
// 调试日志,查看提交数据中的书名
console.log('提交的数据:', formData);
console.log('书名:', formData.name);
console.log('作者:', formData.author);
console.log('出版社:', formData.publisher);
console.log('印刷时间:', formData.printTime);
// 检查是否重复书籍
uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/shopGoods/repeatBook',
method: 'POST',
data: formData,
header: {
'Content-Type': 'application/json'
},
success: (res) => {
if (res.data.data && res.data.data.count != 0) {
// 如果是重复书籍,弹出确认框
const bookName = res.data.data && res.data.data.name ? res.data.data.name
.trim() :
''; // 添加空值检查
// 1. MD5 32位加密小写
const md5Hash = CryptoJS.MD5(bookName).toString(); // 输出 32 位小写十六进制字符串
// 2. 获取首字母并大写
const firstLetter = bookName ? md5Hash.charAt(0).toUpperCase() : '';
console.log('原始书名:', bookName);
console.log('MD5加密后32位小写:', md5Hash);
console.log('加密后字符串的首字母大写:', firstLetter);
const imagePath = res.data.data && res.data.data.image ? res.data.data
.image :
'';
console.log("图片", imagePath)
// 拼接图片地址
const fullImageUrl =
`https://img.buzhiyushu.cn/zhishu1/${firstLetter}/${imagePath}`;
console.log("fullImageUrl", fullImageUrl)
// 根据count值动态设置下拉框的起始字母
const count = res.data.data && res.data.data.count ? res.data.data.count :
0;
const allLetters = ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M',
'N'
];
// 如果count为1从B开始count为2从C开始以此类推
const startIndex = count > 0 ? count - 1 : 0;
if (startIndex >= 0 && startIndex < allLetters.length) {
// 从对应位置截取字母数组
this.popupDialog.seriesOptions = allLetters.slice(startIndex);
// 默认选中第一个字母即对应count的字母
this.popupDialog.selectedSeries = this.popupDialog.seriesOptions[0];
}
this.popupDialog.title = '提示'
this.popupDialog.content = '请仔细核对此书是否为套装书,一号多书等情况?请选择(否:增加库存 是:新增书籍)'
this.popupDialog.confirmText = '是'
this.popupDialog.cancelText = '否'
this.popupDialog.imgSrc = fullImageUrl
this.popupDialog.show = true
this.popupDialog.count = count || 0 // 添加默认值防止count为null
this.popupDialog.subFormData = formData
} else {
// 不是重复书籍,直接提交
this.submitToServer(formData);
}
},
fail: (err) => {
console.error('检查重复书籍失败:', err);
uni.showToast({
title: '网络错误,请稍后重试',
icon: 'none',
duration: 2500
});
this.isSubmitting = false; // 重置提交状态
}
});
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 2000
});
} catch (error) {
console.error('提交失败:', error);
uni.showToast({
title: '提交失败',
icon: 'none',
duration: 2000
});
} finally {
this.isSubmitting = false;
}
},
onPopupConfirm() {
// 直接使用选择的字母作为series参数
this.popupDialog.subFormData.series = this.popupDialog.selectedSeries;
console.log("字母", this.popupDialog.subFormData.series)
// 继续提交流程
this.submitToServer(this.popupDialog.subFormData);
this.popupDialog.show = false
},
// 处理字母选择确认事件
onSeriesConfirm(e) {
this.popupDialog.selectedSeries = e.value[0];
this.popupDialog.showPicker = false;
},
// 根据书名查询在售商品
async getBookName() {
// 检查用户是否可以上传书籍
const canUpload = await checkMemberBooksCount();
if (!canUpload) {
// 如果不能上传,则直接返回,不继续执行
return;
}
// 如果有普通上传的图片,则不允许查询
if (this.hasNormalImages) {
uni.showToast({
title: '已上传图片,不可修改书名',
icon: 'none',
duration: 2000
});
return;
}
try {
// 检查是否有书名
if (!this.bookInfo.bookName) {
uni.showToast({
title: '请输入书名',
icon: 'none',
duration: 2500
});
return;
}
// 检查用户是否可以上传书籍
const canUpload = await checkMemberBooksCount();
if (!canUpload) {
// 如果不能上传,则直接返回,不继续执行
return;
}
// 显示加载提示
uni.showLoading({
title: '查询中...',
mask: true
});
// 获取书籍基本信息
const res = await uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/baseInfo/getBookByName',
method: 'POST',
header: {
'Content-Type': 'application/json'
},
data: {
bookName: this.bookInfo.bookName
}
});
// 处理响应数据
const responseData = Array.isArray(res) ? res[1] : res;
if (responseData.statusCode === 200 && responseData.data && responseData.data.data) {
const resultData = responseData.data.data;
console.log("获取到的书籍信息:", resultData);
// 更新表单数据,保留已有数据
if (resultData) {
this.bookInfo = {
...this.bookInfo,
author: resultData.author || this.bookInfo.author || '',
publisher: resultData.publisher || this.bookInfo.publisher || '',
format: resultData.format || '32',
printTime: resultData.printTime || this.bookInfo.printTime || '',
unifyIsbn: resultData.isbn || this.bookInfo.unifyIsbn || '',
price: resultData.price ? String(resultData.price).replace('元', '') : this.bookInfo
.price || '',
wordage: resultData.wordage || this.bookInfo.wordage || ''
};
}
// 处理ISBN
if (!this.bookInfo.isbn) {
try {
const isbnResponse = await uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/statistic/isbn',
method: 'GET'
});
if (Array.isArray(isbnResponse)) {
this.bookInfo.isbn = isbnResponse[1].data;
} else {
this.bookInfo.isbn = isbnResponse.data;
}
console.log("生成的ISBN:", this.bookInfo.isbn);
} catch (error) {
console.error('获取ISBN失败使用备用方案:', error);
this.bookInfo.isbn = this.generateRandomIsbn();
}
}
// 获取作者和出版社信息
await this.updateAuthorAndPublisher();
// 获取在售商品信息
await this.fetchOnSaleProducts(this.bookInfo.bookName);
uni.showToast({
title: '查询成功',
icon: 'success',
duration: 1500
});
} else {
// 如果没有查到数据也获取ISBN和在售商品信息
if (!this.bookInfo.isbn) {
this.bookInfo.isbn = this.generateRandomIsbn();
}
await this.fetchOnSaleProducts(this.bookInfo.bookName);
uni.showToast({
title: '未找到完整信息,已获取部分数据',
icon: 'none',
duration: 2000
});
}
} catch (error) {
console.error('查询失败:', error);
// 即使请求失败,也尝试获取在售商品信息
try {
if (!this.bookInfo.isbn) {
this.bookInfo.isbn = this.generateRandomIsbn();
}
await this.fetchOnSaleProducts(this.bookInfo.bookName);
} catch (innerError) {
console.error('获取在售商品信息失败:', innerError);
}
uni.showToast({
title: '查询失败,已获取部分数据',
icon: 'none',
duration: 2000
});
} finally {
uni.hideLoading();
}
},
// 图片上传到服务器(带超时和重试机制)
async uploadFilePromise(url, index, retryCount = 0) {
const maxRetries = 2; // 最大重试次数
const timeout = 30000; // 30秒超时
console.log(`uploadFilePromise被调用: url=${url}, index=${index}, retryCount=${retryCount}`);
console.log("fileList1", this.fileList1)
console.log(`当前fileList1状态:`, JSON.stringify(this.fileList1.map(f => ({
status: f.status,
hidden: f.hidden,
name: f.name,
num: f.num
}))));
// 检查参数
if (!url) {
console.error('上传失败: url参数为空');
throw new Error('url参数为空');
}
// 获取当前选项卡下的书名和ISBN
const bookName = this.bookInfo.bookName;
let isbn = this.bookInfo.isbn;
// 获取存储的仓库相关ID
const warehouseId = uni.getStorageSync('warehouseId');
const shelfId = uni.getStorageSync('shelfId');
const locationId = uni.getStorageSync('locationId');
// 检查书名和ISBN
if (!bookName || !isbn) {
console.error(`上传失败: 书名或ISBN为空, 书名=${bookName}, ISBN=${isbn}`);
throw new Error('书名或ISBN为空');
}
console.log(`开始上传图片: 书名=${bookName}, ISBN=${isbn}, 索引=${index}`);
// 图片编号从1开始使用传入的索引+1或者找到对应文件的num值
let num = (index + 1).toString();
// 查找对应的文件是否已有num值
const fileWithUrl = this.fileList1.find(f => f.url === url);
if (fileWithUrl && fileWithUrl.num) {
num = fileWithUrl.num;
}
console.log(`上传图片编号: ${num}`);
return new Promise((resolve, reject) => {
// 设置超时定时器
const timer = setTimeout(() => {
console.error(`图片上传超时(${timeout}ms): ${url}`);
reject(new Error('上传超时'));
}, timeout);
const uploadTask = uni.uploadFile({
url: "https://xcx.uploadfile.yushutx.com/uploadImages",
filePath: url,
name: "file",
timeout: timeout, // 添加超时参数
success: (res) => {
clearTimeout(timer); // 清除超时定时器
// 解析返回结果
console.log('图片上传成功:', res);
// 解析返回结果
const data = JSON.parse(res.data);
console.log("data", data)
const urlData = JSON.parse(data.data);
const imageUrl = urlData.url || url;
console.log("url", imageUrl)
// 将上传成功的图片信息存储到数组中
this.uploadedImages.push({
url: imageUrl,
bookName: bookName,
isbn: isbn,
num: num,
warehouseId: warehouseId,
shelfId: shelfId,
locationId: locationId,
originalUrl: url
});
resolve(imageUrl);
},
fail: async (err) => {
clearTimeout(timer); // 清除超时定时器
console.error('图片上传失败:', err);
// 如果未达到最大重试次数,则重试
if (retryCount < maxRetries) {
console.log(`上传失败,准备重试 (${retryCount + 1}/${maxRetries})...`);
try {
// 等待1秒后重试
await new Promise(resolve => setTimeout(resolve, 1000));
const result = await this.uploadFilePromise(url, index, retryCount + 1);
resolve(result);
} catch (retryError) {
reject(retryError);
}
} else {
reject(err);
}
}
});
});
},
onPopupCancel() {
// 继续提交流程
this.submitToServer(this.popupDialog.subFormData);
this.popupDialog.show = false
},
// 提交到服务器的方法
async submitToServer(formData) {
const validateFormData = (data) => {
const requiredFields = {
name: '书名',
publisher: '出版社',
author: '作者',
printTime: '印刷时间'
};
for (const [field, label] of Object.entries(requiredFields)) {
if (!data[field]) {
throw new Error(`请输入${label}`);
}
}
if (!data.conditionCode) {
throw new Error('请选择品相');
}
if (!data.depotName || !data.shelvesName || !data.freightName) {
throw new Error('请选择仓库/货架/货位');
}
};
try {
// 调试日志,检查提交的数据
console.log('submitToServer数据检查:', formData);
console.log('书名字段:', formData.name);
validateFormData(formData);
const response = await new Promise((resolve, reject) => {
uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/shopGoods/submitFromCopyrightPage',
// url: 'http://192.168.101.209:8080/zhishu/shopGoods/submitFromCopyrightPage',
method: 'POST',
data: formData,
header: {
'Content-Type': 'application/json'
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res);
} else {
reject(new Error('服务器响应错误'));
}
},
fail: (err) => reject(new Error('网络请求失败'))
});
});
// 保存相关信息到本地存储
uni.setStorageSync('lastSelectedStorage', this.selectedStorage);
uni.setStorageSync('lastSelectedWarehouse', this.warehouse);
uni.setStorageSync('lastSelectedShelf', this.shelf);
uni.setStorageSync('lastSelectedLocation', this.location);
// 从第一个API响应中提取ID
const responseData = response.data.data;
const idsToPass = {
depotId: responseData.depotId,
freightId: responseData.freightId,
goodsId: responseData.goodsId,
shelvesId: responseData.shelvesId,
userId: responseData.userId,
artNo: responseData.artNo,
};
// 创建包含ID的新formData
const newFormData = {
...formData,
...idsToPass
};
// 调用newadmin API
try {
await new Promise((resolve, reject) => {
uni.request({
url: 'https://newadmin.buzhiyushu.cn/zhishu/shopGoods/submitFromCopyrightPage',
// url: 'http://localhost:8089/zhishu/shopGoods/submitFromCopyrightPage',
method: 'POST',
data: newFormData,
header: {
'Content-Type': 'application/json'
},
success: (newAdminRes) => {
console.log('newadmin API请求成功:', newAdminRes);
resolve(newAdminRes);
},
fail: (newAdminErr) => {
console.error('newadmin API请求失败:', newAdminErr);
reject(newAdminErr);
}
});
});
} catch (newAdminError) {
console.error('newadmin API调用失败:', newAdminError);
// 不影响主流程,只记录错误
}
// 清空表单数据,但保留货区和品相
this.resetFormData();
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 2000
});
return response.data;
} catch (error) {
console.error('提交失败:', error);
uni.showToast({
title: error.message || '提交失败',
icon: 'none',
duration: 2500
});
throw error;
}
},
// 新增:重置表单数据的方法
resetFormData() {
// 保存当前的货区和品相数据
const currentStorage = this.selectedStorage;
const currentWarehouse = this.warehouse;
const currentShelf = this.shelf;
const currentLocation = this.location;
const currentSelectedSheId = this.selectedSheId;
const currentSelectedFreId = this.selectedFreId;
// 清空表单数据
this.bookInfo = {
bookName: '',
author: '',
publisher: '',
format: '',
printTime: '',
isbn: '',
price: '',
wordage: ''
};
this.imageUrl = '';
this.uploadedImages = [];
this.fileList1 = [];
this.value3 = 1;
this.errorMsg = '';
this.onSaleProducts = [];
this.displayOnSaleProducts = [];
// 恢复货区数据
this.selectedStorage = currentStorage;
this.warehouse = currentWarehouse;
this.shelf = currentShelf;
this.location = currentLocation;
this.selectedSheId = currentSelectedSheId;
this.selectedFreId = currentSelectedFreId;
if (this.$refs.onSaleProductsComponent) {
this.$refs.onSaleProductsComponent.setCompareType('isbn');
}
},
// 获取上书记录
async getBookRecords() {
try {
// 从本地存储获取手机号
const phoneNumber = uni.getStorageSync('phoneNumber');
if (!phoneNumber) {
uni.showToast({
title: '请先登录',
icon: 'none',
duration: 2500
});
return;
}
// 显示加载提示
uni.showLoading({
title: '加载中...'
});
try {
// 调用获取上书记录的方法
const records = await bookRecords.fetchBookRecords(phoneNumber);
console.log("1111", records)
if (!records || records.length === 0) {
uni.showToast({
title: '暂无上书记录',
icon: 'none',
duration: 2500
});
return;
}
// 跳转到上书记录页面并传递数据
uni.navigateTo({
url: '/pkgUser/book-records',
success: (res) => {
// 向打开的页面传递数据
res.eventChannel.emit('bookRecordsData', {
records: records
});
}
});
} finally {
// 确保在任何情况下都隐藏加载提示
uni.hideLoading();
}
} catch (error) {
console.error('获取上书记录失败:', error);
uni.showToast({
title: error.message || '获取上书记录失败',
icon: 'none',
duration: 2500
});
}
},
extractAuthorsAndPublishers() {
const authors = new Set();
const publishers = new Set();
this.onSaleProducts.forEach(item => {
if (item.author) authors.add(item.author);
if (item.publisher) publishers.add(item.publisher);
});
this.authorOptions = Array.from(authors).slice(0, 10);
this.publisherOptions = Array.from(publishers).slice(0, 10);
},
selectAuthor(author) {
this.bookInfo.author = author;
this.authorDropdownVisible = false;
},
selectPublisher(publisher) {
this.bookInfo.publisher = publisher;
this.publisherDropdownVisible = false;
},
selectFormat(format) {
this.bookInfo.format = format;
this.formatDropdownVisible = false;
},
closeAllDropdowns(e) {
// 如果点击事件来自下拉按钮或下拉内容本身,则不关闭
const path = e && (e.path || (e.composedPath && e.composedPath()));
if (path) {
if (path.some(el => el && el.classList && (el.classList.contains('dropdown-btn') || el.classList
.contains('dropdown-list')))) {
return;
}
}
this.authorDropdownVisible = false;
this.publisherDropdownVisible = false;
this.formatDropdownVisible = false;
},
// 添加处理版权页比价的方法
async handleCopyrightCompare(payload) {
try {
const conditionValue = uni.getStorageSync("conditionValue");
const sortType = 7;
const cookies = uni.getStorageSync('cookies');
// 调用获取在售商品的方法,传入 options 对象
const mockData = await this.$selectBookImage.fetchOnSaleProducts(
this.bookInfo.bookName,
sortType,
conditionValue,
cookies, {
publisher: this.bookInfo.publisher,
author: this.bookInfo.author
}
);
// 过滤黑名单店铺
const blockedShopsStr = uni.getStorageSync('blockedShops') || '';
const blockedShops = blockedShopsStr.split(';').filter(shop => shop.trim() !== '');
const filteredData = mockData.filter(product => {
return !blockedShops.some(shop =>
product.shopName && product.shopName.includes(shop.trim())
);
});
// 新增:如果没有数据,提示暂无在售商品数据
if (!filteredData || filteredData.length === 0) {
uni.showToast({
title: '暂无在售商品数据',
icon: 'none',
duration: 2500
});
}
// 更新数据
this.onSaleProducts = [...filteredData];
this.extractAuthorsAndPublishers();
if (this.$refs.onSaleProductsComponent) {
this.$refs.onSaleProductsComponent.updateProducts(this.onSaleProducts);
}
this.calculateReferencePrice();
} catch (error) {
console.error('获取在售商品信息失败:', error);
uni.showToast({
title: '获取在售商品信息失败',
icon: 'none',
duration: 2500
});
}
},
// 下拉刷新钩子
onPullDownRefresh() {
// 重新识别图片(如果有图片)
if (this.imageUrl) {
// this.recognizeImage();
} else {
// 没有图片时,重置识别结果
this.bookInfo = {
bookName: '',
author: '',
publisher: '',
format: '',
printTime: '',
isbn: '',
price: '',
wordage: ''
};
this.onSaleProducts = [];
this.displayOnSaleProducts = [];
}
// 结束下拉刷新动画
setTimeout(() => {
uni.stopPullDownRefresh();
}, 800);
},
// 处理bcode-camera组件拍照结果的方法
async handleBcodeCameraResult(data) {
console.log('handleBcodeCameraResult被调用data:', data);
// 获取拍照结果
const tempFilePath = data.url;
// 如果没有拍照结果,按取消处理
if (!tempFilePath) {
this.handleBcodeCameraCancel();
return;
}
// 新增:显示图片预览和动画
this.previewImageUrl = tempFilePath;
this.showRecognizing = true;
try {
// 保存当前的货区和品相数据
const currentStorage = this.selectedStorage;
const currentWarehouse = this.warehouse;
const currentShelf = this.shelf;
const currentLocation = this.location;
const currentSelectedSheId = this.selectedSheId;
const currentSelectedFreId = this.selectedFreId;
// 保存当前的品相选择
let currentCondition = null;
if (this.$refs.conditionSelect) {
currentCondition = this.$refs.conditionSelect.getSelectedCondition();
console.log('保存当前品相:', currentCondition);
}
// 显示自定义识别中动画
this.showRecognizing = true;
// 获取图片信息
const fileInfo = await new Promise((resolve, reject) => {
uni.getFileInfo({
filePath: tempFilePath,
success: (info) => {
console.log('【当前图片体积】', info.size, '字节', (info.size / 1024)
.toFixed(2) + 'KB');
resolve(info);
},
fail: (err) => {
reject(err);
}
});
});
// 如果图片大于500KB进行压缩
let finalFilePath = tempFilePath;
if (fileInfo.size > 500 * 1024) {
try {
finalFilePath = await this.compressImage(tempFilePath);
} catch (error) {
console.error('图片压缩失败:', error);
this.showRecognizing = false;
uni.showToast({
title: '图片压缩失败',
icon: 'none',
duration: 2500
});
return;
}
}
// OCR识别重试逻辑
const MAX_RETRIES = 3;
const RETRY_DELAY = 7000; // 7秒重试延迟
let retryCount = 0;
const performOCR = async () => {
try {
const ocrResult = await new Promise((resolve, reject) => {
uni.uploadFile({
// url: 'https://book.ocr.buzhiyushu.cn/ocr',
url: 'https://book.xcx.ocr.buzhiyushu.cn/ocr',
filePath: finalFilePath,
name: 'file',
success: (res) => {
console.log("res",res)
if (res.statusCode === 200) {
resolve(res);
} else {
reject(new Error('OCR服务器响应错误'));
}
},
fail: (err) => reject(new Error('OCR请求失败'))
});
});
const ocrData = JSON.parse(ocrResult.data);
if (!ocrData || !ocrData.texts) {
throw new Error('OCR识别结果无效');
}
return ocrData;
} catch (error) {
if (retryCount < MAX_RETRIES) {
retryCount++;
console.log(`OCR识别失败${retryCount}次重试,等待${RETRY_DELAY/1000}秒...`);
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
return await performOCR();
}
throw error;
}
};
// 开始OCR识别
const ocrData = await performOCR();
console.log("ocrData", ocrData)
// 处理OCR结果
if (ocrData.texts) {
// 保存当前的bookInfo只更新识别到的字段
const currentBookInfo = {
...this.bookInfo
};
// 处理开本数据如果不在预设列表中或者OCR结果中没有开本字段则设置为默认值"32"
let formatValue = ocrData.texts.开本 || currentBookInfo.format || '32';
if (formatValue && !this.formatOptions.includes(formatValue)) {
formatValue = "32";
}
// 更新识别到的字段,保留未识别到的原有值
this.bookInfo = {
bookName: ocrData.texts.书名 || currentBookInfo.bookName || '',
author: ocrData.texts.作者 || currentBookInfo.author || '',
publisher: ocrData.texts.出版社 || currentBookInfo.publisher || '',
unifyIsbn: ocrData.texts.书号 || ocrData.texts.ISBN || currentBookInfo.unifyIsbn || '',
printTime: ocrData.texts.出版时间 || currentBookInfo.printTime || '',
price: ocrData.texts.定价 ? ocrData.texts.定价.replace('元', '') : currentBookInfo.price ||
'',
format: formatValue,
wordage: this.processWordage(ocrData.texts.字数) || currentBookInfo.wordage || '',
};
console.log("this.bookInfo", this.bookInfo)
// 检查isbn
const isbn = this.bookInfo.isbn;
if (!isbn || !/^\d{13}$/.test(isbn)) {
try {
const isbnRes = await new Promise((resolve, reject) => {
uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/statistic/isbn',
method: 'GET',
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
}
});
});
this.bookInfo.isbn = isbnRes.data;
} catch (error) {
console.error('获取随机ISBN失败:', error);
}
}
// 将拍摄的照片添加到fileList1中但不上传
const newFile = {
url: tempFilePath,
status: "local", // 改为"local"状态,避免触发上传验证
message: "本地识图照片",
name: `识图-${Date.now()}.jpg`, // 使用时间戳确保唯一性
hidden: true, // 添加hidden属性表示不在UI中显示
num: "999", // 设置为很大的编号,确保排在最后
isOCR: true // 标记为识图照片
};
// 移除之前的识图上传图片(如果存在)
this.fileList1 = this.fileList1.filter(file => !file.name || !file.name.startsWith('识图-'));
// 添加新的识图上传图片(不上传,仅保存)
this.fileList1.push(newFile);
console.log('识图图片已添加到fileList1:', this.fileList1);
// 不再调用uploadFilePromise方法上传图片
// 隐藏识别中动画
this.showRecognizing = false;
// 新增:隐藏图片预览
this.previewImageUrl = '';
// 显示识别成功提示
uni.showToast({
title: '识别成功',
icon: 'success',
duration: 1500
});
// 隐藏相机组件
this.showBcodeCamera = false;
// 恢复显示提交按钮
this.showSubmitButton = true;
this.$emit('camera-status-change', false);
// 获取在售商品信息
if (this.bookInfo.bookName) {
await this.fetchOnSaleProducts(this.bookInfo.bookName);
await this.updateAuthorAndPublisher();
}
// 使用 setTimeout 确保在 DOM 更新后恢复数据
setTimeout(() => {
// 恢复货区数据
this.selectedStorage = currentStorage;
this.warehouse = currentWarehouse;
this.shelf = currentShelf;
this.location = currentLocation;
this.selectedSheId = currentSelectedSheId;
this.selectedFreId = currentSelectedFreId;
// 通过 emit 事件更新 WarehouseSelector 组件
if (this.$refs.warehouseSelector) {
this.$refs.warehouseSelector.$emit('storage-selected', {
storage: currentStorage,
warehouse: currentWarehouse,
shelf: currentShelf,
location: currentLocation,
shelfId: currentSelectedSheId,
locationId: currentSelectedFreId
});
}
// 恢复品相选择
if (this.$refs.conditionSelect && currentCondition) {
this.$refs.conditionSelect.setSelection(currentCondition.name);
}
console.log('已恢复货区数据:', this.selectedStorage, this.warehouse, this.shelf, this
.location);
// 强制更新整个表单
this.$forceUpdate();
}, 300);
}
} catch (error) {
console.error('OCR识别失败:', error);
uni.showToast({
title: '识别失败,请重试',
icon: 'none',
duration: 2500
});
// 隐藏相机组件
this.showBcodeCamera = false;
// 隐藏识别中动画和图片预览
this.showRecognizing = false;
this.previewImageUrl = '';
// 恢复显示提交按钮
this.showSubmitButton = true;
this.$emit('camera-status-change', false);
}
},
// 取消bcode-camera
handleBcodeCameraCancel() {
// 保存当前的货区和品相数据
const currentStorage = this.selectedStorage;
const currentWarehouse = this.warehouse;
const currentShelf = this.shelf;
const currentLocation = this.location;
const currentSelectedSheId = this.selectedSheId;
const currentSelectedFreId = this.selectedFreId;
// 保存当前的品相选择
let currentCondition = null;
if (this.$refs.conditionSelect) {
currentCondition = this.$refs.conditionSelect.getSelectedCondition();
console.log('取消时保存当前品相:', currentCondition);
}
// 隐藏相机组件和识别动画
this.showBcodeCamera = false;
this.showRecognizing = false;
this.previewImageUrl = '';
// 恢复显示提交按钮
this.showSubmitButton = true;
this.$emit('camera-status-change', false);
// 使用 setTimeout 确保在 DOM 更新后恢复数据
setTimeout(() => {
// 恢复货区数据
this.selectedStorage = currentStorage;
this.warehouse = currentWarehouse;
this.shelf = currentShelf;
this.location = currentLocation;
this.selectedSheId = currentSelectedSheId;
this.selectedFreId = currentSelectedFreId;
// 通过 emit 事件更新 WarehouseSelector 组件
if (this.$refs.warehouseSelector) {
this.$refs.warehouseSelector.$emit('storage-selected', {
storage: currentStorage,
warehouse: currentWarehouse,
shelf: currentShelf,
location: currentLocation,
shelfId: currentSelectedSheId,
locationId: currentSelectedFreId
});
}
// 恢复品相选择
if (this.$refs.conditionSelect && currentCondition) {
this.$refs.conditionSelect.setSelection(currentCondition.name);
}
console.log('取消时已恢复货区数据:', this.selectedStorage, this.warehouse, this.shelf, this.location);
// 强制更新整个表单
this.$forceUpdate();
}, 300);
},
// 添加生成ISBN的公共方法
async generateIsbn() {
try {
const response = await uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/statistic/isbn',
method: 'GET'
});
return response.data;
} catch (error) {
console.error('获取随机ISBN失败:', error);
throw error;
}
},
// 添加一个生成随机ISBN的备用方法
generateRandomIsbn() {
// 生成符合ISBN-13格式的随机号码
// 978是图书的EAN前缀
let isbn = "978";
// 添加9位随机数字
for (let i = 0; i < 9; i++) {
isbn += Math.floor(Math.random() * 10).toString();
}
// 计算校验位
let sum = 0;
for (let i = 0; i < 12; i++) {
sum += parseInt(isbn[i]) * (i % 2 === 0 ? 1 : 3);
}
const checkDigit = (10 - (sum % 10)) % 10;
// 添加校验位
isbn += checkDigit;
return isbn;
},
// 压缩图片方法
compressImage(filePath) {
return new Promise((resolve, reject) => {
uni.compressImage({
src: filePath,
quality: 80, // 压缩质量范围0-100
compressedWidth: 800, // 压缩图片的宽度
compressedHeight: 800, // 压缩图片的高度
success: (res) => {
console.log('图片压缩成功:', res.tempFilePath);
resolve(res.tempFilePath);
},
fail: (err) => {
console.error('图片压缩失败:', err);
// 如果压缩失败,返回原图
resolve(filePath);
}
});
});
},
// 显示印刷时间键盘
showPrintTimeKeyboard() {
// 先隐藏可能的系统键盘
uni.hideKeyboard();
// 显示自定义时间选择器
this.printTimePopupVisible = true;
// 如果已有值,解析到年月字段
if (this.bookInfo.printTime) {
const parts = this.bookInfo.printTime.split('/');
if (parts.length >= 1) {
this.printTimeYear = parts[0];
}
if (parts.length >= 2) {
this.printTimeMonth = parts[1];
}
}
this.printTimeActiveInput = 'year';
},
// 关闭印刷时间弹窗
closePrintTimePopup() {
this.printTimePopupVisible = false;
},
// 输入数字
inputPrintTimeDigit(digit) {
if (this.printTimeActiveInput === 'year') {
// 年份限制为4位
if (this.printTimeYear.length < 4) {
this.printTimeYear += digit;
}
// 当年份输入完成后自动切换到月份
if (this.printTimeYear.length === 4) {
this.printTimeActiveInput = 'month';
}
} else {
// 月份限制为2位
if (this.printTimeMonth.length < 2) {
this.printTimeMonth += digit;
// 如果输入的第一位大于1自动补0
if (this.printTimeMonth.length === 1 && parseInt(this.printTimeMonth) > 1) {
this.printTimeMonth = '0' + this.printTimeMonth;
}
// 如果输入的值大于12设为12
if (parseInt(this.printTimeMonth) > 12) {
this.printTimeMonth = '12';
}
}
}
},
// 删除数字
deletePrintTimeDigit() {
if (this.printTimeActiveInput === 'month') {
if (this.printTimeMonth.length > 0) {
this.printTimeMonth = this.printTimeMonth.slice(0, -1);
} else {
// 如果月份已经为空,切换到年份
this.printTimeActiveInput = 'year';
}
}
if (this.printTimeActiveInput === 'year') {
if (this.printTimeYear.length > 0) {
this.printTimeYear = this.printTimeYear.slice(0, -1);
}
}
},
// 使用当前日期
useCurrentDate() {
this.autoFillSelected = !this.autoFillSelected;
if (this.autoFillSelected) {
const now = new Date();
this.printTimeYear = now.getFullYear().toString();
this.printTimeMonth = (now.getMonth() + 1).toString().padStart(2, '0');
this.printTimeActiveInput = 'month';
} else {
// 如果取消自动填充,清空输入
this.printTimeYear = '';
this.printTimeMonth = '';
this.printTimeActiveInput = 'year';
}
},
// 确认印刷时间
confirmPrintTime() {
let printTime = '';
if (this.printTimeYear) {
printTime = this.printTimeYear;
if (this.printTimeMonth) {
printTime += '/' + this.printTimeMonth;
}
}
this.bookInfo.printTime = printTime;
this.closePrintTimePopup();
},
// 添加选择年代的方法
selectDecade(decadePrefix) {
// 切换到填写时间选项卡
this.printTimeTab = 'input';
// 自动填充年份为选择的年代中间年份如1950年代填充为1955
this.printTimeYear = decadePrefix + '5';
// 清空月份
this.printTimeMonth = '';
// 焦点切换到月份
this.printTimeActiveInput = 'month';
// 取消自动填充选择
this.autoFillSelected = false;
},
// 添加resetData方法用于下拉刷新
async resetData() {
// 保存当前的货区数据
const currentStorage = this.selectedStorage;
const currentWarehouse = this.warehouse;
const currentShelf = this.shelf;
const currentLocation = this.location;
const currentSelectedSheId = this.selectedSheId;
const currentSelectedFreId = this.selectedFreId;
// 重置表单数据
this.bookInfo = {
bookName: '',
author: '',
publisher: '',
format: '',
printTime: '',
isbn: '',
price: '',
wordage: '',
unifyIsbn: ''
};
// 重置其他数据
this.value4 = 1.00; // 重置价格
this.value3 = 1; // 重置库存
this.fileList1 = []; // 清空图片列表
this.uploadedImages = []; // 清空已上传图片
this.hasShownUploadMessage = false;
// 重置市场标签
this.marketTags = [{
label: '在售:',
value: 0
},
{
label: '旧:',
value: 0
},
{
label: '新:',
value: 0
},
{
label: '已售:',
value: 0
}
];
// 重置在售商品列表
this.onSaleProducts = [];
this.displayOnSaleProducts = [];
// 重置下拉选项
this.authorOptions = [];
this.publisherOptions = [];
this.authorDropdownVisible = false;
this.publisherDropdownVisible = false;
this.formatDropdownVisible = false;
// 重置分类选择
this.categoryIndexes = [];
this.categoryPathText = '';
this.selectedCategoryId = '';
this.categoryLevels = [];
this.initCategoryPicker(); // 重新初始化选择器
// 等待DOM更新
await this.$nextTick();
// 恢复货区数据
this.selectedStorage = currentStorage;
this.warehouse = currentWarehouse;
this.shelf = currentShelf;
this.location = currentLocation;
this.selectedSheId = currentSelectedSheId;
this.selectedFreId = currentSelectedFreId;
// 重置品相选择
if (this.$refs.conditionSelect) {
this.$refs.conditionSelect.resetSelection();
}
// 重置在售商品组件
if (this.$refs.onSaleProductsComponent) {
this.$refs.onSaleProductsComponent.updateProducts([]);
}
// 通过emit事件更新WarehouseSelector组件
if (this.$refs.warehouseSelector) {
this.$refs.warehouseSelector.$emit('storage-selected', {
storage: currentStorage,
warehouse: currentWarehouse,
shelf: currentShelf,
location: currentLocation,
shelfId: currentSelectedSheId,
locationId: currentSelectedFreId
});
}
// 强制更新视图
this.$forceUpdate();
},
// 处理OCR识别的字数将"千字"转换为实际数字
processWordage(wordage) {
if (!wordage) return '';
// 检查是否包含"千字"
if (typeof wordage === 'string' && wordage.includes('千字')) {
// 提取数字部分
const numMatch = wordage.match(/(\d+(\.\d+)?)/);
if (numMatch && numMatch[1]) {
// 将数字乘以1000
const num = parseFloat(numMatch[1]) * 1000;
return Math.round(num).toString(); // 四舍五入并转为字符串
}
}
return wordage;
},
// 获取图书分类数据
async fetchCategoryData() {
try {
console.log('开始获取分类数据...');
// 获取cookies作为token
const cookies = uni.getStorageSync('cookies');
console.log('获取到的cookies:', cookies);
// if (!cookies) {
// console.error('获取分类失败: 未找到cookies');
// uni.showToast({
// title: '请先登录获取授权',
// icon: 'none',
// duration: 2000
// });
// return;
// }
console.log('使用token获取分类数据...');
uni.showLoading({
title: '加载分类...'
});
// 调用后端接口获取分类数据
console.log('发起API请求到:', 'https://api.buzhiyushu.cn/api/kongfz/getCategory');
const res = await uni.request({
url: 'https://api.buzhiyushu.cn/api/kongfz/getCategory',
method: 'GET',
data: {
token: cookies
},
header: {
'Content-Type': 'application/json'
}
});
uni.hideLoading();
console.log('分类数据API响应:', res);
console.log('响应状态码:', res.statusCode);
// 处理返回的数据,兼容不同格式
const responseData = Array.isArray(res) ? res[1].data : res.data;
console.log('处理后的responseData:', responseData);
if (responseData && responseData.successResponse) {
// 保存完整的分类数据
this.categoryList = responseData.successResponse;
console.log('分类数据获取成功,开始初始化选择器');
this.initCategoryPicker();
console.log('分类数据获取成功:', this.categoryList);
} else {
console.error('获取分类数据失败, 响应不符合预期:', responseData);
console.log('responseData类型:', typeof responseData);
console.log('responseData内容:', JSON.stringify(responseData));
uni.showToast({
title: '获取分类数据失败',
icon: 'none',
duration: 2000
});
}
} catch (error) {
uni.hideLoading();
console.error('获取分类数据异常:', error);
console.error('错误详情:', error.message);
uni.showToast({
title: '获取分类数据失败',
icon: 'none',
duration: 2000
});
}
},
// 分类数据初始化
initCategoryPicker() {
console.log('initCategoryPicker开始执行');
console.log('原始categoryList:', this.categoryList);
// 初始化分类选择器数据
this.categoryColumns = []; // 清空所有列
this.categoryLevels = []; // 清空选中的分类对象
this.categoryIndexes = []; // 清空索引
// 过滤出一级分类
const level1Categories = (this.categoryList || []).filter(item => item.level === 1);
// 如果没有数据,提供默认值
if (level1Categories.length === 0) {
// 设置一个默认的空分类
this.categoryColumns = Array(this.maxCategoryLevel).fill([{
name: '暂无数据',
id: ''
}]);
this.categoryIndexes = Array(this.maxCategoryLevel).fill(0);
this.categoryPathText = '';
this.selectedCategoryId = '';
console.log('没有分类数据,使用默认空分类');
return;
}
// 设置第一列(一级分类)
this.categoryColumns[0] = level1Categories;
this.categoryIndexes[0] = 0;
// 递归初始化所有可能的列
let currentParent = level1Categories[0];
let currentLevel = 1;
this.categoryLevels[0] = currentParent; // 保存一级分类
while (currentLevel < this.maxCategoryLevel) {
// 检查当前选中分类是否有子分类
const children = currentParent.children || [];
// 如果没有子分类或者已经到达最大级别,就中断循环
if (children.length === 0) {
break;
}
// 设置下一列数据
this.categoryColumns[currentLevel] = children;
this.categoryIndexes[currentLevel] = 0;
this.categoryLevels[currentLevel] = children[0];
// 继续下一级
currentParent = children[0];
currentLevel++;
}
// 填充剩余的列(如果需要)
while (this.categoryColumns.length < this.maxCategoryLevel) {
this.categoryColumns.push([{
name: '暂无数据',
id: ''
}]);
this.categoryIndexes.push(0);
this.categoryLevels.push({
name: '暂无数据',
id: ''
});
}
// 设置分类路径文本
this.updateCategoryPathText();
// 设置选中的分类ID叶子节点的ID
this.updateSelectedCategoryId();
console.log('初始化后的分类数据:', {
categoryColumns: this.categoryColumns,
categoryIndexes: this.categoryIndexes,
categoryLevels: this.categoryLevels,
categoryPathText: this.categoryPathText,
selectedCategoryId: this.selectedCategoryId
});
console.log('initCategoryPicker执行完成');
},
// 处理多列选择器的列变化
onCategoryColumnChange(e) {
// 获取当前变化的列和选中的值
const {
column,
value
} = e.detail;
console.log(`列变化: 第${column}列, 值=${value}`);
// 更新对应列的索引
this.categoryIndexes[column] = value;
// 更新选中的分类对象
this.categoryLevels[column] = this.categoryColumns[column][value];
// 如果不是最后一列,需要级联更新后续列
if (column < this.maxCategoryLevel - 1) {
// 从当前列的下一列开始,重置所有后续列
this.updateSubsequentColumns(column + 1);
}
// 更新分类路径和选中ID
this.updateCategoryPathText();
this.updateSelectedCategoryId();
console.log('列变化后的分类数据:', {
categoryColumns: this.categoryColumns,
categoryIndexes: this.categoryIndexes,
categoryLevels: this.categoryLevels
});
},
// 更新后续列的数据
updateSubsequentColumns(startColumn) {
// 获取前一列选中的分类对象
const parentCategory = this.categoryLevels[startColumn - 1];
// 如果父分类不存在或没有子分类,则清空后续所有列
if (!parentCategory || !parentCategory.children || parentCategory.children.length === 0) {
// 从startColumn开始设置所有后续列为空数据
for (let i = startColumn; i < this.maxCategoryLevel; i++) {
this.categoryColumns[i] = [{
name: '暂无数据',
id: ''
}];
this.categoryIndexes[i] = 0;
this.categoryLevels[i] = {
name: '暂无数据',
id: ''
};
}
return;
}
// 设置当前列的数据为父分类的子分类
this.categoryColumns[startColumn] = parentCategory.children;
this.categoryIndexes[startColumn] = 0;
this.categoryLevels[startColumn] = parentCategory.children[0];
// 如果当前列不是最后一列,继续递归更新后续列
if (startColumn < this.maxCategoryLevel - 1) {
this.updateSubsequentColumns(startColumn + 1);
}
},
// 处理多列选择器最终选择确认
onCategoryChange(e) {
const values = e.detail.value;
console.log('分类选择确认:', values);
// 更新所有列的索引
this.categoryIndexes = [...values];
// 更新每个级别选中的分类对象
for (let i = 0; i < values.length; i++) {
// 确保该列存在数据
if (this.categoryColumns[i] && this.categoryColumns[i][values[i]]) {
this.categoryLevels[i] = this.categoryColumns[i][values[i]];
}
}
// 更新分类路径和选中ID
this.updateCategoryPathText();
this.updateSelectedCategoryId();
console.log('已选择分类路径:', this.categoryPathText);
console.log('已选择分类ID:', this.selectedCategoryId);
},
// 更新分类路径显示文本
updateCategoryPathText() {
// 过滤出有效的分类名称(排除"暂无数据"
const validLevels = this.categoryLevels.filter(level => level && level.name && level.name !== '暂无数据');
// 用斜杠连接所有级别的名称
this.categoryPathText = validLevels.map(level => level.name).join(' / ');
console.log('更新分类路径文本:', this.categoryPathText);
},
// 更新选中的分类ID最终叶子节点的ID
updateSelectedCategoryId() {
// 获取有效的分类级别(排除"暂无数据"
const validLevels = this.categoryLevels.filter(level => level && level.id && level.id !== '');
// 如果没有有效级别,则返回空字符串
if (validLevels.length === 0) {
this.selectedCategoryId = '';
return;
}
// 选择最后一个有效级别的ID作为选中的分类ID
this.selectedCategoryId = validLevels[validLevels.length - 1].id;
console.log('更新选中的分类ID:', this.selectedCategoryId);
}
},
}
</script>
<style scoped>
.photo-upload-container {
padding: 20rpx;
padding-bottom: 120rpx;
padding-left: 0;
}
.upload-section {
margin-bottom: 30rpx;
}
.upload-box {
width: 100%;
height: 300rpx;
background-color: #f8f8f8;
border: 2rpx dashed #ddd;
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.upload-icon {
font-size: 60rpx;
color: #999;
margin-bottom: 20rpx;
}
.upload-text {
font-size: 28rpx;
color: #666;
}
.preview-box {
position: relative;
width: 100%;
height: 300rpx;
}
.preview-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.delete-btn {
position: absolute;
top: 20rpx;
right: 20rpx;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
padding: 10rpx 20rpx;
border-radius: 8rpx;
font-size: 24rpx;
}
/* 顶部Tab切换样式 */
.upload-tab-header {
display: flex;
background-color: #ffffff;
border-bottom: 1rpx solid #e5e5e5;
margin: -20rpx -20rpx 20rpx -20rpx;
padding: 0 20rpx;
}
.upload-tab-item {
flex: 1;
padding: 24rpx 0;
text-align: center;
position: relative;
}
.upload-tab-item text {
font-size: 28rpx;
color: #999999;
}
.upload-tab-item.active text {
color: #007AFF;
font-weight: 500;
}
.upload-tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #007AFF;
border-radius: 2rpx;
}
.page-container {
padding: 20rpx;
padding-bottom: 120rpx;
/* 为固定定位的按钮留出空间 */
background-color: #f8f8f8;
min-height: 100vh;
/* 确保容器至少占满整个视口高度 */
box-sizing: border-box;
/* 确保padding不会增加总宽度 */
}
.section-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
/* .result-content {
min-height: 200rpx;
} */
.book-info {
padding: 0;
padding-left: 0;
}
.info-item {
display: flex;
align-items: center;
height: 80rpx;
margin-bottom: 1rpx;
border-bottom: 1px solid #ccc;
background: #fff;
}
.label {
/* text-align: center;
height: 60rpx;
line-height: 60rpx;
color: #000;
font-size: 28rpx;
background-color: #ccc;
border-radius: 8rpx;
margin-right: 20rpx;
flex-shrink: 0;
padding: 0 15rpx; */
padding: 0rpx 10rpx;
text-align: center;
height: 60rpx;
line-height: 60rpx;
color: #000;
font-size: 28rpx;
background-color: #ccc;
border-radius: 8rpx;
margin-right: 20rpx;
flex-shrink: 0;
}
.input-field {
flex: 1;
height: 80rpx;
border: none;
border-radius: 0 10rpx 10rpx 0;
padding: 0 20rpx;
font-size: 28rpx;
background-color: #fff;
text-align: left;
}
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
padding: 20rpx;
background: #fff;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
z-index: 999;
box-sizing: border-box;
}
.submit-btn {
width: 100%;
height: 80rpx;
line-height: 80rpx;
text-align: center;
background-color: #007AFF;
color: #fff;
border-radius: 8rpx;
font-size: 32rpx;
}
.submit-btn:disabled {
background-color: #ccc;
opacity: 0.8;
}
.upload-btn {
margin-left: 20rpx;
padding: 0 15rpx;
height: 60rpx;
line-height: 60rpx;
font-size: 26rpx;
background: #f0f0f0;
color: #007AFF;
border-radius: 8rpx;
border: 1rpx solid #007AFF;
}
.warehouse-item {
display: flex;
align-items: center;
}
.form-container {
padding-left: 10rpx;
background-color: #fff;
}
/*
.info-item-flex {
display: flex;
align-items: center;
} */
.bookname-box {
flex: 2;
display: flex;
align-items: center;
}
.info-item-row {
display: flex;
align-items: center;
gap: 10rpx;
/* 添加间距 */
}
.half-item {
flex: 1;
display: flex;
align-items: center;
position: relative;
}
.half-item .label {
flex-shrink: 0;
width: auto;
/* 让标签宽度自适应内容 */
min-width: 65rpx;
/* 设置最小宽度 */
}
.half-item .input-field {
flex: 1;
height: 80rpx;
border: none;
border-radius: 0 10rpx 10rpx 0;
padding: 0 1rpx;
font-size: 28rpx;
background-color: #fff;
text-align: left;
}
::v-deep .u-picker__view__column__item.data-v-f45a262e {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 32rpx;
text-align: center;
display: block;
color: #303133;
}
.dropdown-btn {
margin-left: 10rpx;
font-size: 24rpx;
background: #eee;
border: none;
border-radius: 4rpx;
padding: 0 10rpx;
cursor: pointer;
height: 60rpx;
width: 50rpx;
display: inline-flex;
align-items: center;
justify-content: center;
}
.dropdown-list {
position: absolute;
background: #fff;
border: 1px solid #ccc;
z-index: 100;
max-height: 300rpx;
overflow-y: auto;
min-width: 100%;
left: 0;
top: 70rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
border-radius: 8rpx;
padding: 8rpx 0;
}
.dropdown-item {
padding: 12rpx 24rpx;
font-size: 28rpx;
color: #333;
cursor: pointer;
transition: background 0.2s;
}
.dropdown-item:hover {
background: #f0f4fa;
color: #007AFF;
}
.dropdown-divider {
height: 1px;
background: #cececb;
margin: 0 12rpx;
}
.format-item {
flex: 0.4;
/* 开本列占40%的宽度 */
}
.isbn-item {
flex: 0.6;
/* 书号列占60%的宽度 */
}
@keyframes scanMove {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(100%);
}
}
.scan-container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 600rpx;
/* 扫描框宽度 */
height: 800rpx;
/* 扫描框高度 */
overflow: hidden;
border: 2px solid #007AFF;
}
.grid-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.2) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.2) 1px, transparent 1px);
background-size: 20px 20px;
opacity: 0.8;
}
.scan-line {
position: absolute;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(to right,
transparent 0%,
#007AFF 20%,
#007AFF 80%,
transparent 100%);
animation: scanMove 2s linear infinite;
box-shadow: 0 0 8px rgba(0, 122, 255, 0.8);
}
/* 自定义识别中动画样式 */
.recognizing-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
}
.recognizing-container {
width: 500rpx;
height: 600rpx;
background-color: rgba(51, 51, 51, 0.9);
border-radius: 16rpx;
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.recognizing-text {
color: white;
font-size: 28rpx;
margin-top: 20rpx;
z-index: 1001;
}
/* 网格背景 */
.recognizing-container .grid-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(0, 122, 255, 0.2) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 122, 255, 0.2) 1px, transparent 1px);
background-size: 20px 20px;
opacity: 0.5;
}
/* 扫描动画 */
@keyframes scanMove {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(100%);
}
}
.recognizing-container .scan-animation {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom,
rgba(0, 0, 0, 0) 0%,
rgba(0, 122, 255, 0.2) 10%,
rgba(0, 122, 255, 0.8) 50%,
rgba(0, 122, 255, 0.2) 90%,
rgba(0, 0, 0, 0) 100%);
animation: scanMove 2s linear infinite;
pointer-events: none;
z-index: 1000;
}
.recognizing-preview-box {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
background: #000;
}
.recognizing-preview-img {
width: 80vw;
height: 60vh;
object-fit: contain;
border-radius: 12rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.3);
}
.recognizing-overlay-on-image {
position: absolute;
top: 50%;
left: 50%;
width: 80vw;
height: 60vh;
transform: translate(-50%, -50%);
pointer-events: none;
}
.scan-line {
position: absolute;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(to right, transparent, #00c3ff, transparent);
animation: scanMoveOnImage 1.5s linear infinite;
z-index: 2;
}
@keyframes scanMoveOnImage {
0% {
top: 0;
}
100% {
top: 95%;
}
}
.recognizing-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
font-size: 32rpx;
text-shadow: 0 2rpx 8rpx #000;
z-index: 3;
}
.blue-block {
width: 8rpx;
height: 32rpx;
background-color: #007AFF;
margin-right: 16rpx;
border-radius: 4rpx;
}
.view-item {
padding: 10rpx;
background-color: #fff;
}
.general-label {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
/* 添加禁用状态的样式 */
.input-field:disabled {
background-color: #f5f5f5;
color: #999;
}
.scan-btn-disabled {
opacity: 0.5;
background-color: #cccccc !important;
color: #999 !important;
}
.print-time-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
justify-content: flex-end;
z-index: 999;
}
.print-time-container {
background-color: #fff;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
overflow: hidden;
}
.print-time-header {
padding: 30rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1rpx solid #eee;
}
.close-btn {
font-size: 40rpx;
color: #999;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.print-time-tabs {
display: flex;
background-color: #fff;
padding: 0 20rpx;
}
.tab-item {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0;
font-size: 28rpx;
}
.tab-line {
position: absolute;
bottom: 0;
width: 60rpx;
height: 4rpx;
background-color: #1976d2;
border-radius: 2rpx;
}
.print-time-content {
padding: 20rpx;
background-color: #fff;
}
.auto-fill-row {
display: flex;
align-items: center;
padding: 20rpx 0;
}
.auto-fill-circle {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
border: 2rpx solid #ddd;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15rpx;
}
.auto-fill-dot {
width: 24rpx;
height: 24rpx;
border-radius: 50%;
background-color: #1976d2;
}
.auto-fill-text {
font-size: 28rpx;
color: #333;
}
.time-input-fields {
display: flex;
justify-content: space-between;
margin-top: 20rpx;
margin-bottom: 20rpx;
}
.input-group {
flex: 1;
margin: 0 10rpx;
}
.time-input {
width: 100%;
height: 80rpx;
border: 1rpx solid #eee;
border-radius: 8rpx;
text-align: center;
font-size: 32rpx;
background-color: #f8f8f8;
}
.numeric-keyboard {
background-color: #edf0f5;
padding: 10rpx;
}
.keyboard-row {
display: flex;
margin-bottom: 10rpx;
}
.key-item {
flex: 1;
height: 100rpx;
margin: 5rpx;
background-color: #fff;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.delete-key {
background-color: #edf0f5;
color: #333;
font-weight: normal;
font-size: 40rpx;
}
.zero-key {
flex: 2;
}
.keyboard-btn {
background-color: #1976d2;
color: white;
font-size: 32rpx;
font-weight: normal;
}
.year-selection {
padding: 20rpx;
}
.year-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.decade-item {
width: 48%;
height: 90rpx;
margin-bottom: 20rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #333;
}
.decade-item:active {
background-color: #e0e0e0;
}
.time-input-view {
flex: 1;
height: 80rpx;
line-height: 80rpx;
padding: 0 20rpx;
font-size: 28rpx;
background-color: #fff;
text-align: left;
color: #333;
}
.time-input-view text {
color: #999;
}
/* 如果没有值时,显示占位符颜色 */
.time-input-view:empty::before {
content: '请输入印刷时间';
color: #999;
}
/* 分类选择器样式 */
.category-container {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-bottom: 10rpx;
/* 减少底部间距 */
}
.picker-single {
padding: 8rpx 40rpx 8rpx 15rpx;
/* 左侧减少内边距,右侧增加内边距给箭头留空间 */
background-color: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
color: #333;
min-height: 50rpx;
/* 减小最小高度 */
display: flex;
align-items: center;
position: relative;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
margin: 0;
/* 移除外边距 */
line-height: 1.2;
/* 设置合理的行高 */
width: 100%;
/* 设置宽度占满容器 */
box-sizing: border-box;
/* 确保内边距计算在宽度内 */
text-align: left;
/* 文字左对齐 */
white-space: nowrap;
/* 防止文字换行 */
overflow: hidden;
/* 超出部分隐藏 */
text-overflow: ellipsis;
/* 文字溢出显示省略号 */
margin-bottom: 1rpx;
}
.picker-single:after {
content: '';
position: absolute;
right: 15rpx;
/* 减少右侧距离 */
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 8rpx solid transparent;
border-right: 8rpx solid transparent;
border-top: 10rpx solid #007AFF;
}
.picker-single:active {
background-color: #e6e6e6;
}
::v-deep .data-v-57280228 {
height: 50rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
</style>