fix:问题修复

This commit is contained in:
huxuejian 2026-08-25 11:12:05 +08:00
parent 77ea2c242d
commit 0b84a35b4e
9 changed files with 410 additions and 2 deletions

View File

@ -1,6 +1,7 @@
VITE_TCB_PATH = "zytHlwHospital"
VITE_TCB_PATH = "hlwyy"
VITE_NEED_LOGIN = "true"
VITE_NEED_IM = "true"
VITE_NEED_CA = "true"
VITE_CORP_ID = "4G7H8J2K9L0M1N3P5Q6R7S8T9U"
VITE_API_URL = "https://hlw.zytzymz.com"
VITE_API_URL = "https://hlwyy.hnkhhospital.com"
VITE_STORE_QRCODE_BASE="https://hlwyy.hnkhhospital.com/hlwyy/hnhlw?type=store&storeId="

View File

@ -60,4 +60,13 @@ export default [
title: "账户管理",
},
},
{
name: "DEPTMANAGE",
path: "/DEPTMANAGE",
component: () => import("../views/dept-manage/dept-manage"),
meta: {
keepAlive: false,
title: "科室管理",
},
}
];

View File

@ -35,6 +35,7 @@ export default defineStore("medicineConfigStore", () => {
usageList: medicineConfigGroup.value['store-medicine-administration'] || [],
unitList: medicineConfigGroup.value['medicine-package-unit'] || [],
dosageFormList: medicineConfigGroup.value['medicine-dosage-form'] || [], // 药品剂型
useTimeList: medicineConfigGroup.value['medicine-use-time'] || [], // 用药时机
}))

View File

@ -0,0 +1,77 @@
<template>
<el-dialog :model-value="visible" :width="width" title="修改科室" @close="close()">
<div class="flex h-50vh">
<el-scrollbar class="flex-shrink-0 w-240px border-r border-gray-200">
<classify-list v-model="deptIds" enableSelect :data="cateList" :mult="false"/>
</el-scrollbar>
<el-scrollbar class="flex-grow">
<div v-for="i in depts" :key="i.value" class="flex items-center py-10px px-15px border-b border-gray-200">
<div class="w-0 flex-grow truncate">{{ i.label }}</div>
<div class="text-gray-500 hover:text-red-500 cursor-pointer" @click="remove(i.value)"> <el-icon
class="flex-shrink-0" :size="14">
<CloseBold />
</el-icon></div>
</div>
</el-scrollbar>
</div>
<template #footer>
<div text-center>
<el-button plain class="w-100px" type="primary" :icon="Plus" @click="close()">取消</el-button>
<el-button class="w-100px" :loading="loading" type="primary" :icon="Plus" @click="confirm()">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { computed, ref, watch } from "vue";
import { ElMessage } from "element-plus";
import classifyList from '@/components/classify-list/classify-list-side.vue';
import { updateHlwPerson } from "@/api/hlw";
const emits = defineEmits(["close", "change"]);
const props = defineProps({
cateList: { type: Array, default: () => ([]) },
dept: { type: Object, default: () => ({}) },
staff: { type: Object, default: () => ({}) },
visible: { type: Boolean, default: false },
width: { type: [String, Number], default: "500px" },
});
const deptIds = ref([]);
const depts = computed(() => props.cateList.filter(item => deptIds.value.includes(item.value)))
const loading = ref(false);
function close() {
emits("close");
}
async function confirm() {
if (loading.value) return;
if (deptIds.value.length === 0) {
ElMessage.error('请选择科室');
} else {
loading.value = true;
const dept = props.cateList.find(item => item._id === deptIds.value[0]);
const { success, message } = await updateHlwPerson({ deptCode: dept.deptId,deptName:dept.deptName,corpId: sessionStorage.getItem('corpId'), _id: props.staff._id });
if (success) {
ElMessage.success('修改成功');
emits('change')
close()
} else {
ElMessage.error(message);
}
loading.value = false;
}
}
function remove(value) {
deptIds.value = deptIds.value.filter(item => item !== value)
}
watch(() => props.visible, (n) => {
if (n) {
const dept =props.cateList.find(item => item.deptId === props.staff.deptCode);
deptIds.value = dept ? [dept._id] : [];
}
}
);
</script>

View File

