diff --git a/src/assets/image/admin/orders/award.svg b/src/assets/image/admin/orders/award.svg new file mode 100644 index 0000000..c8d21a6 --- /dev/null +++ b/src/assets/image/admin/orders/award.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/image/admin/reports/summery-bg.svg b/src/assets/image/admin/reports/summery-bg.svg index ac29ad1..9556e17 100644 --- a/src/assets/image/admin/reports/summery-bg.svg +++ b/src/assets/image/admin/reports/summery-bg.svg @@ -2,8 +2,8 @@ - + - + diff --git a/src/components/PasswordDialog.vue b/src/components/PasswordDialog.vue index c8cb965..36bc1df 100644 --- a/src/components/PasswordDialog.vue +++ b/src/components/PasswordDialog.vue @@ -69,31 +69,26 @@ const rules = { { required: true, message: () => t("password.pleaseInputOld"), - trigger: "blur", }, ], newPassword: [ { required: true, message: () => t("password.pleaseInputNew"), - trigger: "blur", }, { min: 6, message: () => t("password.passwordTooShort"), - trigger: "blur", }, ], confirmPassword: [ { required: true, message: () => t("password.pleaseInputConfirm"), - trigger: "blur", }, { validator: (_, val, cb) => val === form.newPassword ? cb() : cb(new Error(t("password.passwordMismatch"))), - trigger: "blur", }, ], }; diff --git a/src/views/admin/accounts/components/AccountEditDialog.vue b/src/views/admin/accounts/components/AccountEditDialog.vue index 8bb5d8e..585c43d 100644 --- a/src/views/admin/accounts/components/AccountEditDialog.vue +++ b/src/views/admin/accounts/components/AccountEditDialog.vue @@ -240,13 +240,13 @@ const form = reactive(buildForm()); const rules = { username: [ - { required: true, message: () => $t('placeholder.account'), trigger: "blur" }, + { required: true, message: () => $t('placeholder.account') }, ], password: [ - { required: true, message: () => $t('placeholder.password'), trigger: "blur" }, + { required: true, message: () => $t('placeholder.password') }, ], name: [ - { required: true, message: () => $t('account.pleaseInputName'), trigger: "blur" }, + { required: true, message: () => $t('account.pleaseInputName') }, ], hospitalId: [ { @@ -256,7 +256,6 @@ const rules = { } cb(); }, - trigger: "change", }, ], role: [ @@ -267,7 +266,6 @@ const rules = { } cb(); }, - trigger: "change", }, ], }; diff --git a/src/views/admin/accounts/edit.vue b/src/views/admin/accounts/edit.vue index 9deae7c..446e0a0 100644 --- a/src/views/admin/accounts/edit.vue +++ b/src/views/admin/accounts/edit.vue @@ -112,10 +112,10 @@ const form = reactive({ }); const rules = { - username: [{ required: true, message: () => $t('placeholder.account'), trigger: "blur" }], - password: [{ required: true, message: () => $t('placeholder.password'), trigger: "blur" }], - name: [{ required: true, message: () => $t('account.pleaseInputName'), trigger: "blur" }], - userType: [{ required: true, message: () => $t('label.accountType'), trigger: "change" }], + username: [{ required: true, message: () => $t('placeholder.account') }], + password: [{ required: true, message: () => $t('placeholder.password') }], + name: [{ required: true, message: () => $t('account.pleaseInputName') }], + userType: [{ required: true, message: () => $t('label.accountType') }], }; const loadDetail = async () => { diff --git a/src/views/admin/hospitals/components/HospitalDetailDialog.vue b/src/views/admin/hospitals/components/HospitalDetailDialog.vue index a9a68ea..f15294f 100644 --- a/src/views/admin/hospitals/components/HospitalDetailDialog.vue +++ b/src/views/admin/hospitals/components/HospitalDetailDialog.vue @@ -160,6 +160,7 @@ const goEdit = () => emit("edit", props.hospitalId); white-space: nowrap; flex-shrink: 0; flex-grow: 0; + text-align: right; } .value { diff --git a/src/views/admin/hospitals/components/HospitalEditDialog.vue b/src/views/admin/hospitals/components/HospitalEditDialog.vue index 7d88e6c..3999308 100644 --- a/src/views/admin/hospitals/components/HospitalEditDialog.vue +++ b/src/views/admin/hospitals/components/HospitalEditDialog.vue @@ -176,30 +176,27 @@ const rules = { { required: true, message: () => $t("placeholder.hospital"), - trigger: "blur", }, ], customerCategory: [ - { required: true, message: () => $t("label.category"), trigger: "change" }, + { required: true, message: () => $t("label.category") }, ], signDate: [ - { required: true, message: () => $t("label.signDate"), trigger: "change" }, + { required: true, message: () => $t("label.signDate") }, ], acceptDate: [ { required: true, message: () => $t("label.acceptDate"), - trigger: "change", }, ], contractYears: [ - { required: true, message: () => $t("label.years"), trigger: "blur" }, + { required: true, message: () => $t("label.years") }, ], maintenanceEnd: [ { required: true, message: () => $t("label.maintenanceEndDate"), - trigger: "change", }, ], }; diff --git a/src/views/admin/hospitals/components/ServiceRecordDialog.vue b/src/views/admin/hospitals/components/ServiceRecordDialog.vue index 319bc03..8976223 100644 --- a/src/views/admin/hospitals/components/ServiceRecordDialog.vue +++ b/src/views/admin/hospitals/components/ServiceRecordDialog.vue @@ -311,32 +311,32 @@ const form = reactive(defaultForm()); const buildRules = () => { if (props.type === "call") { return { - callTime: [{ required: true, message: "请选择回访时间", trigger: "change" }], - callPerson: [{ required: true, message: "请输入回访人", trigger: "blur" }], - content: [{ required: true, message: "请输入回访内容", trigger: "blur" }], + callTime: [{ required: true, message: "请选择回访时间" }], + callPerson: [{ required: true, message: "请输入回访人" }], + content: [{ required: true, message: "请输入回访内容" }], }; } if (props.type === "inspection") { console.log(111); return { - inspectionTime: [{ required: true, message: "请选择巡检时间", trigger: "change" }], - inspectionPerson: [{ required: true, message: "请输入巡检人", trigger: "blur" }], - content: [{ required: true, message: "请输入巡检内容", trigger: "blur" }], + inspectionTime: [{ required: true, message: "请选择巡检时间" }], + inspectionPerson: [{ required: true, message: "请输入巡检人" }], + content: [{ required: true, message: "请输入巡检内容" }], }; } if (props.type === "training") { return { - trainingDate: [{ required: true, message: "请选择培训日期", trigger: "change" }], - participants: [{ required: true, message: "请输入参与人数", trigger: "blur" }], - trainer: [{ required: true, message: "请输入培训人员", trigger: "blur" }], - topic: [{ required: true, message: "请输入培训主题", trigger: "blur" }], + trainingDate: [{ required: true, message: "请选择培训日期" }], + participants: [{ required: true, message: "请输入参与人数" }], + trainer: [{ required: true, message: "请输入培训人员" }], + topic: [{ required: true, message: "请输入培训主题" }], }; } return { - date: [{ required: true, message: "请选择年份", trigger: "change" }], - quantity: [{ required: true, message: "请输入数量", trigger: "blur" }], - name: [{ required: true, message: "请输入纪念品名称", trigger: "blur" }], + date: [{ required: true, message: "请选择年份" }], + quantity: [{ required: true, message: "请输入数量" }], + name: [{ required: true, message: "请输入纪念品名称" }], }; }; diff --git a/src/views/admin/hospitals/service.vue b/src/views/admin/hospitals/service.vue index e49c11b..2504a02 100644 --- a/src/views/admin/hospitals/service.vue +++ b/src/views/admin/hospitals/service.vue @@ -8,10 +8,21 @@ + + 客户分类 + + + + + + 维保截止日期 + 查询
-
+ @@ -113,7 +124,7 @@ -
+ - + @@ -164,7 +175,8 @@ import { useHospitalStore } from "@/stores/api/hospital"; import MaintenanceDetailDialog from "./components/MaintenanceDetailDialog.vue"; import ServiceRecordDialog from "./components/ServiceRecordDialog.vue"; import MonthlyViewDialog from "./components/MonthlyViewDialog.vue"; - +import { dateRangeShortcuts } from "@/utils/dateShortcuts"; +const dateRange = ref([]); const list = ref([]); const loading = ref(false); const expiringLoading = ref(false); @@ -198,13 +210,19 @@ const formatExpiringDays = (n) => { const loadList = async () => { loading.value = true; try { - const res = await getAdminMaintenance({ + const params = { page: 1, pageSize: 200, keyword: filters.keyword || undefined, + category: filters.category || undefined, year: currentMonth.value.year(), month: currentMonth.value.month() + 1, - }); + } + if (dateRange.value?.length === 2) { + params.maintenanceStart = dateRange.value[0]; + params.maintenanceEnd = dateRange.value[1]; + } + const res = await getAdminMaintenance(params); list.value = res?.list || []; } finally { loading.value = false; @@ -252,7 +270,7 @@ const monthlyVisible = ref(false); onMounted(() => { hospitalStore.ensureLoaded(); loadList(); - loadExpiring(); + // loadExpiring(); }); diff --git a/src/views/admin/orders/components/OrderAwardDialog.vue b/src/views/admin/orders/components/OrderAwardDialog.vue new file mode 100644 index 0000000..319a88f --- /dev/null +++ b/src/views/admin/orders/components/OrderAwardDialog.vue @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file diff --git a/src/views/admin/orders/components/OrderDetailDialog.vue b/src/views/admin/orders/components/OrderDetailDialog.vue index 198b49d..8afb39d 100644 --- a/src/views/admin/orders/components/OrderDetailDialog.vue +++ b/src/views/admin/orders/components/OrderDetailDialog.vue @@ -28,6 +28,25 @@
{{ detail.serviceType }}
+ +
+
+
提出医院
+
{{ detail.hospitalName || '-' }}
+
+
+
提出科室
+
{{ detail.department || '-' }}
+
+
+
提出人员
+
{{ detail.submitter || '-' }}
+
+
+
提交时间
+
{{ detail.createdAt?.split('T').join(' ') || '-' }}
+
+
@@ -49,8 +68,7 @@
附件
- +
@@ -62,25 +80,6 @@
- -
-
-
提出医院
-
{{ detail.hospitalName || '-' }}
-
-
-
提出科室
-
{{ detail.department || '-' }}
-
-
-
提出人员
-
{{ detail.submitter || '-' }}
-
-
-
提交时间
-
{{ detail.createdAt?.split('T').join(' ') || '-' }}
-
-
@@ -90,7 +89,12 @@
{{ log.toStatus }} · {{ log.operator }}
-
+
+
处理备注: +
+
+
+
@@ -322,6 +326,7 @@ watch( white-space: nowrap; flex-shrink: 0; flex-grow: 0; + text-align: right; } .value { @@ -401,7 +406,7 @@ watch( font-weight: 600; } -.log-remark { +.remark-wrap { color: #606266; margin-top: 4px; } diff --git a/src/views/admin/orders/components/OrderFormDialog.vue b/src/views/admin/orders/components/OrderFormDialog.vue index 02bcec9..d6a3445 100644 --- a/src/views/admin/orders/components/OrderFormDialog.vue +++ b/src/views/admin/orders/components/OrderFormDialog.vue @@ -253,35 +253,30 @@ const rules = { { required: true, message: () => $t('msg.pleaseSelectHospital'), - trigger: 'change', }, ], title: [ { required: true, message: () => $t('msg.pleaseInputTitle'), - trigger: 'blur', }, ], serviceType: [ { required: true, message: () => $t('msg.pleaseSelectType'), - trigger: 'blur', }, ], priority: [ { required: true, message: () => $t('msg.pleaseSelectPriority'), - trigger: 'change', }, ], feedbackchannel: [ { required: true, message: () => $t('msg.pleaseSelectFeedbackChannel'), - trigger: 'change', }, ], department: [ @@ -289,7 +284,6 @@ const rules = { required: true, whitespace: true, message: () => $t('msg.pleaseInputDept'), - trigger: 'blur', }, ], submitter: [ @@ -297,7 +291,6 @@ const rules = { required: true, whitespace: true, message: () => $t('msg.pleaseInputName'), - trigger: 'blur', }, ], description: [ @@ -313,7 +306,6 @@ const rules = { return callback(new Error($t('msg.pleaseInputDescription'))); callback(); }, - trigger: 'change', }, ], }; diff --git a/src/views/admin/orders/components/OrderHandleDialog.vue b/src/views/admin/orders/components/OrderHandleDialog.vue index af6fe57..f9d676a 100644 --- a/src/views/admin/orders/components/OrderHandleDialog.vue +++ b/src/views/admin/orders/components/OrderHandleDialog.vue @@ -106,8 +106,7 @@
- +
diff --git a/src/views/admin/orders/components/OrderProcessDialog.vue b/src/views/admin/orders/components/OrderProcessDialog.vue index 7aa0e6a..9605ad2 100644 --- a/src/views/admin/orders/components/OrderProcessDialog.vue +++ b/src/views/admin/orders/components/OrderProcessDialog.vue @@ -3,15 +3,27 @@ top="5vh" @update:model-value="(v) => $emit('update:modelValue', v)" @open="onOpen">
-
处理工单
+
{{ isCompleted ? '修改工单' : '处理工单' }}
- - - - + + + + + + + + + + + + + + + + @@ -73,7 +85,7 @@ @@ -99,14 +111,16 @@ import { } from "@/service/modular/admin"; import { useUserStore } from "@/stores/api/user"; + const { t: $t } = useI18n(); const userStore = useUserStore(); const props = defineProps({ modelValue: { type: Boolean, default: false }, orderId: { type: [String, Number], default: "" }, + isCompleted: { type: Boolean, default: false }, }); -const emit = defineEmits(["update:modelValue", "processed"]); +const emit = defineEmits(["update:modelValue", "processed","openAward"]); const loading = ref(false); const submitting = ref(false); @@ -133,7 +147,7 @@ const form = reactive({ const rules = { status: [ - { required: true, message: () => $t("table.status"), trigger: "change" }, + { required: true, message: () => $t("table.status") }, ], processRemark: [ { @@ -148,7 +162,6 @@ const rules = { return callback(new Error($t("placeholder.remark"))); callback(); }, - trigger: "change", }, ], }; @@ -296,6 +309,7 @@ watch( }, ); + const submit = async () => { if (!formRef.value) return; await formRef.value.validate(async (valid) => { @@ -309,7 +323,13 @@ const submit = async () => { department: form.department, submitter: form.submitter, }); - ElMessage.success($t("msg.editSuccess")); + + // 首次处理完成:弹出奖励层,不直接关闭原弹窗 + if (!props.isCompleted) { + emit("openAward"); + } else { + ElMessage.success($t("msg.editSuccess")); + } emit("update:modelValue", false); emit("processed"); } finally { diff --git a/src/views/admin/orders/components/ReportDetailDialog.vue b/src/views/admin/orders/components/ReportDetailDialog.vue index 4225b19..a4d7391 100644 --- a/src/views/admin/orders/components/ReportDetailDialog.vue +++ b/src/views/admin/orders/components/ReportDetailDialog.vue @@ -38,9 +38,9 @@
感谢贵院一直以来对上海康策的信任与配合。
- 本期我们累计处理服务工单:{{ 28 - }}次,完成率达:{{ 95 }}%;同时安排回访:{{ 3 - }}次、现场巡检:{{ 1 }}次及参与培训:{{ 1 + 本期我们累计处理服务工单:{{detail.total + }}次,完成率达:{{ detail.rate }};同时安排回访:{{ detail.callRecord + }}次、现场巡检:{{ detail.inspectionRecord }}次及参与培训:{{ detail.trainingRecord }}次,力求从响应、预防到能力共建,全方位护航医院信息化环境。
@@ -372,7 +372,7 @@ const loadDetail = async (overrideId) => { // name: "现场", // count: 3 // }, { - // name: "钉钉", + // name: "钉钉",/ // count: 3 // }, { // name: "其他", @@ -527,7 +527,7 @@ const deptOption = computed(() => { .sort((a, b) => b.count - a.count); return { - grid: { left: 10, right: 10, top: 10, bottom: 10 }, + grid: { left: 10, right: 10, top: 20, bottom: 10 }, tooltip: { trigger: "axis", axisPointer: { type: "shadow" }, @@ -898,7 +898,7 @@ const statusClass = (s) => width: 100%; position: relative; height: 28px; - background: #E7EDF6; + background: #C5D0E0; border-radius: 12px 12px 12px 12px; padding: 4px; diff --git a/src/views/admin/orders/components/ReportGenerateDialog.vue b/src/views/admin/orders/components/ReportGenerateDialog.vue index 27b63e0..356d47a 100644 --- a/src/views/admin/orders/components/ReportGenerateDialog.vue +++ b/src/views/admin/orders/components/ReportGenerateDialog.vue @@ -109,9 +109,9 @@ const form = reactive({ }); const rules = { - hospitalId: [{ required: true, message: "请选择医院名称", trigger: "change" }], - type: [{ required: true, message: "请选择报告类型", trigger: "change" }], - year: [{ required: true, message: "请选择年份", trigger: "change" }], + hospitalId: [{ required: true, message: "请选择医院名称" }], + type: [{ required: true, message: "请选择报告类型" }], + year: [{ required: true, message: "请选择年份" }], quarter: [ { validator: (_, value, cb) => { @@ -119,7 +119,6 @@ const rules = { return cb(new Error("季度报告必须选择季度")); cb(); }, - trigger: "change", }, ], }; diff --git a/src/views/admin/orders/list.vue b/src/views/admin/orders/list.vue index 98afc73..5f85389 100644 --- a/src/views/admin/orders/list.vue +++ b/src/views/admin/orders/list.vue @@ -108,8 +108,9 @@ @@ -133,7 +134,7 @@ @@ -183,7 +189,7 @@ import iconAll from "@/assets/image/admin/orders/all.svg"; import iconPending from "@/assets/image/admin/orders/pending.svg"; import iconComplete from "@/assets/image/admin/orders/complete.svg"; import iconHigh from "@/assets/image/admin/orders/high.svg"; - +import OrderAwardDialog from "./components/OrderAwardDialog.vue"; const { t: $t } = useI18n(); const userStore = useUserStore(); const hospitalStore = useHospitalStore(); @@ -202,7 +208,12 @@ const filters = reactive({ type: "", keyword: "", }); - +// 处理成功奖励弹窗可见性(仅首次处理时展示) +const awardVisible = ref(false); +// “继续处理”回调:关闭奖励弹窗 + 关闭处理弹窗 + 通知父组件刷新 +const onAwardContinue = () => { + awardVisible.value = false; +}; const statusClass = (s) => s === "已完成" ? "done" : s === "待处理" ? "pending" : 'info'; @@ -305,14 +316,15 @@ const detailVisible = ref(false); const processVisible = ref(false); const handleVisible = ref(false); const currentOrderId = ref(""); - +const isCompleted = ref(false); const goDetail = (id) => { currentOrderId.value = id; detailVisible.value = true; }; -const goProcess = (id) => { +const goProcess = (id, isCompletedFlag) => { currentOrderId.value = id; processVisible.value = true; + isCompleted.value = isCompletedFlag || false; }; const goHandle = (id) => { currentOrderId.value = id; @@ -434,7 +446,7 @@ const formStyle = computed(() => { border-radius: 12px 12px 12px 12px; border: 1px solid #e0e0e0; overflow: hidden; - + // el-table 的 border 是用伪元素绘制外层 1px(左/右/上) + 内部 cell 的 border-right / border-bottom // 这里把外层 3 条伪元素边框隐藏,仅保留 cell 之间的分隔线,避免与外层自加 border 叠加 @@ -503,7 +515,7 @@ const formStyle = computed(() => { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; - margin-bottom: 24px; + margin-bottom: 24px; } .stat-card { diff --git a/src/views/admin/performance/score.vue b/src/views/admin/performance/score.vue index ecfa777..133e61d 100644 --- a/src/views/admin/performance/score.vue +++ b/src/views/admin/performance/score.vue @@ -10,7 +10,7 @@ 自定义
- 查询
@@ -133,6 +133,7 @@ import inspectorIcon from "@/assets/image/admin/score/inspector.svg"; import trainIcon from "@/assets/image/admin/score/train.svg"; import huifangIcon from "@/assets/image/admin/score/huifang.svg"; import complaintIcon from "@/assets/image/admin/score/complaint.svg"; +import { dateRangeShortcuts } from "@/utils/dateShortcuts"; import { getManagerPointsDetails, getManagerPointsLeaderboard, diff --git a/src/views/hospital/AssetsDialog.vue b/src/views/hospital/AssetsDialog.vue index c2d7cf8..05c5d44 100644 --- a/src/views/hospital/AssetsDialog.vue +++ b/src/views/hospital/AssetsDialog.vue @@ -42,7 +42,7 @@
今日提交工单 - +{{ todayOrder }} 积分 + +{{ todayOrder }} 分
diff --git a/src/views/hospital/SignInDialog.vue b/src/views/hospital/SignInDialog.vue index 0d34621..6950832 100644 --- a/src/views/hospital/SignInDialog.vue +++ b/src/views/hospital/SignInDialog.vue @@ -5,24 +5,26 @@