基本配置修改 优化

This commit is contained in:
lizhenhua 2025-09-08 10:53:33 +08:00
parent b0c2b0cd3b
commit a9f150c446
3 changed files with 971 additions and 0 deletions

View File

@ -0,0 +1,45 @@
import request from '@/utils/request'
// 查询食堂支付记录列表
export function listCanteenRecord(query) {
return request({
url: '/smart-canteen/api/v2/report/consume/list',
method: 'post',
data: query
})
}
//人员报表信息查询
export function peoplelistRecord(query) {
return request({
url: '/smart-canteen/api/v2/report/consume/peoplelist',
method: 'get',
params: query
})
}
//获取组织树
export function getTree(query) {
return request({
url: '/smart-canteen/api/v2/report/tree',
method: 'get',
params: query
})
}
// 查询详情列表
export function getDetailList(query) {
return request({
url: '/smart-canteen/api/v2/report/consume/listByArea',
method: 'post',
data: query
})
}
// 若依内置了 download 工具,页面里直接用 this.download 更方便(见下)
export function download(query) {
return request({
url: '/smart-canteen/api/v2/report/consume/exportExcel',
method: 'post',
data: query,
responseType: 'blob'
})
}

View File

@ -0,0 +1,515 @@
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-form :inline="true" :model="queryParams" class="demo-form-inline" style="display: flex; align-items: center; flex-wrap: wrap;">
<el-form-item label="支付开始时间">
<el-date-picker
v-model="queryParams.startPayTime"
type="datetime"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
clearable
/>
</el-form-item>
<el-form-item label="支付结束时间">
<el-date-picker
v-model="queryParams.endPayTime"
type="datetime"
placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
clearable
/>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button type="success" @click="exportExcel" style="margin-left: 8px;">导出</el-button>
</el-form-item>
<!-- 查询按钮和合计在同一行 -->
<el-form-item style="margin-left: auto;">
<div style="display: inline-block; margin-left: 20px; font-size: 20px; color: #606266;">
合计<b style="color: #67C23A;">{{ pageTotals.total.toFixed(2) }}</b>
</div>
</el-form-item>
</el-form>
<!-- 主表格 -->
<el-table
:data="tableData"
border
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
v-loading="loading"
element-loading-text="数据加载中..."
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
>
<el-table-column label="食堂名称" prop="orgName" align="center" />
<el-table-column label="预订餐消费" prop="reserveAmount" align="center">
<template slot-scope="scope">
<span class="clickable" @click="handleDetail(scope.row,1)">
{{ Math.abs(scope.row.reserveAmount) }}
</span>
</template>
</el-table-column>
<el-table-column label="食堂消费" prop="canteenAmount" align="center">
<template slot-scope="scope">
<span class="clickable" @click="handleDetail(scope.row,3)">
{{ Math.abs(scope.row.canteenAmount) }}
</span>
</template>
</el-table-column>
<el-table-column label="超市消费" prop="superAmount" align="center">
<template slot-scope="scope">
<span class="clickable" @click="handleDetail(scope.row,4)">
{{ Math.abs(scope.row.superAmount) }}
</span>
</template>
</el-table-column>
<el-table-column label="驿站消费" prop="h5Amount" align="center">
<template slot-scope="scope">
<span class="clickable" @click="handleDetail(scope.row,2)">
{{ Math.abs(scope.row.h5Amount) }}
</span>
</template>
</el-table-column>
<el-table-column label="消费补扣" prop="deductionAmount" align="center">
<template slot-scope="scope">
<span class="clickable" @click="handleDetail(scope.row,5)">
{{ Math.abs(scope.row.deductionAmount) }}
</span>
</template>
</el-table-column>
<el-table-column label="总和" align="center">
<template slot-scope="scope">
<span
style="color: #67c23a; font-weight: bold;"
>
{{
(
Math.abs(scope.row.reserveAmount || 0) +
Math.abs(scope.row.canteenAmount || 0) +
Math.abs(scope.row.superAmount || 0) +
Math.abs(scope.row.deductionAmount || 0) +
Math.abs(scope.row.h5Amount || 0)
).toFixed(2)
}}
</span>
</template>
</el-table-column>
</el-table>
<!-- 主表分页 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 详情弹窗 -->
<el-dialog
:visible.sync="detailVisible"
:title="detail.orgName + ' - 消费详情'"
width="1400px"
class="detail-dialog"
>
<!-- 导出按钮 -->
<el-button
type="success"
size="small"
style="margin-bottom: 10px;"
@click="exportDetailExcel"
>
导出详情
</el-button>
<!-- 消费金额展示 -->
<div style="margin-bottom: 10px; font-weight: bold; font-size: 16px;">
当前{{ detailType }}消费金额<span style="color: #409eff;">{{ Math.abs(detailAmount) }}</span>
</div>
<el-table
:data="detailData"
border
style="width: 100%"
height="600px"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
>
<el-table-column
label="序号"
align="center"
type="index"
:index="indexMethod"
width="80"
/>
<el-table-column label="所属组织" prop="orgFullName" align="center" />
<el-table-column label="人员姓名" prop="custName" align="center" />
<el-table-column label="消费金额" prop="amount" align="center">
<template slot-scope="scope">
{{ scope.row.amount }}
</template>
</el-table-column>
<el-table-column label="消费类型" prop="canteenAmount" align="center">
<template slot-scope="scope">
<span class="clickable" @click="handleDetail(scope.row)">
<span :style="{ color: getConsumeTypeColor(scope.row) }">
{{ getConsumeTypeLabel(scope.row) }}
</span>
</span>
</template>
</el-table-column>
<el-table-column label="支付时间" prop="payTime" align="center" />
</el-table>
<!-- 详情分页 -->
<pagination
v-show="detailTotal > 0"
:total="detailTotal"
:page.sync="detailParams.pageNum"
:limit.sync="detailParams.pageSize"
@pagination="getDetailList"
/>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="detailVisible = false">关闭</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { listCanteenRecord, getDetailList } from "@/api/canteen/canteenRecord";
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
export default {
name: "CanteenRecord",
data() {
const today = new Date();
const startOfDay = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(
today.getDate()
).padStart(2, "0")} 00:00:00`;
const endOfDay = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(
today.getDate()
).padStart(2, "0")} 23:59:59`;
return {
queryParams: {
pageNum: 1,
pageSize: 10,
startPayTime: startOfDay,
endPayTime: endOfDay,
orgId: null,
},
detailType: "",
detailAmount: "",
loading: false,
detailAmount: 0, //
total: 0,
tableData: [],
detailVisible: false,
detail: {},
detailData: [],
detailTotal: 0,
detailParams: {
pageNum: 1,
pageSize: 20,
},
};
},
created() {
this.getList();
},
computed: {
pageTotals() {
const totals = { reserve: 0, canteen: 0, super: 0, h5: 0, deduction: 0, total: 0 };
(this.tableData || []).forEach(row => {
const reserve = Math.abs(Number(row.reserveAmount) || 0);
const canteen = Math.abs(Number(row.canteenAmount) || 0);
const sup = Math.abs(Number(row.superAmount) || 0);
const h5 = Math.abs(Number(row.h5Amount) || 0);
const deduction = Math.abs(Number(row.deductionAmount) || 0);
totals.reserve += reserve;
totals.canteen += canteen;
totals.super += sup;
totals.h5 += h5;
totals.deduction += deduction;
});
totals.total = totals.reserve + totals.canteen + totals.super + totals.h5 + totals.deduction;
return totals;
}
},
methods: {
exportExcel() {
if (!this.tableData || this.tableData.length === 0) {
this.$message.warning("暂无数据可导出");
return;
}
// 簿
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet("消费统计");
//
const header = ["食堂名称", "预订餐消费", "食堂消费", "超市消费", "驿站消费","消费补扣","总和"];
sheet.addRow(header);
//
this.tableData.forEach(item => {
sheet.addRow([
item.orgName,
Math.abs(item.reserveAmount || 0),
Math.abs(item.canteenAmount || 0),
Math.abs(item.superAmount || 0),
Math.abs(item.h5Amount || 0),
Math.abs(item.deductionAmount || 0),
(
Math.abs(item.reserveAmount || 0) +
Math.abs(item.canteenAmount || 0) +
Math.abs(item.superAmount || 0) +
Math.abs(item.deductionAmount || 0) +
Math.abs(item.h5Amount || 0)
).toFixed(2)
]);
});
// +
sheet.columns = [
{ header: "所属组织", key: "orgFullName", width: 40 },
{ header: "人员姓名", key: "custName", width: 10 },
{ header: "消费金额", key: "amount", width: 10 },
{ header: "消费类型", key: "flow_type_name", width: 10 },
{ header: "支付时间", key: "payTime", width: 30 },
];
//
sheet.getRow(1).eachCell(cell => {
cell.font = { bold: true, size: 12, color: { argb: "FF000000" } };
cell.alignment = { vertical: "middle", horizontal: "center" };
cell.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "FFEAEAEA" } //
};
cell.border = {
top: { style: "thin" },
left: { style: "thin" },
bottom: { style: "thin" },
right: { style: "thin" }
};
});
// +
sheet.eachRow((row, rowNumber) => {
if (rowNumber !== 1) {
row.eachCell(cell => {
cell.alignment = { vertical: "middle", horizontal: "center" };
cell.border = {
top: { style: "thin", color: { argb: "FFCCCCCC" } },
left: { style: "thin", color: { argb: "FFCCCCCC" } },
bottom: { style: "thin", color: { argb: "FFCCCCCC" } },
right: { style: "thin", color: { argb: "FFCCCCCC" } }
};
});
}
});
//
workbook.xlsx.writeBuffer().then(buffer => {
const fileName = `消费统计_${new Date().toLocaleDateString().replace(/\//g, "-")}.xlsx`;
saveAs(new Blob([buffer], { type: "application/octet-stream" }), fileName);
});
},
/** 导出详情表格 */
exportDetailExcel() {
if (!this.detailData || this.detailData.length === 0) {
this.$message.warning("暂无详情数据可导出");
return;
}
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet("消费详情");
//
const header = ["所属组织", "人员姓名", "消费金额", "消费类型", "支付时间"];
sheet.addRow(header);
//
this.detailData.forEach(item => {
//
let flowTypeLabel = item.flow_type_name || "";
if (!flowTypeLabel) {
const ft = Number(item.flowType ?? item.flow_type);
if (ft === 110) flowTypeLabel = "消费";
else if (ft === 130) flowTypeLabel = "退款";
else if (ft === 120) flowTypeLabel = "补扣";
else flowTypeLabel = "其他";
}
//
const ft = Number(item.flowType ?? item.flow_type);
if (ft === 110 || ft === 120) {
item.amount = -Math.abs(item.amount); //
} else if (ft === 130) {
item.amount = Math.abs(item.amount); // 退
}
sheet.addRow([
item.orgFullName || "",
item.custName || "",
item.amount,
flowTypeLabel,
item.payTime || ""
]);
});
// +
sheet.columns.forEach(col => {
col.width = 18;
col.alignment = { vertical: "middle", horizontal: "center" };
});
//
sheet.getRow(1).eachCell(cell => {
cell.font = { bold: true, size: 12, color: { argb: "FF000000" } };
cell.alignment = { vertical: "middle", horizontal: "center" };
cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFEAEAEA" } };
cell.border = {
top: { style: "thin" },
left: { style: "thin" },
bottom: { style: "thin" },
right: { style: "thin" }
};
});
// +
sheet.eachRow((row, rowNumber) => {
if (rowNumber !== 1) {
row.eachCell(cell => {
cell.alignment = { vertical: "middle", horizontal: "center" };
cell.border = {
top: { style: "thin", color: { argb: "FFCCCCCC" } },
left: { style: "thin", color: { argb: "FFCCCCCC" } },
bottom: { style: "thin", color: { argb: "FFCCCCCC" } },
right: { style: "thin", color: { argb: "FFCCCCCC" } }
};
});
}
});
//
workbook.xlsx.writeBuffer().then(buffer => {
const fileName = `消费详情_${this.detail.orgName}_${new Date().toLocaleDateString().replace(/\//g, "-")}.xlsx`;
saveAs(new Blob([buffer], { type: "application/octet-stream" }), fileName);
});
},
getConsumeTypeLabel(row) {
if(row.flowType ==110){
return '消费'
}else if(row.flowType == 130){
return '退款'
}else if(row.flowType ==120){
return '补扣'
}
},
getConsumeTypeColor(row,type) {
let amount = Number(row.amount || 0)
return amount >= 0 ? 'green' : 'red'
},
tableHeaderStyle() {
return { background: "#f5f7fa", fontWeight: "bold", textAlign: "center" };
},
tableCellStyle() {
return { textAlign: "center" };
},
/** 查询主表 */
getList() {
this.loading = true; //
listCanteenRecord(this.queryParams).then((res) => {
this.tableData = res|| [];
this.loading = false;
});
},
handleQuery() {
if (
this.queryParams.startPayTime &&
this.queryParams.endPayTime &&
this.queryParams.endPayTime < this.queryParams.startPayTime
) {
this.$message.error("结束时间不能早于开始时间");
return;
}
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.queryParams = { pageNum: 1, pageSize: 10, startPayTime: null, endPayTime: null, orgId: null };
this.getList();
},
/** 查看详情 */
handleDetail(row,status) {
this.detail = row;
this.detailAmount = this.getAmountByStatus(row, status); //
this.detailParams.pageNum = 1;
this.detailVisible = true;
if (status === 1) {
this.detailType = "预订餐";
this.detailAmount = row.reserveAmount;
} else if (status === 3) {
this.detailType = "食堂";
this.detailAmount = row.canteenAmount;
} else if (status === 4) {
this.detailType = "超市";
this.detailAmount = row.superAmount;
} else if (status === 2) {
this.detailType = "驿站";
this.detailAmount = row.h5Amount;
}else if (status === 5) {
this.detailType = "补扣";
this.detailAmount = row.deductionAmount;
}
this.getDetailList(status);
},
//
getAmountByStatus(row, status) {
switch (status) {
case 1: return row.reserveAmount;
case 2: return row.h5Amount;
case 3: return row.canteenAmount;
case 4: return row.superAmount;
default: return 0;
}
},
/** 获取详情分页数据 */
getDetailList(status) {
const params = {
conSource: status,
orgName: this.detail.orgName,
pageNum: this.detailParams.pageNum,
pageSize: this.detailParams.pageSize,
startPayTime: this.queryParams.startPayTime,
endPayTime: this.queryParams.endPayTime,
};
getDetailList(params).then((res) => {
this.detailData = res || [];
this.detailTotal = res.total || 0;
});
},
},
};
</script>
<style scoped>
.clickable {
color: #409eff;
cursor: pointer;
font-weight: 500;
}
.clickable:hover {
text-decoration: underline;
}
.detail-dialog ::v-deep .el-table th {
background: #f5f7fa;
font-weight: 600;
}
</style>

