diff --git a/database_migration_add_inventory_threshold.sql b/database_migration_add_inventory_threshold.sql
new file mode 100644
index 0000000..74db1bd
--- /dev/null
+++ b/database_migration_add_inventory_threshold.sql
@@ -0,0 +1,8 @@
+-- 药品库存智能预警功能数据库升级脚本
+-- 添加最低库存阈值字段
+
+-- 为药品信息表添加最低库存阈值字段
+ALTER TABLE `yaopinxinxi` ADD COLUMN `zuidikucunyuzhi` int(11) NULL DEFAULT 0 COMMENT '最低库存阈值' AFTER `kucun`;
+
+-- 更新现有记录,设置默认最低库存阈值为库存的20%(可根据实际需求调整)
+UPDATE `yaopinxinxi` SET `zuidikucunyuzhi` = FLOOR(`kucun` * 0.2) WHERE `zuidikucunyuzhi` = 0 AND `kucun` > 0;
diff --git a/manage_code/src/views/yaopinxinxi/formModel.vue b/manage_code/src/views/yaopinxinxi/formModel.vue
index f0e561a..3208731 100644
--- a/manage_code/src/views/yaopinxinxi/formModel.vue
+++ b/manage_code/src/views/yaopinxinxi/formModel.vue
@@ -55,6 +55,14 @@
+
+
+
+
+
+
药品库存统计
+
+
+
+ 库存预警
+
+
+
+ 采购建议
@@ -111,6 +119,17 @@
{{scope.row.kucun}}
+
+
+ {{scope.row.zuidikucunyuzhi}}
+
+
{
@@ -439,6 +458,51 @@
})
})
}
+ //显示低库存预警
+ const showLowStockAlert = () => {
+ context.$http({
+ url: `${tableName}/lowstock`,
+ method: 'get'
+ }).then(res=>{
+ let lowStockList = res.data.data
+ if(lowStockList.length === 0) {
+ context.$message.success('当前所有药品库存均在正常范围内')
+ return
+ }
+ let message = '以下药品库存低于阈值:\n\n'
+ lowStockList.forEach(item => {
+ message += `药品名称:${item.yaopinmingcheng}\n当前库存:${item.kucun}\n最低阈值:${item.zuidikucunyuzhi}\n\n`
+ })
+ context.$alert(message, '低库存详情', {
+ confirmButtonText: '确定',
+ type: 'warning'
+ })
+ })
+ }
+ //显示采购建议
+ const showPurchaseSuggestions = () => {
+ context.$http({
+ url: `${tableName}/purchase/suggestions`,
+ method: 'get'
+ }).then(res=>{
+ let suggestions = res.data.data
+ if(suggestions.length === 0) {
+ context.$message.success('当前所有药品库存充足,无需采购')
+ return
+ }
+ let message = '药品采购建议清单:\n\n'
+ let totalCost = 0
+ suggestions.forEach(item => {
+ message += `药品名称:${item.yaopinmingcheng}\n规格:${item.guige}\n当前库存:${item.currentStock}\n最低阈值:${item.threshold}\n建议采购数量:${item.suggestedQuantity}\n预计费用:¥${item.estimatedCost.toFixed(2)}\n\n`
+ totalCost += item.estimatedCost
+ })
+ message += `预计总费用:¥${totalCost.toFixed(2)}`
+ context.$alert(message, '采购建议详情', {
+ confirmButtonText: '确定',
+ type: 'success'
+ })
+ })
+ }
import rukujiluFormModel from '@/views/rukujilu/formModel'
const rukujiluFormModelRef = ref(null)
const rukujiluCrossAddOrUpdateHandler = (row,type,crossOptAudit,crossOptPay,statusColumnName,tips,statusColumnValue) => {
@@ -473,15 +537,31 @@
}
//初始化
const init = () => {
- let urlkucun = 'yaopinxinxi/remind/kucun/1'
- urlkucun+=`?remindend=5`
- urlkucun+=`&remindstart=0`
context.$http({
- url: urlkucun,
+ url: `${tableName}/lowstock/count`,
method: 'get'
}).then(res=>{
if(res.data.count>0) {
- context?.$alert(`库存有${res.data.count}条记录达到预警`)
+ context.$alert(`库存有${res.data.count}条记录达到预警`, '库存预警提示', {
+ confirmButtonText: '查看详情',
+ callback: (action) => {
+ if (action === 'confirm') {
+ context.$http({
+ url: `${tableName}/lowstock`,
+ method: 'get'
+ }).then(res=>{
+ let lowStockList = res.data.data
+ let message = '以下药品库存低于阈值:\n\n'
+ lowStockList.forEach(item => {
+ message += `药品名称:${item.yaopinmingcheng}\n当前库存:${item.kucun}\n最低阈值:${item.zuidikucunyuzhi}\n\n`
+ })
+ context.$alert(message, '低库存详情', {
+ confirmButtonText: '确定'
+ })
+ })
+ }
+ }
+ })
}
})
getList()
diff --git a/server_code/src/main/java/com/cl/controller/ChukujiluController.java b/server_code/src/main/java/com/cl/controller/ChukujiluController.java
index 39cece5..b36ece1 100644
--- a/server_code/src/main/java/com/cl/controller/ChukujiluController.java
+++ b/server_code/src/main/java/com/cl/controller/ChukujiluController.java
@@ -28,12 +28,15 @@
import com.cl.entity.view.ChukujiluView;
import com.cl.service.ChukujiluService;
+import com.cl.service.YaopinxinxiService;
import com.cl.service.TokenService;
import com.cl.utils.PageUtils;
import com.cl.utils.R;
import com.cl.utils.MPUtil;
import com.cl.utils.MapUtils;
import com.cl.utils.CommonUtil;
+import com.cl.entity.YaopinxinxiEntity;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
/**
* 出库记录
@@ -47,6 +50,9 @@
public class ChukujiluController {
@Autowired
private ChukujiluService chukujiluService;
+
+ @Autowired
+ private YaopinxinxiService yaopinxinxiService;
@@ -139,9 +145,25 @@ public R detail(@PathVariable("id") Long id){
*/
@RequestMapping("/save")
@SysLog("新增出库记录")
+ @Transactional
public R save(@RequestBody ChukujiluEntity chukujilu, HttpServletRequest request){
//ValidatorUtils.validateEntity(chukujilu);
chukujiluService.insert(chukujilu);
+
+ YaopinxinxiEntity drug = yaopinxinxiService.selectOne(new EntityWrapper()
+ .eq("yaopinmingcheng", chukujilu.getYaopinmingcheng()));
+
+ if (drug != null) {
+ Integer currentStock = drug.getKucun() != null ? drug.getKucun() : 0;
+ Integer outboundQuantity = chukujilu.getKucun() != null ? chukujilu.getKucun() : 0;
+ Integer newStock = currentStock - outboundQuantity;
+ if (newStock < 0) {
+ newStock = 0;
+ }
+ drug.setKucun(newStock);
+ yaopinxinxiService.updateById(drug);
+ }
+
return R.ok();
}
diff --git a/server_code/src/main/java/com/cl/controller/RukujiluController.java b/server_code/src/main/java/com/cl/controller/RukujiluController.java
index 065aeb5..6bab179 100644
--- a/server_code/src/main/java/com/cl/controller/RukujiluController.java
+++ b/server_code/src/main/java/com/cl/controller/RukujiluController.java
@@ -28,12 +28,15 @@
import com.cl.entity.view.RukujiluView;
import com.cl.service.RukujiluService;
+import com.cl.service.YaopinxinxiService;
import com.cl.service.TokenService;
import com.cl.utils.PageUtils;
import com.cl.utils.R;
import com.cl.utils.MPUtil;
import com.cl.utils.MapUtils;
import com.cl.utils.CommonUtil;
+import com.cl.entity.YaopinxinxiEntity;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
/**
* 入库记录
@@ -47,6 +50,9 @@
public class RukujiluController {
@Autowired
private RukujiluService rukujiluService;
+
+ @Autowired
+ private YaopinxinxiService yaopinxinxiService;
@@ -139,9 +145,21 @@ public R detail(@PathVariable("id") Long id){
*/
@RequestMapping("/save")
@SysLog("新增入库记录")
+ @Transactional
public R save(@RequestBody RukujiluEntity rukujilu, HttpServletRequest request){
//ValidatorUtils.validateEntity(rukujilu);
rukujiluService.insert(rukujilu);
+
+ YaopinxinxiEntity drug = yaopinxinxiService.selectOne(new EntityWrapper()
+ .eq("yaopinmingcheng", rukujilu.getYaopinmingcheng()));
+
+ if (drug != null) {
+ Integer currentStock = drug.getKucun() != null ? drug.getKucun() : 0;
+ Integer inboundQuantity = rukujilu.getKucun() != null ? rukujilu.getKucun() : 0;
+ drug.setKucun(currentStock + inboundQuantity);
+ yaopinxinxiService.updateById(drug);
+ }
+
return R.ok();
}
diff --git a/server_code/src/main/java/com/cl/controller/YaopinxinxiController.java b/server_code/src/main/java/com/cl/controller/YaopinxinxiController.java
index 1729cb2..521e441 100644
--- a/server_code/src/main/java/com/cl/controller/YaopinxinxiController.java
+++ b/server_code/src/main/java/com/cl/controller/YaopinxinxiController.java
@@ -381,6 +381,22 @@ public R count(@RequestParam Map params,YaopinxinxiEntity yaopin
return R.ok().put("data", count);
}
+ @RequestMapping("/lowstock")
+ public R getLowStockDrugs() {
+ List lowStockDrugs = yaopinxinxiService.selectLowStockDrugs();
+ return R.ok().put("data", lowStockDrugs).put("count", lowStockDrugs.size());
+ }
+
+ @RequestMapping("/lowstock/count")
+ public R getLowStockCount() {
+ List lowStockDrugs = yaopinxinxiService.selectLowStockDrugs();
+ return R.ok().put("count", lowStockDrugs.size());
+ }
+ @RequestMapping("/purchase/suggestions")
+ public R getPurchaseSuggestions() {
+ List