master
2358328281@qq.com 2 months ago
parent 8d0e2f44f5
commit 48e2b8cacd

@ -246,7 +246,7 @@ export default {
type: "服务类型", type: "服务类型",
status: "状态", status: "状态",
time: "提交时间", time: "提交时间",
submitter: "提交人", submitter: "提出人员",
feedbackchannel: "反馈渠道", feedbackchannel: "反馈渠道",
action: "操作", action: "操作",
hospital: "医院名称", hospital: "医院名称",

@ -82,6 +82,10 @@ export const getAdminReportDetail = (id) => {
export const generateAdminReport = (data) => { export const generateAdminReport = (data) => {
return kcRequest.request(`/admin/reports/generate`, "post", data); return kcRequest.request(`/admin/reports/generate`, "post", data);
}; };
// 重新计算报告数据(重新生成)
export const recalculateAdminReport = (id) => {
return kcRequest.request(`/admin/reports/${id}/recalculate`, "put");
};
// 更新备注 // 更新备注
export const updateAdminReportRemark = (id, data) => { export const updateAdminReportRemark = (id, data) => {
return kcRequest.request(`/admin/reports/${id}/remark`, "put", data); return kcRequest.request(`/admin/reports/${id}/remark`, "put", data);
@ -94,6 +98,10 @@ export const toggleAdminReportSendStatus = (id) => {
export const downloadAdminReport = (id, format) => { export const downloadAdminReport = (id, format) => {
return kcRequest.downloadFile(`/admin/reports/${id}/download?format=${format}`); return kcRequest.downloadFile(`/admin/reports/${id}/download?format=${format}`);
}; };
// 删除报告文件
export const deleteAdminReport = (id) => {
return kcRequest.request(`/admin/reports/${id}`, "delete");
};
// ============== 客户服务1.6 ============== // ============== 客户服务1.6 ==============
// 维保列表 // 维保列表

@ -25,12 +25,15 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="回访人" prop="callPerson"> <el-form-item label="回访人" prop="callPersonId">
<el-input v-model="form.callPerson" placeholder="请输入" maxlength="50" /> <!-- <el-input v-model="form.callPerson" placeholder="请输入" maxlength="50" /> -->
<el-select v-model="form.callPersonId" :placeholder="'选择回访人'" filterable clearable>
<el-option v-for="item in managerOptions" :key="item.id" :label="`${item.name}`" :value="item.id" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="回访内容" prop="content"> <el-form-item label="回访情况" prop="content">
<el-input v-model="form.content" type="textarea" :rows="4" placeholder="请输入回访情况" /> <el-input v-model="form.content" type="textarea" :rows="4" placeholder="请输入回访情况" />
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -48,8 +51,10 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="巡检人" prop="inspectionPerson"> <el-form-item label="巡检人" prop="inspectionPersonId">
<el-input v-model="form.inspectionPerson" placeholder="请输入" maxlength="50" /> <el-select v-model="form.inspectionPersonId" :placeholder="'选择巡检人'" filterable clearable>
<el-option v-for="item in managerOptions" :key="item.id" :label="`${item.name}`" :value="item.id" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -104,8 +109,10 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="培训人员" prop="trainer"> <el-form-item label="培训人员" prop="trainerId">
<el-input v-model="form.trainer" placeholder="请输入培训人员名称" maxlength="50" /> <el-select v-model="form.trainerId" :placeholder="'选择培训人员'" filterable clearable>
<el-option v-for="item in managerOptions" :key="item.id" :label="`${item.name}`" :value="item.id" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -162,11 +169,11 @@
</div> </div>
<div class="history-body"> <div class="history-body">
<template v-if="type === 'call'"> <template v-if="type === 'call'">
<div class="row"><span class="lbl">回访人</span>{{ item.callPerson }}</div> <div class="row"><span class="lbl">回访人</span>{{ item.callPersonName }}</div>
<div class="row"><span class="lbl">回访情况</span>{{ item.content || "—" }}</div> <div class="row"><span class="lbl">回访情况</span>{{ item.content || "—" }}</div>
</template> </template>
<template v-else-if="type === 'inspection'"> <template v-else-if="type === 'inspection'">
<div class="row"><span class="lbl">巡检人</span>{{ item.inspectionPerson }}</div> <div class="row"><span class="lbl">巡检人</span>{{ item.inspectionPersonName }}</div>
<div class="row"><span class="lbl">巡检情况</span>{{ item.content || "—" }}</div> <div class="row"><span class="lbl">巡检情况</span>{{ item.content || "—" }}</div>
<div class="row" v-if="getInspectionFilePath(item)"> <div class="row" v-if="getInspectionFilePath(item)">
<span class="lbl">巡检报告</span> <span class="lbl">巡检报告</span>
@ -179,7 +186,19 @@
</template> </template>
<template v-else-if="type === 'training'"> <template v-else-if="type === 'training'">
<div class="row"><span class="lbl">培训主题</span>{{ item.topic }}</div> <div class="row"><span class="lbl">培训主题</span>{{ item.topic }}</div>
<div class="row"><span class="lbl">参与人员</span>{{ item.participants || "—" }}</div> <el-row :gutter="16">
<el-col :span="8">
<div class="row"><span class="lbl">参与人员</span>{{ item.participants || "—" }}</div>
</el-col>
<el-col :span="8">
<div class="row"><span class="lbl">培训人员</span>{{ item.trainerName || "—" }}</div>
</el-col>
<el-col :span="8">
<div class="row"><span class="lbl">培训日期</span>{{ dayjs(item.trainingDate).format('YYYY-MM-DD') ||
"—"
}}</div>
</el-col>
</el-row>
</template> </template>
<template v-else-if="type === 'gift'"> <template v-else-if="type === 'gift'">
<div class="row"><span class="lbl">纪念品名称</span>{{ item.name }}</div> <div class="row"><span class="lbl">纪念品名称</span>{{ item.name }}</div>
@ -224,6 +243,8 @@ const props = defineProps({
type: { type: String, default: "call" }, type: { type: String, default: "call" },
hospitalId: { type: [String, Number], default: "" }, hospitalId: { type: [String, Number], default: "" },
hospitalName: { type: String, default: "" }, hospitalName: { type: String, default: "" },
managerLoaded: { type: Boolean, default: false },
managerOptions: { type: Array, default: () => [] },
}); });
const emit = defineEmits(["update:modelValue", "saved"]); const emit = defineEmits(["update:modelValue", "saved"]);
@ -288,17 +309,17 @@ const typeLabel = computed(() => title.value.replace("记录", ""));
const defaultForm = () => { const defaultForm = () => {
if (props.type === "call") { if (props.type === "call") {
return { callTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), callPerson: "", content: "" }; return { callTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), callPersonId: "", content: "" };
} }
if (props.type === "inspection") { if (props.type === "inspection") {
return { inspectionTime: dayjs().format("YYYY-MM-DD"), inspectionPerson: "", content: "" }; return { inspectionTime: dayjs().format("YYYY-MM-DD"), inspectionPersonId: "", content: "" };
} }
if (props.type === "training") { if (props.type === "training") {
return { return {
trainingDate: dayjs().format("YYYY-MM-DD"), trainingDate: dayjs().format("YYYY-MM-DD"),
participants: "", participants: "",
trainingMethod: "线上", trainingMethod: "线上",
trainer: "", trainerId: "",
topic: "", topic: "",
}; };
} }
@ -312,7 +333,7 @@ const buildRules = () => {
if (props.type === "call") { if (props.type === "call") {
return { return {
callTime: [{ required: true, message: "请选择回访时间" }], callTime: [{ required: true, message: "请选择回访时间" }],
callPerson: [{ required: true, message: "请输入回访人" }], callPersonId: [{ required: true, message: "请选择回访人" }],
content: [{ required: true, message: "请输入回访内容" }], content: [{ required: true, message: "请输入回访内容" }],
}; };
} }
@ -321,7 +342,7 @@ const buildRules = () => {
return { return {
inspectionTime: [{ required: true, message: "请选择巡检时间" }], inspectionTime: [{ required: true, message: "请选择巡检时间" }],
inspectionPerson: [{ required: true, message: "请输入巡检人" }], inspectionPersonId: [{ required: true, message: "请选择巡检人" }],
content: [{ required: true, message: "请输入巡检内容" }], content: [{ required: true, message: "请输入巡检内容" }],
}; };
} }
@ -329,7 +350,7 @@ const buildRules = () => {
return { return {
trainingDate: [{ required: true, message: "请选择培训日期" }], trainingDate: [{ required: true, message: "请选择培训日期" }],
participants: [{ required: true, message: "请输入参与人数" }], participants: [{ required: true, message: "请输入参与人数" }],
trainer: [{ required: true, message: "请输入培训人员" }], trainerId: [{ required: true, message: "请选择培训人员" }],
topic: [{ required: true, message: "请输入培训主题" }], topic: [{ required: true, message: "请输入培训主题" }],
}; };
} }
@ -389,7 +410,7 @@ const formatTime = (item) => {
} }
if (props.type === "training") { if (props.type === "training") {
const t = item.trainingDate; const t = item.createdAt;
return (dayjs(t).isValid() ? dayjs(t).format("YYYY-MM-DD HH:mm") : "—"); return (dayjs(t).isValid() ? dayjs(t).format("YYYY-MM-DD HH:mm") : "—");
} }
@ -558,7 +579,8 @@ const viewReport = async (filePath) => {
color: #1D2129 !important; color: #1D2129 !important;
} }
.el-input__wrapper { .el-input__wrapper,
.el-select__wrapper {
min-height: 48px; min-height: 48px;
border-radius: 8px 8px 8px 8px; border-radius: 8px 8px 8px 8px;
border: 1px solid #E0E0E0; border: 1px solid #E0E0E0;

@ -165,7 +165,7 @@
<!-- 服务记录弹窗电话回访/现场巡检/培训/纪念品 --> <!-- 服务记录弹窗电话回访/现场巡检/培训/纪念品 -->
<!-- v-if 让弹窗关闭时整个组件卸载下次打开会重新 setuprules 会按最新 type 生成 --> <!-- v-if 让弹窗关闭时整个组件卸载下次打开会重新 setuprules 会按最新 type 生成 -->
<ServiceRecordDialog v-if="recordVisible" v-model="recordVisible" :type="recordType" <ServiceRecordDialog v-if="recordVisible" v-model="recordVisible" :type="recordType"
:hospital-id="currentHospitalId" :hospital-name="currentHospitalName" /> :hospital-id="currentHospitalId" :hospital-name="currentHospitalName" :managerOptions="managerOptions" :managerLoaded="managerLoaded" />
<!-- 客户服务月视图弹窗 --> <!-- 客户服务月视图弹窗 -->
<MonthlyViewDialog v-model="monthlyVisible" /> <MonthlyViewDialog v-model="monthlyVisible" />
@ -176,7 +176,7 @@
import { computed, onMounted, reactive, ref } from "vue"; import { computed, onMounted, reactive, ref } from "vue";
import { Calendar, Phone, View, Reading, Present } from "@element-plus/icons-vue"; import { Calendar, Phone, View, Reading, Present } from "@element-plus/icons-vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { getAdminExpiring, getAdminMaintenance } from "@/service/modular/admin"; import { getAdminExpiring, getAdminMaintenance, getAdminAccounts } from "@/service/modular/admin";
import { useHospitalStore } from "@/stores/api/hospital"; import { useHospitalStore } from "@/stores/api/hospital";
import MaintenanceDetailDialog from "./components/MaintenanceDetailDialog.vue"; import MaintenanceDetailDialog from "./components/MaintenanceDetailDialog.vue";
import ServiceRecordDialog from "./components/ServiceRecordDialog.vue"; import ServiceRecordDialog from "./components/ServiceRecordDialog.vue";
@ -188,6 +188,19 @@ const loading = ref(false);
const expiringLoading = ref(false); const expiringLoading = ref(false);
const expiringList = ref([]); const expiringList = ref([]);
const managerOptions = ref([]);
const managerLoaded = ref(false);
const loadManagers = async () => {
if (managerLoaded.value) return;
try {
const res = await getAdminAccounts({ type: "Admin" });
managerOptions.value = res?.list || [];
managerLoaded.value = true;
} catch (e) {
// request
}
};
// Pinia store // Pinia store
const hospitalStore = useHospitalStore(); const hospitalStore = useHospitalStore();
const hospitals = computed(() => hospitalStore.list); const hospitals = computed(() => hospitalStore.list);
@ -280,6 +293,7 @@ const monthlyVisible = ref(false);
onMounted(() => { onMounted(() => {
hospitalStore.ensureLoaded(); hospitalStore.ensureLoaded();
loadList(); loadList();
loadManagers();
// loadExpiring(); // loadExpiring();
}); });
</script> </script>

@ -21,7 +21,7 @@ import awardIcon from "@/assets/image/admin/orders/award.svg";
defineProps({ defineProps({
modelValue: { type: Boolean, default: false }, modelValue: { type: Boolean, default: false },
points: { type: [String, Number], default: 5 }, points: { type: [String, Number], default: 1 },
}); });
const emit = defineEmits(["update:modelValue", "continue"]); const emit = defineEmits(["update:modelValue", "continue"]);

@ -7,6 +7,7 @@
<img src="@/assets/image/admin/orders/arrow-left.svg" alt="返回" class="icon" /> <img src="@/assets/image/admin/orders/arrow-left.svg" alt="返回" class="icon" />
<span>返回</span> <span>返回</span>
</el-button> </el-button>
<img src="@/assets/image/close-btn.svg" alt="" class="close-btn" @click="closeDialog" />
</div> </div>
<div class="body-wrap" v-loading="loading"> <div class="body-wrap" v-loading="loading">
<div v-if="detail.id" class="handle-form"> <div v-if="detail.id" class="handle-form">
@ -86,12 +87,8 @@
<span>复制工单</span> <span>复制工单</span>
</div> </div>
<div class="line"></div> <div class="line"></div>
<el-popconfirm width="auto" <el-popconfirm width="auto" title="确定删除该工单吗?" confirm-button-text=""
title="确定删除该工单吗?" cancel-button-text="取消" @confirm="onDelete">
confirm-button-text="确定"
cancel-button-text="取消"
@confirm="onDelete"
>
<template #reference> <template #reference>
<div class="action-btn danger"> <div class="action-btn danger">
<img :src="iconDelete" alt="" /> <img :src="iconDelete" alt="" />
@ -106,10 +103,10 @@
<!-- 附件 --> <!-- 附件 -->
<el-form-item label="附件"> <el-form-item label="附件">
<div class="attachment"> <div class="attachment">
<span v-if="!detail.attachments?.length" v-html="$t('orderDetail.noAttachment')"></span> <span v-if="!detail.attachments?.length" v-html="$t('orderDetail.noAttachment')"></span>
<div v-else class="files"> <div v-else class="files">
<el-button v-for="(f, i) in detail.attachments" :key="i" link <el-button v-for="(f, i) in detail.attachments" :key="i" link class="file-item"
class="file-item" @click="viewReport(f)"> @click="viewReport(f)">
<div class="inner"> <div class="inner">
<img :src="iconFile" alt="" class="file-icon" /> <img :src="iconFile" alt="" class="file-icon" />
<span>{{ f.fileName }}</span> <span>{{ f.fileName }}</span>
@ -215,7 +212,7 @@ const closeDialog = () => emit("update:modelValue", false);
// //
const copyOrderData = computed(() => { const copyOrderData = computed(() => {
console.log(detail.value); console.log(detail.value);
const { attachments: _attachments, ...rest } = detail.value || {}; const { attachments: _attachments, ...rest } = detail.value || {};
rest.createdAt = dayjs().format("YYYY-MM-DD HH:mm:ss"); rest.createdAt = dayjs().format("YYYY-MM-DD HH:mm:ss");
return rest; return rest;
@ -375,6 +372,9 @@ const onPreviewDownload = ({ blob, fileName }) => {
.dialog-topbar { .dialog-topbar {
padding: 16px 24px; padding: 16px 24px;
border-bottom: 1px solid #F3F4F6; border-bottom: 1px solid #F3F4F6;
display: flex;
align-items: center;
justify-content: space-between;
.back-btn { .back-btn {
font-weight: 500; font-weight: 500;
@ -392,6 +392,12 @@ const onPreviewDownload = ({ blob, fileName }) => {
margin-right: 4px; margin-right: 4px;
} }
} }
.close-btn {
width: 30px;
height: 30px;
cursor: pointer;
}
} }
.body-wrap { .body-wrap {

@ -12,33 +12,27 @@
<!-- 科室 / 提交人可编辑回显原值 --> <!-- 科室 / 提交人可编辑回显原值 -->
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="8">
<!-- 工单号只读 --> <!-- 工单号只读 -->
<el-form-item :label="$t('table.id')"> <el-form-item :label="$t('table.id')">
<el-input :model-value="detail.orderNo" readonly /> <el-input :model-value="detail.orderNo" readonly />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="8">
<el-form-item :label="$t('table.title')">
<el-input :model-value="detail.title" readonly />
</el-form-item>
</el-col>
</el-row>
<!-- 科室 / 提交人可编辑回显原值 -->
<el-row :gutter="16">
<el-col :span="12">
<el-form-item :label="$t('table.dept')" prop="department"> <el-form-item :label="$t('table.dept')" prop="department">
<el-input v-model="form.department" :placeholder="'请输入科室'" readonly /> <el-input v-model="form.department" :placeholder="'请输入科室'" readonly />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="8">
<el-form-item :label="$t('table.submitter')" prop="submitter"> <el-form-item :label="$t('table.submitter')" prop="submitter">
<el-input v-model="form.submitter" :placeholder="'请输入提交人'" readonly /> <el-input v-model="form.submitter" :placeholder="'请输入提出人员'" readonly />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item :label="$t('table.title')">
<el-input :model-value="detail.title" readonly />
</el-form-item>
<!-- 问题描述可编辑富文本默认回显原值 --> <!-- 问题描述可编辑富文本默认回显原值 -->
<el-form-item :label="$t('label.description')" prop="description"> <el-form-item :label="$t('label.description')" prop="description">
<!-- <div class="rich-editor"> <!-- <div class="rich-editor">
@ -86,7 +80,7 @@
<el-button @click="closeDialog">{{ $t("common.cancel") }}</el-button> <el-button @click="closeDialog">{{ $t("common.cancel") }}</el-button>
<el-button type="primary" :loading="submitting" @click="submit">{{ <el-button type="primary" :loading="submitting" @click="submit">{{
isCompleted ? '确认修改' : '确认处理' isCompleted ? '确认修改' : '确认处理'
}}</el-button> }}</el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
@ -120,7 +114,7 @@ const props = defineProps({
orderId: { type: [String, Number], default: "" }, orderId: { type: [String, Number], default: "" },
isCompleted: { type: Boolean, default: false }, isCompleted: { type: Boolean, default: false },
}); });
const emit = defineEmits(["update:modelValue", "processed","openAward"]); const emit = defineEmits(["update:modelValue", "processed", "openAward"]);
const loading = ref(false); const loading = ref(false);
const submitting = ref(false); const submitting = ref(false);

@ -152,6 +152,7 @@
<div class="body-footer"> <div class="body-footer">
<el-button @click="closeDialog"></el-button> <el-button @click="closeDialog"></el-button>
<!-- <el-button type="primary" :loading="regenerating" :disabled="!detail.id" @click="handleRegenerate"></el-button> -->
<el-button type="primary" @click="emit('download', detail)">下载报告</el-button> <el-button type="primary" @click="emit('download', detail)">下载报告</el-button>
</div> </div>
</el-dialog> </el-dialog>
@ -160,7 +161,7 @@
<script setup> <script setup>
import { computed, nextTick, ref, watch } from "vue"; import { computed, nextTick, ref, watch } from "vue";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { getAdminReportDetail } from "@/service/modular/admin"; import { getAdminReportDetail, recalculateAdminReport } from "@/service/modular/admin";
import { useReportPdfExport } from "@/composables/useReportPdfExport"; import { useReportPdfExport } from "@/composables/useReportPdfExport";
import { useReportDocxExport } from "@/composables/useReportDocxExport"; import { useReportDocxExport } from "@/composables/useReportDocxExport";
import VChart from "vue-echarts"; import VChart from "vue-echarts";
@ -193,6 +194,7 @@ const emit = defineEmits(["update:modelValue", "download"]);
const loading = ref(false); const loading = ref(false);
const exporting = ref(false); const exporting = ref(false);
const regenerating = ref(false);
const detail = ref({}); const detail = ref({});
// PDF : .body-wrap ( .body-header ) // PDF : .body-wrap ( .body-header )
@ -416,6 +418,24 @@ watch(
}, },
); );
// recalculate
const handleRegenerate = async () => {
if (!detail.value?.id) {
ElMessage.warning('暂无报告数据,无法重新生成');
return;
}
regenerating.value = true;
try {
await recalculateAdminReport(detail.value.id);
ElMessage.success('报告重新生成成功');
await loadDetail();
} catch (e) {
ElMessage.error(e?.message || '重新生成失败');
} finally {
regenerating.value = false;
}
};
const closeDialog = () => emit("update:modelValue", false); const closeDialog = () => emit("update:modelValue", false);
const coverPeriod = computed(() => { const coverPeriod = computed(() => {

@ -1,5 +1,6 @@
<template> <template>
<div class="report-page" v-loading="exporting" :element-loading-text="exporting ? `正在生成 ${exportTypeLabel}…` : ''" element-loading-background="rgba(255,255,255,0.7)"> <div class="report-page" v-loading="exporting" :element-loading-text="exporting ? ` ${exportTypeLabel}` : ''"
element-loading-background="rgba(255,255,255,0.7)">
<div class="admin-page-card order-report"> <div class="admin-page-card order-report">
<div class="filter-row"> <div class="filter-row">
<el-form :inline="true" :model="filters" class="admin-filter-form"> <el-form :inline="true" :model="filters" class="admin-filter-form">
@ -15,9 +16,9 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-button type="primary" plain @click="onSearch"></el-button> <el-button type="primary" plain @click="onSearch"></el-button>
<el-button @click="onReset"></el-button> <el-button @click="onReset"></el-button>
<el-button type="primary" @click="generateVisible = true">生成报告</el-button> <el-button type="primary" @click="generateVisible = true">生成报告</el-button>
</el-form> </el-form>
</div> </div>
@ -44,11 +45,12 @@
<span>{{ row.remark || "—" }}</span> <span>{{ row.remark || "—" }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="240" fixed="right"> <el-table-column label="操作" width="280" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button class="op-btn purple-sign smaller" plain type="primary" @click="openView(row)"></el-button> <el-button class="op-btn purple-sign smaller" plain type="primary" @click="openView(row)"></el-button>
<el-button class="op-btn rosein-sign smaller" plain type="warning" @click="openDownload(row)"></el-button> <el-button class="op-btn rosein-sign smaller" plain type="warning" @click="openDownload(row)"></el-button>
<el-button class="op-btn blue-sign smaller" plain type="success" @click="openRemark(row)"></el-button> <el-button class="op-btn blue-sign smaller" plain type="success" @click="openRemark(row)"></el-button>
<el-button class="op-btn yellow-sign smaller" plain type="success" @click="deleteReport(row)"></el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -60,14 +62,17 @@
</div> </div>
</div> </div>
<!-- 下载格式选择 --> <!-- 下载格式选择 -->
<ReportDownloadDialog v-model="downloadVisible" :report-id="currentReportId" @downloaded="onDownloaded" @exportPdf="onExportPdf" @exportDocx="onExportDocx" /> <ReportDownloadDialog v-model="downloadVisible" :report-id="currentReportId" @downloaded="onDownloaded"
@exportPdf="onExportPdf" @exportDocx="onExportDocx" />
<!-- 编辑备注 --> <!-- 编辑备注 -->
<ReportRemarkDialog v-model="remarkVisible" :report-row="currentReportRow" @saved="loadList" /> <ReportRemarkDialog v-model="remarkVisible" :report-row="currentReportRow" @saved="loadList" />
<!-- 报告详情 (silent 模式下不可见,仅供 PDF 截图使用) --> <!-- 报告详情 (silent 模式下不可见,仅供 PDF 截图使用) -->
<ReportDetailDialog ref="detailDialogRef" v-model="detailVisible" :silent="silentExport" :report-row="currentReportRow" :report-id="currentReportId" @download="openDownloadById" @exportDocx="onExportDocx" /> <ReportDetailDialog ref="detailDialogRef" v-model="detailVisible" :silent="silentExport"
:report-row="currentReportRow" :report-id="currentReportId" @download="openDownloadById"
@exportDocx="onExportDocx" />
<!-- 生成报告 --> <!-- 生成报告 -->
<ReportGenerateDialog v-model="generateVisible" @generated="onGenerated" /> <ReportGenerateDialog v-model="generateVisible" @generated="onGenerated" />
@ -76,10 +81,10 @@
<script setup> <script setup>
import { computed, nextTick, onMounted, reactive, ref } from "vue"; import { computed, nextTick, onMounted, reactive, ref } from "vue";
import { ElMessage } from "element-plus"; import { ElMessage,ElMessageBox } from "element-plus";
import { QuestionFilled } from "@element-plus/icons-vue"; import { QuestionFilled } from "@element-plus/icons-vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { getAdminReports, toggleAdminReportSendStatus } from "@/service/modular/admin"; import { getAdminReports, toggleAdminReportSendStatus, deleteAdminReport } from "@/service/modular/admin";
import { useHospitalStore } from "@/stores/api/hospital"; import { useHospitalStore } from "@/stores/api/hospital";
import ReportDownloadDialog from "./components/ReportDownloadDialog.vue"; import ReportDownloadDialog from "./components/ReportDownloadDialog.vue";
import ReportRemarkDialog from "./components/ReportRemarkDialog.vue"; import ReportRemarkDialog from "./components/ReportRemarkDialog.vue";
@ -119,6 +124,25 @@ const loadList = async () => {
} }
}; };
const deleteReport = async (row) => {
try {
await ElMessageBox.confirm(
'确定要删除报告吗?删除后将无法恢复。',
'确认',
{
type: "warning",
confirmButtonText: $t('common.confirm'),
cancelButtonText: $t('common.cancel'),
},
);
await deleteAdminReport(row.id);
ElMessage.success('删除成功');
loadList();
} catch (_) {
/* canceled */
}
};
const onSearch = () => { const onSearch = () => {
page.value = 1; page.value = 1;
loadList(); loadList();
@ -163,9 +187,9 @@ const onExportPdf = async ({ reportId } = {}) => {
list.value.find((r) => r.id === targetId) || list.value.find((r) => r.id === targetId) ||
currentReportRow.value || currentReportRow.value ||
null; null;
currentReportId.value = targetId; currentReportId.value = targetId;
currentReportRow.value = row; currentReportRow.value = row;
// :, // :,
const wasDetailVisible = detailVisible.value; const wasDetailVisible = detailVisible.value;
// silent (), // silent (),
silentExport.value = !wasDetailVisible; silentExport.value = !wasDetailVisible;
@ -220,7 +244,7 @@ const onExportDocx = async ({ reportId } = {}) => {
null; null;
currentReportId.value = targetId; currentReportId.value = targetId;
currentReportRow.value = row; currentReportRow.value = row;
const wasDetailVisible = detailVisible.value; const wasDetailVisible = detailVisible.value;
silentExport.value = !wasDetailVisible; silentExport.value = !wasDetailVisible;
if (!wasDetailVisible) { if (!wasDetailVisible) {
detailVisible.value = true; detailVisible.value = true;

@ -170,7 +170,7 @@ const rankClass = (rank) => {
const ruleIconMap = { const ruleIconMap = {
'服务': "service", '服务': "service",
'巡检': "inspector", '巡检': "inspector",
'表扬': "train", '培训': "train",
'回访': "huifang", '回访': "huifang",
'投诉': "complaint", '投诉': "complaint",
}; };

Loading…
Cancel
Save