@ -0,0 +1,168 @@
<template>
<div bg-fff flex class="h-full">
<div h-full flex-shrink-0 class="w-3/10 min-w-240px max-w-320px border-r border-gray-200">
<classify-list v-bind="componentProps" custom :checked-cate="current" :data="cateList" placeholder="输入科室名称搜索"
label="科室" :label-option="{ edit: '编辑' }" @change="changeCurrent($event)" @search="getCateList()"
@onHandle="handle">
<template #header>
<div color-normal class="text-16px font-semibold mb-15px">科室列表</div>
</template>
</classify-list>
</div>
<div h-full flex-grow>
<my-layout v-if="current">
<layout-item>
<div class="text-16px font-semibold px-15px pt-15px pb-5px">{{ current.label }}</div>
<el-tabs v-model="activeName">
<el-tab-pane name="staff">
<template #label>
<span class="px-15px">科室人员</span>
</template>
</el-tab-pane>
<el-tab-pane name="detail">
<template #label>
<span class="px-15px">科室详情</span>
</template>
</el-tab-pane>
</el-tabs>
</layout-item>
<layout-main v-show="activeName === 'staff'" :scroll="false">
<el-table stripe height="100%" :data="list" v-loading="loading">
<el-table-column prop="doctorName" label="姓名" :min-width="100" />
<el-table-column prop="doctorNo" label="员工工号" :min-width="100" />
<el-table-column prop="job" label="岗位" :min-width="100">
<template #default="{ row }">
{{ jobMap[row.job] || '' }}
</template>
</el-table-column>
<el-table-column prop="deptName" label="科室" :min-width="100" />
<el-table-column fixed="right" class-name="el-table-fixed-column--shadow" label="操作" width="160">
<template #default="{ row }">
<el-text class="cursor-pointer mr-5px" type="primary" @click="changeDept(row)">修改科室</el-text>
<el-text class="cursor-pointer mr-5px" type="primary" @click="remove(row._id)">移除</el-text>
</template>
</el-table-column>
</el-table>
</layout-main>
<layout-main v-if="currentDept" v-show="activeName === 'detail'">
<div class="flex px-15px">
<el-form class="flex-grow" label-suffix="" label-width="90">
<el-form-item label="科室名称">{{ currentDept.deptName }}</el-form-item>
<el-form-item label="科室ID">{{ currentDept.deptId }}</el-form-item>
<el-form-item label="科室介绍">{{ currentDept.deptDesc }}</el-form-item>
</el-form>
<el-button class="flex-shrink-0" text type="primary" @click="handle(currentDept)">编辑</el-button>
</div>
</layout-main>
<layout-item>
<pagination :totalRow="total" :pageSize="pageSize" :currentPage="page" @handle-size-change="changeSize"
@handle-current-change="changePage" />
</layout-item>
</my-layout>
</div>
</div>
<!-- @change="getCateList()" -->
<dept-modal :visible="visible" :width="width" :dept="dept" @close="close" @change="handleDeptChange" />
<change-dept-modal :cateList="cateList" :staff="currentStaff" :visible="changeDeptVisible" :width="changeDeptWidth"
@close="changeDeptClose" @change="getList()" />
</template>
<script setup>
import { computed, ref, onMounted } from "vue";
import { storeToRefs } from 'pinia';
import { ElMessage, ElMessageBox } from "element-plus";
import { getDeptList, addDept, deleteDept, updateDept, sortDeptList, getDeptStaff, removeDeptStaff } from "@/api/dept-manage";
import useModal from "@/hooks/useModal";
import { getHlwPersonList, updateHlwPerson } from "@/api/hlw";
import useClassifyList from "@/components/classify-list/useClassifyList";
import useElPagination from "@/hooks/useElPagination";
import MyLayout, { LayoutMain, LayoutItem } from "@/components/layout";
import pagination from "@/components/pagination/pagination.vue";
import classifyList from "@/components/classify-list/classify-list.vue";
import changeDeptModal from "./change-dept-modal.vue";
import deptModal from "./dept-modal.vue";
const { close, show, visible, width } = useModal(640);
const { close: changeDeptClose, show: changeDeptShow, visible: changeDeptVisible, width: changeDeptWidth } = useModal(640);
const jobList = [
{ label: '互联网医院医生', value: 'doctor' },
{ label: '互联网医院药师', value: 'pharmacist' },
]
const jobMap = jobList.reduce((acc, item) => {
acc[item.value] = item.label;
return acc;
}, {});
const activeName = ref("staff");
const list = ref([]);
const total = ref(0);
const currentStaff = ref({})
const loading = ref(false);
const options = {
add: addDept,
remove: deleteDept,
update: updateDept,
sort: sortDeptList,
getList: getDeptList,
callback: getList,
format: list => list.map(i => ({ ...i, label: i.deptName, value: i._id })),
};
const { cateList, current, getCateList, changeCurrent, componentProps } = useClassifyList(options);
const currentDept = computed(() => cateList.value.find(i => current.value && current.value._id && i._id === current.value._id))
const dept = ref({});
const { page, pageSize, changePage, changeSize } = useElPagination(getList);
const deptCodes = computed(() => {
const childrenIds = current.value && Array.isArray(current.value.childrenIds) ? [...current.value.childrenIds] : [];
const currentId = current.value ? current.value._id : '';
const ids = [currentId, ...childrenIds].filter(Boolean);
return cateList.value.filter(i => ids.includes(i._id)).map(i => i.deptId);
})
function handle(data = {}) {
dept.value = data
show();
}
async function getList() {
if (current.value._id) {
const { data } = await getHlwPersonList({ corpId: sessionStorage.getItem("corpId"), deptCodes: deptCodes.value, page: page.value, pageSize: pageSize.value });
list.value = data && Array.isArray(data.data) ? data.data : [];
total.value = typeof data.total === 'number' && data.total >= 0 ? data.total : 0;
} else {
list.value = [];
total.value = 0
}
}
async function remove(_id) {
await ElMessageBox.confirm("确认是否把该员工移除?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
const { success, message } = await updateHlwPerson({ corpId: sessionStorage.getItem('corpId'), deptCode: '', deptName: '', _id });
if (success) {
ElMessage.success(message);
getList();
} else {
ElMessage.error(message);
}
}
async function handleDeptChange() {
await getCateList();
if (dept.value && current.value && dept.value._id === current.value._id) {
getList();
}
}
function changeDept(staff) {
currentStaff.value = staff;
changeDeptShow();
}
</script>

View File

@ -0,0 +1,110 @@
<template>
<el-dialog :model-value="visible" :width="width" :title="`${dept._id ? '编辑' : '新增'}科室`" @close="close()">
<el-scrollbar wrap-class="el-dialog-body-full-scroll">
<el-form class="p-15px" label-suffiix="" :label-width="100" label-suffix="">
<div v-if="!dept._id && dept.parentId" color-normal class="mb-15px pl-10px text-14px font-semibold">
{{dept.parentName}}下方新增科室
</div>
<el-form-item class="is-required" label="科室名称">
<el-input v-model.trim="form.deptName" :maxlength="10" placeholder="请输入科室名称" />
</el-form-item>
<el-form-item class="is-required" label="科室ID">
<div class="flex-grow">
<el-input v-model="form.deptId" placeholder="请输入科室ID" />
<div class="text-12px text-gray-500 mt-12px">科室ID可以为数字或者字母组合请勿重复</div>
</div>
</el-form-item>
<el-form-item label="科室介绍">
<el-input type="textarea" v-model="form.deptDesc" placeholder="请输入科室介绍" maxlength="500"
:autosize="{ minRows: 6, maxRows: 10 }" resize="none" show-word-limit></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
<template #footer>
<div text-center>
<el-button plain class="w-100px" type="primary" :icon="Plus" @click="close()">取消</el-button>
<el-button class="w-100px" :loading="loading" type="primary" :icon="Plus" @click="confirm()">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { computed, ref, watch } from "vue";
import { ElMessage } from "element-plus";
import { addDept, updateDept } from "@/api/dept-manage";
const emits = defineEmits(["close", "change"]);
const props = defineProps({
dept: { type: Object, default: () => ({}) },
visible: { type: Boolean, default: false },
width: { type: [String, Number], default: "500px" },
});
const form = ref({});
const loading = ref(false);
function close() {
emits("close");
}
function confirm() {
if (loading.value) return;
if (form.value.deptName.trim() === '') {
ElMessage.info("科室名称不能为空");
} else if (form.value.deptId.trim() === '') {
ElMessage.info("科室ID不能为空");
} else if (!/^[a-zA-Z0-9]+$/.test(form.value.deptId.trim())) {
ElMessage.info("科室ID只能由数字或者字母组合");
}
loading.value = true;
if (props.dept._id) {
update()
} else {
add()
}
loading.value = false;
}
async function add() {
const payload = {
corpId: sessionStorage.getItem('corpId'),
params: { ...form.value },
}
if (props.dept.parentId) {
payload.parentId = props.dept.parentId
}
const { success, message } = await addDept(payload);
if (success) {
ElMessage.success(message);
emits('change')
close()
} else {
ElMessage.error(message);
}
}
async function update() {
const payload = {
corpId: sessionStorage.getItem('corpId'),
id: props.dept._id,
params: { ...form.value },
}
const { success, message } = await updateDept(payload);
if (success) {
ElMessage.success(message);
emits('change', payload)
close()
} else {
ElMessage.error(message);
}
}
watch(
() => props.visible,
(n) => {
if (n) {
form.value.deptName = typeof props.dept.deptName === "string" ? props.dept.deptName.trim() : "";
form.value.deptId = typeof props.dept.deptId === "string" ? props.dept.deptId.trim() : "";
form.value.deptDesc = typeof props.dept.deptDesc === "string" ? props.dept.deptDesc.trim() : "";
}
}
);
</script>

View File

@ -23,6 +23,7 @@ export const drugFieldDict = [
{ name: '通用名拼音码', field: 'generic_pinyin', verify: (val, label) => verifyString(val, label) },
{ name: '抗生素级别', field: 'antibiotic_level', verify: (val, label) => verifyListItem(val, [0, 1, 2, 3], false, label, 0) },
{ name: '肿瘤使用', field: 'tumor_use', verify: (val, label) => verifyListItem(val, [0, 1, 2, 3], false, label, 0) },
{ name: '风险等级', field: 'riskLevel', verify: (val, label) => verifyListItem(val, ['低风险', '高风险'], false, label) },
// 仅在线药品库使用:管理分类(处方药 / OTC与剂型
{ name: '管理分类', field: 'manage_category', verify: (val, label) => verifyString(val, label) },
{ name: '剂型', field: 'dosage_form', required: true, verify: (val, label) => verifyString(val, label, 1) },
@ -34,6 +35,7 @@ export const drugFieldDict = [
{ name: '给药标准方式', field: 'administration_method', verify: (val, label) => verifyListItem(val, usageList.map(i => i.name), false, label) },
{ name: '用药标准天数', field: 'days', verify: (val, label) => validateNumber(val, label) },
{ name: '发药标准数量', field: 'recommended_quantity', verify: (val, label) => validateNumber(val, label) },
{ name: '用药时机', field: 'dose_time_name', required: true, libType: 'hlw', verify: (val, label) => verifyString(val, label, 1) },
// 在线药品库扩展说明字段:用药证明 / 使用限制说明
{ name: '用药证明', field: 'medication_proof_desc', verify: (val, label) => verifyString(val, label) },
{ name: '使用限制说明', field: 'usage_restriction_desc', verify: (val, label) => verifyString(val, label) },

View File

@ -35,6 +35,15 @@
</el-row>
<div active-title-bar class="mb-2.5">药品规则配置</div>
<el-row>
<el-col :span="24">
<el-form-item label="风险等级" prop="riskLevel">
<el-select clearable :model-value="form.riskLevel" placeholder="请选择风险等级" class="w-full"
@update:model-value="changeValue($event, 'riskLevel')">
<el-option label="低风险" value="低风险" />
<el-option label="高风险" value="高风险" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="适应诊断" prop="applicableDiagnosisIds">
<div class="w-full">
@ -115,6 +124,7 @@ const unitOptions = computed(() => getOptionNames(medicineUseInfo.value.unitList
const dosageFormList = computed(() => getOptionNames(medicineUseInfo.value.dosageFormList ||[]))
const frequencyOptions = computed(() => getOptionNames(medicineUseInfo.value.frequencyList))
const usageOptions = computed(() => getOptionNames(medicineUseInfo.value.usageList))
const useTimeOptions = computed(() => getOptionNames(medicineUseInfo.value.useTimeList || []))
const antibioticLevelOptions = [
{ label: '0 (无)', value: 0 },
{ label: '1 (非限制使用级)', value: 1 },
@ -178,6 +188,9 @@ const usageInfo = computed(() => [
{ label: '给药标准方式', prop: "administration_method", options: usageOptions.value },
{ label: '用药标准天数', prop: "days", maxlength: 100 },
{ label: '发药标准数量', prop: "recommended_quantity", maxlength: 100 },
...(props.libType === 'hlw'
? [{ label: '用药时机', prop: "dose_time_name", options: useTimeOptions.value }]
: []),
])
const suitableInfo = [
{ label: '适用性别', prop: 'suitableGender', options: [{ label: '通用', value: 'common' }, { label: '男', value: 'male' }, { label: '女', value: 'female' }] },
@ -311,6 +324,7 @@ async function save() {
unit: unitOptions.value,
frequency: frequencyOptions.value,
administration_method: usageOptions.value,
dose_time_name: useTimeOptions.value,
});
if (drug.msgs.length) {
ElMessage.info(drug.msgs[0])

View File

@ -237,6 +237,15 @@
<div v-if="row.specification" class="h-20px"></div>
</template>
</el-table-column>
<el-table-column label="用药时机" prop="usageCode" :min-width="140">
<template #default="{ row, $index }">
<el-select v-model="row.dose_time_name" filterable class="w-full" placeholder="请选择用药时机"
:class="readonly ? 'pointer-events-none' : ''" @change="changeUseTime($event, $index)">
<el-option v-for="item in useTimeList" :key="item.code" :label="item.name" :value="item.name" />
</el-select>
<div v-if="row.specification" class="h-20px"></div>
</template>
</el-table-column>
<el-table-column label="" prop="blank" :min-width="1" />
<el-table-column fixed="right" label="操作" prop="action" :width="100">
<template #default="{ row, $index }">
@ -328,6 +337,7 @@ const medicineUseInfo = computed(() => props.order.consultType === 'onlineMedici
const usageList = computed(() => medicineUseInfo.value.usageList)
const frequencyList = computed(() => medicineUseInfo.value.frequencyList)
const dosageUnitList = computed(() => medicineUseInfo.value.dosageUnitList)
const useTimeList = computed(() => medicineUseInfo.value.useTimeList)
const unitList = computed(() => medicineUseInfo.value.unitList)
const getDrugsApi = computed(() => props.order.consultType === 'onlineMedicinePurchase' ? getOnlineDrugList : getDrugs);
@ -554,6 +564,8 @@ function changeDrug(val, idx) {
item.specification = d.specification || '';
item.package_amount = d.package_amount
item.recommended_quantity = d.recommended_quantity;
const useTime = useTimeList.value.find(i => i.name === d.dose_time_name)
item.dose_time_name = useTime?.name || '';
// 使
item.usage_restriction_desc = d.usage_restriction_desc || '';
item.medication_proof_desc = d.medication_proof_desc || '';
@ -577,6 +589,13 @@ function changeFrequency(val, idx) {
setCalculateTimer(idx)
}
function changeUseTime(val, idx) {
const item = tabs.value[tabIndex.value].drugs[idx];
const doseTime = useTimeList.value.find(item => item.name === val);
item.dose_time_name = doseTime ? doseTime.name : '';
setCalculateTimer(idx)
}
function changeDosageUnit(val, idx) {
const item = tabs.value[tabIndex.value].drugs[idx];
const dosageUnit = dosageUnitList.value.find(item => item.code === val);
@ -633,6 +652,10 @@ async function verify(ignoreRepeat = false) {
ElMessage.info(`${i.drugName}: 给药方式无效`);
return;
}
if (!useTimeList.value.some(item => item.name === i.dose_time_name)) {
ElMessage.info(`${i.drugName}: 用药时机无效`);
return;
}
}
if (inappropriateDrugs.value.length) {
return showUnsuitDrug()
@ -690,6 +713,7 @@ async function submit() {
usageCode: i.usageCode,
usageName: i.usageName,
package_amount: i.package_amount,
dose_time_name: i.dose_time_name,
recommended_quantity: i.recommended_quantity,
forceSelfPay: ['Y', 'N'].includes(i.forceSelfPay) ? i.forceSelfPay : 'N',
limitUsageScope: typeof i.usage_restriction_desc === 'string' && i.usage_restriction_desc.trim() ? 'Y' : 'N'
@ -861,6 +885,8 @@ async function initWithOrder() {
const dosageUnit = dosageUnitList.value.find(i => i.name === cur.dosage_unit);
row.dosage_unit = dosageUnit ? dosageUnit.name : '';
row.dosage_unit_code = dosageUnit ? dosageUnit.code : '';
const useTime = useTimeList.value.find(i => i.name === cur.dose_time_name)
row.dose_time_name = useTime?.name || '';
row.specification = drug.specification || ''
row.package_amount = drug.package_amount
row.recommended_quantity = drug.recommended_quantity