feat(aps): 新增排产单明细批量导入功能
This commit is contained in:
@@ -26,6 +26,15 @@ export function addPlanDetail(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// 批量新增排产单明细
|
||||
export function addPlanDetailBatch(data) {
|
||||
return request({
|
||||
url: '/aps/planDetail/batch',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改排产单明细
|
||||
export function updatePlanDetail(data) {
|
||||
return request({
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<div>
|
||||
<el-button type="primary" plain @click="handleAdd">新增明细</el-button>
|
||||
<el-button type="success" plain @click="handleBatchAdd">批量新增</el-button>
|
||||
<el-button type="info" plain @click="handleImport">导入</el-button>
|
||||
<el-button type="danger" plain @click="handleBatchDelete"
|
||||
:disabled="selectedRows.length === 0">批量删除</el-button>
|
||||
<el-button type="warning" plain @click="handleBatchTransfer"
|
||||
@@ -60,6 +61,11 @@
|
||||
</el-table-column>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<el-table-column label="排产日期" align="center" prop="detailDate" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.detailDate" style="background-color: #fff3e6;" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单号" align="center" prop="orderCode" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.orderCode" style="background-color: #fff3e6;">
|
||||
@@ -491,16 +497,169 @@
|
||||
:loading="buttonLoading">确认新增</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导入对话框 -->
|
||||
<el-dialog title="导入排产单明细" :visible.sync="importDialogVisible" width="900px" append-to-body
|
||||
:close-on-click-modal="false" @close="resetImportState">
|
||||
<div class="import-container">
|
||||
<el-steps :active="importStep" align-center finish-status="success">
|
||||
<el-step title="下载模板" description="下载并填写Excel模板" />
|
||||
<el-step title="上传文件" description="选择填好的文件" />
|
||||
<el-step title="校验数据" description="验证数据完整性" />
|
||||
<el-step title="开始导入" description="预览并确认导入" />
|
||||
</el-steps>
|
||||
|
||||
<div class="import-step-content">
|
||||
<!-- Step 0: 下载模板 -->
|
||||
<div v-show="importStep === 0" class="step-body">
|
||||
<div class="step-download">
|
||||
<i class="el-icon-download step-icon"></i>
|
||||
<p>请先下载Excel模板,按格式填写排产单明细数据</p>
|
||||
<el-button type="primary" icon="el-icon-download" @click="downloadTemplate">下载导入模板</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: 上传文件 -->
|
||||
<div v-show="importStep === 1" class="step-body">
|
||||
<div class="step-upload">
|
||||
<el-upload ref="importUpload" class="custom-upload" drag :auto-upload="false" :show-file-list="false"
|
||||
:on-change="handleImportFileChange" accept=".xlsx,.xls">
|
||||
<div class="upload-zone-body">
|
||||
<div class="upload-zone-icon">
|
||||
<i class="el-icon-upload2"></i>
|
||||
</div>
|
||||
<p class="upload-zone-title">将文件拖到此处,或<span>点击选择</span></p>
|
||||
<p class="upload-zone-tip">支持 .xlsx / .xls 格式</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div v-if="importFile" class="parse-result" :class="errorList.length > 0 ? 'parse-error' : 'parse-ok'">
|
||||
<div class="parse-result-header">
|
||||
<i :class="errorList.length > 0 ? 'el-icon-warning' : 'el-icon-circle-check'"></i>
|
||||
<span class="parse-result-filename">{{ importFile.name }}</span>
|
||||
<span class="parse-result-count">解析 {{ rawData.length }} 条数据</span>
|
||||
</div>
|
||||
<div v-if="errorList.length > 0" class="error-list">
|
||||
<el-table :data="errorList" border max-height="150">
|
||||
<el-table-column prop="rowNum" label="行号" width="80" />
|
||||
<el-table-column prop="errorMsg" label="错误信息" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: 校验数据 -->
|
||||
<div v-show="importStep === 2" class="step-body">
|
||||
<div class="step-validate">
|
||||
<p class="step-desc">点击下方按钮校验数据完整性,已解析 {{ rawData.length }} 条数据</p>
|
||||
<el-button type="success" icon="el-icon-check" @click="handleValidateData"
|
||||
:loading="validateLoading" size="medium" style="margin-bottom: 16px">
|
||||
校验数据
|
||||
</el-button>
|
||||
<div v-if="errorList.length > 0" class="error-list">
|
||||
<el-alert :title="'校验失败,共 ' + errorList.length + ' 条错误'" type="error" show-icon :closable="false" style="margin-bottom: 10px" />
|
||||
<el-table :data="errorList" border max-height="200">
|
||||
<el-table-column prop="rowNum" label="行号" width="80" />
|
||||
<el-table-column prop="errorMsg" label="错误信息" />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-if="isValidated && errorList.length === 0" class="validate-ok">
|
||||
<el-alert title="数据校验通过!" type="success" show-icon :closable="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: 预览并导入 -->
|
||||
<div v-show="importStep === 3" class="step-body">
|
||||
<div class="step-import-container">
|
||||
<div class="data-preview">
|
||||
<div class="section-title">数据预览(共 {{ tableData.length }} 条)</div>
|
||||
<el-table :data="tableData" border max-height="280" style="margin-top: 10px">
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="detailDate" label="排产日期" width="100" />
|
||||
<el-table-column prop="contractCode" label="合同号" width="120" />
|
||||
<el-table-column prop="deliveryDate" label="交货期" width="100" />
|
||||
<el-table-column prop="customerName" label="客户名称" width="120" />
|
||||
<el-table-column prop="productName" label="产品名称" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="usageReq" label="客户用途" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="80" />
|
||||
<el-table-column prop="rollingThick" label="成品厚度" width="80" />
|
||||
<el-table-column prop="productWidth" label="成品宽度" width="80" />
|
||||
<el-table-column prop="planWeight" label="数量(吨)" width="90" />
|
||||
<el-table-column prop="surfaceTreatment" label="表面处理" width="80" />
|
||||
<el-table-column prop="productPackaging" label="包装要求" width="80" />
|
||||
<el-table-column prop="remark" label="其他要求" width="120" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div v-if="importStatus === 'processing'" class="import-progress">
|
||||
<el-progress :percentage="importProgress" />
|
||||
<p>正在导入:{{ importedCount }} / {{ totalCount }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="importStatus === 'finished'" class="import-result">
|
||||
<el-alert :title="'导入完成!共成功导入 ' + importedCount + ' 条数据'" type="success" show-icon :closable="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button v-if="importStep > 0" @click="importStep--" :disabled="importStatus === 'processing'">上一步</el-button>
|
||||
<el-button @click="importDialogVisible = false">关闭</el-button>
|
||||
<el-button v-if="importStep === 0" type="primary" @click="downloadTemplate">下载模板</el-button>
|
||||
<el-button v-if="importStep === 0" type="primary" @click="importStep = 1">已下载,下一步</el-button>
|
||||
<el-button v-if="importStep === 1" type="primary" @click="goValidateStep" :disabled="!importFile || rawData.length === 0">
|
||||
下一步
|
||||
</el-button>
|
||||
<el-button v-if="importStep === 2" type="primary" @click="goImportStep" :disabled="!isValidated || errorList.length > 0">
|
||||
下一步
|
||||
</el-button>
|
||||
<el-button v-if="importStep === 3 && importStatus !== 'finished'" type="primary" @click="startImport"
|
||||
:loading="importLoading">
|
||||
开始导入
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { updatePlanDetail, listPlanDetail, addPlanDetail, delPlanDetail } from "@/api/aps/planDetail";
|
||||
import * as XLSX from 'xlsx'
|
||||
import { updatePlanDetail, listPlanDetail, addPlanDetail, addPlanDetailBatch, delPlanDetail } from "@/api/aps/planDetail";
|
||||
import { getPlanSheet, listPlanSheet } from "@/api/aps/planSheet";
|
||||
import { listOrder } from '@/api/crm/order';
|
||||
import { listOrderItem } from '@/api/crm/orderItem'
|
||||
import PlanSheetList from "@/views/aps/planSheet/PlanSheetList.vue";
|
||||
|
||||
const TEMPLATE_HEADERS = [
|
||||
'排产日期', '合同号', '交货期', '业务员', '客户名称', '产品名称',
|
||||
'客户用途', '材质', '成品厚度', '成品宽度', '数量(吨)',
|
||||
'厚度范围', '宽度范围', '表面质量', '表面处理', '包装要求',
|
||||
'切边要求', '其他要求'
|
||||
]
|
||||
|
||||
const HEADER_MAP = {
|
||||
'排产日期': 'detailDate',
|
||||
'合同号': 'contractCode',
|
||||
'交货期': 'deliveryDate',
|
||||
'业务员': 'salesman',
|
||||
'客户名称': 'customerName',
|
||||
'产品名称': 'productName',
|
||||
'客户用途': 'usageReq',
|
||||
'材质': 'productMaterial',
|
||||
'成品厚度': 'rollingThick',
|
||||
'成品宽度': 'productWidth',
|
||||
'数量(吨)': 'planWeight',
|
||||
'厚度范围': 'markCoatThick',
|
||||
'宽度范围': 'productEdgeReq',
|
||||
'表面质量': 'coatingG',
|
||||
'表面处理': 'surfaceTreatment',
|
||||
'包装要求': 'productPackaging',
|
||||
'切边要求': 'widthReq',
|
||||
'其他要求': 'remark'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "PlanSheet",
|
||||
dicts: ['sys_lines'],
|
||||
@@ -625,6 +784,20 @@ export default {
|
||||
selectedRows: [],
|
||||
// 是否批量操作(批量转单)
|
||||
isBatchTransfer: false,
|
||||
// 导入对话框
|
||||
importDialogVisible: false,
|
||||
importStep: 0,
|
||||
importFile: null,
|
||||
rawData: [],
|
||||
tableData: [],
|
||||
errorList: [],
|
||||
isValidated: false,
|
||||
importProgress: 0,
|
||||
importedCount: 0,
|
||||
totalCount: 0,
|
||||
importStatus: 'idle',
|
||||
validateLoading: false,
|
||||
importLoading: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@@ -1166,6 +1339,218 @@ export default {
|
||||
this.$message.error('批量新增失败');
|
||||
});
|
||||
});
|
||||
},
|
||||
// 打开导入对话框
|
||||
handleImport() {
|
||||
this.importDialogVisible = true
|
||||
this.resetImportState()
|
||||
},
|
||||
// 重置导入状态
|
||||
resetImportState() {
|
||||
this.importStep = 0
|
||||
this.importFile = null
|
||||
this.rawData = []
|
||||
this.tableData = []
|
||||
this.errorList = []
|
||||
this.isValidated = false
|
||||
this.importProgress = 0
|
||||
this.importedCount = 0
|
||||
this.totalCount = 0
|
||||
this.importStatus = 'idle'
|
||||
this.validateLoading = false
|
||||
this.importLoading = false
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.importUpload) {
|
||||
this.$refs.importUpload.clearFiles()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 跳转到校验步骤
|
||||
goValidateStep() {
|
||||
if (!this.importFile || this.rawData.length === 0) return
|
||||
this.importStep = 2
|
||||
},
|
||||
// 跳转到导入步骤
|
||||
goImportStep() {
|
||||
if (!this.isValidated || this.errorList.length > 0) return
|
||||
this.importStep = 3
|
||||
},
|
||||
// 下载导入模板
|
||||
downloadTemplate() {
|
||||
const templateData = [
|
||||
TEMPLATE_HEADERS,
|
||||
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
|
||||
]
|
||||
const wb = XLSX.utils.book_new()
|
||||
const ws = XLSX.utils.aoa_to_sheet(templateData)
|
||||
ws['!cols'] = TEMPLATE_HEADERS.map(() => ({ wch: 14 }))
|
||||
XLSX.utils.book_append_sheet(wb, ws, '排产单明细')
|
||||
XLSX.writeFile(wb, '排产单明细导入模板.xlsx')
|
||||
},
|
||||
// 导入文件选择变化
|
||||
handleImportFileChange(file) {
|
||||
this.isValidated = false
|
||||
this.errorList = []
|
||||
this.tableData = []
|
||||
this.importStatus = 'idle'
|
||||
this.importFile = file.raw
|
||||
this.readExcel()
|
||||
},
|
||||
// 读取Excel文件内容
|
||||
readExcel() {
|
||||
if (!this.importFile) return
|
||||
try {
|
||||
const fileReader = new FileReader()
|
||||
fileReader.readAsArrayBuffer(this.importFile)
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
const data = new Uint8Array(e.target.result)
|
||||
const workbook = XLSX.read(data, { type: 'array' })
|
||||
const sheetName = workbook.SheetNames[0]
|
||||
const worksheet = workbook.Sheets[sheetName]
|
||||
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
|
||||
this.validateHeaders(jsonData[0])
|
||||
this.rawData = jsonData.slice(1).filter(row => row.some(cell => cell !== undefined && cell !== null && cell !== ''))
|
||||
this.formatExcel()
|
||||
if (this.errorList.length === 0) {
|
||||
this.importStatus = 'parsed'
|
||||
this.$message.success(`成功解析Excel,共读取到 ${this.rawData.length} 条数据`)
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorList = [{ rowNum: 0, errorMsg: '解析Excel失败:' + error.message }]
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorList = [{ rowNum: 0, errorMsg: '读取文件失败:' + error.message }]
|
||||
}
|
||||
},
|
||||
// 校验表头
|
||||
validateHeaders(headers) {
|
||||
if (headers.length !== TEMPLATE_HEADERS.length) {
|
||||
this.errorList.push({
|
||||
rowNum: 1,
|
||||
errorMsg: `表头列数不匹配,要求${TEMPLATE_HEADERS.length}列,实际${headers.length}列`
|
||||
})
|
||||
return
|
||||
}
|
||||
headers.forEach((header, index) => {
|
||||
if (String(header || '').trim() !== TEMPLATE_HEADERS[index]) {
|
||||
this.errorList.push({
|
||||
rowNum: 1,
|
||||
errorMsg: `第${index + 1}列表头错误,要求:"${TEMPLATE_HEADERS[index]}",实际:"${header}"`
|
||||
})
|
||||
}
|
||||
})
|
||||
if (this.errorList.length > 0) {
|
||||
this.$message.error('Excel表头格式不符合要求,请检查!')
|
||||
}
|
||||
},
|
||||
// 格式化Excel数据
|
||||
formatExcel() {
|
||||
this.tableData = []
|
||||
if (this.rawData.length === 0) return
|
||||
const currentMaxSeqNo = this.planDetailList.length > 0
|
||||
? Math.max(...this.planDetailList.map(item => parseInt(item.bizSeqNo) || 0))
|
||||
: 0
|
||||
this.rawData.forEach((row, index) => {
|
||||
const rowObj = { bizSeqNo: currentMaxSeqNo + index + 1 }
|
||||
TEMPLATE_HEADERS.forEach((header, colIndex) => {
|
||||
const field = HEADER_MAP[header]
|
||||
const cellValue = row[colIndex]
|
||||
if (cellValue !== undefined && cellValue !== null && cellValue !== '') {
|
||||
rowObj[field] = String(cellValue).trim()
|
||||
}
|
||||
})
|
||||
this.tableData.push(rowObj)
|
||||
})
|
||||
},
|
||||
// 校验数据
|
||||
handleValidateData() {
|
||||
if (this.validateLoading) return
|
||||
if (this.rawData.length === 0) {
|
||||
this.$message.warning('暂无数据可校验')
|
||||
return
|
||||
}
|
||||
this.validateLoading = true
|
||||
this.errorList = []
|
||||
try {
|
||||
this.tableData.forEach((row, i) => {
|
||||
const rowNum = i + 2
|
||||
if (!row.contractCode || row.contractCode.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '合同号不能为空' })
|
||||
}
|
||||
if (!row.customerName || row.customerName.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '客户名称不能为空' })
|
||||
}
|
||||
if (!row.productName || row.productName.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '产品名称不能为空' })
|
||||
}
|
||||
if (!row.productMaterial || row.productMaterial.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '材质不能为空' })
|
||||
}
|
||||
if (row.planWeight && isNaN(Number(row.planWeight))) {
|
||||
this.errorList.push({ rowNum, errorMsg: '数量(吨)必须是数字' })
|
||||
}
|
||||
})
|
||||
this.isValidated = true
|
||||
if (this.errorList.length > 0) {
|
||||
this.$message.error(`数据校验失败,共 ${this.errorList.length} 条错误`)
|
||||
} else {
|
||||
this.$message.success('数据校验通过,可以开始导入')
|
||||
this.importStep = 3
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorList.push({ rowNum: 0, errorMsg: '校验数据时发生错误:' + error.message })
|
||||
} finally {
|
||||
this.validateLoading = false
|
||||
}
|
||||
},
|
||||
// 开始导入
|
||||
startImport() {
|
||||
if (this.importLoading) return
|
||||
if (!this.isValidated) {
|
||||
this.$message.warning('请先校验数据')
|
||||
return
|
||||
}
|
||||
if (this.errorList.length > 0) {
|
||||
this.$message.warning('请先修正校验错误后再导入')
|
||||
return
|
||||
}
|
||||
if (this.tableData.length === 0) {
|
||||
this.$message.warning('暂无数据可导入')
|
||||
return
|
||||
}
|
||||
this.$confirm(`确认导入 ${this.tableData.length} 条排产单明细?`, '导入确认', {
|
||||
confirmButtonText: '确认导入',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.doImport()
|
||||
}).catch(() => {})
|
||||
},
|
||||
// 执行导入
|
||||
doImport() {
|
||||
this.importLoading = true
|
||||
this.importStatus = 'processing'
|
||||
this.totalCount = this.tableData.length
|
||||
this.importedCount = 0
|
||||
this.importProgress = 0
|
||||
const boList = this.tableData.map(row => ({
|
||||
...row,
|
||||
planSheetId: this.currentPlanSheetId
|
||||
}))
|
||||
addPlanDetailBatch(boList).then(() => {
|
||||
this.importedCount = this.totalCount
|
||||
this.importProgress = 100
|
||||
this.importStatus = 'finished'
|
||||
this.$message.success(`导入完成!共成功导入 ${this.importedCount} 条数据`)
|
||||
this.getList()
|
||||
}).catch(error => {
|
||||
this.importStatus = 'idle'
|
||||
this.$message.error('导入失败:' + (error.message || '未知错误'))
|
||||
}).finally(() => {
|
||||
this.importLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1259,4 +1644,211 @@ export default {
|
||||
margin-bottom: 15px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.import-container {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.import-step-content {
|
||||
margin-top: 24px;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
.step-body {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.step-download {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.step-download .step-icon {
|
||||
font-size: 48px;
|
||||
color: #409eff;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.step-download p {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.step-upload {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.custom-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload-dragger {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 40px 20px;
|
||||
border: 2px dashed #dcdfe6;
|
||||
border-radius: 8px;
|
||||
background: #fafbfc;
|
||||
transition: all .3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload-dragger:hover {
|
||||
border-color: #409eff;
|
||||
background: #ecf5ff;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload-dragger.is-dragover {
|
||||
border-color: #409eff;
|
||||
background: #ecf5ff;
|
||||
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.15);
|
||||
}
|
||||
|
||||
.upload-zone-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.upload-zone-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #ecf5ff 0%, #d9ecff 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.upload-zone-icon i {
|
||||
font-size: 28px;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.upload-zone-title {
|
||||
font-size: 15px;
|
||||
color: #606266;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.upload-zone-title span {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.upload-zone-tip {
|
||||
font-size: 12px;
|
||||
color: #c0c4cc;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.parse-result {
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.parse-result-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.parse-result-header i {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.parse-result-filename {
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.parse-result-count {
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.parse-result.parse-ok {
|
||||
border: 1px solid #b7eb8f;
|
||||
}
|
||||
|
||||
.parse-result.parse-ok .parse-result-header {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.parse-result.parse-ok i {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.parse-result.parse-error {
|
||||
border: 1px solid #ffa39e;
|
||||
}
|
||||
|
||||
.parse-result.parse-error .parse-result-header {
|
||||
background: #fff1f0;
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.parse-result.parse-error i {
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.step-validate {
|
||||
padding: 0 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.step-validate .step-desc {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.validate-ok {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.step-import-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.error-list {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.data-preview {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.import-progress {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.import-progress p {
|
||||
margin-top: 8px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.import-result {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user