fix: 优化中药开方功能

This commit is contained in:
2025-03-19 17:06:36 +08:00
parent 3e287233c7
commit aa7e5982d5
15 changed files with 1180 additions and 242 deletions

View File

@@ -4,9 +4,11 @@ import type { NotificationItem } from '@vben/layouts';
import { computed, ref, watch } from 'vue';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
// import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
import { useWatermark } from '@vben/hooks';
// import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons';
// import { CircleHelp } from '@vben/icons';
import {
BasicLayout,
LockScreen,
@@ -65,6 +67,13 @@ const menus = computed(() => [
// TODO 后续放个人中心
// {
// handler: () => {
// UpdatePasswordModalApi.open();
// },
// icon: 'carbon:password',
// text: '修改密码',
// },
// {
// handler: () => {
// openWindow(VBEN_DOC_URL, {
// target: '_blank',
// });
@@ -158,5 +167,6 @@ watch(
<template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" />
</template>
<UpdatePasswordModals />
</BasicLayout>
</template>

View File

@@ -0,0 +1,53 @@
<script lang="ts" setup>
import {Page, useVbenModal} from '@vben/common-ui';
import {message} from 'ant-design-vue';
import {passwordModalForm} from '#/layouts/config/form.ts'
import {useVbenForm} from "#/adapter/form";
import {updatePassword} from "#/views/system/admin/api";
const [Form, formApi] = useVbenForm(passwordModalForm);
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm: async () => {
formApi.validate().then(async (e: any) => {
if (e.valid) {
const values = await formApi.getValues();
modalApi.setState({loading: true, confirmLoading: true});
updatePassword(values).then(() => {
modalApi.close();
message.success('修改成功,请重新登录');
})
.finally(() => {
modalApi.setState({loading: false, confirmLoading: false});
});
}
});
await formApi.validateAndSubmitForm();
},
onOpenChange(isOpen: boolean) {
console.log(isOpen, '开启状态');
// if (isOpen) {
// const {values} =
// modalApi.getData<Record<string, any>>();
// if (values) {
// }
// }
},
});
</script>
<template>
<!-- <Modal class="w-[60%]" title="西(中成)药列表">-->
<Modal class="w-[60%]" title="修改密码">
<Page>
<Form/>
</Page>
</Modal>
</template>
<style lang="scss"></style>

View File

@@ -0,0 +1,105 @@
import type { VbenFormProps } from '#/adapter/form';
import { z } from '#/adapter/form';
const defaultPassword = '';
export const passwordModalForm: VbenFormProps = {
wrapperClass: 'grid-cols-12', // 24栅格,
commonConfig: {
formItemClass: 'col-span-12',
// 所有表单项
componentProps: {
class: 'w-full',
},
},
// handleSubmit: onSubmit,
layout: 'horizontal',
schema: [
{
fieldName: 'password',
label: '旧的密码',
component: 'InputPassword',
help: '5-18位数字、字母、特殊字符组成。',
componentProps: {
placeholder: '请输入密码',
allowClear: true,
},
defaultValue: defaultPassword,
rules: z
.string()
.regex(
/^(?=.*[A-Z0-9])(?=.*[!@#$%^&*])[A-Z0-9!@#$%^&*]{5,18}$/i,
'密码由5-18位数字、字母、特殊字符组成。',
),
dependencies: {
if({ id }) {
return !id;
},
triggerFields: ['id'],
},
// formItemClass: 'col-span-6',
},
{
fieldName: 'new_password',
label: '新的密码',
component: 'InputPassword',
help: '5-18位数字、字母、特殊字符组成。',
componentProps: {
placeholder: '请输入密码',
allowClear: true,
},
defaultValue: defaultPassword,
rules: z
.string()
.regex(
/^(?=.*[A-Z0-9])(?=.*[!@#$%^&*])[A-Z0-9!@#$%^&*]{5,18}$/i,
'密码由5-18位数字、字母、特殊字符组成。',
),
dependencies: {
if({ id }) {
return !id;
},
triggerFields: ['id'],
},
// formItemClass: 'col-span-6',
},
{
fieldName: 'new_password_confirmation',
label: '确认密码',
component: 'InputPassword',
componentProps: {
placeholder: '请输入确认密码',
allowClear: true,
},
defaultValue: defaultPassword,
rules: z
.string()
.regex(/[\w!@#$%^&*]{5,18}/, '密码由5-18位数字、字母、特殊字符组成。'),
dependencies: {
if({ id }) {
return !id;
},
triggerFields: ['id', 'confirmPassword'],
rules: (values) => {
return z
.string()
.regex(
/[\w!@#$%^&*]{5,18}/,
'密码由5-18位数字、字母、特殊字符组成。',
)
.refine(
(confirmPassword) => {
return confirmPassword === values.new_password;
},
{
message: '确认密码必须与密码一致',
},
);
},
},
// formItemClass: 'col-span-6',
},
],
showDefaultActions: false,
};

View File

@@ -136,13 +136,13 @@ const formSchema = computed((): VbenFormSchema[] => {
message: $t('authentication.codeTip', [CODE_LENGTH]),
}),
},
{
component: markRaw(SliderCaptcha),
fieldName: 'captcha',
rules: z.boolean().refine((value) => value, {
message: $t('authentication.verifyRequiredTip'),
}),
},
// {
// component: markRaw(SliderCaptcha),
// fieldName: 'captcha',
// rules: z.boolean().refine((value) => value, {
// message: $t('authentication.verifyRequiredTip'),
// }),
// },
];
});
</script>

View File

@@ -142,6 +142,12 @@ const quickNavItems: WorkbenchQuickNavItem[] = [
title: '供应商管理',
url: '/supplier',
},
{
color: '#00d8ff',
icon: 'ion:bar-chart-outline',
title: '接诊',
url: '/doctor/reception',
},
];
const todoItems = ref<WorkbenchTodoItem[]>([
@@ -177,6 +183,12 @@ const todoItems = ref<WorkbenchTodoItem[]>([
},
]);
const trendItems: WorkbenchTrendItem[] = [
{
avatar: 'svg:logo',
content: `医生开方功能上线啦!`,
date: '2025-3-11',
title: '萧康云医',
},
{
avatar: 'svg:logo',
content: `萧康云医上线啦!`,

View File

@@ -46,6 +46,22 @@ export async function getUseWayList() {
return requestClient.get<any>(`${prefix}drug-use-way-list`, {});
}
/**
* 获取疾病列表
*/
export async function getDiseaseList(name:string) {
return requestClient.get<any>(`${prefix}disease-list`, { params: {
name
} });
}
/**
* 获取疾病列表
*/
export async function getDoctorOrderList() {
return requestClient.get<any>(`${prefix}doctor-order-list`);
}
/**
* 接诊
*/

View File

@@ -0,0 +1,118 @@
<script lang="ts" setup>
import {ref} from 'vue';
import {Page, useVbenModal} from '@vben/common-ui';
import {
Badge,
Button,
Col,
InputSearch,
message,
Row,
} from 'ant-design-vue';
import {
getDiseaseList,
} from '#/views/doctor/doctor-reception/api';
const searchKey = ref('');
const diagnosisList = ref([]);
const selectDiagnosisList = ref('');
const setUpdateDiagnosis = ref();
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm: async () => {
setUpdateDiagnosis.value(selectDiagnosisList.value);
modalApi.close();
message.success('保存成功');
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
setUpdateDiagnosis.value = isOpen ? modalApi.getData()?.updateDiagnosis : null;
const {values} =
modalApi.getData<Record<string, any>>();
if (values) {
selectDiagnosisList.value = values;
}
getDiagnosisList();
}
},
});
/**
* 获取诊断列表
* @param searchKey
*/
function getDiagnosisList(searchKey = '') {
getDiseaseList(searchKey).then((res) => {
diagnosisList.value = res.map((item) => {
item.isSelect = 0;
if (selectDiagnosisList.value) {
// 把values的字符串转为数组根据分解
const valuesArr = selectDiagnosisList.value.split('');
// 判断valuesArr数组中是否有item.name
valuesArr.forEach((value) => {
if (value === item.name) {
item.isSelect = 1;
}
});
}
return item;
});
});
}
/**
* 选择诊断
* @param item
*/
function selectDiagnosis(item) {
// 将当前值转换为数组(过滤空值)
let arr = selectDiagnosisList.value ? selectDiagnosisList.value.split('').filter(Boolean) : [];
if (item.isSelect === 1) {
// 取消选中:从数组中删除元素
arr = arr.filter(name => name !== item.name);
item.isSelect = 0;
} else {
// 选中:确保不重复后添加
if (!arr.includes(item.name)) {
arr.push(item.name);
}
item.isSelect = 1;
}
// 将数组转回字符串更新到响应式变量
selectDiagnosisList.value = arr.join('');
}
</script>
<template>
<!-- <Modal class="w-[60%]" title="西(中成)药列表">-->
<Modal class="w-[60%]" title="常用诊断">
<Page>
<Row :gutter="12">
<Col :span="24">
<InputSearch
:model="searchKey"
enter-button
placeholder="请输想要搜索的内容..."
@search="getDiagnosisList"
/>
</Col>
<Col :span="24">
<Badge v-for="item in diagnosisList" :count="0" class="mt-5">
<Button style="margin: 0 10px;" :type="item.isSelect === 1 ? 'primary': ''" @click="selectDiagnosis(item)">{{ item.name }}</Button>
</Badge>
</Col>
</Row>
</Page>
</Modal>
</template>
<style lang="scss">
</style>

View File

@@ -0,0 +1,152 @@
<script lang="ts" setup>
import {ref} from 'vue';
import {Page, useVbenModal} from '@vben/common-ui';
import {
Badge,
Button,
Col,
InputSearch,
message,
Row,
} from 'ant-design-vue';
import {
getDiseaseList, getDoctorOrderList,
} from '#/views/doctor/doctor-reception/api';
const searchKey = ref('');
const doctorOrderCommonList = ref([]);
const doctorOrderMyList = ref([]);
const selectDiagnosisList = ref('');
const setUpdateDoctorOrder = ref();
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm: async () => {
setUpdateDoctorOrder.value(selectDiagnosisList.value);
modalApi.close();
message.success('保存成功');
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
setUpdateDoctorOrder.value = isOpen ? modalApi.getData()?.updateDoctorOrder : null;
const {values} =
modalApi.getData<Record<string, any>>();
if (values) {
selectDiagnosisList.value = values;
}
getDiagnosisList();
}
},
});
/**
* 获取诊断列表
* @param searchKey
*/
function getDiagnosisList() {
getDoctorOrderList().then((res) => {
doctorOrderCommonList.value = res.common.map((item) => {
item.isSelect = 0;
if (selectDiagnosisList.value) {
// 把values的字符串转为数组根据分解
const valuesArr = selectDiagnosisList.value.split('');
// 判断valuesArr数组中是否有item.name
valuesArr.forEach((value) => {
if (value === item.name) {
item.isSelect = 1;
}
});
}
return item;
});
doctorOrderMyList.value = res.my.map((item) => {
item.isSelect = 0;
if (selectDiagnosisList.value) {
// 把values的字符串转为数组根据分解
const valuesArr = selectDiagnosisList.value.split('');
// 判断valuesArr数组中是否有item.name
valuesArr.forEach((value) => {
if (value === item.content) {
item.isSelect = 1;
}
});
}
return item;
});
});
}
/**
* 选择诊断
* @param item
*/
function selectDiagnosis(item, type = 1) {
// 将当前值转换为数组(过滤空值)
let arr = selectDiagnosisList.value ? selectDiagnosisList.value.split('').filter(Boolean) : [];
if (type === 1) {
if (item.isSelect === 1) {
// 取消选中:从数组中删除元素
arr = arr.filter(name => name !== item.content);
item.isSelect = 0;
} else {
// 选中:确保不重复后添加
if (!arr.includes(item.content)) {
arr.push(item.content);
}
item.isSelect = 1;
}
} else {
if (item.isSelect === 1) {
// 取消选中:从数组中删除元素
arr = arr.filter(name => name !== item.name);
item.isSelect = 0;
} else {
// 选中:确保不重复后添加
if (!arr.includes(item.name)) {
arr.push(item.name);
}
item.isSelect = 1;
}
}
// 将数组转回字符串更新到响应式变量
selectDiagnosisList.value = arr.join('');
}
</script>
<template>
<!-- <Modal class="w-[60%]" title="西(中成)药列表">-->
<Modal class="w-[60%]" title="常用医嘱">
<Page>
<Row :gutter="12">
<Col :span="24">
<InputSearch
:model="searchKey"
enter-button
placeholder="请输想要搜索的内容..."
@search="getDiagnosisList"
/>
</Col>
<Col :span="24">
<Badge v-for="item in doctorOrderMyList" :count="0" class="mt-5">
<Button style="margin: 0 10px;" :type="item.isSelect === 1 ? 'primary': ''" @click="selectDiagnosis(item)">{{ item.content }}</Button>
</Badge>
</Col>
<Col :span="24">
<Badge v-for="item in doctorOrderCommonList" :count="0" class="mt-5">
<Button style="margin: 0 10px;" :type="item.isSelect === 1 ? 'primary': ''" @click="selectDiagnosis(item, 2)">{{ item.name }}</Button>
</Badge>
</Col>
</Row>
</Page>
</Modal>
</template>
<style lang="scss">
</style>

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
@@ -10,6 +10,7 @@ import {
} from '@ant-design/icons-vue';
import {
Badge,
Button,
Card,
CardMeta,
Col,
@@ -22,194 +23,287 @@ import {
Select,
SelectOption,
} from 'ant-design-vue';
import { debounce } from 'lodash-es'; // 或者使用自定义防抖函数
import {
getDrugUseList,
getProductListDoctorReception,
} from '#/views/doctor/doctor-reception/api';
// 搜索关键词
const searchKey = ref('');
// 药品类型1-中药2-西药
const type = ref(1);
// 当前药品回调函数
const currentDrugs = ref();
// 当前患者ID
const activePatientId = ref(0);
// 药品列表
const drugList = ref([]);
// 已选择的药品列表
const selectList = ref([]);
// 药品使用相关数据
const drugUseNum = ref([]);
const drugUseFrequency = ref([]);
const drugUseType = ref([]);
const drugUnit = ref([]);
const drugTime = ref([]);
const drugUseWay = ref([]);
// 当前选中的药品ID
const selectProductId = ref(0);
// 预览图片URL
const previewImage = ref('');
const visible = ref<boolean>(false);
const setVisible = (value, instruction = ''): void => {
// 图片预览控制
const visible = ref(false);
// 设置图片预览状态
const setVisible = (value, instruction = '') => {
visible.value = value;
previewImage.value = instruction;
};
// 本地存储键名
const storageKey = computed(() => `prescriptionData${activePatientId.value}`);
// 获取当前患者的药品数据
const getCurrentDrugs = () => {
selectList.value = JSON.parse(
localStorage.getItem(`prescriptionData${activePatientId.value}`) || '[]',
);
try {
// 从localStorage获取数据并解析
const storedData = localStorage.getItem(storageKey.value);
selectList.value = storedData ? JSON.parse(storedData) : [];
} catch (error) {
console.error('解析处方数据失败:', error);
selectList.value = [];
}
};
/**
* 获取品列表
* @param searchKey
* 获取品列表
* @param {string} searchText - 搜索关键词
*/
function getDrugListByWesternModal(searchKey = '') {
if (searchKey === '' && type.value === 1) {
const getDrugListByWesternModal = debounce(async (searchText = '') => {
if (searchText === '' && type.value === 1) {
drugList.value = [];
return;
}
getCurrentDrugs();
getProductListDoctorReception({
store_id: 2,
type: type.value,
name: searchKey,
}).then((res) => {
// 循环res添加select_number = 0
res.forEach((item) => {
const matched = selectList.value.find(
(value) => value.index_id === item.id,
);
item.select_number = matched ? matched.select_number : 0;
item.drug.number = matched ? matched.number : 1;
try {
const res = await getProductListDoctorReception({
store_id: 2,
type: type.value,
name: searchText,
});
drugList.value = res;
});
}
drugList.value = res.map((item) => {
const matched = selectList.value.find((v) => v.index_id === item.id);
return {
...item,
select_number: matched?.select_number || 0,
drug: {
...item.drug,
number: matched?.number || 1,
},
};
});
} catch (error) {
console.error('获取药品列表失败:', error);
message.error('获取药品列表失败');
}
}, 300);
/**
* 获取药品使用方式列表
*/
function getDrugUseListByWesternModal() {
getDrugUseList().then((res) => {
async function getDrugUseListByWesternModal() {
try {
// 调用API获取药品使用方式列表
const res = await getDrugUseList();
// 更新各种药品使用相关数据
drugUseNum.value = res.drug_use_num;
drugUseFrequency.value = res.drug_use_frequency;
drugUseType.value = res.drug_use_type;
drugUnit.value = res.drug_unit;
drugTime.value = res.drug_time;
drugUseWay.value = res.drug_use_way;
// drugProcessRule.value = res.drug_process_rule;
});
} catch (error) {
console.error('获取药品使用方式列表失败:', error);
message.error('获取药品使用方式列表失败');
}
}
/**
* 添加商品
* 添加商品到处方
* @param {object} data - 商品对象
*/
function addProducts(data) {
// 查找是否已存在
// 查找是否已存在于选择列表中
const existItem = selectList.value.find((item) => item.index_id === data.id);
// 新建商品对象避免污染原始数据
// 创建新的商品对象避免直接修改原始数据
const newProduct = {
// 索引ID用于在列表中查找
index_id: data.id,
// 药品ID
id: data.drug.id,
// 药品名称
drug_name: data.drug.drug_name,
// 药品数量
number: data.drug.number,
use_num: drugUseNum.value.find(
(item) => item.id === data.drug.frequency_id,
),
// 药品使用数量信息
use_num: drugTime.value.find((item) => item.id === data.drug.time_id),
// 药品使用类型信息
use_type: drugUseType.value.find((item) => item.id === data.drug.type_id),
// 药品使用频率信息
use_frequency: drugUseFrequency.value.find(
(item) => item.id === data.drug.frequency_id,
),
// 药品单位信息
unit: drugUnit.value.find((item) => item.id === data.drug.unit_id),
// 药品价格
price: data.price,
// 药品使用方式ID
way_id: data.drug?.way_id,
use_way: drugUseWay.value.find((item) => item.id === data.drug.way_id),
// 药品使用方式信息
use_ways: drugUseWay.value.find((item) => item.id === data.drug.way_id),
// 药品使用时间ID
time_id: data.drug.time_id,
// 药品类型ID
type_id: data.drug.type_id,
// 药品使用频率ID
frequency_id: data.drug.frequency_id,
// 药品单位ID
unit_id: data.drug.unit_id,
// 药品图片
image: data.drug.image,
// 药品说明书
instruction: data.drug.instruction,
// 药品类型
type: data.drug.type,
};
if (existItem) {
// 增量操作
// 已存在,增加数量
const newNumber = existItem.select_number + 1;
// 提前验证
if (newNumber > 100) {
// 验证数量上限
if (newNumber > 100 && type.value === 2) {
message.error(`${existItem.drug_name}数量不能大于100`);
return;
}
// 更新选中列表
// 更新选中列表中的数量
selectList.value = selectList.value.map((item) =>
item.index_id === data.id ? { ...item, select_number: newNumber } : item,
);
syncDrugList(data.id, newNumber); // 同步药品列表
// 同步更新药品列表中的数量
syncDrugList(data.id, newNumber);
// 更新本地存储
updateSelectStorage();
// 提示成功
message.success(`${existItem.drug_name}数量已增加至${newNumber}`);
} else {
// 首次添加初始化数量为1
newProduct.select_number = 1;
// 添加前验证
if (newProduct.select_number > 100) {
message.error(`${newProduct.drug_name}数量不能大于100`);
return;
}
// 添加到选中列表
selectList.value.push(newProduct);
console.log(selectList.value, 'ssssssssss');
syncDrugList(newProduct.index_id, 1); // 同步药品列表
// 同步更新药品列表
syncDrugList(newProduct.index_id, 1);
// 更新本地存储
updateSelectStorage();
// 提示成功
message.success(`已将${newProduct.drug_name}添加到清单中!`);
}
}
/**
* 减少商品
* 减少商品数量
* @param {object} data - 商品对象
*/
function propProducts(data) {
// 查找是否存在于选择列表中
const existItem = selectList.value.find((item) => item.index_id === data.id);
// 如果不存在,提示错误并返回
if (!existItem) {
message.error(`${data.drug.drug_name}不在清单中!`);
return;
}
// 计算新的数量
const newNumber = existItem.select_number - 1;
// 提前验证
// 验证数量下限
if (newNumber < 0) {
message.error(`${data.drug.drug_name}数量不能小于0`);
return;
}
if (newNumber === 0) {
// 移出清单
// 数量为0从清单中移除
selectList.value = selectList.value.filter(
(item) => item.index_id !== data.id,
);
syncDrugList(data.id, 0); // 同步清零
// 同步更新药品列表
syncDrugList(data.id, 0);
// 更新本地存储
updateSelectStorage();
// 提示成功
message.success(`${data.drug.drug_name}已从清单移出!`);
} else {
// 更新数量
selectList.value = selectList.value.map((item) =>
item.index_id === data.id ? { ...item, select_number: newNumber } : item,
);
syncDrugList(data.id, newNumber); // 同步更新
// 同步更新药品列表
syncDrugList(data.id, newNumber);
// 更新本地存储
updateSelectStorage();
// 提示成功
message.success(`${data.drug.drug_name}数量已减少至${newNumber}`);
}
}
/**
* 同步更新药品列表
* 更新本地存储中的选择列表
*/
function updateSelectStorage() {
try {
localStorage.setItem(storageKey.value, JSON.stringify(selectList.value));
} catch (error) {
console.error('保存处方数据失败:', error);
message.error('保存处方数据失败');
}
}
/**
* 同步更新药品列表中的数量
* @param {number} productId - 药品ID
* @param {number} number - 新的数量
*/
function syncDrugList(productId, number) {
// 使用map创建新数组避免直接修改原数组
drugList.value = drugList.value.map((item) =>
item.id === productId ? { ...item, select_number: number } : item,
);
}
// 使用modal组件
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
@@ -217,42 +311,55 @@ const [Modal, modalApi] = useVbenModal({
modalApi.close();
},
onConfirm: async () => {
localStorage.setItem(
`prescriptionData${activePatientId.value}`,
// JSON.stringify(selectData),
JSON.stringify(selectList.value),
);
currentDrugs.value();
// 保存数据
updateSelectStorage();
// 调用回调函数
if (typeof currentDrugs.value === 'function') {
currentDrugs.value();
}
// 关闭modal
modalApi.close();
// 提示成功
message.success('保存成功');
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
// getCurrentDrugs
currentDrugs.value = isOpen ? modalApi.getData()?.getCurrentDrugs : null;
const { values, activePatient_id } =
modalApi.getData<Record<string, any>>();
// 获取回调函数
const data = modalApi.getData();
currentDrugs.value = data?.getCurrentDrugs;
// 获取参数
const { values, activePatient_id } = data || {};
if (values) {
// 设置药品类型
type.value = values;
// 设置患者ID
activePatientId.value = activePatient_id;
// 获取药品列表
getDrugListByWesternModal();
// 获取药品使用方式列表
getDrugUseListByWesternModal();
}
}
},
});
/**
* 选择药品
* @param {number} id - 药品ID
*/
function selectProductChange(id) {
selectProductId.value = id;
}
/**
* 选择中药用法
* @param id
* 选择药品使用方式
* @param {number} id - 使用方式ID
*/
function selectDrugUseWayChange(id) {
// 更新药品列表中的使用方式
drugList.value = drugList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.id === selectProductId.value
? {
...item,
@@ -263,39 +370,29 @@ function selectDrugUseWayChange(id) {
}
: item,
);
// 更新选择列表中的使用方式
selectList.value = selectList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === selectProductId.value
? {
...item,
way_id: id,
use_ways: drugUseWay.value.find(
(value) => value.id === id,
),
use_ways: drugUseWay.value.find((value) => value.id === id),
}
: item,
);
// 更新本地存储
updateSelectStorage();
}
/**
* 选择频次
* @param id
* 选择药品使用频率
* @param {number} id - 频率ID
*/
function selectFrequencyChange(id) {
drugList.value = drugList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.id === selectProductId.value
? {
...item,
drug: {
...item.drug,
frequency_id: id,
},
}
: item,
);
// 更新选择列表中的频率
selectList.value = selectList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === selectProductId.value
? {
...item,
@@ -306,27 +403,18 @@ function selectFrequencyChange(id) {
}
: item,
);
// 更新本地存储
updateSelectStorage();
}
/**
* 选择使用时间
* @param id
* 选择药品使用时间
* @param {number} id - 时间ID
*/
function selectTimeChange(id) {
drugList.value = drugList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.id === selectProductId.value
? {
...item,
drug: {
...item.drug,
time_id: id,
},
}
: item,
);
// 更新选择列表中的时间
selectList.value = selectList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === selectProductId.value
? {
...item,
@@ -335,27 +423,18 @@ function selectTimeChange(id) {
}
: item,
);
// 更新本地存储
updateSelectStorage();
}
/**
* 选择使用方法
* @param id
* 选择药品使用类型
* @param {number} id - 类型ID
*/
function selectTypeChange(id) {
drugList.value = drugList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.id === selectProductId.value
? {
...item,
drug: {
...item.drug,
type_id: id,
},
}
: item,
);
// 更新选择列表中的类型
selectList.value = selectList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === selectProductId.value
? {
...item,
@@ -364,27 +443,18 @@ function selectTypeChange(id) {
}
: item,
);
// 更新本地存储
updateSelectStorage();
}
/**
* 选择单位
* @param id
* 选择药品单位
* @param {number} id - 单位ID
*/
function selectUnitChange(id) {
drugList.value = drugList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.id === selectProductId.value
? {
...item,
drug: {
...item.drug,
unit_id: id,
},
}
: item,
);
// 更新选择列表中的单位
selectList.value = selectList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === selectProductId.value
? {
...item,
@@ -393,28 +463,25 @@ function selectUnitChange(id) {
}
: item,
);
// 更新本地存储
updateSelectStorage();
}
/**
* 更新药品数量
* @param {number} id - 药品ID
* @param {number} number - 新的数量
*/
function updateProductNumber(id, number) {
if (number > 100 || number <= 0) {
// 验证数量范围
if ((number > 100 || number <= 0) && type.value === 2) {
message.error('数量不能大于100或小于1');
return;
}
drugList.value = drugList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.id === id
? {
...item,
drug: {
...item.drug,
number,
},
}
: item,
);
// 更新选择列表中的数量
selectList.value = selectList.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === id
? {
...item,
@@ -422,44 +489,53 @@ function updateProductNumber(id, number) {
}
: item,
);
// 更新本地存储
updateSelectStorage();
}
</script>
<template>
<!-- <Modal class="w-[60%]" title="西(中成)药列表">-->
<Modal class="w-[60%]" title="商品列表">
<!-- 图片预览组件 -->
<Image
:preview="{
visible,
onVisibleChange: setVisible,
}"
visible,
onVisibleChange: setVisible,
}"
:src="previewImage"
:style="{ display: 'none' }"
:width="200"
/>
<Page>
<Row :gutter="12">
<!-- 搜索框 -->
<Col :span="24">
<InputSearch
:model="searchKey"
v-model:value="searchKey"
enter-button
placeholder="请输入商品名称或拼音首拼"
@input="(e) => getDrugListByWesternModal(e.target.value)"
@search="getDrugListByWesternModal"
/>
</Col>
<!-- 药品列表 -->
<Col v-for="item in drugList" :key="item.id" :span="6">
<Badge :count="item.select_number" class="mt-5">
<!-- 中药卡片 -->
<Card v-if="type === 1" hoverable>
<template #actions>
<!-- <MinusOutlined v-if="item.select_number > 0" key="prop" @click="propProducts(item)" />-->
<Button v-if="item.select_number > 0" key="prop" @click="propProducts(item)">从清单移除</Button>
<!-- <ContainerOutlined-->
<!-- @click="setVisible(true, item.drug.instruction)"-->
<!-- />-->
<!-- <PlusOutlined v-if="item.select_number < 1" key="add" @click="addProducts(item)" >添加到清单</PlusOutlined>-->
<Button v-if="item.select_number < 1" key="add" @click="addProducts(item)" >添加到清单</Button>
<!-- <EllipsisOutlined key="ellipsis" />-->
<Button
v-if="item.select_number > 0"
key="prop"
type="link"
@click="propProducts(item)"
>
从清单移除
</Button>
<Button v-else key="add" type="link" @click="addProducts(item)">
添加到清单
</Button>
</template>
<CardMeta
:description="item.drug?.pinyin_simple"
@@ -470,27 +546,32 @@ function updateProductNumber(id, number) {
</template>
</CardMeta>
<div class="card-box mt-5" style="padding: 10px 5px">
<Popover>
<!-- 选择中药煎法-->
<Select
:value="item.drug?.way_id"
class="mt-3 w-full"
@change="selectDrugUseWayChange"
@dropdown-visible-change="selectProductChange(item.id)"
placeholder="煎服"
<p>单价{{item.price}}/g</p>
<!-- 选择中药煎法 -->
<Select
:value="item.drug?.way_id"
class="mt-3 w-full"
placeholder="煎服"
@change="selectDrugUseWayChange"
@dropdown-visible-change="selectProductChange(item.id)"
>
<SelectOption :value="0">煎服</SelectOption>
<SelectOption
v-for="(value, index) in drugUseWay"
:key="index"
:value="value.id"
>
<SelectOption
v-for="(value, index) in drugUseWay"
:key="index"
:value="value.id"
>
{{ value.name }}
</SelectOption>
</Select>
</Popover>
{{ value.name }}
</SelectOption>
</Select>
<div class="mt-3">
<!-- 选择单位-->
<InputNumber v-model:value="item.drug.number" class="w-3/4">
<!-- 数量输入框 -->
<InputNumber
v-model:value="item.drug.number"
class="w-3/4"
@change="updateProductNumber(item.id, item.drug.number)"
>
<template #addonBefore>
<MinusOutlined
key="prop"
@@ -508,18 +589,21 @@ function updateProductNumber(id, number) {
@click="
updateProductNumber(
item.id,
item.drug.number < 1000 ? item.drug.number + 1 : 1000,
item.drug.number < 1000
? item.drug.number + 1
: 1000,
)
"
/>
</template>
</InputNumber>
<!-- 单位选择 -->
<Select
:value="item.drug?.unit_id"
class="w-1/4"
disabled
@change="selectUnitChange"
@dropdown-visible-change="selectProductChange(item.id)"
disabled
>
<SelectOption
v-for="(value, index) in drugUnit"
@@ -543,7 +627,6 @@ function updateProductNumber(id, number) {
@click="setVisible(true, item.drug.instruction)"
/>
<PlusOutlined key="add" @click="addProducts(item)" />
<!-- <EllipsisOutlined key="ellipsis" />-->
</template>
<CardMeta
:description="item.drug?.pinyin_simple"
@@ -565,9 +648,9 @@ function updateProductNumber(id, number) {
</template>
</Popover>
<p class="text-source mt-5">{{ item.drug?.source }}</p>
<!-- 选择频次-->
<!-- 选择频次 -->
<Select
:value="item.drug?.frequency_id"
v-model:value="item.drug.frequency_id"
class="mt-3 w-full"
@change="selectFrequencyChange"
@dropdown-visible-change="selectProductChange(item.id)"
@@ -580,9 +663,9 @@ function updateProductNumber(id, number) {
{{ value.name }}
</SelectOption>
</Select>
<!-- 选择时间-->
<!-- 选择时间 -->
<Select
:value="item.drug?.time_id"
v-model:value="item.drug.time_id"
class="mt-3 w-1/2"
@change="selectTimeChange"
@dropdown-visible-change="selectProductChange(item.id)"
@@ -595,9 +678,9 @@ function updateProductNumber(id, number) {
{{ value.name }}
</SelectOption>
</Select>
<!-- 选择使用方法-->
<!-- 选择使用方法 -->
<Select
:value="item.drug?.type_id"
v-model:value="item.drug.type_id"
class="mt-3 w-1/2"
@change="selectTypeChange"
@dropdown-visible-change="selectProductChange(item.id)"
@@ -611,7 +694,7 @@ function updateProductNumber(id, number) {
</SelectOption>
</Select>
<div class="mt-3">
<!-- 选择单位-->
<!-- 数量输入框 -->
<InputNumber v-model:value="item.drug.number" class="w-3/5">
<template #addonBefore>
<MinusOutlined
@@ -636,8 +719,9 @@ function updateProductNumber(id, number) {
/>
</template>
</InputNumber>
<!-- 单位选择 -->
<Select
:value="item.drug?.unit_id"
v-model:value="item.drug.unit_id"
class="w-2/5"
@change="selectUnitChange"
@dropdown-visible-change="selectProductChange(item.id)"
@@ -659,6 +743,7 @@ function updateProductNumber(id, number) {
</Page>
</Modal>
</template>
<style lang="scss">
.drug-function {
display: -webkit-box;

View File

@@ -2,18 +2,25 @@
import { computed, ref, watch } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { debounce } from 'lodash-es'; // 或者使用自定义防抖函数
import { MinusOutlined, PlusOutlined } from '@ant-design/icons-vue';
import {
Badge,
Button,
Card, CardMeta,
Col,
Descriptions,
Empty,
Image,
ImagePreviewGroup,
InputNumber,
Input,
InputNumber, InputSearch,
message,
Popover,
RadioButton,
RadioGroup,
Row,
Select,
SelectOption,
Tag,
@@ -25,12 +32,15 @@ import {
import { getRegisterStatus } from '#/util/tool';
import {
addWestPrescription,
getDrugUseList,
getPatientItem,
getPatientList,
getProcessRuleList,
getProcessRuleList, getProductListDoctorReception,
receptionApi,
} from '#/views/doctor/doctor-reception/api';
import DiagnosisModal from './components/DiagnosisModal.vue';
import DoctorOrderModal from './components/DoctorOrderModal.vue';
import PrescrtionDetail from './components/PrescrtionDetail.vue';
import WesternModal from './components/WesternModal.vue';
@@ -57,6 +67,7 @@ interface UserPatientHealthInquiry {
is_delete: number;
}
const searchByChinese = ref('');
const tabType = ref(0);
const category = ref(1);
const receptionStatus = ref(0);
@@ -64,6 +75,14 @@ const updateTabType = ref(false);
// 患者数据
const patients = ref<Patient[]>([]);
// 药品使用相关数据
const drugUseNum = ref([]);
const drugUseFrequency = ref([]);
const drugUseType = ref([]);
const drugUnit = ref([]);
const drugTime = ref([]);
const drugUseWay = ref([]);
/**
* 获取患者列表
*/
@@ -113,8 +132,49 @@ const diagnosis = ref('');
const medicalAdvice = ref('');
const treatmentPrice = ref(0);
const selectPatientId = ref(0);
const searchChineseVisible = ref(false);
const ruleType = ref(1);
const prescriptionList = ref([]);
const drugList = ref([]);
/**
* 获取药品使用方式列表
*/
function getDrugUseListByWesternModal() {
getDrugUseList().then((res) => {
// 更新各种药品使用相关数据
drugUseNum.value = res.drug_use_num;
drugUseFrequency.value = res.drug_use_frequency;
drugUseType.value = res.drug_use_type;
drugUnit.value = res.drug_unit;
drugTime.value = res.drug_time;
drugUseWay.value = res.drug_use_way;
// drugProcessRule.value = res.drug_process_rule;
});
}
getDrugUseListByWesternModal();
const selectProductId = ref(0);
function selectProductChange(id) {
selectProductId.value = id;
}
/**
* 选择中药用法
* @param id
*/
function selectDrugUseWayChange(id) {
currentDrugs.value = currentDrugs.value.map((item) =>
// 修改item下面drug的 frequency_id = id
item.index_id === selectProductId.value
? {
...item,
way_id: id,
use_ways: drugUseWay.value.find((value) => value.id === id),
}
: item,
);
updateLocalStorage();
}
/**
* 计算商品总价
*/
@@ -167,15 +227,15 @@ const processingFee = computed(() => {
}
// 模式2单价*用量
if (calcMethod.value === 2) {
return (processRulePrice.value * dosage.value);
return processRulePrice.value * dosage.value;
}
// 模式2单价*用量
if (calcMethod.value === 3) {
let number = currentDrugs.value.reduce(
const number = currentDrugs.value.reduce(
(sum, drug) => sum + drug.number,
0,
);
return (processRulePrice.value * dosage.value * number);
return processRulePrice.value * dosage.value * number;
}
return 0;
});
@@ -363,13 +423,10 @@ const sendPrescription = () => {
currentDrugs.value = [];
diagnosis.value = '';
medicalAdvice.value = '';
packageMethodId.value = 0;
processRuleId.value = 0;
processRuleNoteId.value = 0;
childProcessRuleId.value = 0;
processRulePrice.value = 0;
dosage.value = 0;
dayDosage.value = 0;
packageMethodId.value = 2;
processRulePrice.value = '';
dosage.value = 1;
dayDosage.value = 1;
updateLocalStorage();
});
};
@@ -419,6 +476,46 @@ watch(
const [WesternDrugModal, WesternDrugModalApi] = useVbenModal({
connectedComponent: WesternModal,
});
const [DiagnosisModals, DiagnosisModalApi] = useVbenModal({
connectedComponent: DiagnosisModal,
});
const openDiagnosisModal = () => {
// 打开常用诊断模态框逻辑
DiagnosisModalApi.setData({
values: diagnosis.value,
updateDiagnosis,
});
DiagnosisModalApi.open();
};
/**
* 更新诊断结果
* @param values
*/
function updateDiagnosis(values) {
diagnosis.value = values;
}
/**
* 常用医嘱
*/
const [DoctorOrderModals, DoctorOrderModalApi] = useVbenModal({
connectedComponent: DoctorOrderModal,
});
const openDoctorOrderModal = () => {
// 打开常用诊断模态框逻辑
DoctorOrderModalApi.setData({
values: medicalAdvice.value,
updateDoctorOrder,
});
DoctorOrderModalApi.open();
};
function updateDoctorOrder(values) {
medicalAdvice.value = values;
}
const [PrescrtionDetailModal, PrescrtionDetailModalApi] = useVbenModal({
connectedComponent: PrescrtionDetail,
});
@@ -539,6 +636,115 @@ function selectPackageMethod(id) {
// jishu
const dosage = ref(1);
const dayDosage = ref(1);
function updateChineseNumber() {
updateLocalStorage();
}
/**
* 获取药品列表
* @param {string} searchText - 搜索关键词
*/
const getDrugListByWesternModal = debounce(async (searchText = '') => {
if (searchText === '' && activeCategory.value === 1) {
drugList.value = [];
return;
}
getCurrentDrugs();
try {
const res = await getProductListDoctorReception({
store_id: 2,
type: activeCategory.value,
name: searchText,
});
drugList.value = res.map((item) => {
const matched = currentDrugs.value.find((v) => v.index_id === item.id);
return {
...item,
select_number: matched?.select_number || 0,
drug: {
...item.drug,
number: matched?.number || 1,
},
};
});
} catch (error) {
console.error('获取药品列表失败:', error);
message.error('获取药品列表失败');
}
}, 300);
/**
* 添加商品到处方
* @param {object} data - 商品对象
*/
function addProducts(data) {
// 查找是否已存在于选择列表中
const existItem = currentDrugs.value.find((item) => item.index_id === data.id);
if (existItem) {
message.warn('已经存在了');
return;
}
// 创建新的商品对象(避免直接修改原始数据)
const newProduct = {
// 索引ID用于在列表中查找
index_id: data.id,
// 药品ID
id: data.drug.id,
// 药品名称
drug_name: data.drug.drug_name,
// 药品数量
number: data.drug.number,
// 药品使用数量信息
use_num: drugTime.value.find((item) => item.id === data.drug.time_id),
// 药品使用类型信息
use_type: drugUseType.value.find((item) => item.id === data.drug.type_id),
// 药品使用频率信息
use_frequency: drugUseFrequency.value.find(
(item) => item.id === data.drug.frequency_id,
),
// 药品单位信息
unit: drugUnit.value.find((item) => item.id === data.drug.unit_id),
// 药品价格
price: data.price,
// 药品使用方式ID
way_id: data.drug?.way_id,
// 药品使用方式信息
use_ways: drugUseWay.value.find((item) => item.id === data.drug.way_id),
// 药品使用时间ID
time_id: data.drug.time_id,
// 药品类型ID
type_id: data.drug.type_id,
// 药品使用频率ID
frequency_id: data.drug.frequency_id,
// 药品单位ID
unit_id: data.drug.unit_id,
// 药品图片
image: data.drug.image,
// 药品说明书
instruction: data.drug.instruction,
// 药品类型
type: data.drug.type,
};
// 首次添加初始化数量为1
newProduct.select_number = 1;
// 添加到选中列表
currentDrugs.value.push(newProduct);
// 更新本地存储
updateLocalStorage();
// 提示成功
message.success(`已将${newProduct.drug_name}添加到清单中!`);
}
</script>
<template>
@@ -712,7 +918,12 @@ const dayDosage = ref(1);
<span class="time-line-item-created">{{
item.created_at
}}</span>
<Tag class="ml-5">{{ item.prescription_type === 1? '中药处方': '西药处方' }}</Tag>
<Tag class="ml-5">
{{ item.prescription_type === 1 ? '中药处方' : '西药处方' }} / {{ item.category === 1 ? '自费' : '医保' }}
</Tag>
<!-- <Tag class="ml-5">-->
<!-- {{ item.category === 1 ? '自费' : '医保' }}-->
<!-- </Tag>-->
</TimelineItem>
</Timeline>
</Descriptions.Item>
@@ -745,7 +956,7 @@ const dayDosage = ref(1);
</div>
<div class="mt-5">
<Button type="primary" @click="openWesternModal"> 添加品 </Button>
<Button type="primary" @click="openWesternModal"> 添加品 </Button>
<RadioGroup v-model:value="category" class="ml-5">
<RadioButton :value="1">自费</RadioButton>
<RadioButton :value="2">医保</RadioButton>
@@ -768,7 +979,149 @@ const dayDosage = ref(1);
</ImagePreviewGroup>
</div>
<!-- 已选药品列表 -->
<div class="selected-drugs">
<!-- 中药 -->
<div v-if="activeCategory === 1" class="mb-5 mt-3">
<Row>
<Col
:span="24">
<!-- 添加药品的卡片 -->
<Card title="" class="mt-2">
<template #extra>
</template>
<Popover v-model:open="searchChineseVisible" placement="bottom" trigger="click">
<Input
v-model:value="searchByChinese"
class="w-full"
placeholder="请输入药名或者拼音首拼"
@input="(e) => getDrugListByWesternModal(e.target.value)"
@click="searchChineseVisible = true"
allowClear
addon-before="检索中药:"
>
<!-- <textarea #addonBefore>-->
<!-- 检索中药:-->
<!-- </textarea>-->
</Input>
<!-- -->
<template #content>
<div v-if="searchByChinese !== ''">
<Row style="max-height: 400px; overflow: scroll; padding: 20px;" :gutter="12">
<Col v-for="itemDrug in drugList" :key="itemDrug.id" :span="drugList.length > 1? 4: 24">
<!-- 中药卡片 -->
<Card class="w-full mt-1" hoverable>
<p>{{ itemDrug.drug.drug_name}}</p>
<p>单价:{{itemDrug.price}}/g</p>
<div>
<InputNumber
v-model:value="itemDrug.drug.number"
class="w-full"
@blur="updateChineseNumber"
>
<template #addonAfter> g </template>
</InputNumber>
<Button class="w-full mt-2" type="primary" @click="addProducts(itemDrug)"> 添加到清单 </Button>
</div>
</Card>
</Col>
</Row>
</div>
<Empty v-else />
</template>
</Popover>
<!-- 用法:-->
<!-- 数量:-->
<!-- 单价:-->
</Card>
</Col>
<Col
v-for="(drug, index) in currentDrugs"
:key="drug.id"
:lg="4"
:md="4"
:sm="2"
:xl="8"
:xs="2"
>
<Card :title="drug.drug_name" class="mt-2">
<template #extra>
<Button type="link" @click="removeDrug(index)"> 删除 </Button>
</template>
<div>
<!-- <Input v-model:value="drug.drug_name" />-->
<p>
<span
>用法:{{ drug.use_ways?.name || '煎服' }}{{ drug.number
}}{{ drug.unit.name }}</span>
单价: <span>{{ drug.price }}元</span>
</p>
</div>
<div class="mt-5">
<!-- 选择中药煎法-->
<Select
:value="drug?.way_id"
class="mt-3 w-full mb-2"
placeholder="煎服"
@change="selectDrugUseWayChange"
@dropdown-visible-change="
selectProductChange(drug.index_id)
"
>
<SelectOption :value="0">煎服</SelectOption>
<SelectOption
v-for="(value, index) in drugUseWay"
:key="index"
:value="value.id"
>
{{ value.name }}
</SelectOption>
</Select>
<InputNumber
v-model:value="drug.number"
class="w-full"
@blur="updateChineseNumber"
>
<template #addonAfter> g </template>
</InputNumber>
</div>
</Card>
</Col>
</Row>
<!-- <div
v-for="(drug, index) in currentDrugs"
:key="drug.id"
class="table-row"
>
<div>
<p>
<span>药品名称:{{ drug.drug_name }}</span>
</p>
<p>
<span
>用法:{{ drug.use_way?.name || '煎服' }}{{ drug.number
}}{{ drug.unit.name }}</span>
</p>
</div>
<div>
<div class="quantity-control">
<InputNumber
class="w-full"
v-model:value="drug.number"
@blur="updateChineseNumber"
>
<template #addonAfter> g </template>
</InputNumber>
</div>
</div>
<span>{{ drug.price }}</span>
<div>
<Button type="link" @click="removeDrug(index)">删除</Button>
</div>
</div>-->
</div>
<!-- 西(中成)药列表 -->
<div v-else class="selected-drugs">
<div class="drug-table">
<div class="table-header">
<span v-if="activeCategory !== 1">商品图片</span>
@@ -794,24 +1147,24 @@ const dayDosage = ref(1);
<span>药品名称:{{ drug.drug_name }}</span>
</p>
<p>
<span v-if="activeCategory === 1"
>用法:{{ drug.use_way?.name || '煎服' }}{{ drug.number
}}{{ drug.unit.name }}</span>
<span v-else-if="activeCategory === 2"
>用法:{{
`${drug.use_type?.name}${drug.use_num?.name}${drug.use_type?.name},每次${drug.number}${drug.unit?.name}`
<span>用法:{{
`${drug.use_type?.name}${drug.use_frequency?.name}${drug.use_num?.name},每次${drug.number}${drug.unit?.name}`
}}</span>
</p>
</div>
<div>
<div v-if="activeCategory === 1" class="quantity-control">
<Button type="primary" @click="decrement(index)">-</Button>
<span style="margin: 0 20px">{{ drug.number }}</span>
<Button type="primary" @click="increment(index)">+</Button>
<InputNumber
v-model:value="drug.select_number"
class="w-full"
@blur="updateChineseNumber"
>
<template #addonAfter> g </template>
</InputNumber>
</div>
<div v-else class="quantity-control">
<Button type="primary" @click="decrement(index)">-</Button>
<span style="margin: 0 20px">{{ drug.number }}</span>
<span style="margin: 0 20px">{{ drug.select_number }}</span>
<Button type="primary" @click="increment(index)">+</Button>
</div>
</div>
@@ -939,9 +1292,9 @@ const dayDosage = ref(1);
次/天
</div>
</div>
<Button type="primary">常用诊断</Button>
<Button type="primary" @click="openDiagnosisModal">常用诊断</Button>
<Textarea v-model:value="diagnosis" placeholder="输入诊断结果..." />
<Button type="primary">常用医嘱</Button>
<Button type="primary" @click="openDoctorOrderModal">常用医嘱</Button>
<Textarea v-model:value="medicalAdvice" placeholder="输入医嘱..." />
诊疗费用:
<InputNumber
@@ -960,6 +1313,8 @@ const dayDosage = ref(1);
<div v-else-if="tabType === 0" class="prescription-panel">
<Empty />
</div>
<DiagnosisModals />
<DoctorOrderModals />
<WesternDrugModal />
<PrescrtionDetailModal />
</div>
@@ -992,6 +1347,7 @@ const dayDosage = ref(1);
.patient-card.active {
border-left: 4px solid #455cda;
background-color: rgba(69, 92, 218, 0.1);
}
.status {

View File

@@ -48,6 +48,14 @@ export async function deleteAdmin(data: Record<string, any>) {
return requestClient.post<any>(`${prefix}delete`, data);
}
/**
* 修改密码
* @param data
*/
export async function updatePassword(data: Record<string, any>) {
return requestClient.post<any>(`${prefix}update-password`, data);
}
/**
* 删除管理员
* @param id

View File

@@ -116,6 +116,7 @@
]
},
"dependencies": {
"js-base64": "^3.7.7"
"js-base64": "^3.7.7",
"lodash-es": "^4.17.21"
}
}

View File

@@ -6,7 +6,7 @@ export const LOGIN_PATH = '/auth/login';
/**
* @zh_CN 默认首页地址
*/
export const DEFAULT_HOME_PATH = '/analytics';
export const DEFAULT_HOME_PATH = '/workspace';
export interface LanguageOption {
label: string;

View File

@@ -28,6 +28,8 @@ import { useMagicKeys, whenever } from '@vueuse/core';
import { LockScreenModal } from '../lock-screen';
import UpdatePasswordModal from '../../../../../../apps/web-antd/src/layouts/components/UpdatePasswordModal.vue'
interface Props {
/**
* 头像
@@ -96,7 +98,6 @@ const [openPopover, hoverWatcher] = useHoverToggle(
[refTrigger, refContent],
() => props.hoverDelay,
);
watch(
() => props.trigger === 'hover' || props.trigger === 'both',
(val) => {
@@ -159,9 +160,17 @@ if (enableShortcutKey.value) {
}
});
}
/**
* 修改密码弹窗
*/
const [UpdatePasswordModals, UpdatePasswordModalApi] = useVbenModal({
connectedComponent: UpdatePasswordModal,
});
</script>
<template>
<UpdatePasswordModals />
<LockModal
v-if="preferences.widget.lockScreen"
:avatar="avatar"
@@ -218,6 +227,15 @@ if (enableShortcutKey.value) {
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator v-if="menus?.length" />
<!-- 单独写一个修改密码 -->
<DropdownMenuItem
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
@click="UpdatePasswordModalApi.open()"
>
<VbenIcon icon="carbon:password" class="mr-2 size-4" />
修改密码
</DropdownMenuItem>
<!-- 数组中的菜单跳转 -->
<DropdownMenuItem
v-for="menu in menus"
:key="menu.text"

36
pnpm-lock.yaml generated
View File

@@ -472,6 +472,9 @@ importers:
js-base64:
specifier: ^3.7.7
version: 3.7.7
lodash-es:
specifier: ^4.17.21
version: 4.17.21
devDependencies:
'@changesets/changelog-github':
specifier: 'catalog:'
@@ -3143,20 +3146,20 @@ packages:
resolution: {integrity: sha512-6GT1BJ852gZ0gItNZN2krX5QAmea+cmdjMvsWohArAZ3GmHdnNANEcF9JjPXAMRtQ6Ux5E269ymamg/+WU6tQA==}
engines: {node: '>= 16'}
'@intlify/message-compiler@11.0.0-rc.1':
resolution: {integrity: sha512-TGw2uBfuTFTegZf/BHtUQBEKxl7Q/dVGLoqRIdw8lFsp9g/53sYn5iD+0HxIzdYjbWL6BTJMXCPUHp9PxDTRPw==}
'@intlify/message-compiler@12.0.0-alpha.1':
resolution: {integrity: sha512-rS1Lc99D2uaGqWxlrpGPWdgkq2Jox8xxOS9gdIRhuF2CsuJISWQmwd/TjMnWNhwv9olE0aPEBh1323a61Tfp+g==}
engines: {node: '>= 16'}
'@intlify/shared@10.0.5':
resolution: {integrity: sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==}
engines: {node: '>= 16'}
'@intlify/shared@11.0.0-rc.1':
resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==}
'@intlify/shared@11.1.2':
resolution: {integrity: sha512-dF2iMMy8P9uKVHV/20LA1ulFLL+MKSbfMiixSmn6fpwqzvix38OIc7ebgnFbBqElvghZCW9ACtzKTGKsTGTWGA==}
engines: {node: '>= 16'}
'@intlify/shared@11.0.1':
resolution: {integrity: sha512-lH164+aDDptHZ3dBDbIhRa1dOPQUp+83iugpc+1upTOWCnwyC1PVis6rSWNMMJ8VQxvtHQB9JMib48K55y0PvQ==}
'@intlify/shared@12.0.0-alpha.1':
resolution: {integrity: sha512-ZZ5rtlUcEnhhFS+MTrl0V1UoN3yRninGawP3f1YituJN9217xJvpqCSLa9t8NLaVwVIxsRcq4lQe48D0SigmBg==}
engines: {node: '>= 16'}
'@intlify/unplugin-vue-i18n@6.0.1':
@@ -6606,6 +6609,7 @@ packages:
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
@@ -11180,8 +11184,8 @@ snapshots:
'@intlify/bundle-utils@10.0.0(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))':
dependencies:
'@intlify/message-compiler': 11.0.0-rc.1
'@intlify/shared': 11.0.0-rc.1
'@intlify/message-compiler': 12.0.0-alpha.1
'@intlify/shared': 12.0.0-alpha.1
acorn: 8.14.0
escodegen: 2.1.0
estree-walker: 2.0.2
@@ -11202,23 +11206,23 @@ snapshots:
'@intlify/shared': 10.0.5
source-map-js: 1.2.1
'@intlify/message-compiler@11.0.0-rc.1':
'@intlify/message-compiler@12.0.0-alpha.1':
dependencies:
'@intlify/shared': 11.0.0-rc.1
'@intlify/shared': 12.0.0-alpha.1
source-map-js: 1.2.1
'@intlify/shared@10.0.5': {}
'@intlify/shared@11.0.0-rc.1': {}
'@intlify/shared@11.1.2': {}
'@intlify/shared@11.0.1': {}
'@intlify/shared@12.0.0-alpha.1': {}
'@intlify/unplugin-vue-i18n@6.0.1(@vue/compiler-dom@3.5.13)(eslint@9.17.0(jiti@2.4.2))(rollup@4.28.1)(typescript@5.7.2)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2))
'@intlify/bundle-utils': 10.0.0(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))
'@intlify/shared': 11.0.1
'@intlify/vue-i18n-extensions': 7.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))
'@intlify/shared': 11.1.2
'@intlify/vue-i18n-extensions': 7.0.0(@intlify/shared@11.1.2)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))
'@rollup/pluginutils': 5.1.4(rollup@4.28.1)
'@typescript-eslint/scope-manager': 8.18.1
'@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2)
@@ -11240,11 +11244,11 @@ snapshots:
- supports-color
- typescript
'@intlify/vue-i18n-extensions@7.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))':
'@intlify/vue-i18n-extensions@7.0.0(@intlify/shared@11.1.2)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))':
dependencies:
'@babel/parser': 7.26.3
optionalDependencies:
'@intlify/shared': 11.0.1
'@intlify/shared': 11.1.2
'@vue/compiler-dom': 3.5.13
vue: 3.5.13(typescript@5.7.2)
vue-i18n: 10.0.5(vue@3.5.13(typescript@5.7.2))