Merge branch 'main' of ssh://git.jizhiweb.cn:2222/clinic-v2/web

# Conflicts:
#	src/views/charge/index.vue
This commit is contained in:
LiJianZhao 2025-05-13 11:32:42 +08:00
commit a99c5e654b
9 changed files with 33 additions and 803 deletions

View File

@ -2,27 +2,26 @@
import Panel from '../common/Panel.vue';
import {defineEmits, defineModel,defineProps} from 'vue'
const {status}=defineProps(['status'])
const emit = defineEmits(['save','deleteItem','edit','openCheckOut']);
const emit = defineEmits(['save','deleteItem','edit']);
const save = () => {
emit('save');
};
const openCheckOut= () => {
emit('openCheckOut');
};
const deleteItem = () => {
emit('deleteItem');
};
const totalAmount = defineModel<any>()
const editItem= () => {
emit('edit');
};
</script>
<template>
<Panel :showTools="false" :showHeader="false">
<div class="footer">
<div>总金额<span class="text icon"></span><span class="text">{{ totalAmount || '0' }}</span></div>
<div class="btn-group" v-if="status == 0">
<el-button type="primary" @click="openCheckOut()">追溯码</el-button>
<el-button type="primary" @click="save">收费</el-button>
<div class="btn-group" v-if="status">
<el-button type="primary" disabled>追溯码</el-button>
<el-button type="primary" @click="editItem">收费</el-button>
</div>
</div>
</Panel>

View File

@ -1,85 +0,0 @@
<template>
<Panel :title="'病历'">
<template #tools>
<div class="content">
<div class="model-selector">
<el-select v-model="modelType">
<el-option label="西医模板" :value="0"/>
<el-option label="中医模板" :value="1"/>
<el-option label="口腔模板" :value="2"/>
</el-select>
</div>
</div>
</template>
<div class="container">
<el-form :model="formDate" label-width="auto" ref="formRef">
<el-descriptions
:column="1"
label-width="100px"
border
>
<el-descriptions-item label="主诉">
<div>{{ formDate.mainAppeal}}</div>
</el-descriptions-item>
<el-descriptions-item label="诊断">
<div>{{ formDate.diagnosisSummary}}</div>
</el-descriptions-item>
<el-descriptions-item label="现病史">
<div>{{ formDate.nowMedicalHistory}}</div>
</el-descriptions-item>
<el-descriptions-item label="既往史">
<div>{{ formDate.beforeMedicalHistory}}</div>
</el-descriptions-item>
<el-descriptions-item label="过敏史">
<div>{{ formDate.allergyHistory}}</div>
</el-descriptions-item>
<el-descriptions-item label="体格检查">
<div>{{ formDate.exam}}</div>
</el-descriptions-item>
<el-descriptions-item label="望闻问切" v-if="modelType==1">
<div>{{ formDate.chinaAdjunctCheck}}</div>
</el-descriptions-item>
<el-descriptions-item label="法制" v-if="modelType==1">
<div>{{ formDate.chinaDeal}}</div>
</el-descriptions-item>
<el-descriptions-item label="口腔检查" v-if="modelType==2">
<div>{{ formDate.mouthCheck}}</div>
</el-descriptions-item>
<el-descriptions-item label="辅助检查" v-if="modelType==2 || modelType ==0">
<div>{{ formDate.adjunctCheck}}</div>
</el-descriptions-item>
<el-descriptions-item label="处置" v-if="modelType==0 || modelType ==2">
<div>{{ formDate.deal}}</div>
</el-descriptions-item>
</el-descriptions>
</el-form>
</div>
</Panel>
</template>
<script setup lang="ts">
import {ref} from "vue";
import Panel from "@/components/common/Panel.vue";
const formDate = defineModel<any>();
const modelType = ref(0)
interface ShowConfig {
label: string;
prop: string;
}
</script>
<style scoped lang="scss">
.content {
display: flex;
.model-selector {
width: 100px;
}
}
.container {
margin-left: 20px;
}
</style>

View File

