|  | @@ -0,0 +1,200 @@
 | 
	
		
			
				|  |  | +<script setup lang="ts">
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @Name: index.vue
 | 
	
		
			
				|  |  | + * @Description: 导入页
 | 
	
		
			
				|  |  | + * @Author: Cheney
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +import { Plus, Upload, View } from '@element-plus/icons-vue';
 | 
	
		
			
				|  |  | +import { reactive, ref } from 'vue';
 | 
	
		
			
				|  |  | +import { ElMessage, genFileId, UploadInstance, UploadRawFile } from 'element-plus';
 | 
	
		
			
				|  |  | +import { SUCCESS_CODE, WARNING_CODE } from '/@/utils/requestCode';
 | 
	
		
			
				|  |  | +import * as api from './api';
 | 
	
		
			
				|  |  | +import { VxeGridProps } from 'vxe-table';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const upload = ref<UploadInstance>();
 | 
	
		
			
				|  |  | +const upBtnLoading = ref(false);
 | 
	
		
			
				|  |  | +const filter = reactive({
 | 
	
		
			
				|  |  | +  reportFilter: '',
 | 
	
		
			
				|  |  | +  reportDateFilter: '',
 | 
	
		
			
				|  |  | +  typeFilter: '',
 | 
	
		
			
				|  |  | +  variableFilter: '',
 | 
	
		
			
				|  |  | +});
 | 
	
		
			
				|  |  | +const defaultLabel = ref('ASIN');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const gridOptions = reactive<VxeGridProps>({
 | 
	
		
			
				|  |  | +  loading: upBtnLoading,
 | 
	
		
			
				|  |  | +  round: true,
 | 
	
		
			
				|  |  | +  // border: 'inner',
 | 
	
		
			
				|  |  | +  stripe: true,
 | 
	
		
			
				|  |  | +  resizable: true,
 | 
	
		
			
				|  |  | +  height: 900,
 | 
	
		
			
				|  |  | +  toolbarConfig: {
 | 
	
		
			
				|  |  | +    custom: true,
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  columns: [
 | 
	
		
			
				|  |  | +    // { type: 'seq', width: 70 },
 | 
	
		
			
				|  |  | +    // { field: 'name', title: 'Name' },
 | 
	
		
			
				|  |  | +  ],
 | 
	
		
			
				|  |  | +  data: [],
 | 
	
		
			
				|  |  | +});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @description 替换文件并上传
 | 
	
		
			
				|  |  | + * @param files 文件列表
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function handleExceed(files: any) {
 | 
	
		
			
				|  |  | +  upload.value!.clearFiles();
 | 
	
		
			
				|  |  | +  const file = files[0] as UploadRawFile;
 | 
	
		
			
				|  |  | +  file.uid = genFileId();
 | 
	
		
			
				|  |  | +  upload.value!.handleStart(file);
 | 
	
		
			
				|  |  | +  upload.value!.submit();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * 统一处理响应
 | 
	
		
			
				|  |  | + * @param response 后端返回的响应
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function handleResponse(response: any) {
 | 
	
		
			
				|  |  | +  if (response.code === SUCCESS_CODE) {
 | 
	
		
			
				|  |  | +    ElMessage.success({ message: response.msg, plain: true });
 | 
	
		
			
				|  |  | +  } else if (response.code === WARNING_CODE) {
 | 
	
		
			
				|  |  | +    ElMessage.warning({ message: response.msg, plain: true });
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    ElMessage.error({ message: response.msg, plain: true });
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * 上传文件
 | 
	
		
			
				|  |  | + * @param uploadRequest 上传请求
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +async function handleCustomUpload(uploadRequest: any) {
 | 
	
		
			
				|  |  | +  upBtnLoading.value = true;
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    const { file } = uploadRequest;
 | 
	
		
			
				|  |  | +    const response = await api.uploadFile(file);
 | 
	
		
			
				|  |  | +    handleResponse(response);
 | 
	
		
			
				|  |  | +    processResponseData(response.data);
 | 
	
		
			
				|  |  | +    uploadRequest.onSuccess(response); // 通知 el-upload 上传成功
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.log('==Error==', error);
 | 
	
		
			
				|  |  | +    uploadRequest.onError(error);
 | 
	
		
			
				|  |  | +  } finally {
 | 
	
		
			
				|  |  | +    upBtnLoading.value = false;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * 处理响应数据,更新 gridOptions
 | 
	
		
			
				|  |  | + * @param data 响应数据
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function processResponseData(data: any) {
 | 
	
		
			
				|  |  | +  const limitedData = data.length > 15 ? data.slice(0, 15) : data;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (data.length > 0) {
 | 
	
		
			
				|  |  | +    filter.reportFilter = data[0].Reporting_Range || '';
 | 
	
		
			
				|  |  | +    filter.reportDateFilter = data[0].Reporting_Date || '';
 | 
	
		
			
				|  |  | +    filter.typeFilter = data[0].ASIN ? 'ASIN View' : 'Brand View';
 | 
	
		
			
				|  |  | +    filter.variableFilter = data[0].ASIN ? data[0].ASIN : data[0].brand || '';
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    filter.reportFilter = '';
 | 
	
		
			
				|  |  | +    filter.reportDateFilter = '';
 | 
	
		
			
				|  |  | +    filter.typeFilter = '';
 | 
	
		
			
				|  |  | +    filter.variableFilter = '';
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 动态生成 columns 配置
 | 
	
		
			
				|  |  | +  gridOptions.columns = Object.keys(limitedData[0] || {}).map((key) => {
 | 
	
		
			
				|  |  | +    const title = key.replace(/_/g, ' '); // 将下划线替换成空格
 | 
	
		
			
				|  |  | +    let minWidth = title.length * 10;
 | 
	
		
			
				|  |  | +    if (key === 'ASIN' || key === 'brand') {
 | 
	
		
			
				|  |  | +      minWidth = 130;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +      field: key,
 | 
	
		
			
				|  |  | +      title,
 | 
	
		
			
				|  |  | +      minWidth,
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gridOptions.data = limitedData;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 更新默认标签
 | 
	
		
			
				|  |  | +  if (limitedData[0].brand) {
 | 
	
		
			
				|  |  | +    defaultLabel.value = 'Brand';
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    defaultLabel.value = 'ASIN';
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * 确认导入
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +async function confirmUpload() {
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    const response = await api.confirmUploadFile({ upload: true });
 | 
	
		
			
				|  |  | +    handleResponse(response);
 | 
	
		
			
				|  |  | +    if (response.code === SUCCESS_CODE) {
 | 
	
		
			
				|  |  | +      gridOptions.data = [];
 | 
	
		
			
				|  |  | +      gridOptions.columns = [];
 | 
	
		
			
				|  |  | +      filter.reportFilter = '';
 | 
	
		
			
				|  |  | +      filter.reportDateFilter = '';
 | 
	
		
			
				|  |  | +      filter.typeFilter = '';
 | 
	
		
			
				|  |  | +      filter.variableFilter = '';
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.error('==Error==', error);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</script>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +  <div class="py-2 px-2.5" style="background-color: #f7f7f7">
 | 
	
		
			
				|  |  | +    <el-card body-class="flex justify-between gap-3.5" shadow="hover" style="border: none; margin-bottom: 10px">
 | 
	
		
			
				|  |  | +      <div class="flex gap-7">
 | 
	
		
			
				|  |  | +        <div>
 | 
	
		
			
				|  |  | +          <span class="font-bold mr-2" style="color: #303133">报告类型:</span>
 | 
	
		
			
				|  |  | +          <el-input v-model="filter.reportFilter" :disabled="true" style="width: 200px"></el-input>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <div>
 | 
	
		
			
				|  |  | +          <span class="font-bold mr-2" style="color: #303133">报告日期:</span>
 | 
	
		
			
				|  |  | +          <el-input v-model="filter.reportDateFilter" :disabled="true" style="width: 200px"></el-input>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <div>
 | 
	
		
			
				|  |  | +          <span class="font-bold mr-2" style="color: #303133">类型:</span>
 | 
	
		
			
				|  |  | +          <el-input v-model="filter.typeFilter" :disabled="true" style="width: 200px"></el-input>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <div>
 | 
	
		
			
				|  |  | +          <span class="font-bold mr-2" style="color: #303133">{{ defaultLabel }}:</span>
 | 
	
		
			
				|  |  | +          <el-input v-model="filter.variableFilter" :disabled="true" style="width: 240px"></el-input>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +      <div class="flex gap-3.5">
 | 
	
		
			
				|  |  | +        <!-- 想要不页面不跳动可以加72的高度 -->
 | 
	
		
			
				|  |  | +        <div>
 | 
	
		
			
				|  |  | +          <el-upload
 | 
	
		
			
				|  |  | +            ref="upload"
 | 
	
		
			
				|  |  | +            action="#"
 | 
	
		
			
				|  |  | +            :limit="1"
 | 
	
		
			
				|  |  | +            :show-file-list="false"
 | 
	
		
			
				|  |  | +            :auto-upload="true"
 | 
	
		
			
				|  |  | +            :on-exceed="handleExceed"
 | 
	
		
			
				|  |  | +            :http-request="handleCustomUpload">
 | 
	
		
			
				|  |  | +            <template #trigger>
 | 
	
		
			
				|  |  | +              <el-button :loading="upBtnLoading" plain color="#6366f1" :icon="View">导入预览</el-button>
 | 
	
		
			
				|  |  | +            </template>
 | 
	
		
			
				|  |  | +          </el-upload>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <el-button plain round type="warning" :icon="Upload" @click="confirmUpload">
 | 
	
		
			
				|  |  | +          确认导入
 | 
	
		
			
				|  |  | +        </el-button>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    </el-card>
 | 
	
		
			
				|  |  | +    <el-card shadow="hover" style="border: none">
 | 
	
		
			
				|  |  | +      <div class="text-xl font-bold text-center font-sans subpixel-antialiased">导入预览</div>
 | 
	
		
			
				|  |  | +      <vxe-grid v-bind="gridOptions"></vxe-grid>
 | 
	
		
			
				|  |  | +    </el-card>
 | 
	
		
			
				|  |  | +  </div>
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<style scoped></style>
 |