初始版本,目前线上可用

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,582 @@
<template>
<div>
<el-row>
<baseTableHeader
title="结账登记"
@resetSearch="methods.resetSearch"
@search="methods.search">
<template #content>
<el-form :model="searchForm" :inline="true" label-position="right">
<el-form-item label="逝者姓名">
<el-input
v-model="searchForm.name"
placeholder="请输入逝者姓名"></el-input>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="searchForm.gender">
<el-radio-button value="男" label="男"></el-radio-button>
<el-radio-button value="女" label="女"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="结账日期">
<el-date-picker
v-model="searchForm.purchaseDate"
type="datetimerange"
range-separator=""
start-placeholder="选择日期"
end-placeholder="选择日期"
@change="dataChange" />
</el-form-item>
</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-radio-group
v-model="searchForm.retailState"
size="small"
style="margin-left: 15px">
<el-radio-button label="未结账" :value="0" />
<el-radio-button label="已结账" :value="1" />
</el-radio-group>
</template>
<template #colunm>
<el-table-column
type="index"
width="80"
fixed="left"
align="center"></el-table-column>
<el-table-column
prop="retailState"
label="结账状态"
width="160"
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
prop="deceased.name"
label="逝者姓名"
width="120"
fixed="left"
align="center" />
<el-table-column prop="deceased.gender" label="性别" align="center" />
<el-table-column prop="deceased.age" label="年龄" align="center" />
<el-table-column
prop="deceased.idNumber"
label="身份证"
align="center"
width="180" />
<el-table-column
prop="deceased.familyPhone"
label="购买人电话"
align="center"
width="150" />
<el-table-column
prop="salesAmount"
:label="'销售金额'"
width="150"
align="center" />
<el-table-column
v-if="searchForm.retailState === 1"
label="现金支付"
width="150"
prop="paymentRecord.cashAmount"
align="center">
<template #default="{ row }">
{{ row.paymentRecord?.cashAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="paymentRecord.unionPayAmount"
label="银联支付"
width="150"
v-if="searchForm.retailState === 1"
align="center">
<template #default="{ row }">
{{ row.paymentRecord?.unionPayAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="paymentRecord.cardAmount"
label="刷卡金额"
width="150"
v-if="searchForm.retailState === 1"
align="center">
<template #default="{ row }">
{{ row.paymentRecord?.cardAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="paymentRecord.publicTransferAmount"
label="对公转账"
width="150"
v-if="searchForm.retailState === 1"
align="center">
<template #default="{ row }">
{{ row.paymentRecord?.publicTransferAmount || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="paymentRecord.workshopPayment"
label="车间支付"
v-if="searchForm.retailState === 1"
width="150"
align="center">
<template #default="{ row }">
{{ row.paymentRecord?.workshopPayment || "0.00" }}
</template>
</el-table-column>
<el-table-column
prop="createDate"
:label="searchForm.retailState === 0 ? '录单时间' : '结账时间'"
align="center"
width="200">
<template #default="{ row }">
<span v-if="searchForm.retailState === 0">{{
dayjs(row.createDate).format("YYYY-MM-DD HH:mm:ss")
}}</span>
<span v-if="searchForm.retailState === 1">
{{
dayjs(row.checkoutDate).format("YYYY-MM-DD HH:mm:ss")
}}</span
>
</template>
</el-table-column>
<el-table-column
prop="deceased.name"
label="购买人姓名"
align="center"
width="150" />
<el-table-column prop="remark" label="备注" align="center" />
<el-table-column
width="230"
fixed="right"
align="center"
label="操作">
<template #default="{ row }">
<div style="display: flex; width: 100%; justify-content: center">
<el-button
v-if="row.retailState === 0"
size="small"
type="primary"
@click="methods.add(row)">
结账登记
</el-button>
<el-button
v-if="row.retailState === 1"
size="small"
type="primary"
@click="methods.view(row)">
查看
</el-button>
<el-button
v-if="row.retailState === 1"
size="small"
type="default"
@click="methods.cancel(row)">
作废
</el-button>
<el-button
v-if="row.retailState === 1"
size="small"
type="default"
@click="methods.print(row)">
打印
<template #icon>
<img
src="/assets/icon/打印机.svg"
style="margin-right: 5px"
width="20"
height="20" />
</template>
</el-button>
<el-button
v-if="row.retailState === 0"
size="small"
type="default"
@click="methods.print(row)">
打印
</el-button>
</div>
</template>
</el-table-column>
</template>
</base-table>
</el-card>
<base-curd-dialog
v-model="pageVisibleState.show2LevelPage.value"
:title="pageVisibleState.dialogTitle.value"
width="70%"
:before-close="methods.handleDialogClose"
@addConfim="methods.addConfim"
@editConfim="methods.eidthConfirm"
@closeConfirm="methods.handleDialogClose"
confirmText="结账"
destroy-on-close
:showPageType="pageVisibleState.showPageType">
<template #content>
<checkoutAddOrEdit
:executeType="pageVisibleState.executeType.value"
:deceased="currentRetail"
v-model="currentPayment">
</checkoutAddOrEdit>
</template>
<template #footer>
<el-button @click="methods.print">打印</el-button>
</template>
</base-curd-dialog>
<base-dialog
v-model="cancelState.showDialog"
title="账单作废"
width="50%"
destroy-on-close
@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>
<!-- <base-dialog v-model="showPrint" title="打印预览">
<printRetailPage v-model="currentData"></printRetailPage>
</base-dialog>
<base-dialog v-model="showPrint1" title="打印预览">
<printServicesPage v-model="currentData"></printServicesPage>
</base-dialog> -->
<PrintRetailPage
v-model="showPrint"
:deceased="deceased"
:serviceUrl="serviceUrl">
</PrintRetailPage>
<printServicesPage
v-model="showPrint1"
:deceased="deceased"
:serviceUrl="serviceUrl">
</printServicesPage>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, watch, nextTick } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { userInfor } from "@/store/user/user";
import checkoutAddOrEdit from "./page/checkoutAddOrEdit.vue";
import api from "@/lib/request";
import pageVisible from "@/components/curdDialog/pageVisibleState";
import { tableOptionType } from "@/types/table";
import dayjs from "dayjs";
import { defaultPaymentForm } from "@/defaultForm/defaultPaymentForm";
import { defaultRetail } from "@/defaultForm/defaultRetail";
import PrintRetailPage from "@/components/printPage/printRetailPage.vue";
import printServicesPage from "@/components/printPage/printServicesPage.vue";
const pageVisibleState = new pageVisible({
add: "结账登记",
edit: "登记修改",
view: "查看登记",
});
const globaUser = userInfor().userInfor;
const cancelState = ref({
showDialog: false,
});
const cancelForm = ref({
cancelPerson: globaUser.name,
cancelDate: dayjs().format(),
cancelReason: "",
});
const searchForm = ref({
name: "", // 逝者姓名
gender: "", // 性别 (male / female / other)
checkoutDate: "", // 结账日期 (YYYY-MM-DD)
retailState: 0,
startDate: "",
endDate: "",
purchaseDate: ["", ""],
});
let currentRetail = ref<RegisForm>(defaultRetail());
let showPrint = ref(false);
let showPrint1 = ref(false);
let deceased = ref();
let serviceUrl = ref();
let table = ref();
let currentData = ref();
let tableOption = ref<tableOptionType>({
url: "/checkout-retail/list?retailState=0",
searchUrl: "/checkout-retail/query",
searchParams: searchForm,
executeType: "list",
});
let currentPayment = ref<PaymentForm>(defaultPaymentForm());
watch(
() => searchForm.value.retailState,
(newData) => {
tableOption.value.url =
"/checkout-retail/list?retailState=" + Number(newData);
table.value.methods.setDataType("list");
}
);
const methods = {
view(row: RegisForm) {
currentRetail.value = row;
currentData = row;
currentPayment.value = row.paymentRecord || defaultPaymentForm();
pageVisibleState.showPageType.view = true;
pageVisibleState.showPageType.add = false;
pageVisibleState.executeType.value = "view";
},
add(row: RegisForm) {
currentData.value = row;
currentRetail.value = row;
currentPayment.value = row.paymentRecord || defaultPaymentForm();
if (row.retailState === 1) {
pageVisibleState.showPageType.view = true;
} else {
pageVisibleState.showPageType.add = true;
}
pageVisibleState.executeType.value = "add";
},
print(row: RegisForm) {
deceased.value = row;
serviceUrl.value =
"/deceased-retail/selected-service?retailType=0&deceasedId=" +
row.deceased.id;
if (searchForm.value.retailState === 0) {
showPrint1.value = true;
} else {
showPrint.value = true;
}
},
cancleClose() {
currentRetail.value = defaultRetail();
currentPayment.value = defaultPaymentForm();
},
async addConfim() {
await ElMessageBox.confirm("确定结账吗?", { type: "warning" });
let sendData = {
deceasedRetail: {
...currentRetail.value,
},
currentPayment: {
...currentPayment.value,
},
id: currentData.value.id,
};
const res = await api().post("/checkout-retail/confirmCheckout", sendData);
if (res.code === 200) {
ElMessage.success("结账成功!");
pageVisibleState.show2LevelPage.value = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(res.msg);
}
},
eidthConfirm() {},
search() {
table.value.methods.setDataType("search");
},
resetSearch() {
let retailState = searchForm.value.retailState;
searchForm.value = {
name: "", // 逝者姓名
gender: "", // 性别 (male / female / other)
checkoutDate: "", // 结账日期 (YYYY-MM-DD)
startDate: "",
endDate: "",
purchaseDate: ["", ""],
retailState: retailState,
};
nextTick(() => {
table.value.methods.setDataType("reset");
});
},
handleDialogClose() {
pageVisibleState.show2LevelPage.value = false;
},
cancel(row: RegisForm) {
currentRetail.value = row;
cancelState.value.showDialog = true;
},
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("list");
} else {
ElMessage.error(res.msg);
}
});
},
resetCancel() {
cancelForm.value = {
cancelPerson: globaUser.name,
cancelDate: dayjs().format(),
cancelReason: "",
};
cancelState.value.showDialog = false;
},
};
function dataChange(val: Date[]) {
searchForm.value.startDate = val[0];
searchForm.value.endDate = val[1];
}
const getSummaries = (param: { columns: any[]; data: any[] }) => {
const { columns, data } = param;
const sums: any[] = [];
// 需要统计的字段列表
const sumKeys = [
"salesAmount",
"paymentRecord.cashAmount",
"paymentRecord.unionPayAmount",
"paymentRecord.cardAmount",
"paymentRecord.publicTransferAmount",
"paymentRecord.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;
};
onMounted(async () => {});
</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,303 @@
<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.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-row :gutter="20" v-else">
<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.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.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: () => defaultRetail(),
}
);
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);
});
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;
}
}
request()
.get(
"/deceased-retail/selected-service?deceasedId=" +
props.deceased.deceased.id +
"&retailType=0"
)
.then((res) => {
servicesList.value = res.data?.list || [];
});
</script>
<style lang="scss" scoped></style>