初始版本,目前线上可用

This commit is contained in:
2025-11-19 12:49:16 +08:00
commit cb7f1c45e8
178 changed files with 30336 additions and 0 deletions

View File

@@ -0,0 +1,444 @@
<template>
<div>
<el-row>
<baseTableHeader
title="逝者零售"
@resetSearch="methods.resetSearch"
@search="methods.search">
<template #content>
<el-form :model="searchForm" label-position="right">
<el-row :gutter="12">
<el-col :span="6">
<el-form-item label="逝者姓名">
<el-input
v-model="searchForm.deceased.name"
placeholder="请输入逝者姓名"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="购买人姓名">
<el-input
v-model="searchForm.retail.familyName"
placeholder="请输入购买人姓名"></el-input> </el-form-item
></el-col>
<el-col :span="6">
<el-form-item label="引导员">
<GuideList v-model="searchForm.retail.guide"></GuideList>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="购买日期">
<el-date-picker
v-model="searchForm.retail.purchaseDate"
type="datetimerange"
range-separator=""
start-placeholder="选择日期"
end-placeholder="选择日期"
@change="dataChange" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</baseTableHeader>
</el-row>
<el-card style="margin-top: 8px">
<div style="margin-bottom: 15px">
<el-button
size="small"
type="primary"
@click="methods.add"
v-if="route.path === '/noDepartedSaint'">
<template #icon>
<el-icon>
<CirclePlus />
</el-icon> </template
>新增</el-button
>
</div>
<base-table
:option="tableOption"
ref="table"
border
show-summary
:summary-method="getSummaries">
<template #colunm>
<el-table-column
type="index"
width="80"
fixed="left"
align="center"></el-table-column>
<el-table-column
prop="name"
label="结账"
width="120"
align="center"
fixed="left">
<template #default="{ row }">
<el-tag type="success" v-if="row.retailState === 1"
>已结账</el-tag
>
<el-tag type="danger" v-if="row.retailState === 0">未结账</el-tag>
</template>
</el-table-column>
<el-table-column
prop="deceased.name"
label="逝者姓名"
fixed="left"
align="center" />
<el-table-column
prop="familyName"
label="购买人"
align="center"
fixed="left">
<template #default="{ row }">
<span v-if="row.deceased.familyName">
{{ row.deceased.familyName }}
</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column
prop="createDate"
label="购买日期"
width="200"
align="center" />
<el-table-column
prop="createDate"
label="结算日期"
width="200"
align="center">
<template #default="{ row }">
<span v-if="row.retailState === 1"> {{ row.checkoutDate }} </span>
<span v-else style="color: #999; font-style: italic">--</span>
</template>
</el-table-column>
<el-table-column
prop="salesAmount"
label="销售金额"
width="150"
align="center" />
<el-table-column
label="现金支付"
width="150"
prop="payment.cashAmount"
align="center">
<template #default="{ row }">
{{ row.payment?.cashAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.unionPayAmount"
label="银联支付"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.unionPayAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.cardAmount"
label="刷卡金额"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.cardAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.publicTransferAmount"
label="对公转账"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.publicTransferAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.workshopPayment"
label="车间支付"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.workshopPayment || "0.00" }}
</template>
</el-table-column>
<el-table-column prop="handler" label="经办人" align="center" />
<el-table-column label="引导员" align="center">
<template #default="{ row }">
<span> {{ row.guide ?? row.deceased.guide }} </span>
</template>
</el-table-column>
<el-table-column
width="320"
label="操作"
align="center"
fixed="right">
<template #default="{ row }">
<el-row align="middle" justify="center">
<el-button
v-if="row.retailState !== 1"
size="small"
type="primary"
@click="methods.update(row)">
修改</el-button
>
<el-button @click="methods.viewProduct(row)" size="small">
零售清单</el-button
>
<el-button
size="small"
type="default"
@click="methods.print(row)"
>打印</el-button
>
<el-button
size="small"
type="danger"
v-if="row.retailState !== 1"
@click="methods.delete(row)">
删除</el-button
>
</el-row>
</template>
</el-table-column>
</template>
</base-table>
</el-card>
<retailList v-model="showDialog" :option="retailListTable"></retailList>
<baseDialog
v-model="retailRegisState.showDialog"
top="50px"
:title="
handlerType === 'add'
? '新增登记'
: handlerType === 'update'
? '修改零售登记'
: '零售登记'
"
@close="methods.dialogClose">
<retailRegis
:retailType="1"
v-model="regisForm"
type="零售修改"
:showList="['逝者信息']"
:add="handlerType === 'add'"></retailRegis>
<template #footer>
<el-row justify="center" align="middle" style="margin-top: 15px">
<el-button type="primary" @click="methods.confirmUpdate"
>保存</el-button
>
<el-button type="danger" @click="methods.close">关闭</el-button>
</el-row>
</template>
</baseDialog>
<printServicesPage
v-model="showPrint"
:deceased="deceased"
:serviceUrl="serviceUrl">
</printServicesPage>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { resetParams } from "@/util/globalMethods";
import { globalState } from "@/store";
import retailRegis from "../publicComponents/retailRegis.vue";
import api from "@/lib/request";
import { tableOptionType } from "@/types/table";
import { useRoute } from "vue-router";
import { defaultRetail } from "@/defaultForm/defaultRetail";
import PrintRetailPage from "@/components/printPage/printServicesPage.vue";
import printServicesPage from "@/components/printPage/printServicesPage.vue";
import GuideList from "@/components/guideList/guideList.vue";
const retailRegisState = ref({
showDialog: false,
});
let currentInfor = ref(undefined);
let showDialog = ref(false);
let showPrint = ref(false);
let deceased = ref();
let serviceUrl = ref();
const handlerType = ref("");
const searchForm = reactive({
deceased: {
name: "", // 逝者姓名
},
retail: {
guide: "", // 引导员
purchaseDate: "", // 购买日期
retailType: 1,
startDate: "",
endDate: "",
familyName: "",
},
});
const route = useRoute();
const regisForm = ref<RegisForm>();
let table = ref();
let tableOption = ref<tableOptionType>({
url: "/deceased-retail/list?retailType=1",
searchUrl: "/deceased-retail/query",
searchParams: searchForm,
executeType: "list",
});
let retailListTable = ref<tableOptionType>({
url: "/deceased-retail/selected-service",
searchUrl: "",
searchParams: {},
executeType: "list",
});
const methods = {
update(row: RegisForm) {
regisForm.value = row;
handlerType.value = "update";
retailRegisState.value.showDialog = true;
},
async confirmUpdate() {
await ElMessageBox.confirm("确定保存修改吗?", { type: "warning" });
let sendData = { ...regisForm.value };
api()
.post("/deceased-retail/update", sendData)
.then((res) => {
if (res.code === 200) {
ElMessage.success("修改成功");
table.value.methods.setDataType("list");
retailRegisState.value.showDialog = false;
regisForm.value = defaultRetail();
}
});
},
async delete(row: RegisForm) {
await ElMessageBox.confirm("确定删除该条信息吗?", { type: "warning" });
api()
.get("/deceased-retail/delete", {
params: {
id: row.id,
},
})
.then((res) => {
if (res.code === 200) {
ElMessage.success("删除成功");
table.value.methods.setDataType("list");
}
});
},
add() {
retailRegisState.value.showDialog = true;
handlerType.value = "add";
},
async viewProduct(row: RegisForm) {
retailListTable.value.url =
"/deceased-retail/selected-service?retailType=1&retailId=" +
(row.retailId || row.id);
showDialog.value = true;
},
drawerClose() {
currentInfor.value = undefined;
showDialog.value = false;
},
close() {
retailRegisState.value.showDialog = false;
},
async print(row: RegisForm) {
deceased.value = row;
showPrint.value = true;
serviceUrl.value =
"/deceased-retail/selected-service?retailType=1&retailId=" +
(row.retailId || row.id);
},
dialogClose() {
regisForm.value = defaultRetail();
},
search() {
searchForm.retail.retailType = 1;
table.value.methods.setDataType("search");
},
resetSearch() {
resetParams(searchForm);
table.value.methods.setDataType("reset");
},
};
onMounted(async () => {});
const getSummaries = (param: { columns: any[]; data: any[] }) => {
const { columns, data } = param;
const sums: any[] = [];
// 需要统计的字段列表
const sumKeys = [
"salesAmount",
"payment.cashAmount",
"payment.unionPayAmount",
"payment.cardAmount",
"payment.publicTransferAmount",
"payment.workshopPayment",
];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "合计";
return;
}
if (sumKeys.includes(column.property)) {
const values = data.map((item) => {
const keys = column.property.split(".");
let value = item;
for (const key of keys) {
value = value?.[key] || 0;
}
return Number(value) || 0;
});
if (!values.every((value) => isNaN(value))) {
const sum = values.reduce((prev, curr) => {
return prev + curr;
}, 0);
sums[index] = `${sum.toFixed(2)}`;
} else {
sums[index] = "0.00 元";
}
} else {
sums[index] = "";
}
});
return sums;
};
function dataChange(val: Date[]) {
searchForm.retail.startDate = val[0];
searchForm.retail.endDate = val[1];
}
</script>
<style lang="scss" scoped>
/* 添加汇总行样式 */
:deep(.el-table__footer) {
.cell {
font-weight: 600;
color: #606266;
}
td {
background-color: #f5f7fa !important;
}
}
</style>