View File

@ -0,0 +1,411 @@
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-form :inline="true" :model="queryParams" class="demo-form-inline">
<!-- <el-form-item label="所属组织">
<el-input v-model="queryParams.orgName" placeholder="请输入组织名称" clearable />
</el-form-item> -->
<el-form-item label="所属组织">
<el-cascader
v-model="selectedOrg"
:options="orgOptions"
:show-all-levels="false"
clearable
filterable
placeholder="请选择所属组织"
:props="{
checkStrictly: true,
expandTrigger: 'hover',
value: 'orgId',
label: 'orgName',
children: 'children'
}"
style="width: 260px;"
>
</el-cascader>
</el-form-item>
<el-form-item label="用户姓名">
<el-input v-model="queryParams.custName" placeholder="请输入组织名称" clearable />
</el-form-item>
<el-form-item label="支付开始时间">
<el-date-picker
v-model="queryParams.startPayTime"
type="datetime"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
clearable
/>
</el-form-item>
<el-form-item label="支付结束时间">
<el-date-picker
v-model="queryParams.endPayTime"
type="datetime"
placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
clearable
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button type="success" @click="newexportExcel">导出列表</el-button>
</el-form-item>
</el-form>
<!-- 主表格 -->
<el-table
:data="tableData.slice((pageNum-1)*pageSize,pageNum*pageSize)"
border
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
v-loading="loading"
element-loading-text="数据加载中..."
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
>
<!-- 序号列连续分页序号 -->
<el-table-column
label="序号"
align="center"
type="index"
:index="indexMethod"
width="80"
/>
<el-table-column
label="所属组织"
prop="orgFullName"
align="center"
:show-overflow-tooltip="true"
/>
<el-table-column label="用户姓名" prop="custName" align="center" />
<el-table-column label="用户编号" prop="custId" align="center" />
<el-table-column label="订单类型" prop="flowType" align="center">
<template #default="scope">
<span :style="{ color: getFlowTypeColor(scope.row.flowType), fontWeight: 'bold' }">
{{ getFlowTypeLabel(scope.row.flowType) }}
</span>
</template>
</el-table-column>
<el-table-column label="订单金额" align="center">
<template v-slot="scope">
{{ (Math.abs(scope.row.amount) / 100).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="用户手机号" prop="phone" align="center" />
<el-table-column label="下单时间" prop="ordTime" align="center" />
<el-table-column label="备注" prop="remark" align="center" />
</el-table>
<!-- 主表分页 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 详情弹窗 -->
<el-dialog
:visible.sync="detailVisible"
:title="detail.orgName + ' - 消费详情'"
width="1400px"
class="detail-dialog"
>
<el-button
type="success"
size="small"
style="margin-bottom: 10px;"
@click="exportDetailExcel"
>
导出详情
</el-button>
<el-table
:data="detailData"
border
style="width: 100%"
height="600px"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
>
<el-table-column label="用户姓名" prop="custName" align="center" />
<el-table-column label="用户编号" prop="custId" align="center" />
<el-table-column label="所属组织" prop="orgFullName" align="center" />
<el-table-column label="订单类型" prop="consumeSource" align="center" />
<el-table-column label="订单金额" prop="amount" align="center">
<template slot-scope="scope">
{{ (scope.row.amount / 100).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="用户手机号" prop="phone" align="center" />
<el-table-column label="下单时间" prop="ordTime" align="center" />
<el-table-column label="备注" prop="remark" align="center" />
</el-table>
<!-- 详情分页 -->
<pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="detailVisible = false">关闭</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {getTree, peoplelistRecord,download} from "@/api/canteen/canteenRecord";
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
export default {
data() {
const today = new Date();
const startOfDay = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2,"0")} 00:00:00`;
const endOfDay = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2,"0")}-${String(today.getDate()).padStart(2,"0")} 23:59:59`;
return {
selectedOrg: [], //
orgOptions:[],
queryParams: {
pageNum: 1,
pageSize: 10,
startPayTime: startOfDay,
endPayTime: endOfDay,
orgName: "",
},
detailVisible: false,
detail: {},
tableData: [],
total: 0,
detailData: [],
detailTotal: 0,
detailParams: { pageNum: 1, pageSize: 20 },
loading: false,
pageNum: 1,
pageSize: 10,
};
},
created() {
this.getList();
this.getTree();
},
methods: {
getTree(){
getTree().then(res => {
this.orgOptions = res;
});
},
// orgId
getAllChildIds(node) {
let ids = [node.orgId]; //
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
ids = ids.concat(this.getAllChildIds(child)); //
});
}
return ids;
},
// cascader orgId
getSelectedOrgIds() {
if (!this.selectedOrg || this.selectedOrg.length === 0) return [];
const lastValue = this.selectedOrg[this.selectedOrg.length - 1];
//
let stack = [...this.orgOptions];
let node = null;
for (let val of this.selectedOrg) {
node = stack.find(item => item.orgId === val); // orgId
if (!node) break;
stack = node.children || [];
}
if (node) {
return this.getAllChildIds(node); // orgId
}
return [lastValue]; //
},
indexMethod(index) {
return (this.queryParams.pageNum - 1) * this.queryParams.pageSize + index + 1;
},
//
getFlowTypeLabel(flowType) {
flowType = Number(flowType || 0);
if (flowType === 110) return "消费";
if (flowType === 130) return "退款";
if (flowType === 120) return "消费补扣";
return "其他";
},
//
getFlowTypeColor(flowType) {
flowType = Number(flowType || 0);
if (flowType === 110) return "red"; //
if (flowType === 130) return "green"; // 退绿
return "black";
},
tableHeaderStyle() { return { background: "#f5f7fa", fontWeight: "bold", textAlign: "center" }; },
tableCellStyle() { return { textAlign: "center" }; },
handleQuery() {
if(this.queryParams.startPayTime && this.queryParams.endPayTime && this.queryParams.endPayTime < this.queryParams.startPayTime){
this.$message.error("结束时间不能早于开始时间");
return;
}
this.queryParams.pageNum = 1;
this.getList();
},
getList() {
this.loading = true;
// orgId
this.queryParams.selectedOrg = this.getSelectedOrgIds(); // id
console.log("11111"+ this.queryParams.selectedOrg)
// queryParams.orgPath = this.selectedOrg.join(',');
peoplelistRecord(this.queryParams).then(res => {
this.tableData = res.rows || [];
this.total = Number(res.total) || 0; //
this.loading = false;
});
},
/** 导出主表 */
newexportExcel(){
this.queryParams.selectedOrg = this.getSelectedOrgIds(); // id
this.download('/smart-canteen/api/v2/report/consume/exportExcel', { ...this.queryParams }, `人员信息报表_${Date.now()}.xlsx`)
},
handleDetail(row) {
this.detail = row;
this.detailVisible = true;
this.detailParams.pageNum = 1;
this.getDetailList();
},
getDetailList() {
const params = {
orgName: this.detail.orgName,
pageNum: 1,
pageSize: 10,
startPayTime: this.queryParams.startPayTime,
endPayTime: this.queryParams.endPayTime,
};
getDetailList(params).then(res => {
this.detailData = res.list || [];
this.detailTotal = res.total || 0;
});
},
exportExcel() {
if(!this.tableData || this.tableData.length === 0) {
this.$message.warning("暂无数据可导出");
return;
}
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet("消费统计");
sheet.columns = [
{ header: "用户姓名", key: "custName", width: 15 },
{ header: "用户编号", key: "custId", width: 20 },
{ header: "所属组织", key: "orgFullName", width: 30 },
{ header: "订单类型", key: "consumeSource", width: 15 },
{ header: "订单金额", key: "amount", width: 15 },
{ header: "用户手机号", key: "phone", width: 15 },
{ header: "下单时间", key: "ordTime", width: 20 },
{ header: "备注", key: "remark", width: 25 },
];
this.tableData.forEach(item => sheet.addRow({
custName: item.custName || "",
custId: item.custId || "",
orgFullName: item.orgFullName || "",
flow_type_name: item.flow_type_name || "",
consumeSource: item.consumeSource || "",
ordDate: item.ordDate || "",
amount: item.amount || 0,
phone: item.phone || "",
ordTime: item.ordTime || "",
remark: item.remark || "",
}));
sheet.eachRow((row,rowNumber)=>{
row.eachCell(cell=>{
cell.alignment={vertical:"middle",horizontal:"center"};
cell.border={
top:{style:"thin",color:{argb:"FFCCCCCC"}},
left:{style:"thin",color:{argb:"FFCCCCCC"}},
bottom:{style:"thin",color:{argb:"FFCCCCCC"}},
right:{style:"thin",color:{argb:"FFCCCCCC"}}
};
if(rowNumber===1) cell.fill={type:"pattern",pattern:"solid",fgColor:{argb:"FFEAEAEA"}};
});
});
workbook.xlsx.writeBuffer().then(buffer=>{
saveAs(new Blob([buffer],{type:"application/octet-stream"}), `消费统计_${new Date().toLocaleDateString().replace(/\//g,"-")}.xlsx`);
});
},
/** 导出详情 */
exportDetailExcel() {
if(!this.detailData || this.detailData.length===0){
this.$message.warning("暂无详情数据可导出");
return;
}
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet("消费详情");
sheet.columns = [
{ header: "用户姓名", key: "custName", width: 15 },
{ header: "用户编号", key: "custId", width: 20 },
{ header: "所属组织", key: "orgFullName", width: 30 },
{ header: "订单类型", key: "consumeSource", width: 15 },
{ header: "就餐日期", key: "ordDate", width: 18 },
{ header: "订单金额", key: "amount", width: 15 },
{ header: "用户手机号", key: "phone", width: 15 },
{ header: "下单时间", key: "ordTime", width: 20 },
{ header: "备注", key: "remark", width: 25 },
];
this.detailData.forEach(item=>sheet.addRow({
custName: item.custName || "",
custId: item.custId || "",
orgFullName: item.orgFullName || "",
flow_type_name: item.flow_type_name || "",
consumeSource: item.consumeSource || "",
ordDate: item.ordDate || "",
amount: item.amount || 0,
phone: item.phone || "",
ordTime: item.ordTime || "",
remark: item.remark || "",
}));
sheet.eachRow((row,rowNumber)=>{
row.eachCell(cell=>{
cell.alignment={vertical:"middle",horizontal:"center"};
cell.border={
top:{style:"thin",color:{argb:"FFCCCCCC"}},
left:{style:"thin",color:{argb:"FFCCCCCC"}},
bottom:{style:"thin",color:{argb:"FFCCCCCC"}},
right:{style:"thin",color:{argb:"FFCCCCCC"}}
};
if(rowNumber===1) cell.fill={type:"pattern",pattern:"solid",fgColor:{argb:"FFEAEAEA"}};
});
});
workbook.xlsx.writeBuffer().then(buffer=>{
saveAs(new Blob([buffer],{type:"application/octet-stream"}), `消费详情_${this.detail.orgName}_${new Date().toLocaleDateString().replace(/\//g,"-")}.xlsx`);
});
}
}
};
</script>
<style scoped>
.clickable { color:#409eff; cursor:pointer; font-weight:500; }
.clickable:hover { text-decoration: underline; }
.detail-dialog ::v-deep .el-table th { background: #f5f7fa; font-weight: 600; }
</style>