增加手工入库的功能
This commit is contained in:
parent
6910ed417a
commit
a492ea4091
47
.trae/skills/blood-system/SKILL.md
Normal file
47
.trae/skills/blood-system/SKILL.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
name: blood-system
|
||||
description: 输血系统前端项目编码规范与业务约束。在编写、修改、审查输血系统(blood_vue)前端代码时自动应用,涵盖组件写法、TS类型、接口请求、表单校验、安全约束等规则。
|
||||
---
|
||||
|
||||
# 项目基础信息
|
||||
|
||||
- 项目名称:输血系统
|
||||
- 前端项目:blood_vue
|
||||
- 后端项目:blood
|
||||
- 技术栈:Vue3 + TypeScript + Element Plus + Vite + Pinia + Axios + scss
|
||||
- 后端:springboot + mybatis + redis
|
||||
- 数据库:sqlserver2008
|
||||
- 编码语言:中文注释,提示、弹窗文案使用中文
|
||||
|
||||
# 强制编码规则
|
||||
|
||||
1. 组件统一使用 `<script setup>` 语法糖,禁止使用 Options API;单文件组件结构顺序:script setup lang="ts" → template → style
|
||||
2. 变量命名:小驼峰;常量全大写下划线;组件名大驼峰;禁止拼音命名,业务字段使用业务英文缩写
|
||||
3. TS类型:所有接口入参、返回体、表单对象必须定义 interface/type,禁止 any;尽量使用 readonly 约束只读数据
|
||||
4. 样式:统一使用 scoped,优先使用 Element Plus 自带样式,自定义 class 采用 BEM 命名,禁止全局污染
|
||||
5. 导入:按顺序导入:vue内置包 → 第三方依赖 → 项目组件 → 工具函数 → 静态资源;统一使用 import,不使用 require
|
||||
6. 每次新增组件,需要增加组件注释说明
|
||||
|
||||
# 接口请求规范
|
||||
|
||||
1. 所有请求必须使用项目已封装 axios 实例,禁止直接原生 axios;统一拦截器处理 token、401、500
|
||||
2. 后端返回固定结构 `{code:number, msg:string, data:any}`,code=200 或 0 代表成功;业务异常统一捕获提示
|
||||
3. 接口请求必须写 TS 类型定义,请求参数、返回 data 都要定义 interface;增加注释说明接口用途、业务场景
|
||||
|
||||
# 表单 & 校验
|
||||
|
||||
1. Element Plus ElForm,表单校验规则抽离单独 rules 对象;必填项添加 required:true,提示文案友好
|
||||
2. 检验项目、标本类型、状态下拉选项,统一维护枚举常量,不要硬编码写死在 template
|
||||
3. 保存、提交按钮:提交期间增加 loading 状态,防止重复提交;表单提交前先触发全部校验
|
||||
|
||||
# 业务与安全约束
|
||||
|
||||
1. 禁止:前端硬编码密钥、token、账号密码;禁止直接拼接 SQL 相关参数;禁止 eval 危险函数
|
||||
2. 弹窗提示:操作类动作(删除、取消、作废)必须增加确认弹窗;成功/失败给出 toast 提示
|
||||
|
||||
# AI 输出约束
|
||||
|
||||
1. 输出代码优先完整片段,不要省略关键逻辑;新增组件同时补充 interface 类型
|
||||
2. 给出代码后,附带简短说明:改动点、注意事项、需要后端配合的字段
|
||||
3. 不要生成多余无关代码,保持简洁;如存在多种方案,优先选择和现有项目一致的写法
|
||||
4. 如修改已有代码,先展示原有代码片段,再给出修改后的代码,标注改动位置
|
||||
33
src/api/blood/handInStorage.ts
Normal file
33
src/api/blood/handInStorage.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
export function getBloodBreed(query?: Object) {
|
||||
return request({
|
||||
url: "/bus/bloodbank/handInStorage/getBloodBreed",
|
||||
method: "get",
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
export function saveData(data?: Object) {
|
||||
return request({
|
||||
url: "/bus/bloodbank/handInStorage/saveData",
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function queryList(query?: Object) {
|
||||
return request({
|
||||
url: "/bus/bloodbank/handInStorage/queryList",
|
||||
method: "get",
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
export function queryDetail(query?: Object) {
|
||||
return request({
|
||||
url: "/bus/bloodbank/handInStorage/queryDetail",
|
||||
method: "get",
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
@ -767,6 +767,30 @@ aside {
|
||||
color: #FFF !important;
|
||||
}
|
||||
|
||||
// SelectTable 下拉表格:行高30px,单元格内容垂直居中
|
||||
.select-table-dropdown {
|
||||
// 覆盖 vxe 默认行高(48px)与文字行高(22px),vxe 会按该变量计算单元格内联高度
|
||||
--vxe-ui-table-row-height-default: 30px;
|
||||
--vxe-ui-table-row-line-height: 30px;
|
||||
|
||||
.vxe-table {
|
||||
.vxe-header--column,
|
||||
.vxe-body--column {
|
||||
.vxe-cell {
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
line-height: 30px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.vxe-cell--wrapper {
|
||||
line-height: 30px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条
|
||||
.mytable-style ::-webkit-scrollbar {
|
||||
width: .6rem;
|
||||
|
||||
709
src/views/blood/handInStorage/index.vue
Normal file
709
src/views/blood/handInStorage/index.vue
Normal file
@ -0,0 +1,709 @@
|
||||
<template>
|
||||
<div class="hand-in-storage">
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-left">
|
||||
<el-button type="primary" plain :icon="Search" @click="handleSearch">检索</el-button>
|
||||
<el-button type="success" plain :icon="Plus" @click="handleAdd">新增</el-button>
|
||||
<el-button type="warning" plain :icon="Fold" @click="handleSave" :loading="saveLoading">保存</el-button>
|
||||
<el-button type="info" plain :icon="Printer">打印</el-button>
|
||||
<el-button type="primary" plain :icon="Upload">导入</el-button>
|
||||
<el-button type="danger" plain :icon="Close" @click="handleClose">关闭</el-button>
|
||||
</div>
|
||||
<!-- <div class="toolbar-right">
|
||||
<el-checkbox v-model="printDetail">打印明细</el-checkbox>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="section-title">入库信息</div>
|
||||
<el-form :model="mainForm" label-width="100px" label-position="left">
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="入库单号">
|
||||
<el-input v-model="mainForm.bill_no" disabled placeholder="自动生成" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="入库时间">
|
||||
<el-date-picker v-model="mainForm.occur_date" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="入库时间" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="经手人">
|
||||
<SelectTable v-model:data="mainForm.handle_person" :tableData="userList" placeholder="经手人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="血液来源">
|
||||
<div class="source-box">
|
||||
<el-select v-model="mainForm.source_type" placeholder="血站" style="width: 80px"
|
||||
@change="handleSourceType">
|
||||
<el-option label="血站" value="1" />
|
||||
<el-option label="其它" value="2" />
|
||||
</el-select>
|
||||
<el-input v-model="mainForm.org" placeholder="请输入来源" style="flex: 1" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="血站出库时间">
|
||||
<el-date-picker v-model="mainForm.out_date" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="出库时间" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="mainForm.remark" placeholder="备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="24">
|
||||
<el-checkbox v-model="cancelBlood">取消血液</el-checkbox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="left-panel">
|
||||
<div class="left-panel-scroll">
|
||||
<el-form :model="bloodForm" label-width="90px" label-position="left">
|
||||
<el-form-item label="血液流水号">
|
||||
<el-input v-model="bloodForm.blood_no" placeholder="请输入血液流水号" @keyup.enter="handleScan" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品号">
|
||||
<el-input v-model="bloodForm.product_no" placeholder="产品号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="血液品种">
|
||||
<el-select v-model="bloodForm.blood_breed" placeholder="请选择血液品种" filterable
|
||||
style="width: 100%" @change="handleBreedChange">
|
||||
<el-option v-for="item in bloodBreedList" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="血型">
|
||||
<el-select v-model="bloodForm.blood_type" placeholder="请选择血型" style="width: 100%">
|
||||
<el-option v-for="item in bloodTypeOptions" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="Rh(D)">
|
||||
<el-select v-model="bloodForm.rh_blood_type" placeholder="Rh(D)" style="width: 100%">
|
||||
<el-option label="+" value="+" />
|
||||
<el-option label="-" value="-" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="容量">
|
||||
<div class="capacity-box">
|
||||
<el-input v-model="bloodForm.capacity" placeholder="容量" style="flex: 1" />
|
||||
<el-input v-model="bloodForm.unit" placeholder="单位" style="width: 60px" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="有效日期">
|
||||
<el-date-picker v-model="bloodForm.valid_date" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="有效日期" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="采血日期">
|
||||
<el-date-picker v-model="bloodForm.pick_date" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="采血日期" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入库价格">
|
||||
<el-input-number v-model="bloodForm.price" :precision="2" :step="0.01" :min="0"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Plus" @click="handleAddBlood">添加</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="stat-box">
|
||||
<div class="section-title">汇总信息</div>
|
||||
<BloodTypeStatTable :data="bloodList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-panel">
|
||||
<div class="section-title">入库列表</div>
|
||||
<el-table :data="bloodList" border highlight-current-row @current-change="handleRowSelect">
|
||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||
<el-table-column prop="blood_no" label="血液流水号" width="140" align="center" />
|
||||
<el-table-column prop="blood_breed" label="血液品种" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatBloodBreed(row.blood_breed) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="blood_type" label="血型" width="60" align="center" />
|
||||
<el-table-column prop="rh_blood_type" label="Rh(D)" width="60" align="center" />
|
||||
<el-table-column prop="capacity" label="容量" width="70" align="center" />
|
||||
<el-table-column prop="unit" label="单位" width="60" align="center" />
|
||||
<el-table-column prop="special_deal" label="特别处理" width="80" align="center" />
|
||||
<el-table-column prop="valid_date" label="有效日期" width="150" align="center" />
|
||||
<el-table-column prop="pick_date" label="采血日期" width="150" align="center" />
|
||||
<el-table-column prop="remark" label="备注" align="center" />
|
||||
<el-table-column prop="product_no" label="产品码" width="120" align="center" />
|
||||
<!-- 删除血液 -->
|
||||
<el-table-column label="操作" align="center" :show-overflow-tooltip="false">
|
||||
<template #default="{ row, $index }">
|
||||
<el-button type="primary" text @click="delBlood(row, $index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="searchDialogVisible" title="入库检索" width="700px" :close-on-click-modal="false">
|
||||
<el-form :model="searchForm" label-width="100px">
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="入库单号">
|
||||
<el-input v-model="searchForm.billNo" placeholder="入库单号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="科室">
|
||||
<el-input v-model="searchForm.dept" placeholder="科室" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="入库时间">
|
||||
<div class="date-range">
|
||||
<el-date-picker v-model="searchForm.stime" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="开始时间" style="width: 45%" />
|
||||
<span class="separator">-</span>
|
||||
<el-date-picker v-model="searchForm.etime" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="结束时间" style="width: 45%" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div class="dialog-table-box">
|
||||
<el-button type="primary" :icon="Search" @click="doSearch">查询</el-button>
|
||||
<el-button :icon="Refresh" @click="resetSearch">重置</el-button>
|
||||
<el-table :data="queryResultList" border highlight-current-row height="280"
|
||||
@current-change="handleQueryRowSelect">
|
||||
<el-table-column prop="bill_no" label="入库单号" width="140" align="center" />
|
||||
<el-table-column prop="occur_date" label="入库时间" width="160" align="center" />
|
||||
<el-table-column prop="handle_person" label="经手人" width="100" align="center" />
|
||||
<el-table-column prop="total_money" label="总金额" width="100" align="center" />
|
||||
<el-table-column prop="remark" label="备注" align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="searchDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmSelect">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs'
|
||||
import { Search, Plus, Fold, Printer, Upload, Close, Refresh } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { useCommonDict } from '@/hooks'
|
||||
import { getBloodBreed, saveData, queryList, queryDetail } from '@/api/blood/handInStorage'
|
||||
import BloodTypeStatTable from '@/components/BloodTypeStatTable/index.vue'
|
||||
|
||||
const userInfo = useUserStore()
|
||||
const { getServerTime, bloodBreed: bloodBreedList, getBloodList, userList, getUserData } = useCommonDict()
|
||||
|
||||
const printDetail = ref(false)
|
||||
const cancelBlood = ref(false)
|
||||
const resetBloodAfterScan = ref(false)
|
||||
const saveLoading = ref(false)
|
||||
const searchDialogVisible = ref(false)
|
||||
|
||||
const selectedBloodRow = ref<any>(null)
|
||||
const selectedQueryRow = ref<any>(null)
|
||||
|
||||
const bloodTypeOptions = [
|
||||
{ label: 'A', value: 'A' },
|
||||
{ label: 'B', value: 'B' },
|
||||
{ label: 'O', value: 'O' },
|
||||
{ label: 'AB', value: 'AB' }
|
||||
]
|
||||
|
||||
const mainForm = ref<any>({
|
||||
bill_no: '',
|
||||
occur_date: '',
|
||||
handle_person: userInfo.name,
|
||||
source_type: '1',
|
||||
org: '',
|
||||
out_date: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const bloodForm = ref<any>({
|
||||
blood_no: '',
|
||||
product_no: '',
|
||||
blood_breed: '',
|
||||
blood_type: '',
|
||||
rh_blood_type: '+',
|
||||
capacity: '',
|
||||
unit: '',
|
||||
valid_date: '',
|
||||
pick_date: '',
|
||||
produce_date: '',
|
||||
price: 0,
|
||||
special_deal: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const bloodList = ref<any[]>([])
|
||||
|
||||
const searchForm = ref<any>({
|
||||
billNo: '',
|
||||
dept: '',
|
||||
stime: '',
|
||||
etime: ''
|
||||
})
|
||||
|
||||
const queryResultList = ref<any[]>([])
|
||||
|
||||
const formatBloodBreed = (code: string) => {
|
||||
const item = bloodBreedList.value.find((b: any) => b.value === code)
|
||||
return item ? item.label : code
|
||||
}
|
||||
|
||||
const handleSourceType = () => {
|
||||
if (mainForm.value.source_type === '1') {
|
||||
mainForm.value.org = ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleBreedChange = (val: string) => {
|
||||
if (val) {
|
||||
getBloodBreed({ breedCode: val }).then((res: any) => {
|
||||
if (res.data) {
|
||||
bloodForm.value.unit = res.data.unit || bloodForm.value.unit
|
||||
bloodForm.value.product_no = res.data.station_breed_code || bloodForm.value.product_no
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 入库前必填项校验:血液品种、血型、Rh(D)血型、产品号、容量、有效日期
|
||||
const validateBloodForm = () => {
|
||||
if (!bloodForm.value.blood_breed) {
|
||||
ElMessage.warning('请选择血液品种')
|
||||
return false
|
||||
}
|
||||
if (!bloodForm.value.blood_type) {
|
||||
ElMessage.warning('请选择血型')
|
||||
return false
|
||||
}
|
||||
if (!bloodForm.value.rh_blood_type) {
|
||||
ElMessage.warning('请选择Rh(D)血型')
|
||||
return false
|
||||
}
|
||||
if (!bloodForm.value.product_no) {
|
||||
ElMessage.warning('请输入产品号')
|
||||
return false
|
||||
}
|
||||
if (!bloodForm.value.capacity) {
|
||||
ElMessage.warning('请输入容量')
|
||||
return false
|
||||
}
|
||||
if (!bloodForm.value.valid_date) {
|
||||
ElMessage.warning('请选择有效日期')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const handleScan = () => {
|
||||
const bloodNo = bloodForm.value.blood_no?.trim()
|
||||
if (!bloodNo) return
|
||||
const index = bloodList.value.findIndex(item => item.blood_no === bloodNo)
|
||||
if (cancelBlood.value) {
|
||||
// 取消血液:从入库列表中删除对应血液流水号数据
|
||||
if (index > -1) {
|
||||
const removed = bloodList.value.splice(index, 1)
|
||||
if (selectedBloodRow.value === removed[0]) {
|
||||
selectedBloodRow.value = null
|
||||
}
|
||||
ElMessage.success('已取消血液:' + bloodNo)
|
||||
} else {
|
||||
ElMessage.warning('入库列表中不存在该血液流水号')
|
||||
}
|
||||
bloodForm.value.blood_no = ''
|
||||
return
|
||||
}
|
||||
if (index > -1) {
|
||||
ElMessage.warning('该血液流水号已存在')
|
||||
bloodForm.value.blood_no = ''
|
||||
return
|
||||
}
|
||||
if (!validateBloodForm()) return
|
||||
bloodList.value.push({ ...bloodForm.value })
|
||||
if (resetBloodAfterScan.value) {
|
||||
resetBloodForm()
|
||||
} else {
|
||||
bloodForm.value.blood_no = ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddBlood = () => {
|
||||
if (!bloodForm.value.blood_no) {
|
||||
return ElMessage.warning('请输入血液流水号')
|
||||
}
|
||||
// 勾选“取消血液”时,添加按钮也执行取消删除逻辑
|
||||
if (cancelBlood.value) {
|
||||
handleScan()
|
||||
return
|
||||
}
|
||||
if (!validateBloodForm()) return
|
||||
const exists = bloodList.value.some(item => item.blood_no === bloodForm.value.blood_no)
|
||||
if (exists) {
|
||||
ElMessage.warning('该血液流水号已存在')
|
||||
return
|
||||
}
|
||||
bloodList.value.push({ ...bloodForm.value })
|
||||
resetBloodForm()
|
||||
}
|
||||
|
||||
const resetBloodForm = () => {
|
||||
bloodForm.value = {
|
||||
blood_no: '',
|
||||
product_no: '',
|
||||
blood_breed: '',
|
||||
blood_type: '',
|
||||
rh_blood_type: '+',
|
||||
capacity: '',
|
||||
unit: '',
|
||||
valid_date: '',
|
||||
pick_date: '',
|
||||
produce_date: '',
|
||||
price: 0,
|
||||
special_deal: '',
|
||||
remark: ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleRowSelect = (row: any) => {
|
||||
selectedBloodRow.value = row
|
||||
}
|
||||
|
||||
const delBlood = (row: any, index: number) => {
|
||||
bloodList.value.splice(index, 1)
|
||||
if (selectedBloodRow.value === row) {
|
||||
selectedBloodRow.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
searchDialogVisible.value = true
|
||||
searchForm.value = {
|
||||
billNo: '',
|
||||
dept: '',
|
||||
stime: dayjs().subtract(30, 'day').format('YYYY-MM-DD') + ' 00:00:00',
|
||||
etime: dayjs().format('YYYY-MM-DD') + ' 23:59:59'
|
||||
}
|
||||
doSearch()
|
||||
}
|
||||
|
||||
const doSearch = () => {
|
||||
queryList(searchForm.value).then((res: any) => {
|
||||
queryResultList.value = res.data || []
|
||||
})
|
||||
}
|
||||
|
||||
const resetSearch = () => {
|
||||
searchForm.value = {
|
||||
billNo: '',
|
||||
dept: '',
|
||||
stime: '',
|
||||
etime: ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleQueryRowSelect = (row: any) => {
|
||||
selectedQueryRow.value = row
|
||||
}
|
||||
|
||||
const confirmSelect = () => {
|
||||
if (!selectedQueryRow.value) {
|
||||
ElMessage.warning('请选择一条记录')
|
||||
return
|
||||
}
|
||||
queryDetail({ billNo: selectedQueryRow.value.bill_no }).then((res: any) => {
|
||||
if (res.data) {
|
||||
const main = res.data.xkInstorageMain || {}
|
||||
// 数据库存的是姓名(nick_name),回显时转换回用户代号以匹配下拉选项
|
||||
main.handle_person = userList.value.find(v => v.label === main.handle_person)?.value || main.handle_person
|
||||
mainForm.value = main
|
||||
bloodList.value = res.data.xkBloodInfoList || []
|
||||
}
|
||||
searchDialogVisible.value = false
|
||||
selectedQueryRow.value = null
|
||||
})
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
getServerTime().then((time: string) => {
|
||||
mainForm.value = {
|
||||
bill_no: '',
|
||||
occur_date: time,
|
||||
handle_person: userInfo.name,
|
||||
source_type: '1',
|
||||
org: '',
|
||||
out_date: time,
|
||||
remark: ''
|
||||
}
|
||||
})
|
||||
bloodList.value = []
|
||||
resetBloodForm()
|
||||
selectedBloodRow.value = null
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
if (!mainForm.value.occur_date) {
|
||||
return ElMessage.warning('请选择入库时间')
|
||||
}
|
||||
if (!mainForm.value.handle_person) {
|
||||
return ElMessage.warning('请选择经手人')
|
||||
}
|
||||
if (bloodList.value.length === 0) {
|
||||
return ElMessage.warning('请添加血液信息')
|
||||
}
|
||||
|
||||
const xkInstorageDetailList = bloodList.value.map((item, index) => ({
|
||||
sid: index + 1,
|
||||
bill_no: '',
|
||||
blood_no: item.blood_no,
|
||||
product_no: item.product_no,
|
||||
price: item.price || 0,
|
||||
remark: item.remark || ''
|
||||
}))
|
||||
|
||||
const xkBloodInfoList = bloodList.value.map(item => ({
|
||||
blood_no: item.blood_no,
|
||||
product_no: item.product_no,
|
||||
blood_breed: item.blood_breed,
|
||||
blood_type: item.blood_type,
|
||||
rh_blood_type: item.rh_blood_type,
|
||||
capacity: item.capacity,
|
||||
unit: item.unit,
|
||||
valid_date: item.valid_date,
|
||||
pick_date: item.pick_date,
|
||||
produce_date: item.produce_date,
|
||||
special_deal: item.special_deal,
|
||||
Remark: item.remark || ''
|
||||
}))
|
||||
|
||||
const totalMoney = bloodList.value.reduce((sum: number, item: any) => sum + (Number(item.price) || 0), 0)
|
||||
|
||||
const data = {
|
||||
xkInstorageMain: {
|
||||
bill_no: '',
|
||||
org: mainForm.value.org,
|
||||
out_date: mainForm.value.out_date,
|
||||
occur_date: mainForm.value.occur_date,
|
||||
// 下拉选的是用户代号,入库时写入姓名(nick_name)
|
||||
handle_person: userList.value.find(v => v.value === mainForm.value.handle_person)?.label || mainForm.value.handle_person,
|
||||
remark: mainForm.value.remark,
|
||||
total_money: totalMoney
|
||||
},
|
||||
xkInstorageDetailList,
|
||||
xkBloodInfoList
|
||||
}
|
||||
|
||||
saveLoading.value = true
|
||||
saveData(data).then((res: any) => {
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('保存成功,入库单号:' + res.data)
|
||||
mainForm.value.bill_no = res.data
|
||||
}
|
||||
}).finally(() => {
|
||||
saveLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
ElMessageBox.confirm('确定关闭当前录入吗?未保存的数据将丢失', '提示', {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
handleAdd()
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getBloodList()
|
||||
getUserData()
|
||||
getServerTime().then((time: string) => {
|
||||
mainForm.value.occur_date = time
|
||||
mainForm.value.out_date = time
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hand-in-storage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// height: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
// overflow-y: auto;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
flex: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-section {
|
||||
flex: none;
|
||||
padding: 10px 15px;
|
||||
background: #fafbfc;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
padding: 0 0 6px 10px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 7px;
|
||||
width: 4px;
|
||||
height: 14px;
|
||||
background-color: #409eff;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 380px;
|
||||
flex: 0 0 380px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fafbfc;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.left-panel-scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fafbfc;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
|
||||
.el-table {
|
||||
min-height: 59vh;
|
||||
}
|
||||
}
|
||||
|
||||
// .stat-box {
|
||||
// flex: none;
|
||||
// flex-shrink: 0;
|
||||
// padding-top: 10px;
|
||||
// border-top: 1px solid #ebeef5;
|
||||
// background: #fafbfc;
|
||||
|
||||
// .total-row {
|
||||
// display: flex;
|
||||
// justify-content: space-between;
|
||||
// align-items: center;
|
||||
// padding: 8px 12px;
|
||||
// background: #ecf5ff;
|
||||
// border-radius: 4px;
|
||||
// margin-top: 8px;
|
||||
|
||||
// .total-num {
|
||||
// font-size: 18px;
|
||||
// font-weight: 700;
|
||||
// color: #409eff;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
.source-box {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.capacity-box {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ml20 {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.date-range {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
.separator {
|
||||
margin: 0 8px;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-table-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
:deep(.left-panel .el-form-item__label) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@ -48,8 +48,8 @@ export default defineConfig(({ mode, command }) => {
|
||||
proxy: {
|
||||
// https://cn.vitejs.dev/config/#server-proxy
|
||||
"/dev-api": {
|
||||
// target: "http://localhost:8907",
|
||||
target: "http://47.97.125.165:8907",
|
||||
target: "http://localhost:8907",
|
||||
//target: "http://47.97.125.165:8907",
|
||||
changeOrigin: true,
|
||||
rewrite: (p) => p.replace(/^\/dev-api/, ""),
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user