<script setup>
import{computed,onMounted,ref}from'vue';import{ElMessage}from'element-plus';import{Download,Refresh,UploadFilled}from'@element-plus/icons-vue'
const file=ref(null),result=ref(null),loading=ref(false),history=ref([]),detail=ref(null),detailVisible=ref(false),upload=ref(null);const step=computed(()=>result.value?(result.value.status==='imported'?4:(result.value.error_count?2:3)):(file.value?1:0))
const statusText=s=>({validated:'待确认',validation_failed:'预检失败',imported:'导入成功',import_failed:'导入失败'}[s]||s);const statusType=s=>({validated:'warning',validation_failed:'danger',imported:'success',import_failed:'danger'}[s]||'info')
const api=async(url,opt)=>{const r=await fetch(url,opt),d=await r.json();if(!r.ok||d.status==='error')throw new Error(d.message||d.detail||'请求失败');return d.data};const save=(b,n)=>{const u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download=n;a.click();URL.revokeObjectURL(u)}
const download=async()=>save(await(await fetch('/api/excel-import/template')).blob(),'精度保持性系统_整体导入模板.xlsx');const change=f=>{file.value=f.raw;result.value=null};const precheck=async()=>{loading.value=true;try{const fd=new FormData();fd.append('file',file.value);result.value=await api('/api/excel-import/precheck',{method:'POST',body:fd});await load()}catch(e){ElMessage.error(e.message)}finally{loading.value=false}};const commit=async()=>{loading.value=true;try{const d=await api(`/api/excel-import/${result.value.batch_id}/commit`,{method:'POST'});result.value={...result.value,...d,status:'imported'};ElMessage.success(`导入成功：写入 ${d.imported_count} 条，跳过 ${d.skipped_count} 条`);await load()}catch(e){ElMessage.error(e.message)}finally{loading.value=false}};const load=async()=>history.value=(await api('/api/excel-import/batches?page_size=100')).items||[];const view=async id=>{detail.value=await api(`/api/excel-import/batches/${id}`);detailVisible.value=true};const report=async id=>save(await(await fetch(`/api/excel-import/batches/${id}/error-report`)).blob(),`精度导入批次${id}_错误报告.xlsx`);onMounted(load)
</script>
<template><div class="center"><section class="hero"><div><p>DATA INITIALIZATION CENTER</p><h2>Excel 导入</h2><span>系统初始化与跨表批量维护。日常数据可从对应页面单独导入。</span></div><el-button @click="download"><el-icon><Download/></el-icon>下载整体模板</el-button></section><section class="panel"><el-steps :active="step" simple finish-status="success"><el-step title="选择文件"/><el-step title="预检"/><el-step title="确认写入"/><el-step title="完成"/></el-steps><el-upload ref="upload" drag action="#" accept=".xlsx" :auto-upload="false" :limit="1" :on-change="change"><el-icon class="upload-icon"><UploadFilled/></el-icon><div class="el-upload__text">拖入整体导入文件，或<em>点击选择</em></div></el-upload><div class="actions"><el-button v-if="!result||result.error_count" type="primary" :disabled="!file" :loading="loading" @click="precheck">开始预检</el-button><el-button v-else type="primary" :loading="loading" @click="commit">确认整批导入</el-button><span>预检不写入业务数据；确认后整批事务写入，失败自动回滚。</span></div></section><section v-if="result" class="panel"><div class="stats"><span>工作表<b>{{result.sheet_count}}</b></span><span>数据行<b>{{result.row_count}}</b></span><span>错误<b>{{result.error_count}}</b></span><span>提示<b>{{result.warning_count}}</b></span></div><el-table v-if="result.issues?.length" :data="result.issues" max-height="350"><el-table-column prop="sheet_name" label="工作表"/><el-table-column prop="row_number" label="行" width="60"/><el-table-column prop="column_name" label="列"/><el-table-column prop="message" label="问题说明"/><el-table-column label="操作" width="90"><template #default><el-button text type="danger" @click="report(result.batch_id)">报告</el-button></template></el-table-column></el-table></section><section class="panel"><div class="section-head"><div><h3>导入记录</h3><p>保留预检和写入结果。</p></div><el-button text @click="load"><el-icon><Refresh/></el-icon>刷新</el-button></div><el-table :data="history"><el-table-column prop="batch_id" label="批次" width="75"/><el-table-column prop="file_name" label="文件名"/><el-table-column label="状态" width="120"><template #default="{row}"><el-tag :type="statusType(row.status)">{{statusText(row.status)}}</el-tag></template></el-table-column><el-table-column prop="row_count" label="行数" width="80"/><el-table-column prop="error_count" label="错误" width="80"/><el-table-column prop="imported_count" label="写入" width="80"/><el-table-column label="操作" width="130"><template #default="{row}"><el-button text @click="view(row.batch_id)">详情</el-button><el-button v-if="row.error_count" text type="danger" @click="report(row.batch_id)">报告</el-button></template></el-table-column></el-table></section><el-dialog v-model="detailVisible" title="批次详情" width="min(720px, 94vw)"><el-table v-if="detail?.issues?.length" :data="detail.issues"><el-table-column prop="sheet_name" label="工作表"/><el-table-column prop="row_number" label="行" width="60"/><el-table-column prop="column_name" label="列"/><el-table-column prop="message" label="说明"/></el-table><el-empty v-else description="该批次没有问题"/></el-dialog></div></template>
<style scoped>
.center {
  display: grid;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  gap: 18px;
  overflow: hidden;
}

.hero,
.panel {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  padding: 26px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .86);
  border-radius: 26px;
  background: rgba(255, 255, 255, .7);
  box-shadow: 0 18px 40px rgba(70, 103, 140, .09);
}

.hero,
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.hero > div,
.section-head > div {
  min-width: 0;
}

.hero p {
  margin: 0;
  color: #6889b0;
  font-size: 11px;
  letter-spacing: .18em;
}

.hero h2 { margin: 6px 0; }
.hero span,
.section-head p { color: #74859a; }
.el-steps { margin-bottom: 18px; }

:deep(.el-upload),
:deep(.el-upload-dragger),
:deep(.el-table) {
  width: 100% !important;
  max-width: 100%;
}

:deep(.el-table__inner-wrapper) {
  max-width: 100%;
}

:deep(.el-table__body-wrapper),
:deep(.el-table__header-wrapper) {
  overflow-x: auto;
}

:deep(.el-upload-dragger) {
  min-height: 170px;
  border-radius: 20px;
}

.upload-icon {
  margin-top: 26px;
  font-size: 42px;
  color: #75a2d2;
}

.actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 18px;
  color: #8090a3;
  font-size: 12px;
}

.stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.stats span {
  min-width: 0;
  padding: 16px;
  border-radius: 16px;
  background: #f1f7fd;
  color: #78889b;
}

.stats b {
  display: block;
  margin-top: 5px;
  font-size: 23px;
  color: #243b58;
}

.section-head p { margin: 4px 0 16px; }

@media (max-width: 760px) {
  .hero,
  .section-head,
  .actions {
    align-items: flex-start;
    flex-direction: column;
  }

  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero,
  .panel {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>
