1. pnpm i xlsx
2.工具
/* eslint-disable no-prototype-builtins */
import * as XLSX from 'xlsx';
/*
* @description:
* @param {Object} json 服务端发过来的数据
* @param {String} name 导出Excel文件名字
* @param titleObj 一个存放标题的字段(请根据展示顺序编写写) 格式如下
titleObj={
云飒ID:'ysId',
中文名称:字段名
}
* @param {String} sheetName 导出sheetName名字
*/
export function exportExcel(
json: any,
name: string,
titleObj: object,
sheetName: string
) {
// 获取 所需要的中英文字段名
const filterTitle: any = getObjVal(titleObj, 'value'); // 英文字段
const titleArr: any = getObjVal(titleObj, 'key'); // 中文字段
let data = []; // 最终存放的数据
const tempData: any[] = []; // 筛选出的乱序数据
const sortData = [] as any; // 排序后的数据
// 筛选出符合条件的服务端数据
for (const key1 in json) {
if (json.hasOwnProperty(key1)) {
const element = json[key1];
const rowArr = [];
for (const key2 in element) {
if (element.hasOwnProperty(key2) && filterTitle.includes(key2)) {
rowArr.push({
label: key2,
value: element[key2]
});
}
}
tempData.push(rowArr);
}
}
// 对符合条件数据 按照titleObj 进行排序
tempData.map((item: any) => {
const arr = [] as any;
filterTitle.map((item1: any) => {
item.map((item2: any) => {
if (item1 === item2.label) {
arr.push(item2.value);
}
});
});
sortData.push(arr);
});
// // 隐藏英文字段 数据组装
// data = [filterTitle, titleArr, ...sortData];
// console.log("data", data);
// const ws = XLSX.utils.aoa_to_sheet(data);
// const wb = XLSX.utils.book_new();
// 此处隐藏英文字段表头
// let wsrows = [{ hidden: true }];
// ws["!rows"] = wsrows; // ws - worksheet
// XLSX.utils.book_append_sheet(wb, ws, sheetName);
/* generate file and send to client */
// XLSX.writeFile(wb, name + ".xlsx");
// 不要英文字段
// 数据组装
data = [titleArr, ...sortData];
console.log('data', data, sortData);
const ws = XLSX.utils.aoa_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, sheetName);
XLSX.writeFile(wb, name + '.xlsx');
}
/*
* @description: 分别获取对象的键 或 值
* @param {titleObj} 原始对象
* @flag 标记 key 取键 value 取值
*/
export function getObjVal(titleObj: any, flag: string) {
const arr = [];
// key 取key值
if (flag == 'key') {
for (const key in titleObj) {
if (titleObj.hasOwnProperty(key)) {
arr.push(key);
}
}
return arr;
}
// value 取value 值
if (flag == 'value') {
for (const key in titleObj) {
if (titleObj.hasOwnProperty(key)) {
arr.push(titleObj[key]);
}
}
return arr;
}
}
3.使用
<template>
<div>
<Search :search="moreSearch" :reset="moreReset">
<template v-slot:body>
<el-form-item label="书名">
<el-input v-model="query.book_name" name="book_name" clearable />
</el-form-item>
<el-form-item label="bid">
<el-input v-model="query.bid" name="bid" clearable />
</el-form-item>
<el-form-item label="版权方">
<el-select v-model="query.cp_name" filterable remote clearable :remote-method="remoteMethod"
placeholder="选择版权方">
<el-option v-for="item in cpoptions" :key="item.cp_id" :label="item.cp_name" :value="item.cp_name" />
</el-select>
</el-form-item>
<el-form-item label="日期">
<el-date-picker unlink-panels clearable @change="timeChange" format="YYYY/MM/DD" value-format="YYYY-MM-DD"
v-model="query.time" type="daterange" :default-value="defaultTime2" :shortcuts="shortcuts"
range-separator="To" start-placeholder="开始时间" end-placeholder="结束时间" />
</el-form-item>
</template>
<template v-slot:extra_button>
<el-button type="primary" @click="dataExport" size="default">
<!-- <Icon name="document-arrow-up" className="w-4 h-4 mr-1 -ml-1" /> -->
导出
</el-button>
</template>
</Search>
<div style="margin:8px 0;">
<el-card shadow="hover" :body-style="{ padding: '20px' }">
<div class="stat-wrapper">
<div>订阅结算统计书币: <span class="ml-2 mr-4 stat">{{ statisticalData.yesterday_total_coins || '暂无数据' }}</span></div>
<div>订阅的总金额: <span class="ml-2 mr-4 stat">{{ statisticalData.yesterday_available_amount || '暂无数据' }}</span>
</div>
<div>应结算金额: <span class="ml-2 mr-4 stat">{{ statisticalData.yesterday_final_amount || '暂无数据' }}</span></div>
</div>
</el-card>
</div>
<div class="table-default">
<!-- <Operate :show="open" /> -->
<!-- <div class="set-warpper">
<el-button type="primary" @click="testExport" size="default">导出</el-button>
</div> -->
<el-table :data="tableData" class="mt-3" v-loading="loading">
<el-table-column prop="book_name" label="书名" />
<el-table-column prop="bid" label="bid" />
<el-table-column prop="cp_name" label="版权方" />
<el-table-column prop="yesterday_total_coins" label="订单结算书币" />
<el-table-column prop="yesterday_available_amount" label="订阅金额" />
<el-table-column prop="yesterday_final_amount" label="应结算金额" />
<el-table-column prop="book_settlement_type_str" label="书籍合作模式" />
<el-table-column prop="date" label="创建时间" />
</el-table>
<Paginate />
</div>
<Dialog v-model="visible" :title="title" destroy-on-close>
<Create @close="close(reset)" :primary="id" :api="api" />
</Dialog>
</div>
</template>
<script lang="ts" setup>
import {
computed,
onMounted,
ref
} from 'vue';
import {
useGetList
} from '@/hook/curd/useGetList';
import {
useDestroy
} from '@/hook/curd/useDestroy';
import {
useOpen
} from '@/hook/curd/useOpen';
import {
MenuType
} from '@/enum/app';
// import table2excel from 'js-table2excel'
import moment from 'moment';
import { exportExcel } from '@/utils/exportExcel'
import { shortcuts } from '@/utils/shortcuts'
import http from '@/support/http';
import { cpOptions, subscribeStatisticDataList, subscribeStatisticDataListStatistic } from '@/api/cp/index';
const defaultTime2 = [
moment().startOf('month'), moment().endOf('month')
]
const api = 'contentManage/cp/subscribeStatisticData/list';
const start_date = moment().startOf('month').format('YYYY-MM-DD')
const end_date = moment().endOf('month').format('YYYY-MM-DD')
const dataExport = () => {
let exportTableData = ref([])
subscribeStatisticDataList({ is_export: 1, ...query.value }).then(res => {
console.log(res);
exportTableData.value = res.data
console.log(res, 'exportTableData', exportTableData.value);
console.log(start_date, end_date);
const titleObj = {
"书名": "book_name",
"bid": "bid",
"版权方": "cp_name",
"订单结算书币": "yesterday_total_coins",
"订阅金额": "yesterday_available_amount",
"应结算金额": "yesterday_final_amount",
"书籍合作模式": "book_settlement_type_str",
"创建时间": "date",
};
console.log(tableData.value, 'tableData.value', exportTableData.value);
exportExcel(exportTableData.value, `数据中心${moment().format('YYYY-MM-DD HH:mm:ss')}`, titleObj, "数据中心");
})
}
const timeChange = (e) => {
if (query.value.time) {
const timeArr = toRaw(e);
query.value.start_date = timeArr[0]
query.value.end_date = timeArr[1]
} else {
delete query.value.start_date
delete query.value.end_date
}
}
let { data, query, search, reset, loading } = useGetList(api, true);
const { destroy, deleted } = useDestroy();
const { open, close, title, visible, cp_id } = useOpen();
let cpoptions = ref([]);
let tableData = computed(() => data.value?.data);
let statisticalData = ref({})
const moreSearch = () => {
search();
subscribeStatisticDataListStatistic({ ...query.value }).then(res => {
statisticalData.value = res.data
})
}
const moreReset = () => {
reset()
subscribeStatisticDataListStatistic({ ...query.value }).then(res => {
statisticalData.value = res.data
})
}
const remoteMethod = (query: string) => {
if (query) {
console.log(66666);
initCpOtion({ cp_name: query })
} else {
initCpOtion({})
}
}
const initCpOtion = (params: object) => {
cpOptions(params).then(res => {
cpoptions.value = res.data
})
}
onMounted(() => {
query.value.time = [start_date, end_date];
query.value.start_date = start_date;
query.value.end_date = end_date;
subscribeStatisticDataListStatistic({ ...query.value }).then(res => {
statisticalData.value = res.data
})
initCpOtion({})
search();
deleted(reset);
});
</script>
<style lang="scss" scoped>
.stat-wrapper {
display: flex;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
.stat {
box-sizing: border-box;
font-size: 18px;
font-weight: 550;
padding: 0 12px;
}
}
.set-warpper {
height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>