ry_app/package_a/import/import.vue

493 lines
12 KiB
Vue
Raw Normal View History

2026-01-19 16:52:24 +08:00
<template>
<view class="container">
<!-- 顶部导航栏 -->
<view class="navbar">
<view class="nav-left" @click="goBack">
<text class="iconfont"></text>
</view>
<view class="nav-title">批量导入</view>
<view class="nav-right">
<text class="iconfont">···</text>
</view>
</view>
<!-- 选项卡切换 -->
<view class="tab-bar">
<view class="tab-item" :class="{active: activeTab === 'import'}" @click="activeTab = 'import'">
批量导入
</view>
<view class="tab-item" :class="{active: activeTab === 'record'}" @click="activeTab = 'record'">
导入记录
</view>
</view>
<!-- 批量导入内容区 -->
<view v-if="activeTab === 'import'" class="content">
<!-- 方式1导入进货单核心带完整上传功能 -->
<view class="card">
<view class="card-header">
<view class="method-tag">方式1</view>
<view class="method-title">导入进货单</view>
</view>
<view class="upload-area" @click="pickFile" v-if="!uploadFileName">
<view class="upload-icon">
<text class="iconfont"></text>
</view>
<view class="upload-text">点击上传文件</view>
<view class="upload-desc">仅支持10M以下以xlsxlsx或csv结尾的文件类型</view>
</view>
<!-- 已选择文件展示 -->
<view class="file-selected" v-else>
<view class="file-name">{{uploadFileName}}</view>
<view class="file-opt">
<text class="reupload" @click="pickFile"></text>
<text class="cancel" @click="cancelFile"></text>
</view>
</view>
<!-- 导入按钮 -->
<view class="import-btn-box" v-if="uploadFileName">
<button class="import-btn" :loading="isUploading" @click="uploadAndImport"></button>
</view>
<view class="desc-list">
<text class="desc-item">1. 可导入供应商进货单其他收银系统的商品导出明细</text>
<text class="desc-item">2. 支持录入条形码商品名称零售价库存进货价商品品牌</text>
<text class="desc-item">3. 导入成功后会在原商品基础上增加库存不会覆盖原库存</text>
</view>
</view>
<!-- 方式2通过电脑端录入 -->
<view class="card">
<view class="card-header">
<view class="method-tag">方式2</view>
<view class="method-title">通过电脑端录入</view>
</view>
<view class="card-content">
<view class="content-text">支持导入更大文件更多商品数商品信息</view>
<view class="link-area" @click="openLink">
<text class="link-text">请在电脑端访问 http://e.weidian.com/main</text>
<text class="iconfont"></text>
</view>
</view>
</view>
<!-- 方式3微店商品快速录入 -->
<view class="card">
<view class="card-header">
<view class="method-tag">方式3</view>
<view class="method-title">微店商品快速录入</view>
</view>
<view class="card-content">
<view class="content-text">如果您没有电脑可以试试我们的快捷设置功能</view>
<view class="link-area" @click="goQuickSetup">
<text class="link-text">3-20分钟快速设置价格 ></text>
</view>
</view>
</view>
</view>
<!-- 导入记录内容区补充列表骨架+空数据 -->
<view v-else class="record-content">
<view class="empty-state" v-if="recordList.length == 0">
<text class="empty-icon">📋</text>
<text class="empty-text">暂无导入记录</text>
<text class="empty-subtext">导入商品后记录将展示在这里</text>
</view>
<view class="record-list" v-else>
<view class="record-item" v-for="(item,index) in recordList" :key="index">
<view class="record-name">{{item.fileName}}</view>
<view class="record-info">
<text class="record-time">{{item.createTime}}</text>
<text class="record-status" :class="item.status">{{item.statusText}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
// 导入商品相关API
import { importProductData, getImportRecord } from '@/api/product';
// 导入门店ID获取工具
import { getStoreId } from '@/utils/auth';
export default {
data() {
return {
activeTab: 'import', // 默认选中批量导入
uploadFilePath: '', // 选中的文件临时路径
uploadFileName: '', // 选中的文件名称
isUploading: false, // 是否正在上传/导入中
recordList: [] // 导入记录列表
}
},
onShow() {
// 每次进入页面刷新导入记录
if(this.activeTab == 'record'){
this.getImportRecord();
}
},
methods: {
// 返回上一页
goBack() {
uni.navigateBack({ delta: 1 });
},
// ========== 核心:选择文件并校验 ==========
pickFile() {
uni.chooseFile({
count: 1, // 只允许选择1个文件
type: 'file',
sizeLimit: 10 * 1024 * 1024, // 限制10M以内和页面提示一致
success: (res) => {
const tempFile = res.tempFiles[0];
const fileName = tempFile.name;
const fileSize = tempFile.size;
// 1. 文件大小校验
if (fileSize > 10 * 1024 * 1024) {
return uni.showToast({ title: '文件大小不能超过10M', icon: 'none', duration: 2000 });
}
// 2. 文件格式校验 (严格匹配xls/xlsx/csv)
const suffix = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
const allowSuffix = ['.xls', '.xlsx', '.csv'];
if (!allowSuffix.includes(suffix)) {
return uni.showToast({ title: '仅支持xls、xlsx、csv格式文件', icon: 'none', duration: 2000 });
}
// 校验通过,赋值文件信息
this.uploadFilePath = tempFile.path;
this.uploadFileName = fileName;
uni.showToast({ title: '文件选择成功', icon: 'success', duration: 1500 });
},
fail: () => {
uni.showToast({ title: '文件选择失败,请重新选择', icon: 'none' });
}
});
},
// 取消已选择的文件
cancelFile() {
this.uploadFilePath = '';
this.uploadFileName = '';
},
// ========== 核心:文件上传+商品导入 主逻辑 ✅ 已对接你的真实接口 ✅ ==========
uploadAndImport() {
if (!this.uploadFilePath) return;
this.isUploading = true; // 开启加载状态,防止重复点击
// 准备表单数据
const formData = {
storeId: getStoreId()
};
// 调用API进行商品导入
importProductData(this.uploadFilePath, formData)
.then(res => {
this.isUploading = false;
// 业务成功:导入成功 匹配接口 code=200
if (res.code === 200) {
uni.showToast({
title: `导入成功!共导入 ${res.data} 个商品`,
icon: 'success',
duration: 2500
});
// 重置文件选择状态
this.cancelFile();
}
// 业务失败:导入失败
else {
uni.showModal({
title: '导入失败',
content: res.msg || '文件内容有误,请检查后重新上传',
showCancel: false,
confirmText: '知道了'
});
}
})
.catch(err => {
this.isUploading = false;
console.error('文件上传失败:', err);
uni.showModal({
title: '上传异常',
content: '网络异常或服务器连接失败,请检查接口服务后重试',
showCancel: false,
confirmText: '重新上传'
});
});
},
// 打开电脑端链接
openLink() {
uni.showModal({
title: '温馨提示',
content: '将在浏览器中打开电脑端录入地址',
confirmText: '确认打开',
success: (res) => {
if (res.confirm) {
uni.openURL({
url: 'http://e.weidian.com/main',
fail: () => uni.showToast({ title: '打开失败,请手动复制链接', icon: 'none' })
});
}
}
});
},
// 跳转快速设置页面
goQuickSetup() {
uni.navigateTo({
url: '/pages/quick-setup/quick-setup'
});
},
// 获取导入记录
getImportRecord() {
uni.showLoading({ title: '加载中...', mask: true });
// 调用API获取导入记录
getImportRecord()
.then(res => {
if(res.code == 200){
this.recordList = res.data || [];
}
})
.catch(err => {
console.error('获取导入记录失败:', err);
})
.finally(() => {
uni.hideLoading();
});
}
}
}
</script>
<style scoped>
/* 全局样式重置 */
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
/* 导航栏 */
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #e62318;
color: white;
padding: 20rpx 30rpx;
box-sizing: border-box;
}
.nav-left, .nav-right {
width: 60rpx;
font-size: 32rpx;
}
.nav-title {
font-size: 34rpx;
font-weight: bold;
}
/* 选项卡 */
.tab-bar {
display: flex;
background-color: white;
}
.tab-item {
flex: 1;
text-align: center;
padding: 30rpx 0;
font-size: 32rpx;
color: #333;
border-bottom: 4rpx solid transparent;
}
.tab-item.active {
color: #e62318;
border-bottom-color: #e62318;
font-weight: bold;
}
/* 内容区 */
.content {
padding: 30rpx;
}
/* 卡片通用样式 */
.card {
background-color: white;
border-radius: 16rpx;
margin-bottom: 30rpx;
overflow: hidden;
}
.card-header {
display: flex;
align-items: center;
padding: 30rpx;
background-color: white;
}
.method-tag {
background-color: #e62318;
color: white;
font-size: 24rpx;
padding: 8rpx 16rpx;
border-radius: 12rpx;
margin-right: 20rpx;
}
.method-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
/* 上传区域 */
.upload-area {
margin: 0 30rpx 30rpx;
border: 2rpx dashed #ccc;
border-radius: 12rpx;
padding: 60rpx 30rpx;
text-align: center;
}
.upload-icon {
font-size: 48rpx;
color: #999;
margin-bottom: 20rpx;
}
.upload-text {
font-size: 30rpx;
color: #333;
margin-bottom: 10rpx;
}
.upload-desc {
font-size: 24rpx;
color: #999;
}
/* 已选择文件样式 */
.file-selected {
margin: 0 30rpx 30rpx;
padding: 20rpx;
background: #f9f9f9;
border-radius: 12rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.file-name {
font-size: 28rpx;
color: #333;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-opt {
display: flex;
gap: 20rpx;
}
.reupload {
font-size: 26rpx;
color: #e62318;
}
.cancel {
font-size: 26rpx;
color: #999;
}
/* 导入按钮样式 */
.import-btn-box {
padding: 0 30rpx 20rpx;
}
.import-btn {
width: 100%;
background: #e62318;
color: white;
font-size: 30rpx;
padding: 20rpx 0;
border-radius: 12rpx;
}
/* 描述列表 */
.desc-list {
padding: 0 30rpx 30rpx;
font-size: 26rpx;
color: #666;
line-height: 1.6;
}
.desc-item {
display: block;
margin-bottom: 10rpx;
}
/* 卡片内容区 */
.card-content {
padding: 0 30rpx 30rpx;
font-size: 28rpx;
color: #666;
line-height: 1.5;
}
.content-text {
margin-bottom: 20rpx;
display: block;
}
.link-area {
display: flex;
align-items: center;
color: #e62318;
}
.link-text {
font-size: 28rpx;
margin-right: 10rpx;
}
/* 导入记录样式 */
.record-content {
padding: 30rpx;
}
.empty-state {
text-align: center;
padding: 100rpx 0;
color: #999;
}
.empty-icon {
font-size: 60rpx;
display: block;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 30rpx;
margin-bottom: 10rpx;
display: block;
}
.empty-subtext {
font-size: 24rpx;
}
.record-list {
background: white;
border-radius: 16rpx;
}
.record-item {
padding: 30rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.record-name {
font-size: 30rpx;
color: #333;
margin-bottom: 10rpx;
}
.record-info {
display: flex;
justify-content: space-between;
font-size: 24rpx;
color: #999;
}
.record-status.success {
color: #07c160;
}
.record-status.fail {
color: #e62318;
}
</style>