feat: P0-6 Excel导入导出全套(客户/合同/库存/统计, 自动表头探测)

This commit is contained in:
HHY
2026-09-25 03:30:27 -07:00
parent 436d006b5a
commit 40c16d56a1
14 changed files with 367 additions and 9 deletions
+8
View File
@@ -51,3 +51,11 @@ export async function apiDownload(url: string, filename: string): Promise<void>
link.click()
URL.revokeObjectURL(link.href)
}
/** 上传文件(multipart,自动带 token),返回 envelope data */
export async function apiUpload<T = any>(url: string, file: File): Promise<T> {
const fd = new FormData()
fd.append('file', file)
const res = await http.post(url, fd, { headers: { 'Content-Type': 'multipart/form-data' } })
return res.data.data as T
}
+4 -1
View File
@@ -8,6 +8,7 @@
</el-select>
<el-button type="primary" @click="load">查询</el-button>
<div style="flex:1" />
<el-button @click="exportExcel">导出 Excel</el-button>
<el-button type="primary" plain @click="openCreate">新建合同</el-button>
</div>
<el-table :data="rows" v-loading="loading" stripe>
@@ -89,7 +90,7 @@
import { onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { api } from '../api'
import { api, apiDownload } from '../api'
const router = useRouter()
const rows = ref<any[]>([])
@@ -169,6 +170,8 @@ async function saveReceipt() {
load()
}
function exportExcel() { apiDownload('/api/contracts/excel-out', 'contracts.xlsx') }
onMounted(load)
</script>
+21 -1
View File
@@ -4,6 +4,11 @@
<el-input v-model="keyword" placeholder="姓名/电话/地址" clearable style="width:240px" @keyup.enter="load" />
<el-button type="primary" @click="load">查询</el-button>
<div style="flex:1" />
<el-upload :show-file-list="false" :http-request="doImport" accept=".xlsx,.xls">
<el-button type="warning" plain :loading="importing">导入 Excel</el-button>
</el-upload>
<el-button @click="downloadTemplate">下载模板</el-button>
<el-button @click="exportExcel">导出 Excel</el-button>
<el-button type="primary" plain @click="openEdit()">新增客户</el-button>
</div>
<el-table :data="rows" v-loading="loading" stripe>
@@ -43,7 +48,7 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { api } from '../api'
import { api, apiDownload, apiUpload } from '../api'
const rows = ref<any[]>([])
const total = ref(0)
@@ -89,6 +94,21 @@ async function remove(row: any) {
load()
}
// ---- Excel 导入导出 ----
const importing = ref(false)
async function doImport(opt: any) {
importing.value = true
try {
await apiUpload('/api/customers/excel-in', opt.file as File)
ElMessage.success('导入完成')
load()
} finally { importing.value = false }
}
function downloadTemplate() { apiDownload('/api/customers/excel-template', 'customers_template.xlsx') }
function exportExcel() { apiDownload('/api/customers/excel-out', 'customers.xlsx') }
onMounted(load)
</script>
+4 -1
View File
@@ -8,6 +8,7 @@
<el-radio-button :value="14">近14天</el-radio-button>
<el-radio-button :value="30">近30天</el-radio-button>
</el-radio-group>
<el-button size="small" plain @click="exportExcel">导出统计 Excel</el-button>
</div>
</template>
@@ -43,7 +44,7 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { api } from '../api'
import { api, apiDownload } from '../api'
const days = ref(14)
const byDay = ref<any[]>([])
@@ -75,6 +76,8 @@ async function load() {
statusDist.value = d.status_dist
}
function exportExcel() { apiDownload('/api/reports/excel-statistics', 'statistics.xlsx') }
onMounted(load)
</script>
+19 -1
View File
@@ -8,6 +8,10 @@
</el-select>
<el-button type="primary" @click="load">查询</el-button>
<div style="flex:1" />
<el-upload :show-file-list="false" :http-request="doImport" accept=".xlsx,.xls">
<el-button type="warning" plain :loading="importing">导入 Excel</el-button>
</el-upload>
<el-button @click="exportExcel">导出 Excel</el-button>
<el-button type="primary" plain @click="openEdit()">新增材料</el-button>
</div>
<el-table :data="rows" v-loading="loading" stripe>
@@ -63,7 +67,7 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { api } from '../api'
import { api, apiDownload, apiUpload } from '../api'
const rows = ref<any[]>([])
const total = ref(0)
@@ -111,6 +115,20 @@ async function move(row: any, direction: number) {
load()
}
// ---- Excel 导入导出 ----
const importing = ref(false)
async function doImport(opt: any) {
importing.value = true
try {
await apiUpload('/api/warehouse/excel-in', opt.file as File)
ElMessage.success('导入完成')
load()
} finally { importing.value = false }
}
function exportExcel() { apiDownload('/api/warehouse/excel-out', 'warehouse.xlsx') }
onMounted(load)
</script>