csm调整

master
2358328281@qq.com 2 months ago
parent a158c5f322
commit 13c66287b2

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 323 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.6 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

@ -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",
},
],
};

@ -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",
},
],
};

@ -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 () => {

@ -160,6 +160,7 @@ const goEdit = () => emit("edit", props.hospitalId);
white-space: nowrap;
flex-shrink: 0;
flex-grow: 0;
text-align: right;
}
.value {

@ -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",
},
],
};

@ -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: "请输入纪念品名称" }],
};
};

@ -8,10 +8,21 @@
<el-select v-model="filters.keyword" placeholder="全部医院" clearable filterable style="width: 220px">
<el-option v-for="h in hospitals" :key="h.id" :label="h.name" :value="h.name" />
</el-select>
<span class="filter-label">客户分类</span>
<el-select v-model="filters.category" :placeholder="$t('common.all')" clearable style="width: 140px">
<el-option label="A类客户活跃" value="A" />
<el-option label="B类客户不活跃" value="B" />
<el-option label="C类客户待挽回" value="C" />
</el-select>
<span class="filter-label">维保截止日期</span>
<el-date-picker v-model="dateRange" type="daterange" range-separator="-"
:start-placeholder="$t('common.startDate')" :end-placeholder="$t('common.endDate')"
value-format="YYYY-MM-DD" :shortcuts="dateRangeShortcuts" style="width: 240px" />
<el-button type="primary" plain @click="onSearch"></el-button>
</div>
<div class="filter-right">
<div class="month-switcher">
<!-- <div class="month-switcher">
<el-button class="switch-btn" plain @click="prevMonth">
<div class="inner">
< </div>
@ -20,7 +31,7 @@
<el-button class="switch-btn" plain @click="nextMonth">
<div class="inner">></div>
</el-button>
</div>
</div> -->
<el-button class="monthly-view-btn" type="primary" @click="monthlyVisible = true">
<el-icon>
<Calendar />
@ -113,7 +124,7 @@
<!-- 本月到期提醒 -->
<div class="expiring-section admin-page-card">
<!-- <div class="expiring-section admin-page-card">
<div class="expiring-title border-title">
本月到期提醒
</div>
@ -140,12 +151,12 @@
</div>
</div>
</div>
</div>
</div> -->
<!-- 维保详情/编辑弹窗 -->
<MaintenanceDetailDialog v-model="detailVisible" :hospital-id="currentHospitalId" @saved="onSearch" />
<!-- 服务记录弹窗电话回访/现场巡检/培训/纪念品 -->
<!-- 服务记录弹窗电话回访/现场巡检/培训/纪念品 -->
<!-- v-if 让弹窗关闭时整个组件卸载下次打开会重新 setuprules 会按最新 type 生成 -->
<ServiceRecordDialog v-if="recordVisible" v-model="recordVisible" :type="recordType"
:hospital-id="currentHospitalId" :hospital-name="currentHospitalName" />
@ -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();
});
</script>

@ -0,0 +1,83 @@
<template>
<el-dialog :model-value="modelValue" class="order-award-dialog" :show-close="false" :close-on-click-modal="false"
:close-on-press-escape="false" align-center @update:model-value="(v) => $emit('update:modelValue', v)">
<div class="body-wrap">
<img :src="awardIcon" alt="award" />
<div class="award-title">你真棒!</div>
<div class="award-subtitle">恭喜您完成服务工单</div>
<div class="award-points"><span class="light">+{{ points }}</span>&nbsp;&nbsp;积分</div>
</div>
<div class="body-footer" style="justify-content: center;">
<el-button type="primary" class="award-btn" @click="onContinue">
继续处理
</el-button>
</div>
</el-dialog>
</template>
<script setup>
import awardIcon from "@/assets/image/admin/orders/award.svg";
defineProps({
modelValue: { type: Boolean, default: false },
points: { type: [String, Number], default: 5 },
});
const emit = defineEmits(["update:modelValue", "continue"]);
const onContinue = () => {
emit("update:modelValue", false);
emit("continue");
};
</script>
<style lang="scss">
.order-award-dialog {
width: 458px;
.body-wrap {
padding: 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
img {
width: 90px;
height: 83px;
object-fit: contain;
}
.award-title {
font-size: 22px;
line-height: 38px;
color: #1D2129;
font-weight: 600;
}
.award-subtitle {
font-size: 16px;
line-height: 30px;
color: #1D2129;
}
.award-points {
font-weight: 600;
font-size: 16px;
color: #FF8D28;
line-height: 34px;
.light {
font-size: 24px;
}
}
}
.award-btn {
font-size: 14px;
color: #FFFFFF;
padding: 16px 46px;
}
}
</style>

