Files
his/openhis-ui-vue3/src/views/medicationmanagement/chkstock/chkstockPart/index.vue
chenqi d3df46858b fix(charge): 修复医保支付计算中的潜在空指针异常
- 在 chargeDialog.vue 中为所有 param.detail.find() 调用添加可选链操作符
- 修复了基金支付总额、个人负担总金额和其他支付类型的空指针风险
- 解决了基本医保统筹基金支出等各项支付类型的潜在运行时错误
- 在微信刷卡支付逻辑中同样应用可选链操作符保护
- 修复了 FULAMT_OWNPAY_AMT 计算中的运算符优先级问题

feat(hospitalRecord): 动态替换打印模板中的医院名称

- 在 MedicationDetails.vue 中引入并使用 userStore 获取医院名称
- 修改处置模板打印逻辑以动态替换 {{HOSPITAL_NAME}} 占位符
- 更新处方模板打印功能以支持医院名称的动态替换
- 激活之前被注释掉的模板文件导入语句
- 移除硬编码的医院名称,实现模板的动态化配置
2026-01-13 16:58:43 +08:00

1280 lines
44 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container" v-loading="loading" :element-loading-text="'审批中。。。'">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleSave">批量保存</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Plus" @click="submitAudit">提交审核</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Printer" @click="handlePrint"> 打印单据 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Export" @click="handleExport"> 导出 </el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="primary" plain icon="EditPen" @click="handleTotalAmount">
计算盈亏金额
</el-button>
</el-col> -->
</el-row>
<el-button type="primary" plain icon="Printer" @click="handlePrint"> 打印单据 </el-button>
<el-form
:model="receiptHeaderForm"
ref="receiptHeaderRef"
:inline="true"
label-width="120px"
:rules="rules"
>
<el-form-item label="单据号:" prop="busNo">
<el-input
v-model="receiptHeaderForm.busNo"
placeholder="单据号:"
clearable
style="width: 260px"
disabled
/>
</el-form-item>
<el-form-item label="仓库类型:" prop="purposeTypeEnum">
<el-select
v-model="receiptHeaderForm.purposeTypeEnum"
placeholder=""
clearable
style="width: 150px"
:disabled="data.isEdit"
@change="(value) => handleChangePurposeTypeEnum(value, false)"
>
<el-option
v-for="dict in warehous_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="盘点仓库:" prop="purposeLocationId">
<el-select
v-model="receiptHeaderForm.purposeLocationId"
placeholder=""
clearable
style="width: 150px"
:disabled="data.isEdit"
@change="handleCabinetChange(receiptHeaderForm.purposeLocationId)"
>
<el-option
v-for="cabinet in purposeTypeListOptions"
:key="cabinet.id"
:label="cabinet.name"
:value="cabinet.id"
/>
</el-select>
</el-form-item>
<el-form-item label="货位:" prop="purposeLocation">
<el-select
v-model="receiptHeaderForm.purposeLocation"
placeholder=""
clearable
style="width: 150px"
:disabled="data.isEdit"
>
<el-option
v-for="freight in freightListOptions"
:key="freight.id"
:label="freight.name"
:value="freight.id"
/>
</el-select>
</el-form-item>
<el-form-item label="盘点日期:">
<el-date-picker
v-model="receiptHeaderForm.occurrenceTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetime"
:disabled="data.isEdit"
/>
</el-form-item>
<el-form-item label="药品类型:" prop="medicationType">
<el-select
v-model="receiptHeaderForm.medicationType"
placeholder=""
clearable
style="width: 150px"
:disabled="data.isEdit"
@change="
(value) => {
itemType = value;
}
"
>
<el-option
v-for="itemType in purchase_type"
:key="itemType.value"
:label="itemType.label"
:value="itemType.value"
/>
</el-select>
</el-form-item>
</el-form>
<el-tabs type="border-card">
<el-tab-pane label="盘点单明细">
<el-row :gutter="10" class="mb8" v-if="!viewStatus">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="addNewRow">添加行</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="deleteSelectedRows"
>删除行</el-button
>
</el-col>
</el-row>
<el-form :model="form" :rules="tableRules" ref="formRef" :disabled="viewStatus == 'apply'">
<el-table
v-loading="loading"
:data="form.purchaseinventoryList"
@selection-change="handleSelectionChange"
ref="tableRef"
max-height="500"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="项目" align="center" key="name" prop="name" width="200" fixed>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.name`"
:rules="tableRules.name"
required
>
<el-input
v-if="viewStatus == 'view'"
v-model="scope.row.name"
placeholder=""
disabled
/>
<PopoverList
v-else
@search="handleSearch"
:width="1000"
:modelValue="scope.row.name"
>
<template #popover-content="{}">
<MedicineList
@selectRow="(row) => selectRow(row, scope.$index)"
:searchKey="medicineSearchKey"
:purposeLocationId="receiptHeaderForm.purposeLocationId"
:itemType="receiptHeaderForm.medicationType"
/>
</template>
</PopoverList>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="规格"
align="center"
key="volume"
prop="volume"
width="140"
:show-overflow-tooltip="true"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.volume`"
:rules="tableRules.volume"
>
<el-input disabled v-model="scope.row.volume" placeholder="" />
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="厂家/产地"
align="center"
key="manufacturerText"
prop="manufacturerText"
:show-overflow-tooltip="true"
width="220"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.manufacturerText`"
:rules="tableRules.manufacturerText"
>
<el-input disabled v-model="scope.row.manufacturerText" placeholder="" />
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="产品批号"
align="center"
key="lotNumber"
prop="lotNumber"
width="150"
>
<template #default="scope">
<el-form-item :prop="`purchaseinventoryList.${scope.$index}.lotNumber`">
<el-input
v-model="scope.row.lotNumber"
placeholder=""
disabled
@blur="lotNumberBlur(scope.row, scope.$index)"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="单价 " align="center" key="price" prop="price" width="130">
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.price`"
:rules="tableRules.price"
>
<div class="select_wrapper_div">
<el-input
disabled
v-model="scope.row.price"
placeholder=""
:class="{ 'error-border': scope.row.error }"
>
<template #suffix></template>
</el-input>
</div>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="盘点单位"
align="center"
key="unitCode"
prop="unitCode"
:show-overflow-tooltip="true"
width="90"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.unitCode`"
:rules="tableRules.unitCode"
>
<div class="select_wrapper_div">
<el-select
v-model="scope.row.unitCode"
placeholder="盘点单位"
:disabled="viewStatus == 'view'"
:class="{ 'error-border': scope.row.error }"
@change="(value) => handleUnitCodeChange(scope.row, value)"
>
<el-option
v-for="(item, index) in scope.row.unitList"
:key="index"
:label="item.label"
:value="item.value"
@click="scope.row.currentUnitCode_dictText = item.label"
/>
</el-select>
</div>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="盘前库存"
align="center"
key="orgQuantity"
prop="orgQuantity"
width="120"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.orgQuantity`"
:rules="tableRules.orgQuantity"
>
<el-input v-model="scope.row.orgQuantity" placeholder="" disabled />
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="实盘数量"
align="center"
key="totalQuantityDisplay"
prop="totalQuantityDisplay"
width="120"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.totalQuantityDisplay`"
:rules="tableRules.totalQuantityDisplay"
>
<el-input
:disabled="viewStatus == 'view'"
v-model="scope.row.totalQuantityDisplay"
placeholder=""
@input="handleTotalQuantity(scope.row)"
>
</el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="实盘金额"
align="center"
key="totalPrice"
prop="totalPrice"
width="150"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.totalPrice`"
:rules="tableRules.totalPrice"
>
<div class="select_wrapper_div">
<el-input
v-model="scope.row.totalPrice"
placeholder=""
:class="{ 'error-border': scope.row.error }"
disabled
>
<template #suffix></template>
</el-input>
</div>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="盈亏数量"
align="center"
key="itemQuantityDisplay"
prop="itemQuantityDisplay"
width="110"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.itemQuantityDisplay`"
:rules="tableRules.itemQuantityDisplay"
>
<el-input
v-model="scope.row.itemQuantityDisplay"
placeholder=""
@input="handleItemQuantity(scope.row)"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="盈亏金额"
align="center"
key="profitAmount"
prop="profitAmount"
width="150"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.profitAmount`"
:rules="tableRules.profitAmount"
>
<el-input v-model="scope.row.profitAmount" placeholder="" disabled />
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="盈亏类型"
align="center"
key="reasonCode"
prop="reasonCode"
:show-overflow-tooltip="true"
width="120"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.reasonCode`"
:rules="tableRules.reasonCode"
>
<div class="select_wrapper_div">
<el-select
:disabled="viewStatus == 'view'"
v-model="scope.row.reasonCode"
placeholder="请选择盈亏类型"
:class="{ 'error-border': scope.row.error }"
clearable
>
<el-option
v-for="(item, index) in profit_reason"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="盈亏原因"
align="center"
key="reason"
prop="reason"
:show-overflow-tooltip="true"
width="150"
>
<template #default="scope">
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.reason`"
:rules="tableRules.reason"
>
<el-input
:disabled="viewStatus == 'view'"
v-model="scope.row.reason"
placeholder=""
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column
label="药品追溯码"
align="center"
key="traceNo"
prop="traceNo"
width="130"
>
<template #default="scope">
<el-tooltip
:content="formatContent(scope.row.traceNo)"
placement="top"
popper-class="custom-tooltip"
>
<el-form-item
:prop="`purchaseinventoryList.${scope.$index}.traceNo`"
:rules="tableRules.traceNo"
>
<el-input
v-model="scope.row.traceNo"
placeholder=""
:disabled="viewStatus == 'view'"
:id="'traceNo' + `${scope.$index}`"
@change="(value) => handleTraceNo(value, scope.row)"
/>
</el-form-item>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
v-if="!viewStatus"
label="操作"
align="center"
width="80"
class-name="small-padding fixed-width"
fixed="right"
>
<template #default="scope">
<el-button
link
type="primary"
icon="Edit"
@click="handleScan(scope.row, scope.$index)"
>扫码</el-button
>
</template>
</el-table-column>
</el-table>
<!-- <pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getTransferProductDetails(1)"
/> -->
</el-form>
</el-tab-pane>
</el-tabs>
<el-row
:gutter="10"
class="mb8"
style="margin-top: 15px; display: flex; align-items: center; justify-content: flex-start"
>
<el-col :span="3">
<span>制单人{{ userStore.name }}</span>
</el-col>
<el-col :span="2">
<span>审核人</span>
</el-col>
<el-col :span="2">
<span>单据状态</span>
</el-col>
<el-col :span="6">
<el-row :gutter="8" style="display: flex; align-items: center; justify-content: flex-start">
<el-col :span="10">
<span>合计盈亏金额{{ totalAmountFormatted }}</span>
</el-col>
</el-row>
</el-col>
</el-row>
<TraceNoDialog
:ypName="ypName"
:rowData="rowData"
:openDialog="openTraceNoDialog"
@submit="submit"
@cancel="openTraceNoDialog = false"
/>
</div>
</template>
<script setup name="chkstockPart">
import {
addProductStocktaking,
delProductStocktaking,
getCount,
getDetailInit,
getDispensaryList,
getPharmacyList,
getstocktakingDetail,
submitApproval,
} from '../components/api';
import PopoverList from '@/components/OpenHis/popoverList/index.vue';
import TraceNoDialog from '@/components/OpenHis/TraceNoDialog/index.vue';
import MedicineList from '../components/medicineList.vue';
import {formatDate} from '@/utils/index';
import useUserStore from '@/store/modules/user';
import {useRoute} from 'vue-router';
import {computed, defineEmits, getCurrentInstance, reactive, ref, toRefs, watch} from 'vue';
import {useStore} from '@/store/store';
import useTagsViewStore from '@/store/modules/tagsView';
import templateJson from './components/template';
import {hiprint} from 'vue-plugin-hiprint';
import Decimal from 'decimal.js';
const tagsViewStore = useTagsViewStore();
const store = useStore();
const route = useRoute();
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
const { warehous_type, purchase_type, profit_reason } = proxy.useDict(
'warehous_type',
'purchase_type',
'profit_reason'
);
const viewStatus = ref('');
const loading = ref(false);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const visible = ref(false);
const rowIndex = ref(-1);
const totalAmount = computed(() => {
return form.purchaseinventoryList.reduce((accumulator, currentRow) => {
return new Decimal(accumulator || 0).plus(currentRow.profitAmount || 0).toNumber();
}, 0);
});
const totalAmountFormatted = computed(() => {
return new Decimal(totalAmount.value || 0).toFixed(4);
});
const openTraceNoDialog = ref(false);
const ypName = ref('');
const rowData = ref({});
const form = reactive({
purchaseinventoryList: [],
});
const receiptHeaderForm = reactive({
busNo: undefined,
occurrenceTime: formatDate(new Date()),
locationId: '',
time: '',
});
const data = reactive({
isEdit: false,
isAdding: true,
queryParams: {
pageNo: 1,
pageSize: 10,
searchKey: undefined, // 供应商名称
busNo: undefined, // 编码
statusEnum: undefined, // 状态
supplierId: undefined, // 供应商ID
applyTimeStart: undefined, // 申请时间开始
practitionerId: undefined, // 经手人ID
},
rules: {
purposeLocationId: [{ required: true, message: '请选择盘点仓库', trigger: 'change' }],
medicationType: [{ required: true, message: '请选择药品类型', trigger: 'change' }],
},
tableRules: {
name: [{ required: true, message: '项目不能为空', trigger: 'change' }],
unitCode: [{ required: true, message: '计量单位不能为空', trigger: 'change' }],
itemQuantity: [{ required: true, message: '盈亏数量不能为空', trigger: 'blur' }],
totalQuantity: [{ required: true, message: '实盘数量不能为空', trigger: 'blur' }],
},
});
const { queryParams, rules, tableRules } = toRefs(data);
const purposeTypeListOptions = ref(undefined); // 仓库列表
const freightListOptions = ref(undefined); // 货位列表
const selectedRows = ref([]); // 用于存储选中的行
const emit = defineEmits(['refresh']);
const tableRef = ref(undefined); // 表格引用
const medicineSearchKey = ref('');
const itemType = ref('');
// 监听路由变化
watch(
() => route.query,
(newValue) => {
if (newValue.isEdit) {
data.isEdit = true;
getstocktakingDetail({ busNo: newValue.supplyBusNo }).then((res) => {
editTable(res.data.records);
handleChangePurposeTypeEnum(res.data.records[0].purposeTypeEnum);
});
}
},
{ immediate: true }
);
const currentIndex = ref('');
function handleScan(row, index) {
rowData.value = row;
rowData.value.locationId = receiptHeaderForm.purposeLocationId;
rowData.value.itemType = receiptHeaderForm.medicationType;
ypName.value = row.name;
openTraceNoDialog.value = true;
currentIndex.value = index;
}
function submit(value) {
if (form.purchaseinventoryList[currentIndex.value].traceNo) {
form.purchaseinventoryList[currentIndex.value].traceNo =
form.purchaseinventoryList[currentIndex.value].traceNo + ',' + value;
} else {
form.purchaseinventoryList[currentIndex.value].traceNo = value;
}
openTraceNoDialog.value = false;
}
function formatContent(value) {
let content = '';
if (value) {
value.split(',').forEach((item, index) => {
content += `[${index + 1}] ${item}\n`;
});
return content;
}
}
function addNewRow() {
proxy.$refs['receiptHeaderRef'].validate((valid) => {
if (valid) {
// if (data.isAdding) {
// proxy.$message.warning("请先保存当前行后再新增!");
// return;
// }
const newRow = {
id: '',
definitionId: '',
name: '',
itemBusNo: '',
itemTableName: '',
itemTable: '',
itemType: '',
itemType_enumText: '',
itemQuantity: '',
itemMaxQuantity: '',
itemId: '',
detailJson: '',
supplierId: '',
purposeTypeEnum: '',
purposeLocationId: '',
purposeLocationStoreId: '',
practitionerId: '',
traceNo: '',
invoiceNo: '',
lotNumber: '',
occurrenceTime: '',
startTime: '',
endTime: '',
partPercent: '',
price: '',
totalPrice: '',
sellPrice: '',
minSellPrice: '',
unitCode: '',
unitCode_dictText: '',
minUnitCode: '',
minUnitCode_dictText: '',
volume: '',
wbStr: '',
ybNo: '',
unitList: {}, // 单位列表
isEditing: true, // 标记当前行是否正在编辑
error: false, // 新增 error 字段
isSave: false, // 当前行是否保存
};
form.purchaseinventoryList.push(newRow);
data.isEdit = true;
data.isAdding = true; // 设置标志位为 true表示有未保存的
}
});
}
// 药品列表搜索
function handleSearch(value) {
medicineSearchKey.value = value;
}
// 选择药品
function selectRow(rowValue, index) {
rowIndex.value = index;
form.purchaseinventoryList[index].busNo = receiptHeaderForm.busNo; //单据号
form.purchaseinventoryList[index].purposeLocationId = receiptHeaderForm.purposeLocationId; //盘点仓库
form.purchaseinventoryList[index].purposeTypeEnum = receiptHeaderForm.purposeTypeEnum; //盘点仓库
form.purchaseinventoryList[index].itemId = rowValue.definitionId; // 盘点项目id
form.purchaseinventoryList[index].itemTable = rowValue.itemTableName; // 项目表名,耗材表/药品表
form.purchaseinventoryList[index].name = rowValue.name; // 项目名称
form.purchaseinventoryList[index].volume = rowValue.volume; // 规格
form.purchaseinventoryList[index].manufacturerText = rowValue.manufacturerText; // 厂家产地
form.purchaseinventoryList[index].partPercent = rowValue.partPercent; // 拆零比
form.purchaseinventoryList[index].lotNumber = rowValue.lotNumber; // 批号
form.purchaseinventoryList[index].totalQuantity = 0; // 实盘数量 默认0
form.purchaseinventoryList[index].currentUnitCode = rowValue.unitCode; // 当前选中单位
form.purchaseinventoryList[index].currentUnitCode_dictText = rowValue.unitCode_dictText; // 当前选中单位
form.purchaseinventoryList[index].unitCode = rowValue.unitCode; // 盘点单位,默认大单位
form.purchaseinventoryList[index].unitCode_dictText = rowValue.unitCode_dictText; // 大单位label
form.purchaseinventoryList[index].minUnitCode = rowValue.minUnitCode; // 小单位value
form.purchaseinventoryList[index].minUnitCode_dictText = rowValue.minUnitCode_dictText; // 小单位label
// 维护一个大小单位的map用来判断当前选中单位是大/小单位
form.purchaseinventoryList[index].unitCodeMap = {};
form.purchaseinventoryList[index].unitCodeMap[rowValue.unitCode] = 'unit';
form.purchaseinventoryList[index].unitCodeMap[rowValue.minUnitCode] = 'minUnit';
// 构造单位下拉列表
form.purchaseinventoryList[index].unitList = [
{ label: rowValue.unitCode_dictText, value: rowValue.unitCode },
];
// 拆零比大于1添加小单位选项
if (rowValue.partPercent > 1) {
form.purchaseinventoryList[index].unitList.push({
label: rowValue.minUnitCode_dictText,
value: rowValue.minUnitCode,
});
}
// 获取当前项目当前批次的库存信息
getCount({
itemId: rowValue.definitionId,
orgLocationId: receiptHeaderForm.purposeLocationId,
lotNumber: rowValue.lotNumber,
}).then((res) => {
if (res.data.length > 1) {
proxy.$modal.msgWarning(
`${rowValue.name},批次${rowValue.lotNumber}库存有误,请先确认后再盘点`
);
} else if (res.data.length == 1) {
let inventoryInfo = res.data[0];
form.purchaseinventoryList[index].orgQuantity = formatInventory(
inventoryInfo.orgQuantity,
rowValue.partPercent,
rowValue.unitCode_dictText,
rowValue.minUnitCode_dictText
); // 原仓库数量(小单位)
form.purchaseinventoryList[index].orgQuantityTemp = inventoryInfo.orgQuantity; // 原库存临时变量,用于切换单位显示
form.purchaseinventoryList[index].price = inventoryInfo.price; // 单价 默认大单位价格
form.purchaseinventoryList[index].priceTemp = inventoryInfo.price; // 临时存一下大单位的价格
form.purchaseinventoryList[index].startTime = proxy.formatDateStr(
inventoryInfo.productionDate
); // 生产日期
form.purchaseinventoryList[index].endTime = proxy.formatDateStr(inventoryInfo.expirationDate); // 有效期
form.purchaseinventoryList[index].supplierId = inventoryInfo.supplierId; // 供应商
form.purchaseinventoryList[index].minUnitPrice = (
inventoryInfo.price / rowValue.partPercent
).toFixed(2); // 计算出小单位价格
}
});
}
// 编辑表格 传入获取到的详情列表
function editTable(list) {
list.forEach((item) => {
const rowItem = {};
receiptHeaderForm.purposeLocationId = item.purposeLocationId;
receiptHeaderForm.medicationType = item.itemType;
receiptHeaderForm.purposeTypeEnum = item.purposeTypeEnum.toString();
rowItem.busNo = item.busNo;
rowItem.itemId = item.itemId; // 盘点项目id
rowItem.itemTable =
item.itemType == '1' ? 'med_medication_definition' : 'adm_device_definition'; // 项目表名,耗材表/药品表
rowItem.name = item.itemName; // 项目名称
rowItem.volume = item.totalVolume; // 规格
rowItem.manufacturerText = item.manufacturerText; // 厂家产地
rowItem.partPercent = item.partPercent; // 拆零比
rowItem.lotNumber = item.lotNumber; // 批号
rowItem.currentUnitCode = item.measurementUnitCode; // 盘点时保存的单位
rowItem.unitCode = item.measurementUnitCode; // 盘点时保存的单位
rowItem.unitCode_dictText = item.unitCode_dictText; // 大单位label
rowItem.minUnitCode = item.minUnitCode; // 小单位value
rowItem.minUnitCode_dictText = item.minUnitCode_dictText; // 小单位label
rowItem.reasonCode = item.reasonCode; // 盈亏类型
rowItem.reason = item.reason; // 盈亏原因
rowItem.purposeLocationId = item.purposeLocationId;
rowItem.supplierId = item.supplierId;
// 维护一个大小单位的map用来判断当前选中单位是大/小单位
rowItem.unitCodeMap = {};
rowItem.unitCodeMap[item.unitCode] = 'unit';
rowItem.unitCodeMap[item.minUnitCode] = 'minUnit';
// 构造单位下拉列表
rowItem.unitList = [{ label: item.unitCode_dictText, value: item.unitCode }];
// 拆零比大于1添加小单位选项
if (item.partPercent > 1) {
rowItem.unitList.push({
label: item.minUnitCode_dictText,
value: item.minUnitCode,
});
}
// 判断保存时的盘点单位是大还是小
const isUnit = item.measurementUnitCode == item.unitCode;
rowItem.orgQuantity = isUnit
? formatInventory(
item.orgQuantity,
item.partPercent,
item.unitCode_dictText,
item.minUnitCode_dictText
)
: item.orgQuantity; // 原仓库数量(小单位)
rowItem.itemQuantityDisplay = isUnit
? formatInventory(
item.itemQuantity,
item.partPercent,
item.unitCode_dictText,
item.minUnitCode_dictText
)
: item.itemQuantity; // 盈亏数量(小单位)
rowItem.totalQuantityDisplay = isUnit
? formatInventory(
item.orgQuantity + item.itemQuantity,
item.partPercent,
item.unitCode_dictText,
item.minUnitCode_dictText
)
: item.orgQuantity + item.itemQuantity; // 实盘数量(小单位)
rowItem.itemQuantity = item.itemQuantity;
rowItem.totalQuantity = item.orgQuantity + item.itemQuantity;
rowItem.minUnitPrice = (item.price / item.partPercent).toFixed(2); // 单价 默认大单位价格
rowItem.price = isUnit ? item.price : rowItem.minUnitPrice; // 单价 默认大单位价格
rowItem.priceTemp = item.price; // 临时存一下大单位的价格
rowItem.totalPrice = new Decimal(rowItem.totalQuantity || 0)
.mul(rowItem.minUnitPrice || 0)
.toFixed(2);
// 盈亏金额
rowItem.profitAmount = new Decimal(rowItem.itemQuantity || 0)
.mul(rowItem.minUnitPrice || 0)
.toFixed(2);
// 校验盘前库存 + 盈亏数量 是否等于实盘数量 不相等证明库存有变动
if (item.orgQuantity + item.itemQuantity != item.totalQuantity) {
proxy.$modal.msgWarning(
`${item.itemName},批次${item.lotNumber}库存有变动,实盘数量已自动计算为当前实际库存数量`
);
}
console.log(rowItem, '34567890-');
form.purchaseinventoryList.push(rowItem);
});
console.log(form.purchaseinventoryList, '34567890-');
}
/**
* 格式化库存数量显示(大单位情况)
* @param quantity 小单位库存数量
* @param partPercent 拆零比
* @param unitCode 大单位
* @param minUnitCode 小单位
*/
function formatInventory(quantity, partPercent, unitCode, minUnitCode) {
// 处理负数情况
const isNegative = quantity < 0;
const absQuantity = Math.abs(quantity);
if (absQuantity % partPercent !== 0) {
const integerPart = Math.floor(absQuantity / partPercent);
const decimalPart = absQuantity % partPercent;
let result = integerPart.toString() + ' ' + unitCode;
if (decimalPart > 0) {
result += decimalPart.toString() + ' ' + minUnitCode;
}
return isNegative ? '-' + result : result;
}
// 整除情况
const result = absQuantity / partPercent;
return isNegative ? '-' + result : result;
}
// 单位处理
function handleUnitCodeChange(row, value) {
if (row.unitCodeMap[value] == 'unit') {
// 大单位情况处理
row.price = row.priceTemp;
row.orgQuantity = formatInventory(
row.orgQuantityTemp,
row.partPercent,
row.unitCode_dictText,
row.minUnitCode_dictText
);
} else {
// 小单位处理
row.price = row.minUnitPrice;
row.orgQuantity = row.orgQuantityTemp;
}
// 判断上一次选中的单位是大还是小,如果上一次是大单位,到这里是切换为小的,
if (row.unitCodeMap[row.currentUnitCode] == 'unit') {
// 实盘数量
// row.totalQuantity = row.totalQuantity * row.partPercent;
row.totalQuantityDisplay = row.totalQuantity;
// 实盘金额
row.totalPrice = new Decimal(row.totalQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
// 盈亏数量
row.itemQuantityDisplay = row.itemQuantity;
// 盈亏金额
row.profitAmount = new Decimal(row.itemQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
} else {
// 实盘数量
row.totalQuantityDisplay = formatInventory(
row.totalQuantity,
row.partPercent,
row.unitCode_dictText,
row.minUnitCode_dictText
);
// 实盘金额
row.totalPrice = new Decimal(row.totalQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
// 盈亏数量
row.itemQuantityDisplay = formatInventory(
row.itemQuantity,
row.partPercent,
row.unitCode_dictText,
row.minUnitCode_dictText
);
// 盈亏金额
row.profitAmount = new Decimal(row.itemQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
}
row.currentUnitCode = value;
}
// 处理实盘数量(全都转换为小单位数量传给后端)
function handleTotalQuantity(row) {
if (row.unitCodeMap[row.unitCode] == 'unit') {
// 实盘数量
row.totalQuantity = new Decimal(row.totalQuantityDisplay || 0)
.mul(row.partPercent || 0)
.toNumber();
// 实盘金额
row.totalPrice = new Decimal(row.totalQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
// 盈亏数量
row.itemQuantity = new Decimal(row.totalQuantity || 0)
.minus(row.orgQuantityTemp || 0)
.toNumber();
row.itemQuantityDisplay = formatInventory(
row.itemQuantity,
row.partPercent,
row.unitCode_dictText,
row.minUnitCode_dictText
);
// 盈亏金额
row.profitAmount = new Decimal(row.itemQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
} else {
// 实盘数量
row.totalQuantity = row.totalQuantityDisplay;
// 实盘金额
row.totalPrice = new Decimal(row.totalQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
// 盈亏数量
row.itemQuantity = new Decimal(row.totalQuantity || 0)
.minus(row.orgQuantityTemp || 0)
.toNumber();
row.itemQuantityDisplay = row.itemQuantity;
// 盈亏金额
row.profitAmount = new Decimal(row.itemQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
}
}
// 处理盈亏数量(全都转换为小单位数量传给后端)
function handleItemQuantity(row) {
if (row.unitCodeMap[row.unitCode] == 'unit') {
row.itemQuantity = new Decimal(row.itemQuantityDisplay || 0)
.mul(row.partPercent || 0)
.toNumber();
// 实盘数量
row.totalQuantity = new Decimal(row.orgQuantityTemp || 0)
.plus(row.itemQuantity || 0)
.toNumber();
row.totalQuantityDisplay = formatInventory(
row.totalQuantity,
row.partPercent,
row.unitCode_dictText,
row.minUnitCode_dictText
);
// 实盘金额
row.totalPrice = new Decimal(row.totalQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
// 盈亏金额
row.profitAmount = new Decimal(row.itemQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
} else {
row.itemQuantity = row.itemQuantityDisplay;
// 实盘数量
row.totalQuantity = new Decimal(row.orgQuantityTemp || 0)
.plus(row.itemQuantity || 0)
.toNumber();
row.totalQuantityDisplay = row.totalQuantity;
// 实盘金额
row.totalPrice = new Decimal(row.totalQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
// 盈亏金额
row.profitAmount = new Decimal(row.itemQuantity || 0).mul(row.minUnitPrice || 0).toFixed(2);
}
}
// 打印盘点单
function handlePrint() {
const result = [];
form.purchaseinventoryList = form.purchaseinventoryList.map((item) => {
return {
...item,
price: Number(item.price).toFixed(2),
profitAmount: Number(item.profitAmount).toFixed(2),
reasonCode_dictText: profit_reason.value.filter((k) => k.value == item.reasonCode)[0]?.label,
};
});
result.push({
purposeLocationName: form.purchaseinventoryList[0].purposeLocationName,
name: userStore.name,
totalAmount: new Decimal(totalAmount.value || 0).toFixed(2),
...receiptHeaderForm,
purchaseinventoryList: form.purchaseinventoryList,
});
console.log(result, '345678987654');
const printElements = JSON.parse(
JSON.stringify(templateJson).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName)
);
var hiprintTemplate = new hiprint.PrintTemplate({ template: printElements }); // 定义模板
hiprintTemplate.print2(result, {
// printer: 'EPSON LQ-80KFII',
title: '打印标题',
}); //开始打印
}
// 保存
function handleSave() {
addProductStocktaking(form.purchaseinventoryList).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('保存成功');
}
});
}
/** 选择条数 */
function handleSelectionChange(selection) {
// selectedData.value = selection.map((item) => ({ ...item })); // 存储选择的行数据
ids.value = selection.map((item) => item.id);
selectedRows.value = selection;
single.value = selection.length != 1;
multiple.value = !selection.length;
}
function deleteSelectedRows() {
let length = selectedRows.value.length;
if (length === 0) return;
// 收集需要删除的ID包括已保存和未保存的行
let idsToDelete = selectedRows.value
.filter((item) => item.id) // 只有有ID的才需要从数据库删除
.map((item) => item.id);
let deletePromise;
if (idsToDelete.length > 0) {
// 有需要从数据库删除的行
deletePromise = delProductStocktaking(idsToDelete);
} else {
// 没有需要从数据库删除的行创建一个立即resolve的Promise
deletePromise = Promise.resolve({ code: 200 });
}
deletePromise
.then((res) => {
if (res.code == 200) {
form.purchaseinventoryList = form.purchaseinventoryList.filter(
(row) => !selectedRows.value.includes(row)
);
// 更新状态
if (form.purchaseinventoryList && form.purchaseinventoryList.length > 0) {
data.isEdit = true;
} else {
data.isEdit = false;
}
data.isAdding = false;
proxy.$message.success('删除成功');
} else {
proxy.$message.error('删除失败');
}
})
.catch(() => {
proxy.$message.error('删除失败');
});
}
/**计算合计金额 - 已改为计算属性,自动更新,不再需要手动调用 */
// function handleTotalAmount() {
// totalAmount.value = form.purchaseinventoryList.reduce((accumulator, currentRow) => {
// return accumulator + (Number(currentRow.profitAmount) || 0);
// }, 0);
// }
// function formatSuffixUnitCode(row, quantityField) {
// if (row.unitCode) {
// return (
// row.unitCodeMap[scope.row?.unitCode] == 'minUnit' || row.totalQuantity % row.partPercent == 0
// );
// } else {
// return true;
// }
// }
/** 提交审核 */
function submitAudit() {
let length = form.purchaseinventoryList.length;
if (length < 1) {
proxy.$modal.msgWarning('请先添加单据');
} else {
submitApproval(receiptHeaderForm.busNo).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('提交审批成功');
tagsViewStore.delView(router.currentRoute.value);
// 跳转到盘点管理页面
router.replace({ path: 'chkstockRecord' });
store.clearCurrentDataPD();
emit('refresh');
visible.value = false;
}
});
}
}
function handleTraceNo(value, row) {
row.traceNo = value + ',';
}
// 切换仓库类型获取药房/药库列表 目的仓库切换
function handleChangePurposeTypeEnum(value, type) {
if (value == 16) {
getPharmacyList().then((res) => {
purposeTypeListOptions.value = res.data;
if (!route.query.supplyBusNo && !type) {
receiptHeaderForm.purposeLocationId = '';
}
});
} else if (value == 11) {
getDispensaryList().then((res) => {
purposeTypeListOptions.value = res.data;
if (!route.query.supplyBusNo && !type) {
receiptHeaderForm.purposeLocationId = '';
}
});
}
if (numValue === 16 || numValue === 11) {
console.log('Calling getpharmacyCabinetList for warehouse type:', numValue);
// 使用统一接口获取药房或药库列表
getpharmacyCabinetList().then((res) => {
console.log('getPharmacyCabinetList response:', res);
// 过滤出符合当前类型的仓库列表
const filteredList = res.data.filter(item => item.formEnum === numValue);
purposeTypeListOptions.value = filteredList;
console.log('purposeTypeListOptions set to filtered list:', purposeTypeListOptions.value);
// 设置默认仓库和货位
getinitValue();
}).catch((error) => {
console.error('getPharmacyCabinetList error:', error);
purposeTypeListOptions.value = [];
freightListOptions.value = [];
});
} else if (numValue === 17) {
console.log('Setting hardcoded consumable warehouse');
// 处理耗材库类型
// 参考采购订单模块的实现,硬编码设置中心耗材库信息
purposeTypeListOptions.value = [
{
id: "1",
name: "中心耗材库",
formEnum: 17,
children: []
}
];
console.log('purposeTypeListOptions set to:', purposeTypeListOptions.value);
// 设置默认仓库和货位
getinitValue();
} else {
console.log('Unknown value:', value);
purposeTypeListOptions.value = [];
freightListOptions.value = [];
}
}
// 切换仓库获取货位列表 -20250414
function handleCabinetChange(value) {
receiptHeaderForm.purposeLocation = '';
if (value) {
let purposeTypeListOption = purposeTypeListOptions.value.filter(
(item) => item.id === value.toString()
);
freightListOptions.value = purposeTypeListOption[0] ? purposeTypeListOption[0].children : [];
receiptHeaderForm.purposeLocation =
freightListOptions.value && freightListOptions.value.length > 0
? purposeTypeListOption[0].children[0].name
: '';
} else {
freightListOptions.value = [];
}
}
function getbusNo() {
if (route.query.supplyBusNo) {
receiptHeaderForm.busNo = route.query.supplyBusNo;
viewStatus.value = route.query.view;
sessionStorage.setItem('busNopd', '');
} else {
if (!sessionStorage.getItem('busNopd')) {
getDetailInit().then((response) => {
receiptHeaderForm.busNo = response.data.busNo;
sessionStorage.setItem('busNopd', receiptHeaderForm.busNo);
// busNoAdd.value = response.data.busNo; // 单据号新增
});
} else {
receiptHeaderForm.busNo = sessionStorage.getItem('busNopd');
}
}
}
getbusNo(); // 单据号取得
// 导出
function handleExport() {
proxy.downloadGet(
'/inventory-manage/stocktaking/excel-out',
{
busNo: supplyBusNo.value,
},
`盘点单明细_${proxy.formatDateStr(new Date(), 'YYYY-MM-DD')}.xlsx`
);
}
</script>
<style scoped>
.custom-tree-node {
display: flex;
align-items: center;
}
.title {
font-weight: bold;
font-size: large;
margin-bottom: 10px;
}
.error-border {
border: 1px solid red;
}
</style>