基本配置修改 优化
This commit is contained in:
parent
b0c2b0cd3b
commit
a9f150c446
|
|
@ -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'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
Loading…
Reference in New Issue