演示报表
This commit is contained in:
1 parent
28078ed292
commit
e02f437955
11 files changed
+931
No files matched your search
@@ -0,0 +1,54 @@
|
||||
import request from "/@/utils/request"
|
||||
|
||||
/** 刷卡明细 */
|
||||
export function fetchSwipePage(query?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/swipe/page", method: "get", params: query })
|
||||
}
|
||||
export function delSwipe(ids?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/swipe", method: "delete", data: ids })
|
||||
}
|
||||
export function clearSwipeMonth(bizMonth: string) {
|
||||
return request({ url: `/canteen/canteenReport/swipe/month/${bizMonth}`, method: "delete" })
|
||||
}
|
||||
|
||||
/** 食材能耗 */
|
||||
export function fetchFoodEnergyPage(query?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/foodEnergy/page", method: "get", params: query })
|
||||
}
|
||||
export function delFoodEnergy(ids?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/foodEnergy", method: "delete", data: ids })
|
||||
}
|
||||
export function clearFoodEnergyMonth(bizMonth: string) {
|
||||
return request({ url: `/canteen/canteenReport/foodEnergy/month/${bizMonth}`, method: "delete" })
|
||||
}
|
||||
|
||||
/** 手工调整 */
|
||||
export function fetchAdjustPage(query?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/adjust/page", method: "get", params: query })
|
||||
}
|
||||
export function getAdjust(id: string | number) {
|
||||
return request({ url: `/canteen/canteenReport/adjust/${id}`, method: "get" })
|
||||
}
|
||||
export function addAdjust(obj?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/adjust", method: "post", data: obj })
|
||||
}
|
||||
export function putAdjust(obj?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/adjust", method: "put", data: obj })
|
||||
}
|
||||
export function delAdjust(ids?: Object) {
|
||||
return request({ url: "/canteen/canteenReport/adjust", method: "delete", data: ids })
|
||||
}
|
||||
|
||||
/** 报表计算 */
|
||||
export function reportSummary(bizMonth: string) {
|
||||
return request({ url: "/canteen/canteenReport/summary", method: "get", params: { bizMonth } })
|
||||
}
|
||||
export function reportIncome(bizMonth: string) {
|
||||
return request({ url: "/canteen/canteenReport/income", method: "get", params: { bizMonth } })
|
||||
}
|
||||
export function reportSupplierShare(bizMonth: string) {
|
||||
return request({ url: "/canteen/canteenReport/supplierShare", method: "get", params: { bizMonth } })
|
||||
}
|
||||
export function reportBusiness(bizMonth: string) {
|
||||
return request({ url: "/canteen/canteenReport/business", method: "get", params: { bizMonth } })
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="商户" prop="merchantId">
|
||||
<select-mch v-model="state.queryForm.merchantId" :apiParams="{ types: '1' }" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="餐桌编号" prop="tableNumber">
|
||||
<el-input placeholder="请输入餐桌编号" v-model="state.queryForm.tableNumber" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="商户" prop="merchantId">
|
||||
<select-mch v-model="state.queryForm.merchantId" :apiParams="{ types: '1' }" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分类名称" prop="name" >
|
||||
<el-input placeholder="请输入分类名称" v-model="state.queryForm.name" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="商户" prop="merchantId">
|
||||
<select-mch v-model="state.queryForm.merchantId" :apiParams="{ types: '1' }" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单据编号" prop="inventoryCode">
|
||||
<el-input placeholder="请输入单据编号" v-model="state.queryForm.inventoryCode" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="商户" prop="merchantId">
|
||||
<select-mch v-model="state.queryForm.merchantId" :apiParams="{ types: '1' }" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input placeholder="请输入分类名称" v-model="state.queryForm.name" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="商户" prop="merchantId">
|
||||
<select-mch v-model="state.queryForm.merchantId" :apiParams="{ types: '1' }" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input placeholder="请输入商品名称" v-model="state.queryForm.name" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="业务月" prop="bizMonth">
|
||||
<el-date-picker
|
||||
v-model="state.queryForm.bizMonth"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="选择月份"
|
||||
style="width: 140px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="openForm()">新 增</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary" class="ml10" @click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<el-button icon="download" plain type="primary" class="ml10" @click="exportExcel">导出</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10 mr20" style="float: right" @queryTable="getDataList" />
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="bizMonth" label="业务月" width="100" />
|
||||
<el-table-column prop="adjustType" label="调整类型" width="120" />
|
||||
<el-table-column prop="costCenter" label="成本中心" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="park" label="厂区" width="120" />
|
||||
<el-table-column prop="amount" label="调整金额" width="120" align="right" />
|
||||
<el-table-column prop="remark" label="备注" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button icon="edit-pen" text type="primary" @click="openForm(row)">编辑</el-button>
|
||||
<el-button icon="delete" text type="primary" @click="handleDelete([row.id])">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="formVisible" :title="form.id ? '编辑调整' : '新增调整'" width="520px" destroy-on-close>
|
||||
<el-form :model="form" label-width="100px">
|
||||
<el-form-item label="业务月" required>
|
||||
<el-date-picker v-model="form.bizMonth" type="month" value-format="YYYY-MM" />
|
||||
</el-form-item>
|
||||
<el-form-item label="调整类型">
|
||||
<el-input v-model="form.adjustType" placeholder="跨厂区/开票/其他" />
|
||||
</el-form-item>
|
||||
<el-form-item label="成本中心">
|
||||
<el-input v-model="form.costCenter" placeholder="可空=全局调整" />
|
||||
</el-form-item>
|
||||
<el-form-item label="厂区">
|
||||
<el-input v-model="form.park" />
|
||||
</el-form-item>
|
||||
<el-form-item label="调整金额" required>
|
||||
<el-input-number v-model="form.amount" :precision="2" :step="100" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="formVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="saveForm">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemCanteenReportAdjust">
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||
import { fetchAdjustPage, addAdjust, putAdjust, delAdjust } from "/@/api/canteen/canteenReport"
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: { bizMonth: "2026-07" },
|
||||
pageList: fetchAdjustPage,
|
||||
})
|
||||
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields()
|
||||
state.queryForm = { bizMonth: "2026-07" }
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id)
|
||||
multiple.value = !objs.length
|
||||
}
|
||||
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm("确认删除?")
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await delAdjust(ids)
|
||||
getDataList()
|
||||
useMessage().success("删除成功")
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || "删除失败")
|
||||
}
|
||||
}
|
||||
|
||||
const exportExcel = () => {
|
||||
downBlobFile("/canteen/canteenReport/adjust/export", { ...state.queryForm }, `手工调整_${state.queryForm.bizMonth || ""}.xlsx`)
|
||||
}
|
||||
|
||||
const formVisible = ref(false)
|
||||
const saving = ref(false)
|
||||
const form = reactive<any>({
|
||||
id: undefined,
|
||||
bizMonth: "2026-07",
|
||||
adjustType: "",
|
||||
costCenter: "",
|
||||
park: "",
|
||||
amount: 0,
|
||||
remark: "",
|
||||
})
|
||||
|
||||
const openForm = (row?: any) => {
|
||||
Object.assign(form, {
|
||||
id: undefined,
|
||||
bizMonth: state.queryForm.bizMonth || "2026-07",
|
||||
adjustType: "",
|
||||
costCenter: "",
|
||||
park: "",
|
||||
amount: 0,
|
||||
remark: "",
|
||||
})
|
||||
if (row) {
|
||||
Object.assign(form, row)
|
||||
}
|
||||
formVisible.value = true
|
||||
}
|
||||
|
||||
const saveForm = async () => {
|
||||
if (!form.bizMonth) {
|
||||
useMessage().warning("请填写业务月")
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
if (form.id) {
|
||||
await putAdjust(form)
|
||||
} else {
|
||||
await addAdjust(form)
|
||||
}
|
||||
useMessage().success("保存成功")
|
||||
formVisible.value = false
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || "保存失败")
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view" v-loading="loading">
|
||||
<el-row>
|
||||
<el-form :inline="true" @keyup.enter="loadAll">
|
||||
<el-form-item label="业务月">
|
||||
<el-date-picker v-model="bizMonth" type="month" value-format="YYYY-MM" style="width: 140px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="Search" type="primary" @click="loadAll">计算查询</el-button>
|
||||
<el-button icon="download" plain type="primary" @click="exportCurrent">导出当前页签</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="12" class="mb12" v-if="summary">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="stat">刷卡笔数<br /><b>{{ summary.swipeCount ?? 0 }}</b></div></el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="stat">刷卡合计(元)<br /><b>{{ fmt(summary.swipeAmount) }}</b></div></el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="stat">食材合计(元)<br /><b>{{ fmt(summary.foodAmount) }}</b></div></el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="经营报表" name="business">
|
||||
<el-table :data="businessRows" border size="small" max-height="560" :header-cell-style="headerStyle">
|
||||
<el-table-column prop="type" label="类型" width="110" fixed />
|
||||
<el-table-column prop="category" label="类别" width="110" fixed />
|
||||
<el-table-column v-for="p in parks" :key="p" :label="p" min-width="100" align="right">
|
||||
<template #default="{ row }">{{ fmt(row.parkAmounts?.[p]) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="subtotal" label="小计" width="100" align="right" fixed="right">
|
||||
<template #default="{ row }">{{ fmt(row.subtotal) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="收入合计" name="income">
|
||||
<el-table :data="incomeRows" border size="small" max-height="560" :header-cell-style="headerStyle">
|
||||
<el-table-column prop="groupName" label="收入类别" width="100" fixed />
|
||||
<el-table-column prop="costCenter" label="成本中心" min-width="160" fixed show-overflow-tooltip />
|
||||
<el-table-column v-for="p in parks" :key="p" :label="p" min-width="100" align="right">
|
||||
<template #default="{ row }">{{ fmt(row.parkAmounts?.[p]) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="subtotal" label="小计" width="110" align="right" fixed="right">
|
||||
<template #default="{ row }">{{ fmt(row.subtotal) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="供应商分摊" name="share">
|
||||
<el-table :data="shareRows" border size="small" max-height="560" :header-cell-style="headerStyle">
|
||||
<el-table-column prop="costCenter" label="成本中心" min-width="160" fixed show-overflow-tooltip />
|
||||
<el-table-column v-for="p in shareParks" :key="p" :label="p" min-width="100" align="right">
|
||||
<template #default="{ row }">{{ fmt(row.parkAmounts?.[p]) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="subtotal" label="小计" width="100" align="right">
|
||||
<template #default="{ row }">{{ fmt(row.subtotal) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="boxAndOther" label="包厢及其他" width="110" align="right">
|
||||
<template #default="{ row }">{{ fmt(row.boxAndOther) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="otherAdjust" label="其他调整" width="100" align="right">
|
||||
<template #default="{ row }">{{ fmt(row.otherAdjust) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="invoiceAmount" label="开票金额" width="110" align="right" fixed="right">
|
||||
<template #default="{ row }">{{ fmt(row.invoiceAmount) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemCanteenReportBoard">
|
||||
import { reportSummary, reportIncome, reportSupplierShare, reportBusiness } from "/@/api/canteen/canteenReport"
|
||||
import { useMessage } from "/@/hooks/message"
|
||||
import other from "/@/utils/other"
|
||||
|
||||
const parks = ["敏惠园区", "敏实园区", "敏胜园区", "敏华园区", "湖州园区", "华智一期", "华智二期", "安吉园区"]
|
||||
const shareParks = ["敏惠园区", "敏实园区", "敏胜园区", "敏华园区", "湖州园区", "安吉园区", "华智一期"]
|
||||
|
||||
const bizMonth = ref("2026-07")
|
||||
const activeTab = ref("business")
|
||||
const loading = ref(false)
|
||||
const summary = ref<any>(null)
|
||||
const incomeRows = ref<any[]>([])
|
||||
const shareRows = ref<any[]>([])
|
||||
const businessRows = ref<any[]>([])
|
||||
|
||||
const headerStyle = { background: "var(--el-fill-color-light)", color: "var(--el-text-color-primary)" }
|
||||
|
||||
const fmt = (v: any) => {
|
||||
if (v === null || v === undefined || v === "") return "0"
|
||||
const n = Number(v)
|
||||
if (Number.isNaN(n)) return v
|
||||
return n.toLocaleString("zh-CN", { maximumFractionDigits: 4 })
|
||||
}
|
||||
|
||||
const loadAll = async () => {
|
||||
if (!bizMonth.value) {
|
||||
useMessage().warning("请选择业务月")
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const [s, i, sh, b] = await Promise.all([
|
||||
reportSummary(bizMonth.value),
|
||||
reportIncome(bizMonth.value),
|
||||
reportSupplierShare(bizMonth.value),
|
||||
reportBusiness(bizMonth.value),
|
||||
])
|
||||
summary.value = s.data
|
||||
incomeRows.value = i.data || []
|
||||
shareRows.value = sh.data || []
|
||||
businessRows.value = b.data || []
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || "加载失败")
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const exportCurrent = () => {
|
||||
const map: Record<string, string> = {
|
||||
business: "/canteen/canteenReport/export/business",
|
||||
income: "/canteen/canteenReport/export/income",
|
||||
share: "/canteen/canteenReport/export/supplierShare",
|
||||
}
|
||||
const nameMap: Record<string, string> = {
|
||||
business: "经营报表",
|
||||
income: "收入合计",
|
||||
share: "供应商分摊",
|
||||
}
|
||||
other.downBlobFile(map[activeTab.value], { bizMonth: bizMonth.value }, `${nameMap[activeTab.value]}_${bizMonth.value}.xlsx`)
|
||||
}
|
||||
|
||||
onMounted(loadAll)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stat {
|
||||
text-align: center;
|
||||
line-height: 1.6;
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
.stat b {
|
||||
font-size: 18px;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.mb12 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="业务月" prop="bizMonth">
|
||||
<el-date-picker
|
||||
v-model="state.queryForm.bizMonth"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="选择月份"
|
||||
style="width: 140px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="厂区" prop="park">
|
||||
<el-input v-model="state.queryForm.park" clearable placeholder="厂区" style="width: 140px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="供应商" prop="supplier">
|
||||
<el-input v-model="state.queryForm.supplier" clearable placeholder="供应商" style="width: 140px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="upload-filled" type="primary" class="ml10" @click="openImport">Excel 导入</el-button>
|
||||
<el-button icon="download" plain type="primary" class="ml10" @click="exportExcel">导出</el-button>
|
||||
<el-button icon="Delete" plain type="danger" class="ml10" :disabled="!state.queryForm.bizMonth" @click="clearMonth">
|
||||
清空当月
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary" class="ml10" @click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10 mr20" style="float: right" @queryTable="getDataList" />
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" fixed />
|
||||
<el-table-column type="index" label="#" width="50" fixed />
|
||||
<el-table-column prop="bizMonth" label="业务月" width="90" fixed />
|
||||
<el-table-column prop="bizDate" label="时间" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="supplier" label="供应商" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="receiptNo" label="收货单号" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="category" label="类别" width="90" show-overflow-tooltip />
|
||||
<el-table-column prop="productCode" label="商品编码" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="productName" label="品名" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="unit" label="单位" width="70" />
|
||||
<el-table-column prop="qty" label="数量" width="90" align="right" />
|
||||
<el-table-column prop="unitPrice" label="单价" width="90" align="right" />
|
||||
<el-table-column prop="listPrice" label="定价" width="90" align="right" />
|
||||
<el-table-column prop="priceDiff" label="单价差异" width="90" align="right" />
|
||||
<el-table-column prop="settleUnitPrice" label="结算单价" width="90" align="right" />
|
||||
<el-table-column prop="settleAmount" label="结算总金额" width="110" align="right" />
|
||||
<el-table-column prop="amount" label="金额" width="100" align="right" />
|
||||
<el-table-column prop="amountDiff" label="金额差异" width="100" align="right" />
|
||||
<el-table-column prop="warehouse" label="食堂仓库" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="park" label="厂区" width="100" />
|
||||
<el-table-column prop="classify" label="分类" width="80" />
|
||||
<el-table-column prop="energyAmount" label="能耗" width="90" align="right" />
|
||||
<el-table-column prop="laborAmount" label="人工" width="90" align="right" />
|
||||
<el-table-column prop="consumableAmount" label="耗材" width="90" align="right" />
|
||||
<el-table-column prop="outsourceAmount" label="外协" width="90" align="right" />
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="importVisible" title="导入食材能耗" width="520px" :close-on-click-modal="false" destroy-on-close>
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="mb-4"
|
||||
title="可直接上传整本报表 Excel,系统自动读取「食材能耗」sheet。数量/单价/定价按表填写;结算单价、结算总金额为空时自动计算。默认覆盖所选业务月。"
|
||||
/>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="业务月" required>
|
||||
<el-date-picker v-model="importBizMonth" type="month" value-format="YYYY-MM" />
|
||||
</el-form-item>
|
||||
<el-form-item label="覆盖当月">
|
||||
<el-switch v-model="replaceMonth" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Excel 文件" required>
|
||||
<el-upload
|
||||
ref="importUploadRef"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
accept=".xlsx,.xls"
|
||||
:on-change="onImportFileChange"
|
||||
:on-remove="() => (importFile = null)"
|
||||
>
|
||||
<el-button type="primary">选择文件</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="importVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="importLoading" @click="submitImport">开始导入</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="errorVisible" title="导入校验失败" width="640px" :close-on-click-modal="false">
|
||||
<el-alert type="error" :closable="false" show-icon class="mb-3" :title="errorTitle" />
|
||||
<el-table :data="errorData" max-height="420" border size="small">
|
||||
<el-table-column prop="lineNum" label="行号" width="90" align="center" />
|
||||
<el-table-column label="错误说明" min-width="360">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-for="(e, i) in row.errors || row.reasons || []" :key="i" type="danger" class="mr-1 mb-1">
|
||||
{{ e }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="errorVisible = false">知道了</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemCanteenReportFoodEnergy">
|
||||
import type { UploadFile, UploadInstance } from "element-plus"
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||
import { fetchFoodEnergyPage, delFoodEnergy, clearFoodEnergyMonth } from "/@/api/canteen/canteenReport"
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||
import request from "/@/utils/request"
|
||||
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: { bizMonth: "2026-07" },
|
||||
pageList: fetchFoodEnergyPage,
|
||||
})
|
||||
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields()
|
||||
state.queryForm = { bizMonth: "2026-07" }
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id)
|
||||
multiple.value = !objs.length
|
||||
}
|
||||
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm("确认删除选中数据?")
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await delFoodEnergy(ids)
|
||||
getDataList()
|
||||
useMessage().success("删除成功")
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || "删除失败")
|
||||
}
|
||||
}
|
||||
|
||||
const clearMonth = async () => {
|
||||
const m = state.queryForm.bizMonth
|
||||
if (!m) return
|
||||
try {
|
||||
await useMessageBox().confirm(`确认清空 ${m} 全部食材能耗?`)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await clearFoodEnergyMonth(m)
|
||||
getDataList()
|
||||
useMessage().success("已清空")
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || "清空失败")
|
||||
}
|
||||
}
|
||||
|
||||
const exportExcel = () => {
|
||||
downBlobFile("/canteen/canteenReport/foodEnergy/export", { ...state.queryForm }, `食材能耗_${state.queryForm.bizMonth || ""}.xlsx`)
|
||||
}
|
||||
|
||||
const importVisible = ref(false)
|
||||
const importLoading = ref(false)
|
||||
const importBizMonth = ref("2026-07")
|
||||
const replaceMonth = ref(true)
|
||||
const importFile = ref<File | null>(null)
|
||||
const importUploadRef = ref<UploadInstance>()
|
||||
const errorVisible = ref(false)
|
||||
const errorTitle = ref("导入失败")
|
||||
const errorData = ref<any[]>([])
|
||||
|
||||
const openImport = () => {
|
||||
importBizMonth.value = state.queryForm.bizMonth || "2026-07"
|
||||
importVisible.value = true
|
||||
}
|
||||
|
||||
const onImportFileChange = (file: UploadFile) => {
|
||||
importFile.value = (file.raw as File) || null
|
||||
}
|
||||
|
||||
const showImportErrors = (err: any) => {
|
||||
const list = Array.isArray(err?.data) ? err.data : []
|
||||
errorTitle.value = err?.msg || `导入校验失败,共 ${list.length || 0} 行有问题`
|
||||
if (list.length) {
|
||||
errorData.value = list
|
||||
errorVisible.value = true
|
||||
}
|
||||
useMessage().error(errorTitle.value)
|
||||
}
|
||||
|
||||
const submitImport = async () => {
|
||||
if (!importBizMonth.value) {
|
||||
useMessage().warning("请选择业务月")
|
||||
return
|
||||
}
|
||||
if (!importFile.value) {
|
||||
useMessage().warning("请选择 Excel 文件")
|
||||
return
|
||||
}
|
||||
const fd = new FormData()
|
||||
fd.append("file", importFile.value)
|
||||
importLoading.value = true
|
||||
try {
|
||||
const res: any = await request({
|
||||
url: "/canteen/canteenReport/foodEnergy/import",
|
||||
method: "post",
|
||||
params: { bizMonth: importBizMonth.value, replaceMonth: replaceMonth.value },
|
||||
data: fd,
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
timeout: 600000,
|
||||
})
|
||||
useMessage().success(res.msg || "导入成功")
|
||||
importVisible.value = false
|
||||
importFile.value = null
|
||||
importUploadRef.value?.clearFiles()
|
||||
state.queryForm.bizMonth = importBizMonth.value
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
showImportErrors(err)
|
||||
} finally {
|
||||
importLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,258 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="业务月" prop="bizMonth">
|
||||
<el-date-picker
|
||||
v-model="state.queryForm.bizMonth"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="选择月份"
|
||||
style="width: 140px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="厂区" prop="park">
|
||||
<el-input v-model="state.queryForm.park" clearable placeholder="厂区" style="width: 140px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收入类别" prop="incomeType">
|
||||
<el-select v-model="state.queryForm.incomeType" clearable placeholder="全部" style="width: 140px">
|
||||
<el-option v-for="t in incomeTypes" :key="t" :label="t" :value="t" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本中心" prop="costCenter">
|
||||
<el-input v-model="state.queryForm.costCenter" clearable placeholder="核对成本" style="width: 160px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="工号" prop="empNo">
|
||||
<el-input v-model="state.queryForm.empNo" clearable placeholder="工号" style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="upload-filled" type="primary" class="ml10" @click="openImport">Excel 导入</el-button>
|
||||
<el-button icon="download" plain type="primary" class="ml10" @click="exportExcel">导出</el-button>
|
||||
<el-button icon="Delete" plain type="danger" class="ml10" :disabled="!state.queryForm.bizMonth" @click="clearMonth">
|
||||
清空当月
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary" class="ml10" @click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10 mr20" style="float: right" @queryTable="getDataList" />
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="bizMonth" label="业务月" width="90" />
|
||||
<el-table-column prop="empNo" label="工号" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="empName" label="姓名" width="90" show-overflow-tooltip />
|
||||
<el-table-column prop="legalEntity" label="法律归属" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="deptName" label="部门" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="consumeArea" label="消费区域" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="settleCounter" label="结算台" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="consumeAmount" label="消费金额" width="100" align="right" />
|
||||
<el-table-column prop="incomeType" label="收入类别" width="100" />
|
||||
<el-table-column prop="costCenter" label="核对成本" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="park" label="厂区" width="100" />
|
||||
<el-table-column prop="remarkTag" label="备注标识" width="90" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="importVisible" title="导入刷卡明细" width="520px" :close-on-click-modal="false" destroy-on-close>
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="mb-4"
|
||||
title="可直接上传整本「202607食堂报表」Excel,系统会自动读取「刷卡明细」sheet;也可只上传该 sheet。导入默认覆盖所选业务月。"
|
||||
/>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="业务月" required>
|
||||
<el-date-picker v-model="importBizMonth" type="month" value-format="YYYY-MM" placeholder="yyyy-MM" />
|
||||
</el-form-item>
|
||||
<el-form-item label="覆盖当月">
|
||||
<el-switch v-model="replaceMonth" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Excel 文件" required>
|
||||
<el-upload
|
||||
ref="importUploadRef"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
accept=".xlsx,.xls"
|
||||
:on-change="onImportFileChange"
|
||||
:on-remove="() => (importFile = null)"
|
||||
>
|
||||
<el-button type="primary">选择文件</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="importVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="importLoading" @click="submitImport">开始导入</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="errorVisible" title="导入校验失败" width="640px" :close-on-click-modal="false">
|
||||
<el-alert type="error" :closable="false" show-icon class="mb-3" :title="errorTitle" />
|
||||
<el-table :data="errorData" max-height="420" border size="small">
|
||||
<el-table-column prop="lineNum" label="行号" width="90" align="center" />
|
||||
<el-table-column label="错误说明" min-width="360">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-for="(e, i) in row.errors || row.reasons || []" :key="i" type="danger" class="mr-1 mb-1">
|
||||
{{ e }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="errorVisible = false">知道了</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemCanteenReportSwipe">
|
||||
import type { UploadFile, UploadInstance } from "element-plus"
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||
import { fetchSwipePage, delSwipe, clearSwipeMonth } from "/@/api/canteen/canteenReport"
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||
import request from "/@/utils/request"
|
||||
|
||||
const incomeTypes = ["员工刷卡", "支付宝", "包厢收入", "其他收入", "利润调整", "开票结算", "无法收回"]
|
||||
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: { bizMonth: "2026-07" },
|
||||
pageList: fetchSwipePage,
|
||||
})
|
||||
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields()
|
||||
state.queryForm = { bizMonth: "2026-07" }
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id)
|
||||
multiple.value = !objs.length
|
||||
}
|
||||
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm("确认删除选中数据?")
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await delSwipe(ids)
|
||||
getDataList()
|
||||
useMessage().success("删除成功")
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || "删除失败")
|
||||
}
|
||||
}
|
||||
|
||||
const clearMonth = async () => {
|
||||
const m = state.queryForm.bizMonth
|
||||
if (!m) return
|
||||
try {
|
||||
await useMessageBox().confirm(`确认清空 ${m} 全部刷卡明细?`)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await clearSwipeMonth(m)
|
||||
getDataList()
|
||||
useMessage().success("已清空")
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || "清空失败")
|
||||
}
|
||||
}
|
||||
|
||||
const exportExcel = () => {
|
||||
downBlobFile("/canteen/canteenReport/swipe/export", { ...state.queryForm }, `刷卡明细_${state.queryForm.bizMonth || ""}.xlsx`)
|
||||
}
|
||||
|
||||
const importVisible = ref(false)
|
||||
const importLoading = ref(false)
|
||||
const importBizMonth = ref("2026-07")
|
||||
const replaceMonth = ref(true)
|
||||
const importFile = ref<File | null>(null)
|
||||
const importUploadRef = ref<UploadInstance>()
|
||||
const errorVisible = ref(false)
|
||||
const errorTitle = ref("导入失败")
|
||||
const errorData = ref<any[]>([])
|
||||
|
||||
const openImport = () => {
|
||||
importBizMonth.value = state.queryForm.bizMonth || "2026-07"
|
||||
importVisible.value = true
|
||||
}
|
||||
|
||||
const onImportFileChange = (file: UploadFile) => {
|
||||
importFile.value = (file.raw as File) || null
|
||||
}
|
||||
|
||||
const showImportErrors = (err: any) => {
|
||||
const list = Array.isArray(err?.data) ? err.data : []
|
||||
errorTitle.value = err?.msg || `导入校验失败,共 ${list.length || 0} 行有问题`
|
||||
if (list.length) {
|
||||
errorData.value = list
|
||||
errorVisible.value = true
|
||||
}
|
||||
useMessage().error(errorTitle.value)
|
||||
}
|
||||
|
||||
const submitImport = async () => {
|
||||
if (!importBizMonth.value) {
|
||||
useMessage().warning("请选择业务月")
|
||||
return
|
||||
}
|
||||
if (!importFile.value) {
|
||||
useMessage().warning("请选择 Excel 文件")
|
||||
return
|
||||
}
|
||||
const fd = new FormData()
|
||||
fd.append("file", importFile.value)
|
||||
importLoading.value = true
|
||||
try {
|
||||
const res: any = await request({
|
||||
url: "/canteen/canteenReport/swipe/import",
|
||||
method: "post",
|
||||
params: { bizMonth: importBizMonth.value, replaceMonth: replaceMonth.value },
|
||||
data: fd,
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
timeout: 600000,
|
||||
})
|
||||
useMessage().success(res.msg || "导入成功")
|
||||
importVisible.value = false
|
||||
importFile.value = null
|
||||
importUploadRef.value?.clearFiles()
|
||||
state.queryForm.bizMonth = importBizMonth.value
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
showImportErrors(err)
|
||||
} finally {
|
||||
importLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -3,6 +3,9 @@
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="商户" prop="merchantId">
|
||||
<select-mch v-model="state.queryForm.merchantId" :apiParams="{ types: '5' }" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类目ID" prop="categoryId">
|
||||
<el-input placeholder="请输入类目ID" v-model="state.queryForm.categoryId" />
|
||||
</el-form-item>
|
||||
|
||||
Reference in new issue
Block a user