View File

@@ -0,0 +1,6 @@
<template>
<router-view></router-view>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,453 @@
<template>
<div>
<el-row>
<baseTableHeader
title="无逝者零售"
@resetSearch="methods.resetSearch"
@search="methods.search">
<template #content>
<el-form :model="searchForm" label-position="right">
<el-row :gutter="12">
<el-col :span="6">
<el-form-item label="逝者姓名">
<el-input
v-model="searchForm.deceased.name"
placeholder="请输入逝者姓名"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="购买人姓名">
<el-input
v-model="searchForm.retail.familyName"
placeholder="请输入购买人姓名"></el-input> </el-form-item
></el-col>
<el-col :span="6">
<el-form-item label="引导员">
<GuideList v-model="searchForm.retail.guide"></GuideList>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="购买日期">
<el-date-picker
v-model="searchForm.retail.purchaseDate"
type="datetimerange"
range-separator=""
start-placeholder="选择日期"
end-placeholder="选择日期"
@change="dataChange" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</baseTableHeader>
</el-row>
<el-card style="margin-top: 8px">
<base-table
:option="tableOption"
ref="table"
border
show-summary
:summary-method="getSummaries">
<template #toolsBar>
<el-button size="small" type="primary" @click="methods.add">
<template #icon>
<el-icon>
<CirclePlus />
</el-icon> </template
>新增</el-button
>
</template>
<template #colunm>
<el-table-column
type="index"
width="80"
fixed="left"
align="center"></el-table-column>
<el-table-column label="结账" align="center" width="120" fixed="left">
<template #default="{ row }">
<el-tag type="success" v-if="row.retailState === 1"
>已结账</el-tag
>
<el-tag type="danger" v-if="row.retailState === 0">未结账</el-tag>
</template>
</el-table-column>
<el-table-column
prop="familyName"
label="购买人"
align="center"
fixed="left">
<template #default="{ row }">
<span v-if="row.familyName">{{ row.familyName }}</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column
prop="deceasedName"
label="逝者姓名"
align="center"
fixed="left">
<template #default="{ row }">
<span v-if="row.deceasedName">{{ row.deceasedName }}</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column
prop="createDate"
label="购买日期"
width="200"
align="center" />
<el-table-column
prop="createDate"
label="结算日期"
width="200"
align="center">
<template #default="{ row }">
<span v-if="row.retailState === 1"> {{ row.checkoutDate }} </span>
<span v-else style="color: #999; font-style: italic">--</span>
</template>
</el-table-column>
<el-table-column prop="salesAmount" label="销售金额" align="center" />
<el-table-column
label="现金支付"
width="150"
prop="payment.cashAmount"
align="center">
<template #default="{ row }">
{{ row.payment?.cashAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.unionPayAmount"
label="银联支付"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.unionPayAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.cardAmount"
label="刷卡金额"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.cardAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.publicTransferAmount"
label="对公转账"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.publicTransferAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="payment.workshopPayment"
label="车间支付"
width="150"
align="center">
<template #default="{ row }">
{{ row.payment?.workshopPayment || "0.00" }}
</template>
</el-table-column>
<el-table-column prop="handler" label="经办人" align="center" />
<el-table-column prop="guide" label="引导员" align="center" />
<el-table-column
width="320"
label="操作"
align="center"
fixed="right">
<template #default="{ row }">
<el-row align="middle" justify="center">
<el-button
v-if="row.retailState === 0"
size="small"
type="primary"
@click="methods.update(row)">
修改</el-button
>
<el-button @click="methods.viewProduct(row)" size="small">
零售清单</el-button
>
<el-button
size="small"
type="default"
@click="methods.print(row)"
>打印</el-button
>
<!-- <el-button
type="primary"
v-if="row.retailState === 0"
@click="methods.checkout(row)"
>结账</el-button
> -->
<el-button
size="small"
type="danger"
v-if="row.retailState !== 1"
@click="methods.delete(row)">
删除</el-button
>
</el-row>
</template>
</el-table-column>
</template>
</base-table>
</el-card>
<retailList v-model="showDialog" :option="retailListTable"></retailList>
<baseDialog
v-model="retailRegisState.showDialog"
top="30px"
:title="
handlerType === 'add'
? '新增无逝者零售'
: handlerType === 'update'
? '修改无逝者登记'
: '零售登记'
"
@close="methods.dialogClose">
<retailRegis
v-model="regisForm"
:add="handlerType === 'add'"
:retailType="2"
:type="
handlerType === 'add'
? '新增无逝者零售'
: handlerType === 'update'
? '修改无逝者登记'
: '零售登记'
"></retailRegis>
<template #footer>
<el-row justify="center" align="middle" style="margin-top: 15px">
<el-button type="primary" @click="methods.addConfirm">保存</el-button>
<el-button type="danger" @click="methods.close">关闭</el-button>
</el-row>
</template>
</baseDialog>
<printServicesPage
v-model="showPrint"
:deceased="deceased"
:serviceUrl="serviceUrl">
</printServicesPage>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { resetParams } from "@/util/globalMethods";
import { globalState } from "@/store";
import retailRegis from "../publicComponents/retailRegis.vue";
import api from "@/lib/request";
import { tableOptionType } from "@/types/table";
import { defaultRetail } from "@/defaultForm/defaultRetail";
import printServicesPage from "@/components/printPage/printServicesPage.vue";
import GuideList from "@/components/guideList/guideList.vue";
let retailListTable = ref<tableOptionType>({
url: "/deceased-retail/selected-service",
searchUrl: "",
searchParams: {},
executeType: "list",
});
let showPrint = ref(false);
let deceased = ref();
let serviceUrl = ref();
const retailRegisState = ref({
showDialog: false,
});
let currentInfor = ref(undefined);
let showDialog = ref(false);
const handlerType = ref("新增无逝者零售");
const searchForm = reactive({
deceased: {
name: "",
},
retail: {
guide: "", // 引导员
purchaseDate: "", // 购买日期
retailType: 2,
familyName: "",
},
});
const regisForm = ref<RegisForm>();
let table = ref();
let tableOption = ref<tableOptionType>({
url: "/deceased-retail/list?retailType=2",
searchUrl: "/deceased-retail/query",
searchParams: searchForm,
executeType: "list",
});
const methods = {
update(row: RegisForm) {
regisForm.value = row;
handlerType.value = "update";
retailRegisState.value.showDialog = true;
},
async delete(row: RegisForm) {
await ElMessageBox.confirm("确定删除该条信息吗?", { type: "warning" });
const res = await api().get("deceased-retail/delete", {
params: {
id: row.id,
},
});
if (res.code === 200) {
ElMessage.success("删除成功");
table.value.methods.setDataType("list");
} else {
ElMessage.error(res);
}
},
add() {
retailRegisState.value.showDialog = true;
handlerType.value = "add";
},
viewProduct(row: RegisForm) {
retailListTable.value.url =
"/deceased-retail/selected-service?retailType=2&retailId=" + row.id;
showDialog.value = true;
},
drawerClose() {
currentInfor.value = undefined;
showDialog.value = false;
},
async addConfirm() {
let url = "/no-deceased-retail/add";
if (handlerType.value === "update") url = "/no-deceased-retail/update";
await ElMessageBox.confirm("确定保存吗?", {
type: "warning",
});
let sendData = { ...regisForm.value };
api()
.post(url, sendData)
.then((res) => {
if (res.code === 200) {
ElMessage.success("保存成功!");
retailRegisState.value.showDialog = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(res.msg);
}
});
},
async checkout(row: RegisForm) {
await ElMessageBox.confirm("确定结账吗?", { type: "warning" });
api()
.get("/no-deceased-retail/checkout", {
params: {
id: Number(row.id),
},
})
.then((res) => {
if (res.code === 200) {
ElMessage.success("结账成功!");
retailRegisState.value.showDialog = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(res.msg);
}
});
},
close() {
retailRegisState.value.showDialog = false;
},
async print(row: any) {
deceased.value = row;
showPrint.value = true;
serviceUrl.value =
"/deceased-retail/selected-service?retailType=2&retailId=" + row.id;
},
dialogClose() {
regisForm.value = defaultRetail();
},
search() {
searchForm.retail.retailType = 2;
table.value.methods.setDataType("search");
},
resetSearch() {
resetParams(searchForm);
table.value.methods.setDataType("reset");
},
};
const getSummaries = (param: { columns: any[]; data: any[] }) => {
const { columns, data } = param;
const sums: any[] = [];
// 需要统计的字段列表
const sumKeys = [
"salesAmount",
"payment.cashAmount",
"payment.unionPayAmount",
"payment.cardAmount",
"payment.publicTransferAmount",
"payment.workshopPayment",
];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "合计";
return;
}
if (sumKeys.includes(column.property)) {
const values = data.map((item) => {
const keys = column.property.split(".");
let value = item;
for (const key of keys) {
value = value?.[key] || 0;
}
return Number(value) || 0;
});
if (!values.every((value) => isNaN(value))) {
const sum = values.reduce((prev, curr) => {
return prev + curr;
}, 0);
sums[index] = `${sum.toFixed(2)}`;
} else {
sums[index] = "0.00 元";
}
} else {
sums[index] = "";
}
});
return sums;
};
function dataChange(val: Date[]) {
searchForm.retail.startDate = val[0];
searchForm.retail.endDate = val[1];
}
</script>
<style lang="scss" scoped>
/* 添加汇总行样式 */
:deep(.el-table__footer) {
.cell {
font-weight: 600;
color: #606266;
}
td {
background-color: #f5f7fa !important;
}
}
</style>