@ -70,7 +70,6 @@ const clickTab = (item: any) => {
curStatus.value = item.status
emit('changeTab')
curItem.value = {}
}
const setDate = function () {
if (datePickerRef.value) {
@ -99,7 +98,6 @@ const itemId = defineModel()
onMounted(() => {
selectedDate.value = getCurrentDate()
initStatusList()
curItem.value = itemId
if (curStatus.value == 1) {
init()
}
@ -117,8 +115,15 @@ const init = async () => {
endTime: getEndOfDay(new Date(selectedDate.value))
}
}, {catch_error: true});
list.value = data.list
if (itemId.value != null) {
list.value.forEach((item: any, index: any) => {
if (item.id == itemId.value) {
clickLi(item, false)
}
})
}
} catch (e) {
} finally {
@ -138,7 +143,7 @@ const initStatusList = () => {
}
const clickLi = (item: any, showBox: any = true) => {
curItem.value = item
if (item!=null&&item.status == 1 && showBox) {
if (item != null && item.status == 1 && showBox) {
ElMessageBox.confirm(`您将要接诊${item.name}`, "提示", {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -225,6 +230,7 @@ watch(() => selectedDate.value, (newValue, oldValue) => {
position: relative;
margin: 16px 0;
padding: 0 16px;
.search-icon {
position: absolute;
left: 32px;
@ -234,6 +240,7 @@ watch(() => selectedDate.value, (newValue, oldValue) => {
height: 16px; //
z-index: 1;
}
.search-input {
width: 100%;
height: 42px;
@ -255,9 +262,11 @@ watch(() => selectedDate.value, (newValue, oldValue) => {
display: flex;
min-height: 0;
flex-direction: column;
ul {
flex: 1;
min-height: 0;
.list-item {
height: 48px;
display: flex;
@ -269,9 +278,11 @@ watch(() => selectedDate.value, (newValue, oldValue) => {
color: rgba(34, 42, 57, 0.7);
font-style: normal;
cursor: pointer;
span {
display: flex;
align-items: center;
.avatar {
width: 26px;
height: 26px;

View File

@ -1,261 +0,0 @@
<template>
<Panel :title="'药品耗材'">
<div class="content">
<div class="list">
<ul>
<li class="item" v-for="(item, index) in list" :key="index">
<div class="index">{{ index + 1 }}</div>
<div class="name">
<el-popover
placement="top-start"
trigger="hover"
width="500"
@show="getHilistInfo(item)"
@hide="colosInfo"
>
<template #reference>
{{ item.name }}
</template>
<div class="detail">
<div style="display: flex;justify-content: space-between">
<div style="font-size: 18px;font-weight: 500;color: #000">{{ hilistInfo.name }}[{{ hilistInfo.json?.category||'-' }}]</div>
<div>{{ item.selectedPrice }}/{{ item.selectedUnit }}</div>
</div>
<div style="display: flex;justify-content: space-between">
<div>规格:{{hilistInfo.json?.dosage_specifications||'-'}}</div>
<div>生产厂商:{{hilistInfo.json?.producer||'-'}}</div>
<div>限价:{{hilistInfo.json?.stock||'0'}}</div>
</div>
<div style="display: flex;justify-content: space-between">
<div>批准文号:{{hilistInfo.json?.approval_number||'-'}}</div>
<div>本位码:{{hilistInfo.json?.standard_code ||'-'}}</div>
</div>
<div style="display: flex;justify-content: space-between">
<div>限价:{{ hilistInfo.hilistPricUplmtAmt ? hilistInfo.hilistPricUplmtAmt : '无' }}</div>
<div>限价类型:{{ hilistInfo.hilistLmtpricType ? hilistInfo.hilistLmtpricType : '无' }}</div>
</div>
</div>
</el-popover>
</div>
<div class="price">{{ item.selectedPrice || '0' }}</div>
<div class="unit">
<div class="unit-content">
<el-input-number v-model="item.selectedNum" min="1" size="small"></el-input-number>
<el-dropdown>
<span style="line-height: 30px;margin-left: 10px">{{ item.selectedUnit }}</span>
<template #dropdown>
<el-dropdown-menu v-if="item.trdnFlag == 1">
<el-dropdown-item @click="selectUnit(item,item.packagingUnit)">{{ item.packagingUnit }}
</el-dropdown-item>
<el-dropdown-item @click="selectUnit(item,item.minPackagingUnit)">{{ item.minPackagingUnit }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<div class="sub-price">{{ item.unitPrice * item.selectedNum }}</div>
<div class="delete">
<div @click="deleteItem(item.id)" class="delete-btn">
<el-icon>
<Close/>
</el-icon>
</div>
</div>
</li>
</ul>
</div>
<div class="search">
<div class="search-input">
<SearchInput
:request-api="itemSearchApi"
:show-config="itemShowConfig"
@selectedCallBack="itemSelect"
:placeholder="'请输入药材名称'"
:disabled="disabled"
@focus="focus"
>
</SearchInput>
</div>
<span style="margin-right: 24px">
{{ sumPrice }}
</span>
</div>
</div>
</Panel>
</template>
<script setup lang="ts">
import Panel from "@/components/common/Panel.vue";
import SearchInput from "@/components/SearchInput.vue";
import {CircleClose, Close} from "@element-plus/icons-vue";
import {watch, ref, computed} from "vue";
import {post} from "@/utils/request.ts";
const props = defineProps({
status: {
type: Number,
default: 0
}
})
const disabled = computed(() => {
if (props.status === 1) {
return true
}
})
const itemSearchApi = "goods/goods/search";
const itemShowConfig = [
{
label: "项目名称",
prop: "name",
},
{
label: "项目类型",
prop: "type",
},
{
label: "售价",
prop: "unitPrice",
},
]
const itemSelect = (row: any) => {
row.selectedNum = 1
row.selectedUnit = row.packagingUnit
row.selectedPrice = row.unitPrice
list.value.push(row)
}
const deleteItem = (id: any) => {
list.value = list.value.filter((item) => item.id !== id);
};
const list = defineModel<any[]>({default: () => []});
const selectUnit = (item: any, unit: any) => {
item.selectedUnit = unit;
if (unit == item.packagingUnit) {
item.selectedPrice = item.unitPrice
return
}
if (unit == item.minPackagingUnit) {
item.selectedPrice = item.disassemblyPrice
}
}
const sumPrice = ref(0)
const emit = defineEmits(['focus'])
const focus = (e: any) => {
emit('focus', e)
}
const hilistInfo = ref<any>({})
const getHilistInfo = (item: any) => {
if (item.hilistCode) {
post("social/directory/getByCode", {code: item.hilistCode}).then((res: any) => {
hilistInfo.value = res
})
}
}
const colosInfo = () => {
hilistInfo.value = {}
}
watch(() => list.value, (newList) => {
sumPrice.value = newList.reduce((total, item) => {
return total + (item.selectedNum || 0) * (item.selectedPrice || 0);
}, 0);
}, {deep: true})
</script>
<style scoped lang="scss">
@use "@/assets/scss/base";
.content {
display: flex;
flex-direction: column;
.list {
flex: 1;
min-height: 0;
.item {
height: 30px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
.index {
height: 100%;
width: 50px;
text-align: center;
line-height: 30px;
}
.name {
flex: 1;
margin-left: 10px;
height: 100%;
line-height: 30px;
}
.code {
flex: 1;
margin-left: 10px;
height: 100%;
line-height: 30px;
}
.price {
height: 100%;
width: 100px;
text-align: center;
line-height: 30px;
}
.unit {
height: 100%;
width: 180px;
margin-left: 10px;
line-height: 30px;
.unit-content {
display: flex;
align-items: center;
}
}
.sub-price {
height: 100%;
line-height: 30px;
}
.delete {
height: 100%;
width: 100px;
text-align: center;
line-height: 30px;
.delete-btn {
cursor: pointer;
&:hover {
color: base.$primary-color;
}
}
}
}
}
.search {
height: 64px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
.search-input {
height: 100%;
flex: 1;
}
}
}
</style>

View File

@ -1,96 +0,0 @@
<template>
<Panel :title="'药品耗材'">
<div class="content">
<div class="list">
<ul>
<li class="item" v-for="(item, index) in list" :key="index">
<span class="index">{{ index + 1 }}</span>
<span class="name">{{ item.name }}</span>
<span class="unit">{{ item.selectedNum || 0 }}{{ item.selectedUnit }}</span>
<span class="price">{{ item.selectedPrice || '0' }}</span>
</li>
</ul>
</div>
<div class="search">
<span style="margin-left: 24px">合计</span>
<span style="margin-right: 24px">{{ list.reduce((acc, cur) => acc + cur.selectedNum*cur.selectedPrice, 0) }}</span>
</div>
</div>
</Panel>
</template>
<script setup lang="ts">
import Panel from "@/components/common/Panel.vue";
const list = defineModel<any[]>({default: () => []});
</script>
<style scoped lang="scss">
.content {
display: flex;
flex-direction: column;
.list {
flex: 1;
min-height: 0;
.item {
height: 30px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
justify-content: space-between;
.index {
height: 100%;
width: 50px;
text-align: center;
line-height: 30px;
border-right: 1px solid #EAEAEC;
}
.name {
flex: 1;
margin-left: 10px;
border-right: 1px solid #EAEAEC;
height: 100%;
line-height: 30px;
}
.type {
flex: 1;
margin-left: 10px;
border-right: 1px solid #EAEAEC;
height: 100%;
line-height: 30px;
}
.unit {
flex: 1;
margin-left: 10px;
border-right: 1px solid #EAEAEC;
height: 100%;
line-height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.price {
height: 100%;
width: 200px;
line-height: 30px;
border-right: 1px solid #EAEAEC;
text-align: center;
}
}
}
.search {
height: 64px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>

View File

@ -1,218 +0,0 @@
<template>
<Panel :title="'服务项目'">
<div class="content">
<div class="list">
<ul>
<li class="item" v-for="(item, index) in list" :key="index">
<div class="index">{{ index + 1 }}</div>
<div class="name">
<el-popover
width="485"
@show="show(item)"
@hide="hide"
>
<template #reference>
{{ item.itemName }}
</template>
<div class="detail">
<div style="display: flex;justify-content: space-between">
<div style="font-size: 18px;font-weight: 500;color: #000">{{
itemInfo.name
}}[{{ chrgitm_lv[itemInfo.chrgitmLv as keyof typeof chrgitm_lv || '-'] || '-' }}]
</div>
<div>{{ item.unitPrice }}/{{ item.unit }}</div>
</div>
<div style="display: flex;justify-content: space-between">
<div>限制条件:{{ itemInfo.lmtUsedFlag == 0 ? '否' : itemInfo.lmtUsedFlag == 1 ? '是' : '-' }}</div>
<div> 医保码:{{ item.itemSocialCode || '-' }}</div>
</div>
</div>
</el-popover>
</div>
<div class="price">{{ item.unitPrice }}</div>
<div class="unit">
<div style="display: flex; align-items: center;">
<el-input-number v-model="item.selectedNum" min="1" size="small"></el-input-number>
<span style="margin-left: 10px; line-height: 30px;">{{ item.unit }}</span>
</div>
</div>
<div class="sub-price">{{ item.unitPrice * item.selectedNum }}</div>
<div class="delete">
<div @click="deleteItem(item.id)" class="delete-btn">
<el-icon>
<Close/>
</el-icon>
</div>
</div>
</li>
</ul>
</div>
<div class="search">
<div class="search-input">
<SearchInput
:request-api="serviceSearchApi"
:show-config="serviceShowConfig"
@selectedCallBack="serviceSelect"
:placeholder="'请输入项目名称'"
:disabled="disabled"
@focus="focus"
>
</SearchInput>
</div>
<span style="margin-right: 24px">{{
list.reduce((acc, cur) => acc + cur.unitPrice * cur.selectedNum, 0)
}}</span></div>
</div>
</Panel>
</template>
<script setup lang="ts">
import {defineModel, computed, defineEmits, ref} from "vue";
import Panel from "@/components/common/Panel.vue";
import {Close} from '@element-plus/icons-vue'
import SearchInput from "@/components/SearchInput.vue";
import {post} from "@/utils/request.ts";
import chrgitm_lv from "@/assets/config/directory/chrgitmLv.json"
const props = defineProps({
status: {
type: Number,
default: 0
}
})
const disabled = computed(() => {
if (props.status === 1) {
return true
}
})
const serviceSearchApi = "item/search";
const serviceShowConfig = [
{
label: "服务名称",
prop: "itemName",
},
{
label: "单价",
prop: "unitPrice",
},
{
label: "单位",
prop: "unit",
},
]
const serviceSelect = (row: any) => {
row.selectedNum = 1
list.value.push(row)
}
const list = defineModel<any[]>({default: () => []});
const deleteItem = (id: any) => {
list.value = list.value.filter((item) => item.id !== id);
};
const emit = defineEmits(['focus'])
const focus = (e: any) => {
emit('focus', e)
}
const itemInfo = ref<any>({});
const show = (item: any) => {
post('social/directory/getItemByCode', {code: item.itemSocialCode}).then((res: any) => {
itemInfo.value = res
})
}
const hide = () => {
itemInfo.value = {}
}
</script>
<style scoped lang="scss">
@use "@/assets/scss/base";
.content {
display: flex;
flex-direction: column;
.list {
flex: 1;
min-height: 0;
.item {
height: 30px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
.index {
height: 100%;
width: 50px;
text-align: center;
line-height: 30px;
}
.name {
flex: 1;
margin-left: 10px;
height: 100%;
line-height: 30px;
white-space: nowrap; /* 防止文本换行 */
overflow: hidden; /* 隐藏溢出的文本 */
text-overflow: ellipsis; /* 显示省略号 */
}
.code {
flex: 1;
margin-left: 10px;
height: 100%;
line-height: 30px;
}
.price {
height: 100%;
width: 100px;
text-align: center;
line-height: 30px;
}
.unit {
height: 100%;
width: 180px;
margin-left: 10px;
line-height: 30px;
}
.sub-price {
height: 100%;
line-height: 30px;
}
.delete {
height: 100%;
width: 100px;
text-align: center;
line-height: 30px;
.delete-btn {
cursor: pointer;
&:hover {
color: base.$primary-color;
}
}
}
}
}
.search {
width: 100%;
height: 64px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
.search-input {
height: 100%;
flex: 1;
}
}
}
</style>

View File

@ -1,120 +0,0 @@
<template>
<Panel :title="'服务项目'">
<div class="content">
<div class="list">
<ul>
<li class="item" v-for="(item, index) in list" :key="index">
<span class="index">{{ index + 1 }}</span>
<span class="name"> <el-popover
width="485"
@show="show(item)"
@hide="hide"
>
<template #reference>
{{ item.itemName }}
</template>
<div class="detail">
<div style="display: flex;justify-content: space-between">
<div style="font-size: 18px;font-weight: 500;color: #000">{{ itemInfo.name }}[{{ chrgitm_lv[itemInfo.chrgitmLv as keyof typeof chrgitm_lv || '-'] || '-' }}]</div>
<div>{{ item.unitPrice }}/{{item.unit }}</div>
</div>
<div style="display: flex;justify-content: space-between">
<div>限制条件:{{ itemInfo.lmtUsedFlag == 0 ? '否' : itemInfo.lmtUsedFlag == 1 ? '是' : '-'}}</div>
<div> 医保码:{{item.itemSocialCode||'-'}}</div>
</div>
</div>
</el-popover>
</span>
<span class="unit">{{item.selectedNum}}{{ item.selectedUnit }}</span>
<span class="price">{{ item.selectedPrice }}</span>
</li>
</ul>
</div>
<div class="search">
<span style="margin-left: 24px">合计</span>
<span style="margin-right: 24px">{{ list.reduce((acc, cur) => acc + cur.selectedNum*cur.selectedPrice, 0) }}</span>
</div>
</div>
</Panel>
</template>
<script setup lang="ts">
import Panel from "@/components/common/Panel.vue";
import {ref} from "vue";
import {post} from "@/utils/request.ts";
import chrgitm_lv from "@/assets/config/directory/chrgitmLv.json"
const list = defineModel<any[]>({default: () => []});
const itemInfo = ref<any>({});
const show = (item:any) => {
post('social/directory/getItemByCode',{code:item.itemSocialCode}).then((res:any)=>{
itemInfo.value = res
})
}
const hide = () => {
itemInfo.value = {}
}
</script>
<style scoped lang="scss">
.content {
display: flex;
flex-direction: column;
.list {
flex: 1;
min-height: 0;
.item {
height: 30px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
justify-content: space-between;
.index{
height: 100%;
width: 50px;
text-align: center;
border-right: 1px solid #EAEAEC;
line-height: 30px;
}
.name{
flex: 1;
margin-left: 10px;
border-right: 1px solid #EAEAEC;
height: 100%;
line-height: 30px;
}
.code{
flex: 1;
margin-left: 10px;
border-right: 1px solid #EAEAEC;
height: 100%;
line-height: 30px;
}
.unit{
width: 60px;
margin-left: 10px;
border-right: 1px solid #EAEAEC;
height: 100%;
line-height: 30px;
text-align: center;
}
.price{
height: 100%;
width: 200px;
line-height: 30px;
border-right: 1px solid #EAEAEC;
text-align: center;
}
}
}
.search {
height: 64px;
border-top: 1px solid #EAEAEC;
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>

View File

@ -110,6 +110,14 @@
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="费用类型">
<el-form-item prop="type">
<el-select v-model="edit_data.type">
<el-option label="普通" :value="1"></el-option>
<el-option label="医保" :value="2"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item
label="备注">
<el-form-item>

View File

@ -6,7 +6,6 @@
<div class="middle">
<el-scrollbar>
<div class="case">
<!-- <CaseDetail v-if="patientRegistration.status==3" v-model="formData"></CaseDetail>-->
<Case ref="caseRef" v-model="formData" :disabled="curRegister?.status !=2" :isShowFrom="isShowFrom"
@focus="focus"></Case>
</div>
@ -40,17 +39,10 @@
import MedicalQueue from "@/components/outpatient/MedicalQueue.vue";
import MedicalHistory from "@/components/outpatient/MedicalHistory.vue";
import Case from "@/components/outpatient/Case.vue";
import ServiceItems from "@/components/outpatient/ServiceItems.vue";
import PharmaceuticalConsumables from "@/components/outpatient/PharmaceuticalConsumables.vue";
import {ref, watch, nextTick, onMounted} from "vue";
import Settlement from "@/components/outpatient/Settlement.vue";
import {post} from "@/utils/request.ts";
import {type Action, ElMessage, ElMessageBox} from "element-plus";
import ServiceItemsDetail from "@/components/outpatient/ServiceItemsDetail.vue";
import PharmaceuticalConsumablesDetail from "@/components/outpatient/PharmaceuticalConsumablesDetail.vue";
import CaseDetail from "@/components/outpatient/CaseDetail.vue";
import {apiConfig} from "@/assets/config/apiConfig.ts";
import PatientCard from "@/components/charge/PatientCard.vue";
import ServiceDetail from "@/components/common/service/ServiceDetail.vue";
@ -118,11 +110,10 @@ const patientCardRef = ref()
const patientRegistration = ref<any>({})
const clickItem = (item: any) => {
curRegister.value = item
if(!item)return
if (!item) return
registerId.value = item.id
itemId.value = item.id
patientId.value = item.patientInfoId
if (item.status == 2) {
initFormData()
}
@ -140,7 +131,7 @@ const clickItem = (item: any) => {
}
nextTick(() => {
medicalHistoryRef.value?.init(patientId.value);
patientCardRef.value?.init(curRegister.value.id)
patientCardRef.value?.init(curRegister.value?.id)
})
}
@ -153,6 +144,7 @@ const cancelReception = () => {
const changeTab = (e: any) => {
initFormData()
patientRegistration.value = {}
itemId.value = null
nextTick(() => {
medicalHistoryRef.value?.clearList();
})