Files
his/backup/vxetable-migration-20260602/medicationmanagement/storeReconciliation/index.vue
华佗 1d21661a78 feat: Spring Boot 3.5.14 全量升级 + 组件升级
核心升级:
- Spring Boot 2.7.18 → 3.5.14
- MyBatis Plus 3.5.5 → 3.5.16 (spring-boot3-starter)
- Springdoc 1.8.0 → 2.8.6 (OpenAPI 3)
- Flowable 6.8.0 → 7.1.0
- Druid 1.2.x → 1.2.28 (boot3-starter)
- kotlin-reflect 1.9.10 → 1.9.25

迁移适配:
- javax → jakarta 命名空间 (620+ 文件)
- Swagger 注解迁移到 OpenAPI 3 (@Tag/@Schema/@Operation/@Parameter)
- Spring Security 6.2 适配 (antMatchers→requestMatchers, EnableMethodSecurity)
- Druid 包名迁移 (boot→boot3)
- Redis 配置路径迁移 (spring.redis→spring.data.redis)
- Flyway 适配 (flyway-database-postgresql)
- Flowable 7.x 适配 (MULE_TASK_IMAGE 移除)

修复:
- spring-boot-maven-plugin 2.5.15→3.5.14 (SPI服务发现失效)
- mybatis-plus-boot-starter 3.5.5→3.5.16 (kotlin-reflect+fastjson2冲突)
- Flowable database-schema-update 启用自动建表

验证: 23/23 测试通过, 1374 API端点正常
2026-06-04 22:39:49 +08:00

510 lines
14 KiB
Vue
Executable File

