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端点正常
This commit is contained in:
2026-06-04 22:39:10 +08:00
parent b8d719429d
commit 1d21661a78
781 changed files with 57907 additions and 1301 deletions

View File

@@ -0,0 +1,525 @@
<template>
<div class="app-container">
<!-- 顶部查询条件 -->
<div class="table-header">
<el-select
v-model="searchParams.locationId"
class="table-header-search"
placeholder="请选择库房"
>
<el-option
v-for="item in locationOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="searchParams.startTime"
type="date"
placeholder="选择开始时间"
value-format="YYYY-MM-DD"
style="margin-right: 15px"
/>
<el-date-picker
v-model="searchParams.endTime"
class="table-header-search"
type="date"
placeholder="选择结束时间"
value-format="YYYY-MM-DD"
/>
<el-button
class="table-header-button"
type="primary"
@click="handleSearch"
>
查询
</el-button>
<el-button
class="table-header-button"
@click="resetForm"
>
重置
</el-button>
</div>
<!-- 数据表格 -->
<div class="table-container">
<el-table
v-loading="loading"
:data="reconciliationData"
style="width: 100%"
border
>
<el-table-column
prop="locationId_dictText"
label="库房"
min-width="150"
show-overflow-tooltip
/>
<el-table-column
prop="initialAmount"
label="期初金额"
min-width="160"
align="right"
/>
<el-table-column
prop="finalAmount"
label="期末金额"
min-width="160"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 1)"
>
{{ scope.row.finalAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="expectFinalAmount"
label="预期期末金额"
min-width="160"
align="right"
/>
<el-table-column
prop="offsetAmount"
label="偏移量"
min-width="100"
align="right"
/>
<el-table-column
prop="purchaseInAmount"
label="采购入库金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 2)"
>
{{ scope.row.purchaseInAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="purchaseInNumber"
label="采购入库单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="purchaseReturnAmount"
label="采购出库金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 3)"
>
{{ scope.row.purchaseReturnAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="purchaseReturnNumber"
label="采购出库单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="applyOutAmount"
label="领用出库金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 4)"
>
{{ scope.row.applyOutAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="applyOutNumber"
label="领用出库单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="applyReturnAmount"
label="领用退货金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 5)"
>
{{ scope.row.applyReturnAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="applyReturnNumber"
label="领用退货单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="transferInAmount"
label="调拨入库金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 6)"
>
{{ scope.row.transferInAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="transferInNumber"
label="调拨入库单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="transferOutAmount"
label="调拨出库金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 10)"
>
{{ scope.row.transferOutAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="transferOutNumber"
label="调拨出库单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="checkProfitLossAmount"
label="盘点盈亏金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 7)"
>
{{ scope.row.checkProfitLossAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="checkProfitLossNumber"
label="盘点盈亏单据数"
min-width="120"
align="right"
/>
<el-table-column
prop="lossAmount"
label="报损金额"
min-width="100"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 8)"
>
{{ scope.row.lossAmount }}
</div>
</template>
</el-table-column>
<el-table-column
prop="lossNumber"
label="报损单据数"
min-width="100"
align="right"
/>
<el-table-column
prop="drugIssueAmount"
label="药品发放金额"
min-width="120"
align="right"
>
<template #default="scope">
<div
style="color: dodgerblue;cursor: pointer;"
@click="skipToPage(scope, 9)"
>
{{ scope.row.drugIssueAmount }}
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup>
import {onMounted, reactive, ref} from 'vue';
import {ElMessage} from 'element-plus';
// 导入路由钩子
import {useRouter} from 'vue-router';
// 假设API模块存在实际项目中需要根据实际情况导入
import {getList, getPharmacyList} from './components/api.js';
// 创建路由实例
const router = useRouter();
// 搜索参数
const searchParams = reactive({
locationId: '',
startTime: '',
endTime: ''
});
// 搜索表单引用
const searchFormRef = ref(null);
// 库房选项
const locationOptions = ref([]);
// 对账数据
const reconciliationData = ref([]);
// 加载状态
const loading = ref(false);
// 格式化金额
const formatMoney = (value) => {
if (value === null || value === undefined) return '0.00';
return Number(value).toFixed(2);
};
// 格式化日期为YYYY-MM-DD
const formatDate = (date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 设置默认日期范围(今日之前一个月)
const setDefaultDateRange = () => {
const today = new Date();
// 结束时间为昨天
const endDate = new Date(today);
endDate.setDate(today.getDate() - 1);
// 开始时间为一个月前的今天
const startDate = new Date(today);
startDate.setMonth(today.getMonth() - 1);
// 处理月份溢出如1月减1个月变为12月
if (startDate.getMonth() === 11 && today.getMonth() === 0) {
startDate.setFullYear(today.getFullYear() - 1);
}
// 确保日期有效性(处理不同月份天数差异)
const lastDayOfMonth = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 0).getDate();
if (startDate.getDate() > lastDayOfMonth) {
startDate.setDate(lastDayOfMonth);
}
searchParams.startTime = formatDate(startDate);
searchParams.endTime = formatDate(endDate);
};
// 查询数据
const handleSearch = async () => {
try {
loading.value = true;
// 构建查询参数并拼接时间
const params = {
locationId: searchParams.locationId
};
// 处理开始时间,拼接 00:00:00
if (searchParams.startTime) {
params.startTime = searchParams.startTime + ' 00:00:00';
}
// 处理结束时间,拼接 00:00:00
if (searchParams.endTime) {
params.endTime = searchParams.endTime + ' 00:00:00';
}
// 调用API获取数据实际项目中替换为真实API调用
const response = await getList(params);
loading.value = false;
console.log('查询结果:', response)
reconciliationData.value = [];
reconciliationData.value.push(response.data.data)
} catch (error) {
ElMessage.error('获取对账数据失败: ' + (error.message || '未知错误'));
console.error('Failed to get reconciliation data:', error);
} finally {
loading.value = false;
}
};
// 重置表单
const resetForm = () => {
searchFormRef.value?.resetFields();
// 重置后重新设置默认日期范围
setDefaultDateRange();
};
// 获取库房列表
const getLocationList = async () => {
try {
// 调用API获取库房数据实际项目中替换为真实API调用
const response = await getPharmacyList();
locationOptions.value = response.data.locationListOptions || [];
// 默认选择第一个库房
if (locationOptions.value.length > 0) {
searchParams.locationId = locationOptions.value[0].value;
}
handleSearch()
} catch (error) {
ElMessage.error('获取库房数据失败: ' + (error.message || '未知错误'));
console.error('Failed to get location list:', error);
}
};
// 跳转到对应页面的函数
const skipToPage = (records, index) => {
// 获取当前选中的库房ID和日期范围
const { startTime, endTime } = searchParams;
console.log(records.row)
const { locationId } = records.row;
// 根据index跳转到不同页面
let path = '';
switch (index) {
case 1:
path = '/aa/4/chkstockPartDetails'; // 库存
break;
case 2:
path = '/aa/4/purchaseDocumentDetsils'; // 采购入库页
break;
case 3:
path = '/aa/4/purchaseReturnDetsils'; // 采购退货页
break;
case 4:
path = '/aa/4/requisitionDetails'; // 领用出库页
break;
case 5:
path = '/aa/4/returnOrutboundDetails'; // 领用退库页
break;
case 6:
case 10:
path = '/aa/4/transferManagentDetails'; // 调拨页
break;
case 7:
path = '/aa/4/chkstockPartDetails'; // 盘点页
break;
case 8:
path = '/aa/4/lossReportingDetails'; // 报损页
break;
case 9:
path = '/aa/3/medicationDetails'; // 药品发放
break;
default:
ElMessage.warning('无效的页面索引');
return;
}
// 跳转到对应页面并传递参数
if(index === 10) {
router.push({
path: path,
query: {
sourceLocationId: locationId,
occurrenceTimeSTime: startTime,
occurrenceTimeETime: endTime,
}
});
}else if(index ===1) {
router.push({
path: path,
query: {
sourceLocationId: locationId,
time: endTime,
type: '1'
}
});
}else {
router.push({
path: path,
query: {
purposeLocationId: locationId,
occurrenceTimeSTime: startTime,
occurrenceTimeETime: endTime
}
});
}
}
// 组件初始化
onMounted(() => {
// 设置默认日期范围
setDefaultDateRange();
getLocationList();
});
</script>
<style scoped>
.table-header-search {
width: 200px;
float: left;
margin-right: 15px;
}
.table-header {
margin-top: 0px;
margin-bottom: 15px;
overflow: hidden;
}
.table-header-button {
float: right;
margin-left: 10px;
}
.table-container {
background-color: #fff;
padding: 16px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
overflow-x: auto;
}
.text-red {
color: #f56c6c;
}
.text-green {
color: #67c23a;
}
</style>