feat: P0-6 Excel导入导出全套(客户/合同/库存/统计, 自动表头探测)
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user