View File

@@ -0,0 +1,512 @@
<template>
<el-form
style="max-height: 72vh; overflow-y: auto"
ref="formRef"
:model="regisForm"
label-width="120px"
label-position="right">
<inforCard title="逝者信息" v-if="showList.includes('逝者信息')">
<el-row :gutter="20" v-if="!regisForm.deceased">
<el-col :span="8">
<el-form-item label="逝者姓名" prop="name">
<el-input
v-model="regisForm.name"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="证件号码" prop="idNumber">
<el-input
v-model="regisForm.idNumber"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别" prop="gender">
<el-radio-group
v-model="regisForm.gender"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
">
<el-radio-button label="男" value="男"></el-radio-button>
<el-radio-button label="女" value="女"></el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年龄" prop="age">
<el-input
v-model="regisForm.age"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-else>
<el-col :span="8">
<el-form-item label="逝者姓名" prop="name">
<el-input
v-model="regisForm.deceased.name"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="证件号码" prop="idNumber">
<el-input
v-model="regisForm.deceased.idNumber"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别" prop="gender">
<el-radio-group
v-model="regisForm.deceased.gender"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
">
<el-radio-button label="男" value="男"></el-radio-button>
<el-radio-button label="女" value="女"></el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年龄" prop="age">
<el-input
v-model="regisForm.deceased.age"
:disabled="
props.type !== '服务修改' && props.type !== '服务登记'
" />
</el-form-item>
</el-col>
</el-row>
</inforCard>
<inforCard title="购买信息">
<el-row :gutter="20">
<el-col :span="8" v-if="props.retailType === 2">
<el-form-item label="逝者姓名" prop="deceasedName">
<el-input
v-model="regisForm.deceasedName"
placeholder="请输入逝者姓名" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form v-model="regisForm"></el-form>
<el-form-item label="引导员" prop="guide">
<GuideList v-model="regisForm.guide"></GuideList>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="购买人" prop="buyer">
<el-input
:disabled="
props.type !== '服务修改' &&
props.type !== '服务登记' &&
props.type !== '新增无逝者零售' &&
props.type !== '修改无逝者登记'
"
v-model="regisForm.familyName"
placeholder="请输入购买人姓名" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="购买人联系电话" prop="buyer">
<el-input
:disabled="
props.type !== '服务修改' &&
props.type !== '服务登记' &&
props.type !== '新增无逝者零售' &&
props.type !== '修改无逝者登记'
"
v-model="regisForm.familyPhone"
placeholder="请输入购买人电话" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所在区域">
<el-cascader
:disabled="
props.type !== '服务修改' &&
props.type !== '服务登记' &&
props.type !== '新增无逝者零售' &&
props.type !== '修改无逝者登记'
"
:options="pcaTextArrData"
v-model="selectedOptions"
@change="methods.pcaChange"></el-cascader> </el-form-item
></el-col>
<el-col :span="8">
<el-form-item label="详细地址">
<el-input
v-model="regisForm.address"
:disabled="
props.type !== '服务修改' &&
props.type !== '服务登记' &&
props.type !== '新增无逝者零售' &&
props.type !== '修改无逝者登记'
"
placeholder="请输入你的地址"></el-input> </el-form-item
></el-col>
<el-col :span="8">
<el-form-item label="购买日期" prop="purchaseDate">
<el-date-picker
v-model="regisForm.purchaseDate"
type="datetime"
placeholder="选择日期"
format="YYYY-MM-DD: HH:mm:ss" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="经办人" prop="handler">
<el-input
v-model="regisForm.handler"
disabled
placeholder="请输入经办人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售金额" prop="salesAmount">
<el-input
v-model.number="regisForm.salesAmount"
disabled
type="number">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</inforCard>
<inforCard title="已选服务项目">
<div style="display: flex; align-items: center">
<el-button
type="primary"
size="small"
@click="methods.addServiceItem"
v-if="props.type !== '零售结算'"
>新增项目</el-button
>
<el-button
type="default"
size="small"
@click="methods.customInput"
v-if="props.type !== '零售结算'"
>手工录入</el-button
>
</div>
<el-table
:data="regisForm.services"
:style="{ marginTop: (props.type !== '零售结算' ? 15 : 0) + 'px' }">
<el-table-column type="index" label="序号" width="80" />
<el-table-column prop="name" label="项目名称" />
<el-table-column prop="quantity" label="数量" width="80">
<template #default="{ row }">
<span v-if="row.name === '殡仪定制服务'">
<el-input v-model="row.quantity"></el-input>
</span>
<span v-else>{{ row.quantity }}</span>
</template>
</el-table-column>
<el-table-column prop="unit" label="单位" width="80">
<template #default="{ row }">
<span v-if="row.name === '殡仪定制服务'">
<el-input v-model="row.unit"></el-input>
</span>
<span v-else>{{ row.unit }}</span>
</template>
</el-table-column>
<el-table-column prop="price" label="单价(元)">
<template #default="{ row }">
<span v-if="row.name === '殡仪定制服务'">
<el-input v-model="row.price"></el-input>
</span>
<span v-else>
{{ row.price }}
</span>
</template>
</el-table-column>
<el-table-column prop="price" label="总金额">
<template #default="{ row }">
{{ row.price * row.quantity }}
</template>
</el-table-column>
<el-table-column prop="remark" width="200" label="备注">
<template #default="{ row }">
<el-tooltip
class="box-item"
effect="dark"
:content="row.remark"
placement="top">
<p
style="
white-space: nowrap; /* 强制不换行 */
overflow: hidden; /* 隐藏溢出内容 */
text-overflow: ellipsis; /* 显示省略号 */
">
{{ row.remark }}
</p>
</el-tooltip>
</template>
</el-table-column>
<el-table-column>
<template #default="{ row }">
<el-button
type="danger"
size="small"
v-if="props.showServiceDelBtn"
@click="methods.removeProduct(row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</inforCard>
<base-curd-dialog
v-model="customServiceState.show2LevelPage.value"
title="手工录入服务"
width="50%"
@addConfim="addConfim"
@closeConfirm="handleDialogClose"
:showPageType="customServiceState.showPageType">
<template #content>
<serviceListaddOrEdit
type="手工录入服务"
:executeType="customServiceState.executeType.value"
v-model="currentServiceItem"></serviceListaddOrEdit>
</template>
<template #footer>
<el-button type="primary" @click="methods.confirmCustomService"
>确定</el-button
>
</template>
</base-curd-dialog>
<el-drawer
v-model="serviceItemState.showDrawer"
size="50%"
:with-header="false">
<serviceItemSelect v-model="regisForm.services"></serviceItemSelect>
</el-drawer>
</el-form>
</template>
<script lang="ts" setup>
import { computed, nextTick, onMounted, ref, watch } from "vue";
import { userInfor } from "@/store/user/user";
import serviceItemSelect from "./serviceItemSelect.vue";
import dayjs from "dayjs";
import api from "@/lib/request";
import pageVisible from "@/components/curdDialog/pageVisibleState";
import { ElMessage, ElMessageBox } from "element-plus";
import serviceListaddOrEdit from "../../serviceList/serviceItem/page/addOrEdit.vue";
import { defaultRetail } from "@/defaultForm/defaultRetail";
import { defaultServiceItem } from "@/defaultForm/defaultSerivceItem";
import { pcaTextArr } from "element-china-area-data";
import GuideList from "@/components/guideList/guideList.vue";
const formRef = ref();
const userStoreState = userInfor();
const serviceItemState = ref({
showDrawer: false,
});
const customServiceState = new pageVisible({
add: "新增服务项目",
edit: "服务项目编辑",
view: "服务项目查看",
});
// 表单数据
const regisForm = defineModel<RegisForm>({
default: defaultRetail(),
});
const selectedOptions = ref([
regisForm.value.province,
regisForm.value.city,
regisForm.value.area,
]);
const pcaTextArrData = ref(pcaTextArr);
const props = withDefaults(
defineProps<{
add?: boolean;
type?: RegistrationType;
showServiceDelBtn?: boolean;
retailType?: number;
showList?: string[];
}>(),
{
add: false,
showServiceDelBtn: true,
type: "服务登记",
retailType: 0,
showList: () => [],
}
);
if (["零售登记", "服务登记"].includes(props.type)) {
regisForm.value.serviceItems = "";
regisForm.value.services = [];
}
const methods = {
addServiceItem() {
if (!regisForm.value.services?.length) {
regisForm.value.services = [];
}
serviceItemState.value.showDrawer = true;
},
removeProduct(row: Product) {
let index = regisForm.value.services?.findIndex(
(item: any) => item.name === row.name
);
regisForm.value.services = regisForm.value.services?.filter(
(_, i) => i !== index
);
},
customInput() {
customServiceState.show2LevelPage.value = true;
},
async confirmCustomService() {
if (!currentServiceItem.value.name)
return ElMessage.warning("服务项目名称不能为空!");
if (
currentServiceItem.value.price <= 0 ||
currentServiceItem.value.quantity <= 0
) {
await ElMessageBox.confirm(
"该商品售价或商品数量为0是否继续",
"提示",
{
type: "warning",
}
);
if (!regisForm.value.services) regisForm.value.services = [];
regisForm.value.services.push({ ...currentServiceItem.value });
customServiceState.show2LevelPage.value = false;
currentServiceItem.value = defaultServiceItem();
return;
}
await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
type: "warning",
});
if (!regisForm.value.services) regisForm.value.services = [];
regisForm.value.services.push({ ...currentServiceItem.value });
customServiceState.show2LevelPage.value = false;
currentServiceItem.value = defaultServiceItem();
},
pcaChange(data: { [key: string]: any }) {
regisForm.value.province = data[0];
regisForm.value.city = data[1];
regisForm.value.area = data[2];
},
};
onMounted(async () => {
if (
!["零售登记", "服务登记"].includes(props.type) &&
(regisForm.value.deceasedId || regisForm.value.id)
) {
let url =
"/deceased-retail/selected-service?deceasedId=" +
(regisForm.value.deceasedId || regisForm.value.id) +
"&retailType=" +
props.retailType;
if (regisForm.value.id && props.retailType === 2) {
url =
"/deceased-retail/selected-service?retailId=" +
regisForm.value.id +
"&retailType=" +
props.retailType;
}
if (["零售修改", "零售结算"].includes(props.type)) {
url =
"/deceased-retail/selected-service?retailId=" +
regisForm.value.id +
"&retailType=" +
props.retailType;
}
const selectedService = await api().get(url);
regisForm.value.services = selectedService.data.list;
}
watch(
() => regisForm.value.services,
(newVal) => {
if (newVal) {
regisForm.value.salesAmount = 0;
newVal?.forEach(
(item) => (regisForm.value.salesAmount += item.price * item.quantity)
);
if (props.type === "服务登记") {
regisForm.value.serviceItems = newVal
.map((item) => item.id)
.join(",");
}
}
},
{ deep: true }
);
regisForm.value = {
...regisForm.value,
handler: regisForm.value.handler || userStoreState.userInfor.name || "",
purchaseDate:
regisForm.value.purchaseDate ||
dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"),
};
});
let currentServiceItem = ref<ServiceItemType>(defaultServiceItem());
async function addConfim() {
await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
type: "warning",
});
if (!regisForm.value.services) regisForm.value.services = [];
regisForm.value.services.push({ ...currentServiceItem.value });
// await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
// type: "warning",
// });
// let res = await api().post("/service-item/add", currentServiceItem.value);
// if (res.code === 200) {
// ElMessage.success("添加成功");
// customServiceState.show2LevelPage.value = false;
// } else {
// ElMessage.error(res.msg);
// }
}
function handleDialogClose() {
customServiceState.show2LevelPage.value = false;
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,353 @@
<template>
<div class="service-selection">
<!-- 标题 -->
<h2 class="title">服务项目选择</h2>
<!-- 搜索框 -->
<el-form>
<el-row :gutter="15" style="margin-top: 15px">
<el-col :span="8">
<el-form-item label="商品名称">
<el-input
v-model="searchKeyword"
placeholder="请输入商品名称"
clearable />
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="价格">
<el-input-number
v-model="price"
:min="0"
clearable
placeholder="请输入价格"
type="number"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-divider style="margin: 8px 0; margin-bottom: 30px" />
<!-- 两列布局 -->
<div
class="content"
v-loading="lodaing"
element-loading-text="数据加载中....">
<!-- 左侧树结构 -->
<div class="left">
<el-tree
ref="tree"
:data="categoryTree"
:props="treeProps"
show-checkbox
check-strictly
@check="getCheckedKeys" />
</div>
<!-- 右侧商品列表 -->
<div class="right">
<div
v-for="(item, index) in categoryServiceList"
:key="index"
class="item">
<!-- 商品信息 -->
<div class="item-info">
<div class="item-name">商品名称{{ item.name }}</div>
<div class="item-group">
所属分类{{
categoryTreeAll.find((fitem) => fitem.id === item.parentId)
?.name || "无"
}}
</div>
<div class="item-price">
{{ item.price }} / {{ item.unit || "(暂无单位)" }}
</div>
</div>
<!-- 添加/删除按钮 -->
<div class="item-actions">
<!-- <el-button
v-if="!item.quantity || item.quantity === 0"
type="primary"
@click="addItem(item)">
<span style="color: #fff"> 添加</span>
</el-button>
<div v-else class="quantity-control">
<el-button type="danger" @click="removeItem(item)"></el-button>
<span class="quantity">{{ item.quantity }}</span>
<el-button type="primary" @click="addItem(item)"> </el-button>
</div> -->
<el-input-number
style="margin-top: 5px"
v-model="item.quantity"
:min="0"
@change="methods.quantityChange(item)" />
</div>
</div>
</div>
</div>
<!-- 底部悬浮框 -->
<div class="footer">
<div class="footer-item">
<span>总金额</span>
<span
><span class="red-font">{{ totalAmount }} </span></span
>
</div>
<!-- <div class="footer-item">
<span>减免金额</span>
<span
><span class="green-font">
{{ discountAmount }}
</span>
</span
>
</div>
<div class="footer-item">
<span>实收金额</span>
<span
><span class="red-font">
{{ actualAmount }}
</span>
</span
>
</div> -->
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from "vue";
import api from "@/lib/request";
const emits = defineEmits(["selectedProduct"]);
const products = defineModel<Product[]>();
// 搜索关键词
const searchKeyword = ref("");
const price = ref(0);
const lodaing = ref(false);
// 分类树数据
const categoryTree = ref([]);
const categoryTreeAll = ref([]);
const categoryServiceAll = ref<Product[]>([]);
const selectedCategory = ref([]);
const tree = ref();
const categoryServiceList = computed(() => {
let resData: Product[] = [];
selectedCategory.value.forEach((item) => {
let findData = categoryServiceAll.value.filter(
(fitem) => fitem.parentId === item.id
);
if (findData) {
resData = [...resData, ...findData];
}
});
let res = selectedCategory.value.length ? resData : categoryServiceAll.value;
if (searchKeyword.value) {
res = res.filter((item) => item.name.includes(searchKeyword.value));
let includeCategory = categoryTreeAll.value.filter((category) =>
category.name.includes(searchKeyword.value)
);
categoryServiceAll.value.forEach((item) => {
includeCategory.forEach((iitem) => {
if (
item.parentId === iitem.id &&
!res.find((fitem) => fitem.name === item.name)
) {
res.unshift(item);
}
});
});
}
if (price.value && price.value !== 0) {
res = res.filter((fitem) => Number(fitem.price) === price.value);
}
return res;
});
// 树结构配置
const treeProps = {
children: "children",
label: "name",
};
const syncProductsWithCategoryServiceAll = () => {
if (!products.value) return; // 防止 products 为空时报错
categoryServiceAll.value.forEach((item) => {
const findItem = products.value?.find(
(newItem) => newItem.name === item.name
);
if (findItem) {
item.quantity = findItem.quantity;
} else {
item.quantity = 0;
}
});
};
watch(
() => products.value,
(newVal) => {
syncProductsWithCategoryServiceAll();
},
{
deep: true,
immediate: true,
}
);
// 总金额
const totalAmount = computed(() => {
return categoryServiceAll.value.reduce(
(sum, item) => sum + item.price * (item.quantity || 0),
0
);
});
const methods = {
quantityChange(item: any) {
let findData = products.value?.find(
(findItem) => findItem.name === item.name
);
if (!findData) {
products.value?.push(item);
} else {
findData.quantity = item.quantity;
}
},
};
const getCheckedKeys = (data: any) => {
selectedCategory.value = tree.value.getCheckedNodes();
};
onMounted(async () => {
lodaing.value = true;
let treeList = await api().get("/service-category/list");
let allTreeList = await api().get("/service-category/list", {
params: { all: true },
});
let allService = await api().get("/service-item/list", {
params: { all: true },
});
categoryTree.value = treeList.data.list;
categoryServiceAll.value = allService.data.list;
categoryTreeAll.value = allTreeList.data.list;
syncProductsWithCategoryServiceAll();
lodaing.value = false;
});
</script>
<style lang="scss" scoped>
.service-selection {
position: relative;
overflow: hidden;
.title {
font-size: 18px;
font-weight: bold;
}
.search-box {
margin-bottom: 20px;
width: 50%;
}
.left {
width: 200px;
margin-right: 20px;
}
.right {
flex: 1;
overflow-y: auto;
padding-bottom: 30px;
max-height: calc(100vh - 150px);
flex-wrap: wrap;
display: flex;
width: 100%;
justify-content: space-between;
align-items: flex-start;
}
.content {
display: flex;
justify-content: space-between;
.item {
display: flex;
flex-wrap: wrap;
width: calc(50% - 10px);
align-items: center;
margin-bottom: 10px;
padding: 10px;
border: 1px solid #eee;
border-radius: 4px;
flex-direction: column;
// .item-image {
// width: 100px;
// height: 100px;
// margin-right: 10px;
// }
.item-info {
flex: 1;
}
.item-name {
font-weight: bold;
}
.item-category,
.item-group,
.item-price {
font-size: 12px;
color: #666;
}
.item-actions {
margin-left: 10px;
}
}
}
}
.quantity-control {
display: flex;
align-items: center;
}
.quantity {
margin: 0 10px;
}
.footer {
position: fixed;
bottom: 0;
right: 0;
width: 50%;
z-index: 10;
background: #fff;
padding: 10px 20px;
border-top: 1px solid #eee;
display: flex;
justify-content: space-around;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
.footer-item {
font-size: 14px;
}
.red-font,
.green-font {
font-size: 18px;
color: #f04b22;
font-weight: bold;
padding-right: 8px;
}
.green-font {
color: #67c23a;
}
}
</style>

View File

@@ -0,0 +1,307 @@
<template>
<div>
<inforCard title="逝者信息">
<el-form :model="checkoutForm" label-width="120px" disabled>
<el-row :gutter="20" v-if="deceased.deceased">
<el-col :span="8">
<el-form-item label="姓名">
<el-input
:prefix-icon="User"
v-model="deceased.deceased.name"
disabled
placeholder="姓名">
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别">
<el-radio-group v-model="deceased.deceased.gender" disabled>
<el-radio-button value="男" label="男"></el-radio-button>
<el-radio-button value="女" label="女"></el-radio-button>
</el-radio-group> </el-form-item
></el-col>
<el-col :span="8">
<el-form-item label="证件号码" prop="idNumber">
<el-input v-model="deceased.deceased.idNumber" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年龄">
<el-input
v-model="deceased.deceased.age"
disabled
placeholder="年龄">
</el-input> </el-form-item
></el-col>
<el-col :span="8">
<el-form-item label="购买人名" prop="buyer">
<el-input v-model="deceased.deceased.familyName" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="购买人电话" prop="buyer">
<el-input v-model="deceased.deceased.familyPhone" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="购买日期" prop="purchaseDate">
<el-date-picker
v-model="deceased.purchaseDate"
type="datetime"
format="YYYY-MM-DD: HH:mm:ss" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售金额" prop="salesAmount">
<el-input v-model.number="deceased.salesAmount" type="number">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-else>
<!-- <el-col :span="8">
<el-form-item label="姓名">
<el-input
:prefix-icon="User"
v-model="deceased.name"
disabled
placeholder="姓名">
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别">
<el-radio-group v-model="deceased.gender" disabled>
<el-radio-button value="男" label="男"></el-radio-button>
<el-radio-button value="女" label="女"></el-radio-button>
</el-radio-group> </el-form-item
></el-col>
<el-col :span="8">
<el-form-item label="证件号码" prop="idNumber">
<el-input v-model="deceased.idNumber" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年龄">
<el-input v-model="deceased.age" disabled placeholder="年龄">
</el-input> </el-form-item
></el-col> -->
<el-col :span="8">
<el-form-item label="购买人姓名" prop="buyer">
<el-input v-model="deceased.familyName" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="购买人电话" prop="buyer">
<el-input v-model="deceased.familyPhone" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="购买日期" prop="purchaseDate">
<el-date-picker
v-model="deceased.purchaseDate"
type="datetime"
format="YYYY-MM-DD: HH:mm:ss" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售金额" prop="salesAmount">
<el-input v-model.number="deceased.salesAmount" type="number">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</inforCard>
<inforCard title="已选服务项目">
<el-table
:data="servicesList"
style="max-height: 160px; overflow-y: auto">
<el-table-column type="index" label="序号" width="80" />
<el-table-column prop="name" label="项目名称" />
<el-table-column prop="quantity" label="数量" />
<el-table-column prop="unit" label="单位" />
<el-table-column prop="price" label="单价">
<template #default="{ row }"> {{ row.price }} </template>
</el-table-column>
<el-table-column prop="price" label="总金额">
<template #default="{ row }">
{{ row.price * row.quantity }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" />
</el-table>
</inforCard>
<inforCard title="结账列表">
<el-form
ref="formRef"
:model="checkoutForm"
label-width="120px"
label-position="right">
<el-row :gutter="20">
<!-- 第一行 -->
<el-col :span="8">
<el-form-item label="结账日期" prop="checkoutDate">
<el-date-picker
v-model="checkoutForm.checkoutDate"
type="date"
placeholder="结账日期"
format="YYYY-MM-DD"
disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算日期" prop="settlementDate">
<el-date-picker
v-model="checkoutForm.settlementDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="经办人" prop="handler">
<el-input
disabled
v-model="checkoutForm.handler"
placeholder="经办人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="现金金额" prop="cash">
<el-input
v-model.number="checkoutForm.cashAmount"
type="number"
:min="0"
@input="caleValue('cashAmount')">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="银联" prop="unionPay">
<el-input
v-model.number="checkoutForm.unionPayAmount"
type="number"
:min="0"
@input="caleValue('unionPayAmount')">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="银行卡" prop="cardPay">
<el-input
v-model.number="checkoutForm.cardAmount"
type="number"
:min="0"
@input="caleValue('cardAmount')">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="对公" prop="transfer">
<el-input
v-model.number="checkoutForm.publicTransferAmount"
type="number"
:min="0"
@input="caleValue('publicTransferAmount')">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="车间支付" prop="transfer">
<el-input
v-model.number="checkoutForm.workshopPayment"
type="number"
:min="0"
@input="caleValue('workshopPayment')">
<template #append></template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</inforCard>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch } from "vue";
// @ts-ignore
import { User } from "@element-plus/icons-vue";
import dayjs from "dayjs";
import { userInfor } from "@/store/user/user";
import { defaultRetail } from "@/defaultForm/defaultRetail";
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
import request from "@/lib/request";
const props = withDefaults(
defineProps<{
executeType?: string;
deceased: RegisForm;
}>(),
{
deceased: () => {
return {
...defaultRetail(),
deceased: {},
};
},
}
);
const emit = defineEmits(["updateData"]);
const userInforStore = userInfor().userInfor;
let checkoutForm = defineModel({ default: defaultPaymentForm() });
let servicesList = ref([]);
onMounted(() => {
checkoutForm.value.handler =
checkoutForm.value.handler || (userInforStore.name as string);
request()
.get(
"/deceased-retail/selected-service?retailId=" +
props.deceased.id +
"&retailType=" +
props.deceased.retailType
)
.then((res) => {
servicesList.value = res.data?.list || [];
});
});
let keys = [
"cashAmount",
"unionPayAmount",
"cardAmount",
"publicTransferAmount",
"workshopPayment",
];
function caleValue(keyVal: string) {
let total = 0;
let currentVal = checkoutForm.value[keyVal];
keys.forEach((key) => {
if (keyVal !== key) {
let tempVal = Number(checkoutForm.value[key]).toFixed(2);
total = Number(total) + Number(tempVal);
}
});
let salesAmount = Number(props.deceased.salesAmount);
if (salesAmount - (total + currentVal) < 0) {
checkoutForm.value[keyVal] = salesAmount - total;
}
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,643 @@
<template>
<div>
<el-row>
<baseTableHeader
title="零售结算"
@resetSearch="methods.resetSearch"
@search="methods.search">
<template #content>
<el-form :model="searchForm" label-position="right">
<el-row :gutter="12">
<el-col :span="6">
<el-form-item label="逝者姓名">
<el-input
v-model="searchForm.deceased.name"
placeholder="请输入逝者姓名"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="购买人姓名">
<el-input
v-model="searchForm.retail.familyName"
placeholder="请输入购买人姓名"></el-input> </el-form-item
></el-col>
<el-col :span="6">
<el-form-item label="引导员">
<GuideList
v-model="
searchForm.retail.guide
"></GuideList> </el-form-item
></el-col>
<el-col :span="8">
<el-form-item label="购买日期">
<el-date-picker
v-model="searchForm.retail.purchaseDate"
type="datetimerange"
range-separator="至"
start-placeholder="选择日期"
end-placeholder="选择日期"
@change="dataChange" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</baseTableHeader>
</el-row>
<el-card style="margin-top: 8px">
<div style="margin-bottom: 15px">
<el-button
size="small"
type="primary"
@click="methods.add"
v-if="route.path === '/noDepartedSaint'">
<template #icon>
<el-icon>
<CirclePlus />
</el-icon> </template
>新增</el-button
>
</div>
<div>
<base-table
:option="tableOption"
ref="table"
border
show-summary
:summary-method="getSummaries">
<template #toolsBar>
<el-radio-group
v-model="searchForm.retail.retailType"
size="small"
style="margin-left: 15px">
<el-radio-button label="逝者零售" :value="1" />
<el-radio-button label="无逝者零售" :value="2" />
</el-radio-group>
</template>
<template #colunm>
<el-table-column
type="index"
width="80"
fixed="left"
align="center"></el-table-column>
<el-table-column
prop="deceased.name"
label="逝者姓名"
width="100"
fixed="left"
v-if="searchForm.retail.retailType === 1"
align="center">
</el-table-column>
<el-table-column
prop="name"
label="结账"
width="100"
fixed="left"
align="center">
<template #default="{ row }">
<el-tag
:type="
row.retailState === 0
? 'danger'
: row.retailState === 1
? 'success'
: 'info'
">
{{
row.retailState === 0
? "未结账"
: row.retailState === 1
? "已结账"
: "未知"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="购买人" align="center" fixed="left">
<template #default="{ row }">
<span>{{ row.familyName || row.deceased?.name }}</span>
</template>
</el-table-column>
<el-table-column
prop="familyPhone"
label="购买人电话"
width="120"
align="center">
<template #default="{ row }">
<span>{{ row.deceased?.familyPhone || row.familyPhone }}</span>
</template>
</el-table-column>
<el-table-column
prop="purchaseDate"
label="购买日期"
width="200"
align="center" />
<el-table-column
prop="checkoutDate"
label="结算日期"
width="200"
align="center">
<template #default="{ row }">
<span v-if="row.retailState === 1">
{{ row.checkoutDate }}
</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column prop="handler" label="经办人" align="center" />
<el-table-column
width="100"
prop="salesAmount"
label="销售金额"
align="center" />
<el-table-column
label="现金支付"
prop="payment.cashAmount"
width="100"
align="center">
<template #default="{ row }">
{{ row.payment?.cashAmount || "0.00" }} 元
</template>
</el-table-column>
<el-table-column
prop="payment.unionPayAmount"
label="银联支付"
width="100"
align="center">
<template #default="{ row }">
{{ row.payment?.unionPayAmount || "0.00" }} 元
</template>
</el-table-column>
<el-table-column
prop="payment.cardAmount"
label="刷卡金额"
width="100"
align="center">
<template #default="{ row }">
{{ row.payment?.cardAmount || "0.00" }} 元
</template>
</el-table-column>
<el-table-column
prop="payment.publicTransferAmount"
label="对公转账"
width="100"
align="center">
<template #default="{ row }">
{{ row.payment?.publicTransferAmount || "0.00" }} 元
</template>
</el-table-column>
<el-table-column
prop="payment.workshopPayment"
label="车间支付"
width="100"
align="center">
<template #default="{ row }">
{{ row.payment?.workshopPayment || "0.00" }} 元
</template>
</el-table-column>
<el-table-column prop="guide" label="引导员" align="center" />
<el-table-column
width="300"
label="操作"
align="center"
fixed="right">
<template #default="{ row }">
<el-row align="middle" justify="center">
<el-button
size="small"
type="primary"
v-if="row.retailState === 1"
@click="methods.hanlderView(row)">
查看</el-button
>
<el-button
type="primary"
size="small"
@click="methods.checkout(row)"
v-if="row.retailState === 0"
>结账</el-button
>
<el-button
v-if="row.retailState === 1"
size="small"
type="default"
@click="methods.cancel(row)">
作废
</el-button>
<el-button @click="methods.viewProduct(row)" size="small">
零售清单</el-button
>
<el-button @click="methods.print(row)" size="small"
>打印</el-button
>
</el-row>
</template>
</el-table-column>
</template>
</base-table>
</div>
</el-card>
<retailList v-model="showDialog" :option="retailListTable"></retailList>
<baseDialog
v-model="retailRegisState.showDialog"
top="50px"
title="零售结算">
<retailRegis
v-model="regisForm"
:retailType="searchForm.retail.retailType"
:showServiceDelBtn="handlerType !== 'view'"
:add="handlerType === 'add'"
type="零售结算"></retailRegis>
<template #footer>
<el-row justify="center" align="middle" style="margin-top: 15px">
<el-button type="danger" @click="methods.close">关闭</el-button>
</el-row>
</template>
</baseDialog>
<base-curd-dialog
v-model="pageVisibleState.show2LevelPage.value"
:title="pageVisibleState.dialogTitle.value"
width="70%"
:before-close="methods.handleDialogClose"
@addConfim="methods.addConfim"
@closeConfirm="methods.handleDialogClose"
confirmText="结账"
destroy-on-close
:showPageType="pageVisibleState.showPageType">
<template #content>
<checkoutAddOrEdit
:executeType="pageVisibleState.executeType.value"
:deceased="currentData"
v-model="currentPayment">
</checkoutAddOrEdit>
</template>
<template #footer>
<el-button type="primary" @click="methods.addConfim"
>确定结账</el-button
></template
>
</base-curd-dialog>
<printServicesPage
v-model="showPrint"
:deceased="deceased"
:serviceUrl="serviceUrl">
</printServicesPage>
<base-dialog
v-model="cancelState.showDialog"
title="账单作废"
width="50%"
@closeConfirm="methods.cancleClose">
<el-form :model="cancelForm" label-width="120px" style="padding: 20px">
<el-row :gutter="20">
<el-col :span="12">
<!-- 注销申请人 -->
<el-form-item label="作废申请人">
<el-input disabled v-model="cancelForm.cancelPerson" />
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 注销日期 -->
<el-form-item label="作废日期">
<el-date-picker
disabled
v-model="cancelForm.cancelDate"
type="date" />
</el-form-item>
</el-col>
<el-col :span="24">
<!-- 注销原因 -->
<el-form-item label="作废原因">
<el-input
v-model="cancelForm.cancelReason"
type="textarea"
placeholder="请输入作废原因" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="flex-center">
<el-button type="primary" @click="methods.submitCancel"
>作废</el-button
>
<el-button @click="methods.resetCancel">取消</el-button>
</div>
</template>
</base-dialog>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, watch, nextTick } from "vue";
import { dayjs, ElMessage, ElMessageBox } from "element-plus";
import { resetParams } from "@/util/globalMethods";
import { globalState } from "@/store";
import retailRegis from "../publicComponents/retailRegis.vue";
import api from "@/lib/request";
import { tableOptionType } from "@/types/table";
import { useRoute } from "vue-router";
import pageVisible from "@/components/curdDialog/pageVisibleState";
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
import checkoutAddOrEdit from "./page/checkoutAddOrEdit.vue";
import printServicesPage from "@/components/printPage/printServicesPage.vue";
import { defaultRetail } from "@/defaultForm/defaultRetail";
import { userInfor } from "@/store/user/user";
import GuideList from "@/components/guideList/guideList.vue";
const pageVisibleState = new pageVisible({
add: "结账登记",
edit: "登记修改",
view: "查看登记",
});
let retailListTable = ref<tableOptionType>({
url: "/deceased-retail/selected-service",
searchUrl: "",
searchParams: {},
executeType: "list",
});
const retailRegisState = ref({
showDialog: false,
});
let currentRetail = ref<RegisForm>(defaultRetail());
let currentInfor = ref(undefined);
let showDialog = ref(false);
let showPrint = ref(false);
let deceased = ref();
let serviceUrl = ref();
const handlerType = ref("");
const searchForm = ref({
retail: {
guide: "", // 引导员
startDate: "",
endDate: "",
purchaseDate: ["", ""],
retailType: 1,
familyName: "",
},
deceased: {
name: "", // 逝者姓名
familyName: "",
},
});
let currentPayment = ref<PaymentForm>(defaultPaymentForm());
let currentData = ref();
const route = useRoute();
const regisForm = ref<RegisForm>();
const cancelState = ref({
showDialog: false,
});
const globaUser = userInfor().userInfor;
const cancelForm = ref({
cancelPerson: globaUser.name,
cancelDate: dayjs().format(),
cancelReason: "",
});
let table = ref();
let tableOption = ref<tableOptionType>({
url: "/deceased-retail/list?retailType=" + searchForm.value.retail.retailType,
searchUrl: "/deceased-retail/query",
searchParams: searchForm.value,
executeType: "list",
});
const methods = {
add() {
retailRegisState.value.showDialog = true;
handlerType.value = "add";
},
cancel(row: RegisForm) {
currentRetail.value = row;
cancelState.value.showDialog = true;
},
viewProduct(row: RegisForm) {
retailListTable.value.url =
"/deceased-retail/selected-service?retailId=" + row.id;
showDialog.value = true;
},
drawerClose() {
currentInfor.value = undefined;
showDialog.value = false;
},
async checkout(row: RegisForm) {
currentData.value = row;
pageVisibleState.dialogTitle.value = "零售结算";
pageVisibleState.show2LevelPage.value = true;
},
async hanlderView(row: RegisForm) {
// await ElMessageBox.confirm("确定结账吗?");
regisForm.value = row;
retailRegisState.value.showDialog = true;
handlerType.value = "view";
pageVisibleState.dialogTitle.value = "零售查看";
},
close() {
retailRegisState.value.showDialog = false;
},
async cancle() {
await ElMessageBox.confirm("确定作废该条吗?", { type: "error" });
retailRegisState.value.showDialog = false;
ElMessage.success("作废成功!");
},
print(row: RegisForm) {
deceased.value = row;
serviceUrl.value = `/deceased-retail/selected-service?retailType=${searchForm.value.retail.retailType}&retailId=${row.id}`;
nextTick(() => {
showPrint.value = true;
});
},
search() {
table.value.methods.setDataType("search");
},
resetSearch() {
searchForm.value = {
retail: {
guide: "", // 引导员
startDate: "",
endDate: "",
purchaseDate: ["", ""],
retailType: 1,
familyName: "",
},
deceased: {
name: "", // 逝者姓名
familyName: "",
},
};
tableOption.value.searchParams = searchForm.value;
nextTick(() => {
table.value.methods.setDataType("search");
});
},
async addConfim() {
await ElMessageBox.confirm("确定结账吗?", { type: "warning" });
let sendData = {
deceased: {
...currentData.value,
},
currentPayment: {
...currentPayment.value,
},
id: currentData.value.id,
};
let url = "/checkout/deceasedCheckout";
const res = await api().post(url, sendData);
if (res.code === 200) {
ElMessage.success("结账成功!");
pageVisibleState.show2LevelPage.value = false;
nextTick(() => {
table.value.methods.setDataType("search");
currentPayment.value = defaultPaymentForm();
currentData.value = undefined;
});
} else {
ElMessage.error(res.msg);
}
},
handleDialogClose() {
pageVisibleState.show2LevelPage.value = false;
currentData.value = undefined;
currentPayment.value = defaultPaymentForm();
},
cancleClose() {
cancelForm.value = {
cancelPerson: globaUser.name,
cancelDate: dayjs().format(),
cancelReason: "",
};
},
async submitCancel() {
if (!cancelForm.value.cancelReason) {
return ElMessage.error("请输入作废原因");
}
await ElMessageBox.confirm("确定作废吗?", { type: "warning" });
let sendData = {
deceasedRetailId: currentRetail.value.id,
cancelForm: { ...cancelForm.value },
cancelType: 0,
};
api()
.post("/cancel/cancel", sendData)
.then((res) => {
if (res.code === 200) {
ElMessage.success("作废提交成功!");
methods.resetCancel();
cancelForm.value = {
cancelPerson: globaUser.name,
cancelDate: dayjs().format(),
cancelReason: "",
};
table.value.methods.setDataType("search");
} else {
ElMessage.error(res.msg);
}
});
},
resetCancel() {
cancelForm.value = {
cancelPerson: globaUser.name,
cancelDate: dayjs().format(),
cancelReason: "",
};
cancelState.value.showDialog = false;
},
};
watch(
() => searchForm.value.retail.retailType,
() => {
table.value.methods.setDataType("search");
}
);
function dataChange(val: Date[]) {
searchForm.value.retail.startDate = val[0];
searchForm.value.retail.endDate = val[1];
}
const getSummaries = (param: { columns: any[]; data: any[] }) => {
const { columns, data } = param;
const sums: any[] = [];
// 需要统计的字段列表
const sumKeys = [
"salesAmount",
"payment.cashAmount",
"payment.unionPayAmount",
"payment.cardAmount",
"payment.publicTransferAmount",
"payment.workshopPayment",
];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "合计";
return;
}
if (sumKeys.includes(column.property)) {
const values = data.map((item) => {
const keys = column.property.split(".");
let value = item;
for (const key of keys) {
value = value?.[key] || 0;
}
return Number(value) || 0;
});
if (!values.every((value) => isNaN(value))) {
const sum = values.reduce((prev, curr) => {
return prev + curr;
}, 0);
sums[index] = `${sum.toFixed(2)}`;
} else {
sums[index] = "0.00 元";
}
} else {
sums[index] = "";
}
});
return sums;
};
</script>
<style lang="scss" scoped>
/* 添加汇总行样式 */
:deep(.el-table__footer) {
.cell {
font-weight: 600;
color: #606266;
}
td {
background-color: #f5f7fa !important;
}
}
</style>