@ -28,6 +28,25 @@
<div class="value">{{ detail.serviceType }}</div>
</div>
</div>
<!-- 第五行4 -->
<div class="detail-row row-4">
<div class="detail-item">
<div class="label">提出医院</div>
<div class="value">{{ detail.hospitalName || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提出科室</div>
<div class="value">{{ detail.department || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提出人员</div>
<div class="value">{{ detail.submitter || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提交时间</div>
<div class="value">{{ detail.createdAt?.split('T').join(' ') || '-' }}</div>
</div>
</div>
<!-- 第二行1 -->
<div class="detail-row row-1">
<div class="detail-item">
@ -49,8 +68,7 @@
<div class="detail-item">
<div class="label">附件</div>
<div class="value">
<el-empty style="padding:0;" v-if="!detail.attachments?.length"
:description="$t('orderDetail.noAttachment')" :image-size="80" />
<span v-if="!detail.attachments?.length" v-html="$t('orderDetail.noAttachment')"></span>
<div v-else class="files">
<el-button v-for="(f, i) in detail.attachments" :key="i" link type="primary"
class="file-item" @click="viewReport(f.filePath, f.fileName)">
@ -62,25 +80,6 @@
</div>
</div>
</div>
<!-- 第五行4 -->
<div class="detail-row row-4">
<div class="detail-item">
<div class="label">提出医院</div>
<div class="value">{{ detail.hospitalName || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提出科室</div>
<div class="value">{{ detail.department || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提出人员</div>
<div class="value">{{ detail.submitter || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提交时间</div>
<div class="value">{{ detail.createdAt?.split('T').join(' ') || '-' }}</div>
</div>
</div>
</div>
@ -90,7 +89,12 @@
<el-timeline-item v-for="(log, i) in detail.statusLogs || []" :key="i" :timestamp="log.createdAt"
placement="top">
<div class="log-title">{{ log.toStatus }} · {{ log.operator }}</div>
<div class="log-remark" v-html="log.remark"></div>
<div class="remark-wrap" style="display: flex; align-items: start;">
<div class="remark-title" style="font-weight: 600;color:var(--el-text-color-primary);">处理备注
</div>
<div class="log-remark" v-html="log.remark"></div>
</div>
</el-timeline-item>
</el-timeline>
</div>
@ -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;
}

@ -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',
},
],
};

@ -106,8 +106,7 @@
<!-- 附件 -->
<el-form-item label="附件">
<div class="attachment">
<el-empty style="padding:0;" v-if="!detail.attachments?.length"
:description="$t('orderDetail.noAttachment')" :image-size="80" />
<span v-if="!detail.attachments?.length" v-html="$t('orderDetail.noAttachment')"></span>
<div v-else class="files">
<el-button v-for="(f, i) in detail.attachments" :key="i" link
class="file-item" @click="viewReport(f)">

@ -3,15 +3,27 @@
top="5vh" @update:model-value="(v) => $emit('update:modelValue', v)" @open="onOpen">
<div class="body-wrap" v-loading="loading">
<div class="body-header">
<div class="body-title">处理工单</div>
<div class="body-title">{{ isCompleted ? '修改工单' : '处理工单' }}</div>
<img src="@/assets/image/close-btn.svg" alt="" class="close-btn" @click="closeDialog" />
</div>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" v-if="detail.id">
<!-- 工单号只读 -->
<el-form-item :label="$t('table.id')">
<el-input :model-value="detail.orderNo" readonly />
</el-form-item>
<!-- 科室 / 提交人可编辑回显原值 -->
<el-row :gutter="16">
<el-col :span="12">
<!-- 工单号只读 -->
<el-form-item :label="$t('table.id')">
<el-input :model-value="detail.orderNo" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<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">
@ -73,7 +85,7 @@
<div class="body-footer">
<el-button @click="closeDialog">{{ $t("common.cancel") }}</el-button>
<el-button type="primary" :loading="submitting" @click="submit">{{
$t("btn.confirm")
isCompleted ? '确认修改' : '确认处理'
}}</el-button>
</div>
</el-dialog>
@ -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 {

@ -38,9 +38,9 @@
<div class="summary-text">
<span class="light">感谢贵院一直以来对上海康策的信任与配合</span> <br>
<span class="em">
本期我们累计处理服务工单<span class="blue">{{ 28
}}</span>完成率达<span class="green">{{ 95 }}%</span>同时安排回访<span class="cyan">{{ 3
}}</span>现场巡检<span class="yellow">{{ 1 }}</span>及参与培训<span class="purple">{{ 1
本期我们累计处理服务工单<span class="blue">{{detail.total
}}</span>完成率达<span class="green">{{ detail.rate }}</span>同时安排回访<span class="cyan">{{ detail.callRecord
}}</span>现场巡检<span class="yellow">{{ detail.inspectionRecord }}</span>及参与培训<span class="purple">{{ detail.trainingRecord
}}</span>力求从响应预防到能力共建全方位护航医院信息化环境
</span> <br>
<span class="light">
@ -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;

@ -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",
},
],
};

@ -108,8 +108,9 @@
</el-table-column>
<el-table-column :label="$t('table.title')" min-width="300" show-overflow-tooltip>
<template #default="{ row }">
<span class="title-link" :style="{color:row.colorTag}" style="text-decoration: underline;" @click="goHandle(row.id)">{{ row.title
}}</span>
<span class="title-link" :style="{ color: row.colorTag }" style="text-decoration: underline;"
@click="goHandle(row.id)">{{ row.title
}}</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.type')" prop="serviceType" width="120" />
@ -133,7 +134,7 @@
<el-table-column :label="$t('table.action')" width="160" fixed="right">
<template #default="{ row }">
<el-button class="handle smaller" plain :class="row.status === '已完成' ? 'purple-sign' : 'rosein-sign'"
@click="goProcess(row.id)">{{
@click="goProcess(row.id, row.status === '已完成' ? true : false)">{{
row.status === "已完成" ? $t("btn.modify") : $t("btn.process")
}}</el-button>
<el-button class="blue-sign smaller" type="primary" plain @click="goDetail(row.id)">{{
@ -156,10 +157,15 @@
<OrderDetailDialog v-model="detailVisible" :order-id="currentOrderId" @updated="loadList" />
<!-- 处理工单 弹窗 -->
<OrderProcessDialog v-model="processVisible" :order-id="currentOrderId" @processed="loadList" />
<OrderProcessDialog v-model="processVisible" :order-id="currentOrderId" :is-completed="isCompleted"
@processed="loadList" @openAward="awardVisible = true" />
<!-- 工单处理/详情一体化 弹窗点击标题进入 -->
<OrderHandleDialog v-model="handleVisible" :order-id="currentOrderId" @updated="loadList" />
<!-- 处理成功奖励弹窗 -->
<OrderAwardDialog v-model="awardVisible" @continue="onAwardContinue" />
</div>
</template>
@ -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 {

@ -10,7 +10,7 @@
<el-button :class="['period-tab', { active: isCustom }]" plain @click="onPickCustom"></el-button>
</div>
<div v-if="isCustom" class="custom-range">
<el-date-picker v-model="customRange" type="daterange" range-separator="-" start-placeholder=""
<el-date-picker :shortcuts="dateRangeShortcuts" v-model="customRange" type="daterange" range-separator="-" start-placeholder=""
end-placeholder="结束日期" value-format="YYYY-MM-DD" style="width: 240px" />
<el-button type="primary" class="search-btn" plain @click="onSearch"></el-button>
</div>
@ -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,

@ -42,7 +42,7 @@
</div>
<div class="detail">
<span class="detail-name">今日提交工单</span>
<span class="detail-points">+{{ todayOrder }} </span>
<span class="detail-points">+{{ todayOrder }} </span>
</div>
</div>
<div class="detail-item">

@ -5,24 +5,26 @@
<!-- ============ 头部标题 / 副标题 / 装饰图 ============ -->
<div class="signin-header">
<h3 class="signin-title" :class="{ 'is-signed': signedIn }">
<template v-if="signedIn">
<!-- <template v-if="signedIn"> -->
<template v-if="true">
连续签到<span class="title-num">{{ streakDays }}</span>
<template v-if="rank > 0">排名第<span class="title-num">{{ rank }}</span></template>
<template v-else></template>
</template>
<template v-else>
<!-- <template v-else>
每日签到 <span class="title-num">领积分</span>
</template>
</template> -->
</h3>
<p class="signin-subtitle">
<template v-if="signedIn">
<!-- <template v-if="signedIn"> -->
<template v-if="true">
当前积分: <span class="title-num">{{ totalPoints }}</span>
<template v-if="beatPercent > 0">{{ beatPercent }}%</template>
<template v-else></template>
&nbsp;您已击败全国{{ beatPercent }}%的医院
<!-- <template v-else></template> -->
</template>
<template v-else>
<!-- <template v-else>
坚持签到积分兑好礼
</template>
</template> -->
</p>
</div>
@ -66,13 +68,8 @@
</el-dialog>
<!-- 签到成功 今日未抽奖则弹出抽奖弹窗(抽过则不再弹,避免重复打扰) -->
<LotteryDialog
v-model="lotteryVisible"
:drawable="!hasDrawn"
:batch-goal="500"
:batch-current="0"
@success="onLotterySuccess"
/>
<LotteryDialog v-model="lotteryVisible" :drawable="!hasDrawn" :batch-goal="500" :batch-current="0"
@success="onLotterySuccess" />
</template>
<script setup>

@ -28,6 +28,21 @@
<div class="value">{{ detail.serviceType }}</div>
</div>
</div>
<!-- 第五行3不展示"提出医院"医院端默认就是当前登录医院 -->
<div class="detail-row row-3">
<div class="detail-item">
<div class="label">提出科室</div>
<div class="value">{{ detail.department || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提出人员</div>
<div class="value">{{ detail.submitter || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提交时间</div>
<div class="value">{{ detail.createdAt?.split('T').join(' ') || '-' }}</div>
</div>
</div>
<!-- 第二行1 -->
<div class="detail-row row-1">
<div class="detail-item">
@ -49,11 +64,10 @@
<div class="detail-item">
<div class="label">附件</div>
<div class="value">
<el-empty style="padding:0;" v-if="!detail.attachments?.length"
:description="$t('orderDetail.noAttachment')" :image-size="80" />
<span v-if="!detail.attachments?.length" v-html="$t('orderDetail.noAttachment')"></span>
<div v-else class="files">
<el-button v-for="(f, i) in detail.attachments" :key="i" link type="primary"
class="file-item" @click="viewReport(f.filePath, f.fileName)">
<el-button v-for="(f, i) in detail.attachments" :key="i" link type="primary" class="file-item"
@click="viewReport(f.filePath, f.fileName)">
<el-icon>
<Document />
</el-icon>{{ f.fileName }}
@ -62,29 +76,13 @@
</div>
</div>
</div>
<!-- 第五行3不展示"提出医院"医院端默认就是当前登录医院 -->
<div class="detail-row row-3">
<div class="detail-item">
<div class="label">提出科室</div>
<div class="value">{{ detail.department || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提出人员</div>
<div class="value">{{ detail.submitter || '-' }}</div>
</div>
<div class="detail-item">
<div class="label">提交时间</div>
<div class="value">{{ detail.createdAt?.split('T').join(' ') || '-' }}</div>
</div>
</div>
</div>
<div class="section" v-if="detail.logs?.length">
<div class="section-title">{{ $t('orderDetail.statusChange') }}</div>
<el-timeline>
<el-timeline-item v-for="(log, i) in detail.logs || []" :key="i" :timestamp="log.createdAt"
placement="top">
<el-timeline-item v-for="(log, i) in detail.logs || []" :key="i" :timestamp="log.createdAt" placement="top">
<div class="log-title">{{ log.action }} · {{ log.operator }}</div>
<div class="log-remark" v-html="log.remark"></div>
</el-timeline-item>
@ -97,8 +95,7 @@
<el-button type="primary" plain style="margin-left:auto" @click="closeDialog">
取消
</el-button>
<el-button v-if="detail.status !== '' && detail.status !== ''" type="primary"
@click="editVisible = true">
<el-button v-if="detail.status !== '已完成' && detail.status !== '已取消'" type="primary" @click="editVisible = true">
{{ $t('btn.edit') }}
</el-button>
</div>
@ -291,6 +288,7 @@ const onEditSuccess = () => {
white-space: nowrap;
flex-shrink: 0;
flex-grow: 0;
text-align: right;
}
.value {

@ -236,17 +236,17 @@ const form = reactive({
});
const rules = {
title: [{ required: true, message: () => $t('msg.pleaseInputTitle'), trigger: "blur" }],
serviceType: [{ required: true, message: () => $t('msg.pleaseSelectType'), trigger: "change" }],
priority: [{ required: true, message: () => $t('msg.pleaseSelectPriority'), trigger: "change" }],
title: [{ required: true, message: () => $t('msg.pleaseInputTitle') }],
serviceType: [{ required: true, message: () => $t('msg.pleaseSelectType') }],
priority: [{ required: true, message: () => $t('msg.pleaseSelectPriority') }],
feedbackchannel: [
{ required: true, message: () => $t('msg.pleaseSelectFeedbackChannel'), trigger: "change" },
{ required: true, message: () => $t('msg.pleaseSelectFeedbackChannel') },
],
department: [
{ required: true, whitespace: true, message: () => $t('msg.pleaseInputDept'), trigger: "blur" },
{ required: true, whitespace: true, message: () => $t('msg.pleaseInputDept') },
],
submitter: [
{ required: true, whitespace: true, message: () => $t('msg.pleaseInputName'), trigger: "blur" },
{ required: true, whitespace: true, message: () => $t('msg.pleaseInputName') },
],
description: [
{
@ -260,7 +260,6 @@ const rules = {
if (!text && !hasImage) return callback(new Error($t('msg.pleaseInputDescription')));
callback();
},
trigger: "change",
},
],
};

@ -39,7 +39,7 @@
<div class="section">
<div class="section-title">{{ $t('label.attachment') }} ({{ (detail.attachments || []).length }})</div>
<el-empty v-if="!detail.attachments?.length" :description="$t('orderDetail.noAttachment')" :image-size="80" />
<span v-if="!detail.attachments?.length" v-html="$t('orderDetail.noAttachment')"></span>
<div v-else class="files">
<el-button
v-for="(f, i) in detail.attachments"

@ -130,7 +130,7 @@
</div>
</template>
<el-table class="jifen-table" header-cell-class-name="jifen-table-header-cell" :data="details" height="400" v-loading="loading"
<el-table class="jifen-table" header-cell-class-name="jifen-table-header-cell" :data="details" max-height="400" v-loading="loading"
border stripe>
<el-table-column label="时间" prop="createdAt" width="170" />
<el-table-column label="来源" prop="source" width="140">
@ -206,7 +206,7 @@
<!-- ========== 签到弹窗 ========== -->
<SignInDialog v-model="signInVisible" :signed-in="!!summary.isSignIn" :total-points="totalPoints"
:consecutive-sign-in-days="consecutiveSignInDays" :sign-in-rank="signInRank" :beat-percent="beatPercent"
@success="onSignInSuccess" />
@success="onSignInSuccess" :hasDrawn="summary.isDraw" />
<!-- 我的资产弹窗已迁到 AdminLayout 全局(AssetDialogStore 控制)避免重复弹窗 -->
@ -474,18 +474,17 @@ const exchangeForm = reactive({
});
const exchangeRules = {
recipientName: [
{ required: true, message: "请输入收件人姓名", trigger: "blur" },
{ required: true, message: "请输入收件人姓名" },
],
recipientPhone: [
{ required: true, message: "请输入手机号码", trigger: "blur" },
{ required: true, message: "请输入手机号码" },
{
pattern: /^[\d\-+ ]{7,15}$/,
message: "请输入有效的手机号码",
trigger: "blur",
},
],
recipientAddress: [
{ required: true, message: "请输入详细收件地址", trigger: "blur" },
{ required: true, message: "请输入详细收件地址" },
],
};
const exchangeFormRef = ref();

@ -13,7 +13,7 @@
}}</el-button>
</div>
<div v-if="isCustom" class="custom-range">
<el-date-picker v-model="dateRange" type="daterange" range-separator="-"
<el-date-picker :shortcuts="dateRangeShortcuts" v-model="dateRange" type="daterange" range-separator="-"
:start-placeholder="$t('common.startDate')" :end-placeholder="$t('common.endDate')"
value-format="YYYY-MM-DD" style="width: 240px" />
<el-button type="primary" class="search-btn" plain @click="onSearch"></el-button>
@ -294,12 +294,34 @@ const chartOption = computed(() => {
height: 14,
startValue: sliderStartValue,
endValue: sliderEndValue,
zoomLock: true,
showDetail: false,
showDataShadow: false,
fillerColor: "rgba(50,137,251,0.12)",
borderColor: "transparent",
backgroundColor: "#F2F3F5",
moveHandleSize: 0,
zoomLock: true,
brushSelect: false,
fillerColor: "#3289fb66", // 0.12
// 14
handleSize: 14,
handleIcon: 'path://M2,2 L22,2 L22,22 L2,22 Z M9,5 L9,19 M12,5 L12,19 M15,5 L15,19',
// +
handleStyle: {
color: '#3289fb',
// borderRadius: 2, // 0 2
// borderWidth: 7,
shadowBlur: 0,
cursor: 'pointer',
},
//
emphasis: {
handleStyle: {
cursor: 'pointer',
}
},
},
]
: [],

@ -97,14 +97,12 @@ const rules = {
{
required: true,
message: () => t("login.pleaseEnterUserName"),
trigger: "blur",
},
],
password: [
{
required: true,
message: () => t("login.pleaseEnterPassWord"),
trigger: "blur",
},
],
};

Loading…
Cancel
Save