feat: 111
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :model-value="visible" @update:model-value="handleUpdateVisible" title="添加药材" width="600px" destroy-on-close>
|
||||
<el-form :model="form" label-width="120px" ref="formRef" class="mt-2" :rules="formRules">
|
||||
<!-- 药材下拉 + 未找到按钮 -->
|
||||
<el-form-item v-if="!isAddingNew" label="药材名称" prop="medicinalTypeId" style="display: flex; align-items: center">
|
||||
<el-select v-model="form.medicinalTypeId" placeholder="请选择药材" filterable style="flex: 1; margin-right: 8px">
|
||||
<el-option v-for="item in medicinalList" :key="item.id" :label="item.dictLabel" :value="item.id" />
|
||||
</el-select>
|
||||
<el-button type="text" @click="handleNotFound">未找到</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 新药材输入框 -->
|
||||
<el-form-item label="新药材名称" v-if="isAddingNew" prop="medicinalName">
|
||||
<el-input v-model="form.medicinalName" placeholder="请输入新药材名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="添加量(g)" prop="addWeight">
|
||||
<el-input v-model.number="form.addWeight" type="number" min="0.01" step="0.01" placeholder="请输入添加量" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 改为总价输入 -->
|
||||
<el-form-item label="总价" prop="totalPrice">
|
||||
<el-input v-model.number="form.totalPrice" type="number" min="0" step="0.01" placeholder="请输入总价(元)" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确认添加</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed } from "vue";
|
||||
import { medicinalApi } from "@/api/modules/biz/WeiBingJu/medicinal";
|
||||
import { ElMessage, ElForm, FormRules } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false }
|
||||
});
|
||||
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
||||
|
||||
const medicinalList = ref<any[]>([]);
|
||||
const isAddingNew = ref(false);
|
||||
|
||||
const formRef = ref<InstanceType<typeof ElForm>>();
|
||||
const form = reactive({
|
||||
medicinalTypeId: null as number | null,
|
||||
addWeight: 0,
|
||||
// 前端改为 totalPrice
|
||||
totalPrice: 0,
|
||||
medicinalName: ""
|
||||
});
|
||||
|
||||
// 动态表单校验(注意 totalPrice 字段)
|
||||
const formRules = computed<FormRules>(() => ({
|
||||
medicinalTypeId: [{ required: !isAddingNew.value, message: "请选择药材", trigger: "change" }],
|
||||
medicinalName: [{ required: isAddingNew.value, message: "请输入新药材名称", trigger: "blur" }],
|
||||
addWeight: [
|
||||
{ required: true, message: "请输入添加量", trigger: "blur" },
|
||||
{ type: "number", min: 0.01, message: "添加量不能小于0.01", trigger: "blur" }
|
||||
],
|
||||
totalPrice: [
|
||||
{ required: true, message: "请输入总价", trigger: "blur" },
|
||||
{ type: "number", min: 0, message: "总价不能为负", trigger: "blur" }
|
||||
]
|
||||
}));
|
||||
|
||||
const fetchMedicinalList = async () => {
|
||||
try {
|
||||
const res = await medicinalApi.getDictList();
|
||||
medicinalList.value = res.data || [];
|
||||
} catch (err) {
|
||||
ElMessage.error("加载药材列表失败");
|
||||
medicinalList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
async newVal => {
|
||||
if (newVal) {
|
||||
handleResetForm();
|
||||
await fetchMedicinalList();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleUpdateVisible = (newVisible: boolean) => {
|
||||
emit("update:visible", newVisible);
|
||||
if (!newVisible) {
|
||||
handleResetForm();
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
const handleCancel = () => emit("update:visible", false);
|
||||
const handleResetForm = () => {
|
||||
form.medicinalTypeId = null;
|
||||
form.addWeight = 0;
|
||||
form.totalPrice = 0;
|
||||
form.medicinalName = "";
|
||||
isAddingNew.value = false;
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
const handleNotFound = () => {
|
||||
isAddingNew.value = true;
|
||||
form.medicinalTypeId = null;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算单价,并校验 addWeight > 0
|
||||
if (!form.addWeight || form.addWeight <= 0) {
|
||||
ElMessage.warning("添加量需大于 0");
|
||||
return;
|
||||
}
|
||||
|
||||
// unitPrice = totalPrice / addWeight,保留两位
|
||||
const unitPrice = parseFloat((form.totalPrice / form.addWeight).toFixed(2));
|
||||
|
||||
// 构造后端期望的 payload(注意把 totalPrice 改为 unitPrice)
|
||||
const payload: any = {
|
||||
medicinalTypeId: form.medicinalTypeId,
|
||||
addWeight: form.addWeight,
|
||||
unitPrice: unitPrice,
|
||||
medicinalName: form.medicinalName
|
||||
};
|
||||
|
||||
try {
|
||||
await medicinalApi.addMedicinal(payload);
|
||||
ElMessage.success("添加成功");
|
||||
emit("update:visible", false);
|
||||
emit("refreshList");
|
||||
} catch (err: any) {
|
||||
ElMessage.error(err.message || "添加失败");
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,225 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="props.visible"
|
||||
:title="`${props.medicinalName} - 添加记录`"
|
||||
width="1200px"
|
||||
@close="handleDialogClose"
|
||||
@update:model-value="handleUpdateVisible"
|
||||
append-to-body
|
||||
>
|
||||
<ProTable ref="proTableRef" title="添加记录" :columns="columns" :request-api="getAdditionRecordsApi" :row-key="rowKey" :show-selection="false">
|
||||
<!-- 行内列 slot:addWeight -->
|
||||
<template #addWeight="{ row }">
|
||||
<template v-if="editingId === row.id">
|
||||
<el-input-number v-model.number="editModel.addWeight" :min="0.01" :step="0.01" controls-position="right" size="small" />
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ row.addWeight }}
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- unitPrice 列:只展示单价,不编辑 -->
|
||||
<template #unitPrice="{ row }">
|
||||
{{ (row.unitPrice ?? 0).toFixed(2) }}
|
||||
</template>
|
||||
|
||||
<!-- totalPrice 列:查看时显示合计,编辑时可以修改 -->
|
||||
<template #totalPrice="{ row }">
|
||||
<template v-if="editingId === row.id">
|
||||
<el-input-number
|
||||
v-model.number="editModel.totalPrice"
|
||||
:min="0"
|
||||
:step="0.01"
|
||||
controls-position="right"
|
||||
size="small"
|
||||
placeholder="输入总价(元)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ ((row.addWeight ?? 0) * (row.unitPrice ?? 0)).toFixed(2) }}
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- addTime 格式化 -->
|
||||
<template #addTime="{ row }">
|
||||
{{ row.addTime ? formatDate(row.addTime) : "-" }}
|
||||
</template>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<template #operation="{ row }">
|
||||
<template v-if="editingId === row.id">
|
||||
<el-button size="small" type="primary" @click="saveRowEdit(row)" :loading="saving"> 保存 </el-button>
|
||||
<el-button size="small" @click="cancelRowEdit">取消</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="text" size="small" @click="startRowEdit(row)"> 编辑 </el-button>
|
||||
<el-button type="text" size="small" text-color="#ff4d4f" @click="handleDeleteRecord(row.id)"> 删除 </el-button>
|
||||
</template>
|
||||
</template>
|
||||
</ProTable>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 单行行内编辑版本(总价 totalPrice 输入):
|
||||
* - 点击「编辑」:将该行复制到 editModel(editModel.addWeight & editModel.totalPrice),记录 editingId(只允许单行编辑)
|
||||
* - 保存:计算 unitPrice = totalPrice / addWeight,发送 unitPrice 到后端
|
||||
* - 取消:不调用后端,直接清除 editingId(恢复显示)
|
||||
*/
|
||||
|
||||
import { defineProps, defineEmits, ref, reactive, watch, nextTick } from "vue";
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import { medicinalApi } from "@/api";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false },
|
||||
medicinalId: { type: Number, required: true },
|
||||
medicinalName: { type: String, default: "药材" }
|
||||
});
|
||||
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
||||
|
||||
// proTable 引用(用于 refresh)
|
||||
const proTableRef = ref<any | null>(null);
|
||||
|
||||
// 当前正在编辑的行 id(单行)
|
||||
const editingId = ref<number | null>(null);
|
||||
|
||||
// 编辑模型(只存一行):注意 totalPrice 而不是 unitPrice
|
||||
const editModel = reactive({
|
||||
addWeight: 0,
|
||||
totalPrice: 0
|
||||
});
|
||||
|
||||
// 保存中标记,避免重复提交
|
||||
const saving = ref(false);
|
||||
|
||||
// 列定义,slotName 使用 prop 名称(与 ProTable slot 对应)
|
||||
const columns = [
|
||||
{ prop: "addWeight", label: "添加量(g)", minWidth: 120, slotName: "addWeight" },
|
||||
{ prop: "unitPrice", label: "单价(元/g)", minWidth: 120, slotName: "unitPrice" },
|
||||
{ prop: "totalPrice", label: "总价(元)", minWidth: 120, slotName: "totalPrice" },
|
||||
{ prop: "addTime", label: "添加时间", minWidth: 200, slotName: "addTime" },
|
||||
{ prop: "addUserName", label: "添加人员", minWidth: 150 },
|
||||
{ prop: "operation", label: "操作", width: 180, fixed: "right", slotName: "operation" }
|
||||
];
|
||||
|
||||
const rowKey = (row: any) => row.id;
|
||||
|
||||
// 打开弹窗时刷新表格
|
||||
watch(
|
||||
() => props.visible,
|
||||
async val => {
|
||||
if (val && props.medicinalId) {
|
||||
await nextTick();
|
||||
proTableRef.value?.refresh?.();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 将 ProTable 的请求透传到后端(ProTable 会带上 pageNum/pageSize 等)
|
||||
const getAdditionRecordsApi = (params: any) => {
|
||||
return medicinalApi.getAdditionRecords(props.medicinalId, params);
|
||||
};
|
||||
|
||||
// 开始编辑:把当前行复制到 editModel(addWeight 和 totalPrice)
|
||||
const startRowEdit = (row: any) => {
|
||||
if (editingId.value !== null && editingId.value !== row.id) {
|
||||
ElMessage.warning("请先保存或取消当前正在编辑的行");
|
||||
return;
|
||||
}
|
||||
editingId.value = row.id;
|
||||
editModel.addWeight = row.addWeight ?? 0;
|
||||
// 后端返回的是 unitPrice,前端要显示/编辑 totalPrice = unitPrice * addWeight
|
||||
editModel.totalPrice = Number(((row.unitPrice ?? 0) * (row.addWeight ?? 1)).toFixed(2));
|
||||
};
|
||||
|
||||
// 取消编辑:清空 editingId(恢复显示)
|
||||
const cancelRowEdit = () => {
|
||||
editingId.value = null;
|
||||
editModel.addWeight = 0;
|
||||
editModel.totalPrice = 0;
|
||||
};
|
||||
|
||||
// 保存编辑:计算 unitPrice = totalPrice / addWeight -> 发送到后端
|
||||
const saveRowEdit = async (row: any) => {
|
||||
// 基本校验
|
||||
if (!editModel.addWeight || editModel.addWeight <= 0) {
|
||||
ElMessage.warning("添加量需大于 0");
|
||||
return;
|
||||
}
|
||||
if (editModel.totalPrice < 0) {
|
||||
ElMessage.warning("总价不能为负");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
// 计算 unitPrice(保留两位)
|
||||
const unitPrice = parseFloat((editModel.totalPrice / editModel.addWeight).toFixed(2));
|
||||
|
||||
await medicinalApi.updateAdditionRecord(row.id, {
|
||||
addWeight: editModel.addWeight,
|
||||
unitPrice: unitPrice
|
||||
});
|
||||
|
||||
ElMessage.success("保存成功");
|
||||
// 刷新表格并退出编辑
|
||||
await proTableRef.value?.refresh?.();
|
||||
emit("refreshList");
|
||||
cancelRowEdit();
|
||||
} catch (err: any) {
|
||||
ElMessage.error(err?.message || "保存失败");
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 删除记录
|
||||
const handleDeleteRecord = async (id: number) => {
|
||||
ElMessageBox.confirm("确定要删除这条添加记录吗?删除后不可恢复!", "确认删除", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
await medicinalApi.deleteAdditionRecord(id);
|
||||
ElMessage.success("删除成功");
|
||||
await proTableRef.value?.refresh?.();
|
||||
emit("refreshList");
|
||||
} catch (err: any) {
|
||||
ElMessage.error(err?.message || "删除失败");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
/* 用户取消删除 */
|
||||
});
|
||||
};
|
||||
|
||||
// 格式化时间
|
||||
const formatDate = (dateStr: string) => {
|
||||
const d = new Date(String(dateStr).replace(" ", "T"));
|
||||
return isNaN(d.getTime()) ? dateStr : d.toLocaleString();
|
||||
};
|
||||
|
||||
// 处理弹窗关闭
|
||||
const handleDialogClose = () => {
|
||||
editingId.value = null;
|
||||
editModel.addWeight = 0;
|
||||
editModel.totalPrice = 0;
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
const handleUpdateVisible = (newVal: boolean) => {
|
||||
if (!newVal) handleDialogClose();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,85 +0,0 @@
|
||||
<template>
|
||||
<!-- 关键修改:v-model → :visible + @update:visible -->
|
||||
<el-dialog :visible="visible" @update:visible="handleUpdateVisible" :title="`${medicinalName} - 消耗记录`" width="800px">
|
||||
<el-table v-loading="loading" :data="consumptionRecords" border style="width: 100%" empty-text="暂无消耗记录">
|
||||
<el-table-column prop="amountG" label="使用量(g)" width="120"></el-table-column>
|
||||
<el-table-column label="使用人员" width="200">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.personName }}</span>
|
||||
<el-tag size="small" type="info" v-if="scope.row.isRelative" style="margin-left: 8px">
|
||||
家属({{ scope.row.employeeName || "未知员工" }})
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="useTime" label="使用时间" width="200">
|
||||
<template #default="scope">
|
||||
{{ scope.row.useTime ? new Date(scope.row.useTime).toLocaleString() : "-" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits, ref, watch } from "vue";
|
||||
import { getConsumptionRecords, Medicinal } from "@/api/modules/biz/WeiBingJu/medicinal";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
// 1. 接收父组件prop
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
medicinalId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
medicinalName: {
|
||||
type: String,
|
||||
default: "药材"
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 定义发射事件:update:visible + 关闭通知
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 状态数据
|
||||
const loading = ref(false);
|
||||
const consumptionRecords = ref<Medicinal.ConsumptionRecord[]>([]);
|
||||
|
||||
// 3. 监听弹窗状态变化
|
||||
const handleUpdateVisible = (newVisible: boolean) => {
|
||||
emit("update:visible", newVisible);
|
||||
// 弹窗关闭时清空数据
|
||||
if (!newVisible) {
|
||||
consumptionRecords.value = [];
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
|
||||
// 监听visible变化:弹窗显示时加载消耗记录
|
||||
watch(
|
||||
() => props.visible,
|
||||
async newVal => {
|
||||
if (newVal && props.medicinalId) {
|
||||
await fetchConsumptionRecords();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 加载消耗记录
|
||||
const fetchConsumptionRecords = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getConsumptionRecords({ medicinalId: props.medicinalId });
|
||||
consumptionRecords.value = res;
|
||||
} catch (err: any) {
|
||||
ElMessage.error(err.message || "加载消耗记录失败");
|
||||
consumptionRecords.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<el-card class="mt-4">
|
||||
<ProTable ref="proTable" title="药材列表" :columns="columns" :request-api="medicinalApi.page">
|
||||
<template #tableHeader>
|
||||
<!-- 新增按钮:保持框架一致的 s-button 写法 -->
|
||||
<s-button suffix="药材" @click="onOpenAdd" />
|
||||
</template>
|
||||
|
||||
<template #operation="scope">
|
||||
<s-button link :opt="FormOptEnum.VIEW" size="small" @click="handleViewConsumption(scope.row)"> 查看消耗记录 </s-button>
|
||||
<s-button link :opt="FormOptEnum.VIEW" size="small" class="ml-2" @click="handleViewAddition(scope.row)"> 查看添加记录 </s-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
</el-card>
|
||||
|
||||
<!-- 消耗记录弹窗 -->
|
||||
<consumption-record-dialog v-model:visible="showConsumptionDialog" :medicinal-id="currentMedicinalId" :medicinal-name="currentMedicinalName" />
|
||||
|
||||
<!-- 添加记录弹窗 -->
|
||||
<addition-record-dialog
|
||||
:visible="showAdditionDialog"
|
||||
:medicinal-id="currentMedicinalId"
|
||||
:medicinal-name="currentMedicinalName"
|
||||
@update:visible="val => (showAdditionDialog = val)"
|
||||
@refresh-list="handleRefresh"
|
||||
/>
|
||||
|
||||
<!-- 新增药材弹窗 -->
|
||||
<add-medicinal-dialog v-model:visible="showAddMedicinalDialog" @refresh-list="handleRefresh" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx" name="sysModule">
|
||||
import { medicinalApi, MedicinalInfo } from "@/api";
|
||||
import { ref } from "vue";
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import type { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
|
||||
|
||||
import { FormOptEnum } from "@/enums";
|
||||
|
||||
// 子组件
|
||||
//import ConsumptionRecordDialog from "./components/ConsumptionRecordDialog.vue";
|
||||
import AdditionRecordDialog from "./components/AdditionRecordDialog.vue";
|
||||
import AddMedicinalDialog from "./components/AddMedicinalDialog.vue";
|
||||
|
||||
const proTable = ref<ProTableInstance | null>(null);
|
||||
|
||||
const showConsumptionDialog = ref(false);
|
||||
const showAdditionDialog = ref(false);
|
||||
const showAddMedicinalDialog = ref(false);
|
||||
|
||||
const currentMedicinalId = ref<number | null>(null);
|
||||
const currentMedicinalName = ref<string>("");
|
||||
|
||||
const columns: ColumnProps<MedicinalInfo>[] = [
|
||||
{ type: "selection", fixed: "left", width: 80 },
|
||||
{ prop: "medicinalName", label: "药材名称", search: { el: "input" } },
|
||||
{ prop: "stock", label: "药材库存(g)" },
|
||||
{ prop: "usedCost", label: "使用成本" },
|
||||
{ prop: "remainingValue", label: "剩余价值" },
|
||||
{ prop: "operation", label: "操作", width: 240, fixed: "right" }
|
||||
];
|
||||
|
||||
// 打开新增药材弹窗
|
||||
function onOpenAdd() {
|
||||
showAddMedicinalDialog.value = true;
|
||||
}
|
||||
|
||||
// 查看消耗记录
|
||||
function handleViewConsumption(row: MedicinalInfo) {
|
||||
currentMedicinalId.value = row.medicinalId ?? (row as any).id ?? null;
|
||||
currentMedicinalName.value = row.medicinalName ?? "";
|
||||
showConsumptionDialog.value = true;
|
||||
}
|
||||
|
||||
// 查看添加记录
|
||||
function handleViewAddition(row: MedicinalInfo) {
|
||||
console.log("查看添加记录", row);
|
||||
// 直接设置正确的ID和名称,然后显示弹窗
|
||||
currentMedicinalId.value = row.medicinalId ?? (row as any).id ?? null;
|
||||
currentMedicinalName.value = row.medicinalName ?? "";
|
||||
showAdditionDialog.value = true;
|
||||
}
|
||||
|
||||
// 刷新列表
|
||||
function handleRefresh() {
|
||||
proTable.value?.refresh?.();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.table-box {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.ml-2 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,714 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :model-value="visible" @update:model-value="handleUpdateVisible" :title="dialogTitle" width="900px" destroy-on-close>
|
||||
<!-- 人员信息 -->
|
||||
<el-card shadow="hover" class="mb-4">
|
||||
<template #header><span>人员信息</span></template>
|
||||
<el-form :model="personForm" label-width="120px" :disabled="!isEdit" ref="personFormRef" :rules="personFormRules">
|
||||
<!-- 1. 人员类型 -->
|
||||
<el-form-item label="人员类型" required prop="isEmployee">
|
||||
<el-radio-group v-model="personForm.isEmployee" @change="handlePersonTypeChange">
|
||||
<el-radio :label="true">公司员工</el-radio>
|
||||
<el-radio :label="false">员工家属</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 2. 员工场景:员工选择/新增 -->
|
||||
<template v-if="personForm.isEmployee">
|
||||
<!-- 员工下拉选择(默认显示) -->
|
||||
<el-form-item v-if="showEmployeeSelect" label="员工姓名" required prop="employeeId">
|
||||
<el-select
|
||||
v-model="personForm.employeeId"
|
||||
placeholder="搜索或选择员工"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleEmployeeSearch"
|
||||
@change="handleEmployeeChange"
|
||||
clearable
|
||||
>
|
||||
<!-- 正常员工选项 -->
|
||||
<el-option v-for="emp in employeeOptions" :key="emp.id" :label="emp.name" :value="emp.id" />
|
||||
<!-- 未找到选项(仅搜索后无结果时显示) -->
|
||||
<el-option v-if="employeeOptions.length === 0 && employeeKeyword" :key="0" :label="`未找到,新增员工:${employeeKeyword}`" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 员工新增文本框(点击"未找到"后显示) -->
|
||||
<el-form-item v-if="!showEmployeeSelect" label="员工姓名" required prop="newEmployeeName">
|
||||
<el-input
|
||||
v-model="personForm.newEmployeeName"
|
||||
placeholder="输入新员工姓名"
|
||||
@blur="() => (personForm.name = personForm.newEmployeeName)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 3. 家属场景:关联员工选择 + 家属选择/新增 -->
|
||||
<template v-else>
|
||||
<!-- 3.1 关联员工选择(第一步) -->
|
||||
<el-form-item v-if="showRelatedEmployeeSelect" label="关联员工" required prop="relatedEmployeeId">
|
||||
<el-select
|
||||
v-model="personForm.relatedEmployeeId"
|
||||
placeholder="搜索或选择关联员工"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleRelatedEmployeeSearch"
|
||||
@change="handleRelatedEmployeeChange"
|
||||
clearable
|
||||
>
|
||||
<!-- 正常关联员工选项 -->
|
||||
<el-option v-for="emp in relatedEmployeeOptions" :key="emp.id" :label="emp.name" :value="emp.id" />
|
||||
<!-- 未找到选项 -->
|
||||
<el-option
|
||||
v-if="relatedEmployeeOptions.length === 0 && relatedEmployeeKeyword"
|
||||
:key="0"
|
||||
:label="`未找到,新增关联员工:${relatedEmployeeKeyword}`"
|
||||
:value="0"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 3.2 关联员工新增(点击"未找到"后显示) -->
|
||||
<el-form-item v-if="!showRelatedEmployeeSelect" label="关联员工姓名" required prop="newRelatedEmployeeName">
|
||||
<el-input v-model="personForm.newRelatedEmployeeName" placeholder="输入新关联员工姓名" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 3.3 家属选择(选择关联员工后显示) -->
|
||||
<el-form-item v-if="showRelativeSelect && personForm.relatedEmployeeId" label="家属姓名" required prop="relativeId">
|
||||
<el-select
|
||||
v-model="personForm.relativeId"
|
||||
placeholder="搜索或选择家属"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleRelativeSearch"
|
||||
@change="handleRelativeChange"
|
||||
clearable
|
||||
>
|
||||
<!-- 正常家属选项 -->
|
||||
<el-option v-for="rel in relativeOptions" :key="rel.id" :label="rel.name" :value="rel.id" />
|
||||
<!-- 未找到选项 -->
|
||||
<el-option v-if="relativeOptions.length === 0 && relativeKeyword" :key="0" :label="`未找到,新增家属:${relativeKeyword}`" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 3.4 家属新增(点击"未找到"后显示 / 关联员工新增时同步显示) -->
|
||||
<el-form-item v-if="!showRelativeSelect || !showRelatedEmployeeSelect" label="家属姓名" required prop="newRelativeName">
|
||||
<el-input
|
||||
v-model="personForm.newRelativeName"
|
||||
placeholder="输入新家属姓名"
|
||||
@blur="() => (personForm.name = personForm.newRelativeName)"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 3.5 亲属关系(家属场景必选) -->
|
||||
<el-form-item label="亲属关系" required prop="relationShip" v-if="personForm.relatedEmployeeId || !showRelatedEmployeeSelect">
|
||||
<el-select v-model="personForm.relationShip" clearable>
|
||||
<el-option v-for="item in relationTypes" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 4. 公共信息:年龄/体重/身高(复用原有逻辑) -->
|
||||
<el-form-item label="年龄" prop="age">
|
||||
<el-input v-model.number="personForm.age" placeholder="输入年龄" />
|
||||
</el-form-item>
|
||||
<el-form-item label="体重(kg)" prop="weight">
|
||||
<el-input v-model.number="personForm.weight" placeholder="输入体重" />
|
||||
</el-form-item>
|
||||
<el-form-item label="身高(cm)" prop="height">
|
||||
<el-input v-model.number="personForm.height" placeholder="输入身高" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 药材消耗、诊断建议等原有模块(保持不变) -->
|
||||
<el-card shadow="hover" class="mb-4">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span>药材消耗</span>
|
||||
<el-button v-if="isEdit" type="primary" size="small" @click="handleAddHerb"> 添加药材 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="herbList" border :disabled="!isEdit" empty-text="暂无药材消耗记录">
|
||||
<el-table-column label="药材名称" required>
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-model="scope.row.medicinalId"
|
||||
placeholder="搜索或选择药材"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="kw => handleHerbSearch(kw, scope.$index)"
|
||||
@change="val => handleHerbChange(val, scope.$index)"
|
||||
:disabled="!isEdit"
|
||||
clearable
|
||||
>
|
||||
<el-option v-for="item in scope.row.medicinalOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
<el-option
|
||||
v-if="scope.row.medicinalOptions.length === 0 && scope.row.keyword"
|
||||
:key="0"
|
||||
:label="`新增药材:${scope.row.keyword}`"
|
||||
:value="0"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input v-if="scope.row.showNewInput" v-model="scope.row.newName" placeholder="输入新药材名称" class="mt-2" :disabled="!isEdit" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="消耗(g)" required>
|
||||
<template #default="scope">
|
||||
<el-input v-model.number="scope.row.amountG" type="number" min="0.1" placeholder="输入消耗克数" :disabled="!isEdit" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.note" placeholder="输入备注" :disabled="!isEdit" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" v-if="isEdit">
|
||||
<template #default="scope">
|
||||
<el-button type="text" text-color="#ff4d4f" @click="handleDeleteHerb(scope.$index)"> 删除 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<div class="flex gap-4 mb-4">
|
||||
<el-card shadow="hover" class="flex-1">
|
||||
<template #header><span>诊断结果</span></template>
|
||||
<el-input v-model="prescriptionForm.diagnosisResult" type="textarea" rows="5" placeholder="输入诊断结果" :disabled="!isEdit" />
|
||||
</el-card>
|
||||
<el-card shadow="hover" class="flex-1">
|
||||
<template #header><span>用药建议</span></template>
|
||||
<el-input v-model="prescriptionForm.userMedicinaAdvice" type="textarea" rows="5" placeholder="输入用药建议" :disabled="!isEdit" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-card shadow="hover" class="mb-4">
|
||||
<el-form-item label="就诊时间" required>
|
||||
<el-date-picker
|
||||
v-model="prescriptionForm.visitDate"
|
||||
type="datetime"
|
||||
placeholder="选择就诊时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
:disabled="!isEdit"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSave" v-if="isEdit">
|
||||
{{ prescriptionId ? "保存修改" : "新增处方" }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed, nextTick } from "vue";
|
||||
import { ElMessage, ElMessageBox, ElForm, FormItemRule } from "element-plus";
|
||||
import { prescriptionApi } from "@/api/modules/biz/WeiBingJu/prescription";
|
||||
|
||||
// 1. props/emit定义
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false },
|
||||
prescriptionId: { type: Number, default: 0 },
|
||||
isEdit: { type: Boolean, default: false }
|
||||
});
|
||||
const emit = defineEmits(["update:visible", "close", "refreshList"]);
|
||||
|
||||
// 2. 基础变量
|
||||
const dialogTitle = computed(() => {
|
||||
if (props.prescriptionId === 0) return "新增就诊处方";
|
||||
return props.isEdit ? "编辑处方" : "处方详情";
|
||||
});
|
||||
const loading = ref(false);
|
||||
const personFormRef = ref<InstanceType<typeof ElForm>>();
|
||||
const relationTypes = ref<any[]>([]); // 亲属关系列表
|
||||
const herbList = ref<any[]>([]); // 药材列表(原有逻辑)
|
||||
|
||||
// 3. 处方表单(原有逻辑)
|
||||
const prescriptionForm = reactive({
|
||||
diagnosisResult: "",
|
||||
userMedicinaAdvice: "",
|
||||
visitDate: new Date().toISOString().slice(0, 16) // 默认当前时间
|
||||
});
|
||||
|
||||
// 4. 人员表单(核心重构:区分员工/家属场景)
|
||||
const personForm = reactive({
|
||||
// 基础字段
|
||||
id: undefined, // 人员ID(编辑时用)
|
||||
name: "", // 人员姓名(最终提交用)
|
||||
isEmployee: true, // 是否员工(true=员工,false=家属)
|
||||
|
||||
// 员工场景字段
|
||||
employeeId: undefined, // 已选员工ID
|
||||
newEmployeeName: "", // 新增员工姓名
|
||||
|
||||
// 家属场景字段
|
||||
relatedEmployeeId: undefined, // 关联员工ID
|
||||
newRelatedEmployeeName: "", // 新增关联员工姓名
|
||||
relativeId: undefined, // 已选家属ID
|
||||
newRelativeName: "", // 新增家属姓名
|
||||
relationShip: undefined, // 亲属关系ID
|
||||
|
||||
// 公共字段
|
||||
age: undefined,
|
||||
weight: undefined,
|
||||
height: undefined
|
||||
});
|
||||
|
||||
// 5. 下拉/新增状态控制(核心:控制显示隐藏)
|
||||
const state = reactive({
|
||||
// 员工场景
|
||||
showEmployeeSelect: true, // 是否显示员工下拉(默认显示)
|
||||
employeeOptions: [] as any[], // 员工下拉选项
|
||||
employeeKeyword: "", // 员工搜索关键词
|
||||
|
||||
// 家属场景
|
||||
showRelatedEmployeeSelect: true, // 是否显示关联员工下拉(默认显示)
|
||||
relatedEmployeeOptions: [] as any[], // 关联员工下拉选项
|
||||
relatedEmployeeKeyword: "", // 关联员工搜索关键词
|
||||
|
||||
showRelativeSelect: true, // 是否显示家属下拉(默认显示)
|
||||
relativeOptions: [] as any[], // 家属下拉选项
|
||||
relativeKeyword: "" // 家属搜索关键词
|
||||
});
|
||||
|
||||
// 6. 表单验证规则
|
||||
const personFormRules = reactive<Record<string, FormItemRule[]>>({
|
||||
isEmployee: [{ required: true, message: "请选择人员类型", trigger: "change" }],
|
||||
employeeId: [{ required: true, message: "请选择员工", trigger: "change" }],
|
||||
newEmployeeName: [{ required: true, message: "请输入员工姓名", trigger: "blur" }],
|
||||
relatedEmployeeId: [{ required: true, message: "请选择关联员工", trigger: "change" }],
|
||||
newRelatedEmployeeName: [{ required: true, message: "请输入关联员工姓名", trigger: "blur" }],
|
||||
relativeId: [{ required: true, message: "请选择家属", trigger: "change" }],
|
||||
newRelativeName: [{ required: true, message: "请输入家属姓名", trigger: "blur" }],
|
||||
relationShip: [{ required: true, message: "请选择亲属关系", trigger: "change" }],
|
||||
age: [{ type: "number", message: "请输入合法年龄", trigger: "blur" }],
|
||||
weight: [{ type: "number", message: "请输入合法体重", trigger: "blur" }],
|
||||
height: [{ type: "number", message: "请输入合法身高", trigger: "blur" }]
|
||||
});
|
||||
|
||||
// 7. 初始化逻辑(监听弹窗显示/隐藏)
|
||||
watch(
|
||||
() => props.visible,
|
||||
async val => {
|
||||
if (val) {
|
||||
await fetchRelationTypes(); // 加载亲属关系
|
||||
if (props.prescriptionId) {
|
||||
await fetchPrescriptionDetail(); // 编辑/详情:加载已有数据
|
||||
} else {
|
||||
resetForm(); // 新增:重置表单
|
||||
}
|
||||
} else {
|
||||
resetForm(); // 弹窗关闭:重置表单
|
||||
emit("close");
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 8. 基础接口请求(原有逻辑优化)
|
||||
// 加载亲属关系
|
||||
const fetchRelationTypes = async () => {
|
||||
try {
|
||||
const res = await prescriptionApi.getRelationTypes();
|
||||
relationTypes.value = res || [];
|
||||
} catch (err) {
|
||||
relationTypes.value = [];
|
||||
ElMessage.error("加载亲属关系失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 加载处方详情(编辑/详情场景)
|
||||
const fetchPrescriptionDetail = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await prescriptionApi.getDetail({ id: props.prescriptionId });
|
||||
if (!res) return;
|
||||
|
||||
// 填充处方信息
|
||||
prescriptionForm.diagnosisResult = res.diagnosisResult || "";
|
||||
prescriptionForm.userMedicinaAdvice = res.userMedicinaAdvice || "";
|
||||
prescriptionForm.visitDate = res.visitDate || new Date().toISOString().slice(0, 16);
|
||||
|
||||
// 填充人员信息
|
||||
const { person } = res;
|
||||
if (person) {
|
||||
personForm.id = person.id;
|
||||
personForm.name = person.name;
|
||||
personForm.isEmployee = person.EmployeeId === undefined; // 员工:EmployeeId为空
|
||||
personForm.age = person.age;
|
||||
personForm.weight = person.weight;
|
||||
personForm.height = person.height;
|
||||
personForm.relationShip = person.RelationShip;
|
||||
|
||||
// 员工场景:赋值员工ID
|
||||
if (personForm.isEmployee) {
|
||||
personForm.employeeId = person.id;
|
||||
state.employeeOptions = [{ id: person.id, name: person.name }];
|
||||
}
|
||||
// 家属场景:赋值关联员工ID和家属ID
|
||||
else {
|
||||
personForm.relatedEmployeeId = person.EmployeeId;
|
||||
personForm.relativeId = person.id;
|
||||
// 加载关联员工选项
|
||||
state.relatedEmployeeOptions = [{ id: person.EmployeeId, name: res.employeeName || "" }];
|
||||
// 加载家属选项
|
||||
state.relativeOptions = [{ id: person.id, name: person.name }];
|
||||
}
|
||||
}
|
||||
|
||||
// 填充药材信息(原有逻辑)
|
||||
herbList.value = (res.herbs || []).map((h: any) => ({
|
||||
medicinalId: h.medicinalId,
|
||||
medicinalOptions: [{ id: h.medicinalId, name: h.medicinalName }],
|
||||
keyword: h.medicinalName,
|
||||
showNewInput: false,
|
||||
newName: "",
|
||||
amountG: h.amountG,
|
||||
note: h.note || ""
|
||||
}));
|
||||
} catch (err) {
|
||||
ElMessage.error("加载处方详情失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 9. 员工场景交互逻辑
|
||||
// 员工下拉搜索
|
||||
const handleEmployeeSearch = async (keyword: string) => {
|
||||
state.employeeKeyword = keyword.trim();
|
||||
if (!keyword) {
|
||||
state.employeeOptions = [];
|
||||
return;
|
||||
}
|
||||
// 调用接口查询员工(personType=1表示员工)
|
||||
const res = await prescriptionApi.getPersonList({ personType: 1, keyword });
|
||||
state.employeeOptions = res || [];
|
||||
};
|
||||
|
||||
// 员工下拉选择(含"未找到"逻辑)
|
||||
const handleEmployeeChange = async (val: number) => {
|
||||
if (val === 0) {
|
||||
// 点击"未找到":隐藏下拉,显示新增文本框
|
||||
state.showEmployeeSelect = false;
|
||||
personForm.employeeId = undefined; // 清空下拉值
|
||||
personForm.newEmployeeName = state.employeeKeyword; // 预填搜索关键词
|
||||
} else {
|
||||
// 选择已有员工:显示下拉,清空新增文本框
|
||||
state.showEmployeeSelect = true;
|
||||
personForm.newEmployeeName = "";
|
||||
// 赋值人员姓名
|
||||
const selectedEmp = state.employeeOptions.find(emp => emp.id === val);
|
||||
if (selectedEmp) personForm.name = selectedEmp.name;
|
||||
}
|
||||
};
|
||||
|
||||
// 10. 家属场景交互逻辑
|
||||
// 关联员工下拉搜索
|
||||
const handleRelatedEmployeeSearch = async (keyword: string) => {
|
||||
state.relatedEmployeeKeyword = keyword.trim();
|
||||
if (!keyword) {
|
||||
state.relatedEmployeeOptions = [];
|
||||
return;
|
||||
}
|
||||
// 调用接口查询员工(personType=1表示员工)
|
||||
const res = await prescriptionApi.getPersonList({ personType: 1, keyword });
|
||||
state.relatedEmployeeOptions = res || [];
|
||||
};
|
||||
|
||||
// 关联员工下拉选择(含"未找到"逻辑)
|
||||
const handleRelatedEmployeeChange = async (val: number) => {
|
||||
if (val === 0) {
|
||||
// 点击"未找到":隐藏关联员工下拉,显示新增文本框+家属新增文本框
|
||||
state.showRelatedEmployeeSelect = false;
|
||||
state.showRelativeSelect = false; // 隐藏家属下拉
|
||||
personForm.relatedEmployeeId = undefined;
|
||||
personForm.newRelatedEmployeeName = state.relatedEmployeeKeyword;
|
||||
personForm.relativeId = undefined;
|
||||
} else {
|
||||
// 选择已有关联员工:显示关联员工下拉,加载家属列表
|
||||
state.showRelatedEmployeeSelect = true;
|
||||
state.showRelativeSelect = true; // 显示家属下拉
|
||||
personForm.newRelatedEmployeeName = "";
|
||||
personForm.newRelativeName = "";
|
||||
// 加载该员工的家属(personType=2表示家属,传employeeId)
|
||||
await handleLoadRelatives(val);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载关联员工的家属列表
|
||||
const handleLoadRelatives = async (employeeId: number) => {
|
||||
try {
|
||||
const res = await prescriptionApi.getPersonList({
|
||||
personType: 2, // 假设personType=2表示家属
|
||||
employeeId
|
||||
});
|
||||
state.relativeOptions = res || [];
|
||||
} catch (err) {
|
||||
state.relativeOptions = [];
|
||||
ElMessage.error("加载家属列表失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 家属下拉搜索
|
||||
const handleRelativeSearch = async (keyword: string) => {
|
||||
state.relativeKeyword = keyword.trim();
|
||||
if (!keyword || !personForm.relatedEmployeeId) {
|
||||
state.relativeOptions = [];
|
||||
return;
|
||||
}
|
||||
// 调用接口查询家属(传关联员工ID)
|
||||
const res = await prescriptionApi.getPersonList({
|
||||
personType: 2,
|
||||
employeeId: personForm.relatedEmployeeId,
|
||||
keyword
|
||||
});
|
||||
state.relativeOptions = res || [];
|
||||
};
|
||||
|
||||
// 家属下拉选择(含"未找到"逻辑)
|
||||
const handleRelativeChange = async (val: number) => {
|
||||
if (val === 0) {
|
||||
// 点击"未找到":隐藏家属下拉,显示家属新增文本框
|
||||
state.showRelativeSelect = false;
|
||||
personForm.relativeId = undefined;
|
||||
personForm.newRelativeName = state.relativeKeyword;
|
||||
} else {
|
||||
// 选择已有家属:显示家属下拉,清空新增文本框
|
||||
state.showRelativeSelect = true;
|
||||
personForm.newRelativeName = "";
|
||||
// 赋值家属姓名
|
||||
const selectedRel = state.relativeOptions.find(rel => rel.id === val);
|
||||
if (selectedRel) personForm.name = selectedRel.name;
|
||||
}
|
||||
};
|
||||
|
||||
// 11. 人员类型切换逻辑(重置状态)
|
||||
const handlePersonTypeChange = () => {
|
||||
// 重置所有状态
|
||||
state.showEmployeeSelect = true;
|
||||
state.showRelatedEmployeeSelect = true;
|
||||
state.showRelativeSelect = true;
|
||||
state.employeeOptions = [];
|
||||
state.relatedEmployeeOptions = [];
|
||||
state.relativeOptions = [];
|
||||
state.employeeKeyword = "";
|
||||
state.relatedEmployeeKeyword = "";
|
||||
state.relativeKeyword = "";
|
||||
|
||||
// 重置表单字段
|
||||
personForm.employeeId = undefined;
|
||||
personForm.newEmployeeName = "";
|
||||
personForm.relatedEmployeeId = undefined;
|
||||
personForm.newRelatedEmployeeName = "";
|
||||
personForm.relativeId = undefined;
|
||||
personForm.newRelativeName = "";
|
||||
personForm.relationShip = undefined;
|
||||
personForm.name = "";
|
||||
|
||||
// 重置表单验证
|
||||
nextTick(() => {
|
||||
personFormRef.value?.clearValidate();
|
||||
});
|
||||
};
|
||||
|
||||
// 12. 药材相关逻辑(保持原有)
|
||||
const handleAddHerb = () => {
|
||||
herbList.value.push({
|
||||
medicinalId: undefined,
|
||||
medicinalOptions: [],
|
||||
keyword: "",
|
||||
showNewInput: false,
|
||||
newName: "",
|
||||
amountG: undefined,
|
||||
note: ""
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteHerb = (index: number) => {
|
||||
herbList.value.splice(index, 1);
|
||||
};
|
||||
|
||||
const handleHerbSearch = async (keyword: string, index: number) => {
|
||||
const res = await prescriptionApi.searchMedicinals({ keyword });
|
||||
herbList.value[index].keyword = keyword;
|
||||
herbList.value[index].medicinalOptions = res || [];
|
||||
};
|
||||
|
||||
const handleHerbChange = (val: number | 0, index: number) => {
|
||||
if (val === 0) {
|
||||
herbList.value[index].showNewInput = true;
|
||||
herbList.value[index].newName = herbList.value[index].keyword;
|
||||
} else {
|
||||
herbList.value[index].showNewInput = false;
|
||||
herbList.value[index].newName = "";
|
||||
}
|
||||
};
|
||||
|
||||
// 13. 表单提交/取消逻辑(优化参数组装)
|
||||
const handleSave = async () => {
|
||||
// 表单验证
|
||||
if (!personFormRef.value?.validate()) return;
|
||||
// 药材验证
|
||||
if (herbList.value.length === 0) {
|
||||
return ElMessage.warning("请至少添加一条药材消耗记录");
|
||||
}
|
||||
// 诊断结果验证
|
||||
if (!prescriptionForm.diagnosisResult.trim()) {
|
||||
return ElMessage.warning("请输入诊断结果");
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
// 处理新增员工/家属的情况
|
||||
let newPersonId: number | undefined = personForm.id;
|
||||
if (!newPersonId) {
|
||||
if (personForm.isEmployee) {
|
||||
// 新增员工
|
||||
if (state.showEmployeeSelect) {
|
||||
newPersonId = personForm.employeeId; // 选择已有员工
|
||||
} else {
|
||||
// 新增员工:调用addPerson接口
|
||||
newPersonId = await prescriptionApi.addPerson({
|
||||
name: personForm.newEmployeeName.trim(),
|
||||
isEmployee: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 新增家属:先处理关联员工(如有新增)
|
||||
let relatedEmpId = personForm.relatedEmployeeId;
|
||||
if (!state.showRelatedEmployeeSelect) {
|
||||
// 新增关联员工
|
||||
relatedEmpId = await prescriptionApi.addPerson({
|
||||
name: personForm.newRelatedEmployeeName.trim(),
|
||||
isEmployee: true
|
||||
});
|
||||
}
|
||||
|
||||
// 新增家属
|
||||
if (state.showRelativeSelect) {
|
||||
newPersonId = personForm.relativeId; // 选择已有家属
|
||||
} else {
|
||||
// 新增家属:调用addPerson接口
|
||||
newPersonId = await prescriptionApi.addPerson({
|
||||
name: personForm.newRelativeName.trim(),
|
||||
isEmployee: false,
|
||||
EmployeeId: relatedEmpId,
|
||||
RelationShip: personForm.relationShip
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 组装药材参数
|
||||
const herbParams = herbList.value.map(h => ({
|
||||
medicinalId: h.medicinalId,
|
||||
amountG: h.amountG,
|
||||
note: h.note?.trim()
|
||||
}));
|
||||
|
||||
// 最终提交参数
|
||||
const submitParams = {
|
||||
id: props.prescriptionId || undefined,
|
||||
PersonId: newPersonId, // 人员ID(新增/编辑后的值)
|
||||
diagnosisResult: prescriptionForm.diagnosisResult.trim(),
|
||||
userMedicinaAdvice: prescriptionForm.userMedicinaAdvice.trim(),
|
||||
visitDate: prescriptionForm.visitDate,
|
||||
herbs: herbParams
|
||||
};
|
||||
|
||||
// 提交保存
|
||||
await prescriptionApi.save(submitParams);
|
||||
ElMessage.success(props.prescriptionId ? "修改成功" : "新增成功");
|
||||
emit("update:visible", false);
|
||||
emit("refreshList");
|
||||
} catch (err: any) {
|
||||
ElMessage.error(err.message || "保存失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
if (props.isEdit) {
|
||||
ElMessageBox.confirm("是否放弃未保存的修改?", "确认取消", { type: "warning" })
|
||||
.then(() => emit("update:visible", false))
|
||||
.catch(); // 无逻辑时可省略函数体
|
||||
} else {
|
||||
emit("update:visible", false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateVisible = (newVisible: boolean) => {
|
||||
emit("update:visible", newVisible);
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
// 重置处方表单
|
||||
prescriptionForm.diagnosisResult = "";
|
||||
prescriptionForm.userMedicinaAdvice = "";
|
||||
prescriptionForm.visitDate = new Date().toISOString().slice(0, 16);
|
||||
|
||||
// 重置人员表单
|
||||
Object.assign(personForm, {
|
||||
id: undefined,
|
||||
name: "",
|
||||
isEmployee: true,
|
||||
employeeId: undefined,
|
||||
newEmployeeName: "",
|
||||
relatedEmployeeId: undefined,
|
||||
newRelatedEmployeeName: "",
|
||||
relativeId: undefined,
|
||||
newRelativeName: "",
|
||||
relationShip: undefined,
|
||||
age: undefined,
|
||||
weight: undefined,
|
||||
height: undefined
|
||||
});
|
||||
|
||||
// 重置状态
|
||||
Object.assign(state, {
|
||||
showEmployeeSelect: true,
|
||||
employeeOptions: [],
|
||||
employeeKeyword: "",
|
||||
showRelatedEmployeeSelect: true,
|
||||
relatedEmployeeOptions: [],
|
||||
relatedEmployeeKeyword: "",
|
||||
showRelativeSelect: true,
|
||||
relativeOptions: [],
|
||||
relativeKeyword: ""
|
||||
});
|
||||
|
||||
// 重置药材列表
|
||||
herbList.value = [];
|
||||
|
||||
// 重置表单验证
|
||||
nextTick(() => {
|
||||
personFormRef.value?.clearValidate();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
.gap-4 {
|
||||
gap: 16px;
|
||||
}
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,103 +0,0 @@
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<el-card class="mt-4">
|
||||
<ProTable ref="proTable" title="处方列表" :columns="columns" :request-api="getPrescriptionListApi" :row-key="rowKey">
|
||||
<template #tableHeader>
|
||||
<s-button suffix="处方" type="success" @click="handleAddPrescription" />
|
||||
</template>
|
||||
|
||||
<template #operation="scope">
|
||||
<s-button link :opt="FormOptEnum.VIEW" size="small" @click="handleViewDetail(scope.row.id)"> 查看详情 </s-button>
|
||||
<s-button link :opt="FormOptEnum.EDIT" size="small" class="ml-2" @click="handleEdit(scope.row.id)" v-if="scope.row.canEdit">
|
||||
编辑
|
||||
</s-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
</el-card>
|
||||
|
||||
<!-- 弹窗:查看/编辑处方 -->
|
||||
<prescription-detail-dialog
|
||||
:visible="showDetailDialog"
|
||||
:prescription-id="currentPrescriptionId"
|
||||
:is-edit="isEdit"
|
||||
@update:visible="val => (showDetailDialog = val)"
|
||||
@refresh-list="handleRefresh"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="prescriptionModule">
|
||||
import { ref } from "vue";
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import type { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
|
||||
import { prescriptionApi } from "@/api";
|
||||
import PrescriptionDetailDialog from "./components/PrescriptionDetailDialog.vue";
|
||||
import { FormOptEnum } from "@/enums";
|
||||
|
||||
// ProTable ref
|
||||
const proTable = ref<ProTableInstance | null>(null);
|
||||
|
||||
// 弹窗状态
|
||||
const showDetailDialog = ref(false);
|
||||
const currentPrescriptionId = ref<number | null>(null);
|
||||
const isEdit = ref(false);
|
||||
|
||||
// 表格列配置
|
||||
const columns: ColumnProps<any>[] = [
|
||||
{ type: "selection", fixed: "left", width: 80 },
|
||||
{ prop: "personName", label: "就诊人", search: { el: "input" } },
|
||||
{
|
||||
prop: "personType",
|
||||
label: "就诊人类型",
|
||||
formatter: (row: any) => (row.personType === 1 ? "公司员工" : `员工家属(${row.employeeName || "未知"})`)
|
||||
},
|
||||
{ prop: "visitDate", label: "就诊时间" },
|
||||
{ prop: "operation", label: "操作", width: 180, fixed: "right" }
|
||||
];
|
||||
|
||||
// rowKey定义
|
||||
const rowKey = (row: any) => row.id;
|
||||
|
||||
// 请求接口
|
||||
const getPrescriptionListApi = (params: any) => {
|
||||
return prescriptionApi.getList(params);
|
||||
};
|
||||
|
||||
// 新增处方
|
||||
const handleAddPrescription = () => {
|
||||
currentPrescriptionId.value = null;
|
||||
isEdit.value = true;
|
||||
showDetailDialog.value = true;
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleViewDetail = (id: number) => {
|
||||
currentPrescriptionId.value = id;
|
||||
isEdit.value = false;
|
||||
showDetailDialog.value = true;
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (id: number) => {
|
||||
currentPrescriptionId.value = id;
|
||||
isEdit.value = true;
|
||||
showDetailDialog.value = true;
|
||||
};
|
||||
|
||||
// 刷新表格
|
||||
const handleRefresh = () => {
|
||||
proTable.value?.refresh?.();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.table-box {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.ml-2 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -5,34 +5,23 @@
|
||||
!-->
|
||||
<template>
|
||||
<div class="main-box">
|
||||
<TreeFilter
|
||||
ref="treeFilter"
|
||||
label="name"
|
||||
title="组织列表"
|
||||
:request-api="sysOrgApi.tree"
|
||||
:default-value="initParam.orgId"
|
||||
@change="changeTreeFilter"
|
||||
/>
|
||||
<TreeFilter ref="treeFilter" label="name" title="组织列表" :request-api="sysOrgApi.tree"
|
||||
:default-value="initParam.orgId" @change="changeTreeFilter" />
|
||||
<div class="table-box">
|
||||
<ProTable ref="proTable" :columns="columns" :request-api="sysRoleApi.page" :init-param="initParam">
|
||||
<!-- 表格 header 按钮 -->
|
||||
<template #tableHeader="scope">
|
||||
<s-button suffix="角色" @click="onOpen(FormOptEnum.ADD)" />
|
||||
<s-button
|
||||
type="danger"
|
||||
plain
|
||||
suffix="角色"
|
||||
:opt="FormOptEnum.DELETE"
|
||||
:disabled="!scope.isSelected"
|
||||
@click="onDelete(scope.selectedListIds, '删除所选角色')"
|
||||
/>
|
||||
<s-button type="danger" plain suffix="角色" :opt="FormOptEnum.DELETE" :disabled="!scope.isSelected"
|
||||
@click="onDelete(scope.selectedListIds, '删除所选角色')" />
|
||||
</template>
|
||||
<!-- 状态 -->
|
||||
<template #status="scope">
|
||||
<el-tag v-if="scope.row.status === CommonStatusEnum.ENABLE" type="success">{{
|
||||
dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status)
|
||||
}}</el-tag>
|
||||
<el-tag v-else type="danger">{{ dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status) }}</el-tag>
|
||||
}}</el-tag>
|
||||
<el-tag v-else type="danger">{{ dictStore.dictTranslation(SysDictEnum.COMMON_STATUS, scope.row.status)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
<!-- 操作 -->
|
||||
<template #operation="scope">
|
||||
@@ -43,7 +32,8 @@
|
||||
<el-link type="primary" :underline="false" :icon="ArrowDown"> 授权 </el-link>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(item, index) in cmdEnum" :key="index" :command="command(scope.row, item)">{{ item }}</el-dropdown-item>
|
||||
<el-dropdown-item v-for="(item, index) in cmdEnum" :key="index" :command="command(scope.row, item)">{{
|
||||
item }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -59,15 +49,9 @@
|
||||
<!-- 授权权限组件 -->
|
||||
<GrantPermission ref="grantPermissionRef" />
|
||||
<!-- 用户选择器 -->
|
||||
<user-selector
|
||||
ref="userSelectorRef"
|
||||
:org-tree-api="sysOrgApi.tree"
|
||||
:position-tree-api="sysPositionApi.tree"
|
||||
:role-tree-api="sysRoleApi.tree"
|
||||
:user-selector-api="sysUserApi.selector"
|
||||
multiple
|
||||
@successful="handleChooseUser"
|
||||
/>
|
||||
<user-selector ref="userSelectorRef" :org-tree-api="sysOrgApi.tree" :position-tree-api="sysPositionApi.tree"
|
||||
:role-tree-api="sysRoleApi.tree" :user-selector-api="sysUserApi.selector" multiple
|
||||
@successful="handleChooseUser" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -209,14 +193,14 @@ function handleCommand(command: Command) {
|
||||
successful: RefreshTable
|
||||
});
|
||||
break;
|
||||
case cmdEnum.GrantMobileResource:
|
||||
// 打开授权移动端资源组件
|
||||
grantMobileResourceRef.value?.onOpen({
|
||||
opt: FormOptEnum.EDIT,
|
||||
record: command.row,
|
||||
successful: RefreshTable
|
||||
});
|
||||
break;
|
||||
// case cmdEnum.GrantMobileResource:
|
||||
// // 打开授权移动端资源组件
|
||||
// grantMobileResourceRef.value?.onOpen({
|
||||
// opt: FormOptEnum.EDIT,
|
||||
// record: command.row,
|
||||
// successful: RefreshTable
|
||||
// });
|
||||
// break;
|
||||
case cmdEnum.GrantPermission:
|
||||
// 打开授权权限组件
|
||||
grantPermissionRef.value?.onOpen({
|
||||
|
||||
@@ -6,11 +6,17 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<el-tabs v-model="activeName" class="-mt-4">
|
||||
<el-tab-pane label="系统配置" name="sysConfig"><SysBaseConfig :sys-configs="sysBase" /></el-tab-pane>
|
||||
<el-tab-pane label="安全配置" name="safety"><SafetyConfig :sys-configs="safetyConfig" /></el-tab-pane>
|
||||
<el-tab-pane label="MQTT配置" name="mqtt"><MqttConfig :sys-configs="mqttConfig" /></el-tab-pane>
|
||||
<el-tab-pane label="文件配置" name="file">开发中......</el-tab-pane>
|
||||
<el-tab-pane label="其他配置" name="other"><OtherConfig v-if="activeName === 'other'" /></el-tab-pane>
|
||||
<el-tab-pane label="系统配置" name="sysConfig">
|
||||
<SysBaseConfig :sys-configs="sysBase" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="安全配置" name="safety">
|
||||
<SafetyConfig :sys-configs="safetyConfig" />
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="MQTT配置" name="mqtt"><MqttConfig :sys-configs="mqttConfig" /></el-tab-pane>
|
||||
<el-tab-pane label="文件配置" name="file">开发中......</el-tab-pane> -->
|
||||
<el-tab-pane label="其他配置" name="other">
|
||||
<OtherConfig v-if="activeName === 'other'" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
@@ -19,7 +25,7 @@
|
||||
import SysBaseConfig from "./components/sysBaseConfig.vue";
|
||||
import SafetyConfig from "./components/safetyConfig/index.vue";
|
||||
import OtherConfig from "./components/otherConfig/index.vue";
|
||||
import MqttConfig from "./components/mqttConfig/index.vue";
|
||||
// import MqttConfig from "./components/mqttConfig/index.vue";
|
||||
import { SysConfig, sysConfigApi } from "@/api";
|
||||
import { SysConfigTypeEnum } from "@/enums";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user