<template>
<div class="app-container">
<el-form
ref="queryForm"
:model="queryParams"
label-width="120px"
:inline="true"
>
<el-form-item
label="药品名称/编码/拼音/五笔码"
prop="searchKey"
label-width="200px"
>
<el-input
v-model="queryParams.searchKey"
placeholder="请输入"
clearable
style="width: 350px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item
label="期初备份单据号"
prop="startBusNo"
>
<el-select
v-model="queryParams.startBusNo"
filterable
clearable
placeholder="请选择"
@change="handleQuery"
>
<el-option
v-for="(item, index) in backUpOptions"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item
label="期末备份单据号"
prop="endBusNo"
>
<el-select
v-model="queryParams.endBusNo"
filterable
clearable
placeholder="请选择"
@change="handleQuery"
>
<el-option
v-for="(item, index) in backUpOptions"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item
label="库房"
prop="locationId"
>
<el-select
v-model="queryParams.locationId"
placeholder="请选择库房"
filterable
clearable
@change="handleQuery"
>
<el-option
v-for="item in locationOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
label="是否发生过业务"
prop="isBus"
>
<el-select
v-model="queryParams.isBus"
filterable
clearable
@change="handleQuery"
>
<el-option
v-for="item in [
{ id: 1, name: '已发生业务' },
{ id: 0, name: '未发生业务' },
]"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
label="是否账平"
prop="isBalance"
>
<el-select
v-model="queryParams.isBalance"
filterable
clearable
@change="handleQuery"
>
<el-option
v-for="item in [
{ id: 1, name: '已平账' },
{ id: 0, name: '未平账' },
]"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="handleQuery"
>
查询
</el-button>
<el-button @click="resetQuery">
重置
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
:data="tableData"
border
stripe
element-loading-text="数据加载中..."
:header-cell-style="{ backgroundColor: '#f5f7fa', color: '#303133' }"
empty-text="暂无数据"
>
<el-table-column
type="expand"
width="48"
>
<template #default="{ row }">
<el-row
:gutter="10"
style="width: 100%"
>
<el-form
label-width="100px"
:inline="true"
>
<el-form-item
label="发药单据数"
:class="computedClass(row)"
>
{{ row.dispenseOrderCount }}
</el-form-item>
<el-form-item
label="退药单据数"
:class="computedClass(row)"
>
{{ row.returnOrderCount }}
</el-form-item>
<el-form-item
label="采购单据数"
:class="computedClass(row)"
>
{{ row.purchaseOrderCount }}
</el-form-item>
<el-form-item
label="退库单据数"
:class="computedClass(row)"
>
{{ row.purchaseReturnOrderCount }}
</el-form-item>
<el-form-item
label="调拨进单据数"
:class="computedClass(row)"
>
{{ row.transferInOrderCount }}
</el-form-item>
<el-form-item
label="调拨出单据数"
:class="computedClass(row)"
>
{{ row.transferOutOrderCount }}
</el-form-item>
<el-form-item
label="报损单据数"
:class="computedClass(row)"
>
{{ row.lossOrderCount }}
</el-form-item>
<el-form-item
label="盘点单据数"
:class="computedClass(row)"
>
{{ row.stocktakeOrderCount }}
</el-form-item>
<el-form-item
label="领用单据数"
:class="computedClass(row)"
>
{{ row.issueOrderCount }}
</el-form-item>
<el-form-item
label="退领单据数"
:class="computedClass(row)"
>
{{ row.returnIssueOrderCount }}
</el-form-item>
</el-form>
</el-row>
<el-row
:gutter="40"
style="width: 100%"
>
<el-col
:span="16"
class="formula-wrapper"
>
<div class="formula">
<template
v-for="segment in balanceSegments"
:key="segment.label"
>
<span
v-if="segment.operator"
class="formula-operator"
>
{{ segment.operator }}
</span>
<span class="formula-label">{{ segment.label }}</span>
<span>(</span>
<span :class="computedClass(row)">
{{ formatInventoryUnit(row[segment.field], row) }}
</span>
<span>)</span>
</template>
<span class="formula-operator">=</span>
<span class="formula-label">推算期末数</span>
<span>(</span>
<span :class="computedClass(row)">{{ computedEndNum(row) }}</span>
<span>)</span>
</div>
</el-col>
<el-col
:span="4"
class="formula-wrapper"
>
<span>期末数量</span>
<span>(</span>
<span :class="computedClass(row)">
{{ formatInventoryUnit(row.endCount, row) }}
</span>
<span>)</span>
<span class="formula-operator">-</span>
<span>推测期末数量</span>
<span>(</span>
<span :class="computedClass(row)">{{ computedEndNum(row) }}</span>
<span>)</span>
<span class="formula-operator">=</span>
<span>盈亏数量</span>
<span>(</span>
<span :class="computedClass(row)">
{{ formatInventoryUnit(row.profitLossDiff, row) }}</span>
<span>)</span>
</el-col>
</el-row>
</template>
</el-table-column>
<el-table-column
prop="itemName"
label="药品名称"
align="center"
width="200"
/>
<el-table-column
prop="itemNo"
label="项目编号"
align="center"
/>
<el-table-column
prop="unitCode_dictText"
label="单位"
align="center"
/>
<el-table-column
prop="minUnitCode_dictText"
label="最小单位"
align="center"
/>
<el-table-column
prop="totalVolume"
label="规格"
align="center"
/>
<el-table-column
prop="categoryCode_dictText"
label="药品分类"
align="center"
/>
<el-table-column
prop="manufacturerText"
label="生产厂家"
align="center"
width="300"
/>
<el-table-column
prop="partPercent"
label="拆零比"
align="center"
/>
<el-table-column
prop="isBalance"
label="是否账平"
align="center"
width="100"
>
<template #default="scope">
<el-tag
v-if="scope.row.isBalance == 1"
type="success"
>
已平账
</el-tag>
<el-tag
v-else-if="scope.row.isBalance == 0"
type="danger"
>
未平账
</el-tag>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
:total="total"
@pagination="getList"
/>
</div>
</template>
<script setup name="storeReconciliation">
import {onMounted, reactive, ref, watch} from 'vue';
import {ElMessage} from 'element-plus';
import {getBackupList, getPharmacyCabinetList, getStoreReconciliationList,} from './components/api.js';
import {formatInventory} from '@/utils/his.js';
const loading = ref(false);
const total = ref(0);
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
searchKey: '',
startBusNo: '',
endBusNo: '',
locationId: '',
isBus: 1,
isBalance: 0,
});
// 获取库存单位
function formatInventoryUnit(num, row) {
return formatInventory(num, row.partPercent, row.unitCode_dictText, row.minUnitCode_dictText);
}
// 推算期末数
function computedEndNum(row) {
if (!row) return '';
const {
startCount = 0,
dispenseCount = 0,
returnCount = 0,
purchaseCount = 0,
purchaseReturnCount = 0,
transferInCount = 0,
transferOutCount = 0,
lossCount = 0,
stocktakeCount = 0,
issueCount = 0,
returnIssueCount = 0,
} = row;
const endCount =
Number(startCount || 0) -
Number(dispenseCount || 0) +
Number(returnCount || 0) +
Number(purchaseCount || 0) -
Number(purchaseReturnCount || 0) +
Number(transferInCount || 0) -
Number(transferOutCount || 0) -
Number(lossCount || 0) +
Number(stocktakeCount || 0) -
Number(issueCount || 0) +
Number(returnIssueCount || 0);
return formatInventoryUnit(endCount, row);
}
function computedClass(row) {
if (row.isBalance == 1) {
return 'label-green';
}
if (row.isBalance == 0) {
return 'label-red';
}
return '';
}
// function
const handleQuery = () => {
queryParams.pageNo = 1;
getList();
};
const resetQuery = () => {
queryParams.locationId = '';
queryParams.startBusNo = '';
queryParams.endBusNo = '';
queryParams.isBus = 1;
queryParams.isBalance = 0;
handleQuery();
};
const tableData = ref([]);
const getList = async () => {
const response = await getStoreReconciliationList(queryParams);
tableData.value = response?.data?.records || [];
total.value = response?.data?.total || 0;
};
const locationOptions = ref([]);
const getLocationList = async () => {
try {
const response = await getPharmacyCabinetList();
locationOptions.value = response?.data || [];
queryParams.locationId = response?.data[0].id;
} catch (error) {
ElMessage.error('获取库房列表失败,请稍后重试');
}
};
const backUpOptions = ref([]);
const getBackupOptionsList = async () => {
try {
const response = await getBackupList();
backUpOptions.value = response?.data || [];
queryParams.startBusNo = response?.data[backUpOptions.value.length - 1];
} catch (error) {
ElMessage.error('获取备份单号失败,请稍后重试');
}
};
const balanceSegments = [
{ label: '期初数', field: 'startCount', operator: null },
{ label: '发药数', field: 'dispenseCount', operator: '-' },
{ label: '退药数', field: 'returnCount', operator: '+' },
{ label: '入库数', field: 'purchaseCount', operator: '+' },
{ label: '退库数', field: 'purchaseReturnCount', operator: '-' },
{ label: '调拨进数', field: 'transferInCount', operator: '+' },
{ label: '调拨出数', field: 'transferOutCount', operator: '-' },
{ label: '报损数', field: 'lossCount', operator: '-' },
{ label: '盘点数', field: 'stocktakeCount', operator: '+' },
{ label: '领用数', field: 'issueCount', operator: '-' },
{ label: '领用退数', field: 'returnIssueCount', operator: '+' },
];
watch(
[() => queryParams.locationId, () => queryParams.startBusNo],
([newLocationId, newStartBusNo]) => {
if (newLocationId && newStartBusNo) {
getList();
}
}
);
onMounted(() => {
getBackupOptionsList();
getLocationList();
});
</script>
<style lang="scss" scoped>
.label-red {
color: #f56c6c;
}
.label-green {
color: #67c23a;
}
.formula-wrapper {
margin-top: 8px;
margin-left: 12px;
}
.formula-wrapper span {
font-size: 14px;
font-weight: bold;
}
.formula {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 4px;
font-size: 14px;
line-height: 28px;
}
.formula-label {
font-weight: 500;
}
.formula-operator {
padding: 0 2px;
color: #909399;
}
</style>