|
|
@@ -0,0 +1,521 @@
|
|
|
+<template>
|
|
|
+ <div class="ehr-page">
|
|
|
+ <Header />
|
|
|
+ <section class="hero">
|
|
|
+ <div class="hero-inner">
|
|
|
+ <h1 class="hero-title">下午好,晓华</h1>
|
|
|
+ <p class="hero-desc">
|
|
|
+ 今天是 {{ new Date().toLocaleDateString() }}。您有 5 条流程待处理。
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="hero-accent" aria-hidden="true"></div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <!-- 任务统计 -->
|
|
|
+ <section class="total">
|
|
|
+ <div class="total-card" v-for="(item, index) in stats" :key="index">
|
|
|
+ <div class="card-icon" :style="{ backgroundColor: item.bgcolor }">
|
|
|
+ <Icon :icon="item.icon" />
|
|
|
+ </div>
|
|
|
+ <div class="card-content">
|
|
|
+ <p class="card-title">{{ item.title }}</p>
|
|
|
+ <p class="card-number">{{ item.number }}</p>
|
|
|
+ </div>
|
|
|
+ <div v-if="item.extra" class="card-extra">
|
|
|
+ {{ item.extra }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <div class="content">
|
|
|
+ <div class="tabs" role="tablist" aria-label="EHR模块">
|
|
|
+ <button
|
|
|
+ class="tab"
|
|
|
+ type="button"
|
|
|
+ role="tab"
|
|
|
+ :class="{ active: activeKey === 'all' }"
|
|
|
+ :aria-selected="activeKey === 'all'"
|
|
|
+ @click="setAll"
|
|
|
+ >
|
|
|
+ 全部
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ v-for="tab in tabs"
|
|
|
+ :key="tab.groupName"
|
|
|
+ class="tab"
|
|
|
+ :class="{ active: tab.groupName === activeKey }"
|
|
|
+ type="button"
|
|
|
+ role="tab"
|
|
|
+ :aria-selected="tab.groupName === activeKey"
|
|
|
+ @click="getById(tab)"
|
|
|
+ >
|
|
|
+ <span class="tab-title">{{ tab.groupName }}</span>
|
|
|
+ <span class="tab-sub">{{ tab.remark }}</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="panel" role="tabpanel">
|
|
|
+ <div class="panel-head">
|
|
|
+ <div>
|
|
|
+ <p class="panel-title">{{ activeTab.groupName }}</p>
|
|
|
+ <p class="panel-subtitle">{{ activeTab.remark }}</p>
|
|
|
+ </div>
|
|
|
+ <div class="panel-meta">
|
|
|
+ <span class="panel-count"
|
|
|
+ >{{ activeTab.flowRespVOS.length }} 项</span
|
|
|
+ >
|
|
|
+ <span class="panel-note">流程与表单</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="items-grid">
|
|
|
+ <div
|
|
|
+ v-for="item in activeTab.flowRespVOS"
|
|
|
+ :key="item.id"
|
|
|
+ class="item-card"
|
|
|
+ @click="go(item)"
|
|
|
+ >
|
|
|
+ <div class="item-top">
|
|
|
+ <div class="item-icon">
|
|
|
+ <Icon :icon="item.icon || 'mdi:file-document-outline'" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="item-body">
|
|
|
+ <p class="item-name">{{ item.flowName }}</p>
|
|
|
+ <p class="item-desc">{{ item.remark || "暂无描述" }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 修复宽度:自适应包裹按钮 -->
|
|
|
+
|
|
|
+ <Footer />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import Header from "@components/home/header.vue";
|
|
|
+import Footer from "@components/home/Footer.vue";
|
|
|
+import { computed, ref, onMounted } from "vue";
|
|
|
+import { Icon } from "@iconify/vue";
|
|
|
+import { getFlows } from "@/api/user";
|
|
|
+
|
|
|
+const tabs = ref([]);
|
|
|
+
|
|
|
+const activeKey = ref("all");
|
|
|
+
|
|
|
+const allTab = computed(() => {
|
|
|
+ const flowRespVOS = tabs.value.flatMap((tab) => tab.flowRespVOS || []);
|
|
|
+ return {
|
|
|
+ groupName: "全部",
|
|
|
+ remark: "全部流程",
|
|
|
+ flowRespVOS,
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+const activeTab = computed(() => {
|
|
|
+ if (activeKey.value === "all") {
|
|
|
+ return allTab.value;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ tabs.value.find((tab) => tab.groupName === activeKey.value) || allTab.value
|
|
|
+ );
|
|
|
+});
|
|
|
+
|
|
|
+const stats = [
|
|
|
+ {
|
|
|
+ icon: "mdi:clock-outline",
|
|
|
+ title: "我的待办",
|
|
|
+ number: "05",
|
|
|
+ extra: "+2 今日",
|
|
|
+ bgcolor: "#fff7ed",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: "mdi:check-circle-outline",
|
|
|
+ title: "已办事项",
|
|
|
+ number: "128",
|
|
|
+ bgcolor: "#eff6ff",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: "mdi:arrow-right-bold-box-outline",
|
|
|
+ title: "发起流程",
|
|
|
+ number: "42",
|
|
|
+ extra: "85% 准时",
|
|
|
+ bgcolor: "#eff6ff",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: "mdi:file-document-outline",
|
|
|
+ title: "草箱箱",
|
|
|
+ number: "03",
|
|
|
+ bgcolor: "#fef3c7",
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const getAll = async () => {
|
|
|
+ const res = await getFlows({
|
|
|
+ pageNo: 1,
|
|
|
+ pageSize: 99,
|
|
|
+ });
|
|
|
+
|
|
|
+ tabs.value = res;
|
|
|
+};
|
|
|
+
|
|
|
+const setAll = () => {
|
|
|
+ activeKey.value = "all";
|
|
|
+};
|
|
|
+
|
|
|
+const getById = (tab) => {
|
|
|
+ activeKey.value = tab.groupName;
|
|
|
+};
|
|
|
+
|
|
|
+const go = (item) => {
|
|
|
+ console.log("跳转", item);
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ getAll();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+:global(body) {
|
|
|
+ background-color: #f4f4f2;
|
|
|
+}
|
|
|
+
|
|
|
+/* .ehr-page {
|
|
|
+ color: #1f2a37;
|
|
|
+ background: linear-gradient(180deg, #f4f4f2 0%, #f7f6f3 50%, #f2f1ef 100%);
|
|
|
+ min-height: 100vh;
|
|
|
+} */
|
|
|
+
|
|
|
+.hero {
|
|
|
+ position: relative;
|
|
|
+ padding: 72px 6vw 48px;
|
|
|
+ overflow: hidden;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.hero-inner {
|
|
|
+ max-width: 920px;
|
|
|
+}
|
|
|
+
|
|
|
+.hero-title {
|
|
|
+ font-size: clamp(18px, 2vw, 22px);
|
|
|
+ line-height: 1.2;
|
|
|
+ margin: 16px 0 12px;
|
|
|
+ color: #111827;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.hero-desc {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #4b5563;
|
|
|
+ max-width: 720px;
|
|
|
+ line-height: 1.8;
|
|
|
+}
|
|
|
+
|
|
|
+.hero-accent {
|
|
|
+ position: absolute;
|
|
|
+ top: -120px;
|
|
|
+ right: -140px;
|
|
|
+ width: 360px;
|
|
|
+ height: 360px;
|
|
|
+ background: radial-gradient(
|
|
|
+ circle at 30% 30%,
|
|
|
+ rgba(2, 64, 155, 0.25),
|
|
|
+ transparent 65%
|
|
|
+ );
|
|
|
+ border-radius: 50%;
|
|
|
+ opacity: 0.9;
|
|
|
+ pointer-events: none;
|
|
|
+}
|
|
|
+
|
|
|
+.content {
|
|
|
+ padding: 0 6vw 80px;
|
|
|
+ /* height: 80vh; */
|
|
|
+}
|
|
|
+
|
|
|
+.tabs {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
|
|
|
+ gap: 16px;
|
|
|
+ margin-bottom: 28px;
|
|
|
+}
|
|
|
+
|
|
|
+.tab {
|
|
|
+ padding: 18px 20px;
|
|
|
+ border-radius: 14px;
|
|
|
+ /* border: 1px solid #e5e7eb; */
|
|
|
+ background: #ffffff;
|
|
|
+ text-align: left;
|
|
|
+ transition: all 0.25s ease;
|
|
|
+ cursor: pointer;
|
|
|
+ box-shadow: 0 12px 24px rgba(15, 23, 42, 0.05);
|
|
|
+}
|
|
|
+
|
|
|
+.tab:hover {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ border-color: #02409b;
|
|
|
+}
|
|
|
+
|
|
|
+.tab.active {
|
|
|
+ background: linear-gradient(135deg, #02409b 0%, #0b2f6d 60%, #0b1f45 100%);
|
|
|
+ border-color: transparent;
|
|
|
+ color: #f9fafb;
|
|
|
+ box-shadow: 0 18px 36px rgba(2, 64, 155, 0.25);
|
|
|
+}
|
|
|
+
|
|
|
+.tab-title {
|
|
|
+ display: block;
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-sub {
|
|
|
+ display: block;
|
|
|
+ font-size: 12px;
|
|
|
+ color: inherit;
|
|
|
+ opacity: 0.75;
|
|
|
+}
|
|
|
+
|
|
|
+.panel {
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 24px;
|
|
|
+ padding: 28px 28px 32px;
|
|
|
+
|
|
|
+ box-shadow: 0 26px 48px rgba(15, 23, 42, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.panel-head {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 24px;
|
|
|
+
|
|
|
+ padding-bottom: 20px;
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-title {
|
|
|
+ font-size: 22px;
|
|
|
+ color: #111827;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-subtitle {
|
|
|
+ color: #6b7280;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-meta {
|
|
|
+ text-align: right;
|
|
|
+ color: #6b7280;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-count {
|
|
|
+ display: block;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #111827;
|
|
|
+}
|
|
|
+
|
|
|
+.items-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 18px;
|
|
|
+ padding: 22px 22px 18px;
|
|
|
+ border-radius: 22px;
|
|
|
+ background: #ffffff;
|
|
|
+ border: 1px solid #edf0f5;
|
|
|
+ box-shadow: 0 14px 30px rgba(15, 23, 42, 0.06);
|
|
|
+ transition:
|
|
|
+ transform 0.2s ease,
|
|
|
+ border-color 0.2s ease,
|
|
|
+ box-shadow 0.2s ease;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.item-card:hover {
|
|
|
+ transform: translateY(-3px);
|
|
|
+ border-color: rgba(2, 64, 155, 0.25);
|
|
|
+ box-shadow: 0 18px 36px rgba(15, 23, 42, 0.08);
|
|
|
+ color: #02409b !important;
|
|
|
+}
|
|
|
+
|
|
|
+.item-top {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+
|
|
|
+.item-body {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-icon {
|
|
|
+ width: 52px;
|
|
|
+ height: 52px;
|
|
|
+ border-radius: 16px;
|
|
|
+ background: #f5f7fb;
|
|
|
+ display: grid;
|
|
|
+ place-items: center;
|
|
|
+
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-icon :deep(svg) {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-role {
|
|
|
+ font-size: 12px;
|
|
|
+ letter-spacing: 0.2em;
|
|
|
+ color: #c7ced9;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.item-name {
|
|
|
+ font-size: 16px;
|
|
|
+
|
|
|
+ line-height: 1.45;
|
|
|
+ /* font-weight: 600; */
|
|
|
+}
|
|
|
+
|
|
|
+.item-desc {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #6b7280;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+.item-footer {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ color: #94a3b8;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-usage {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-flame {
|
|
|
+ width: 18px;
|
|
|
+ height: 18px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: grid;
|
|
|
+ place-items: center;
|
|
|
+ background: rgba(255, 108, 0, 0.12);
|
|
|
+ color: #ff6c00;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.item-arrow {
|
|
|
+ font-size: 22px;
|
|
|
+ color: #cbd5e1;
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 720px) {
|
|
|
+ .hero {
|
|
|
+ padding: 56px 7vw 36px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .panel-head {
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+ }
|
|
|
+
|
|
|
+ .panel-meta {
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.total {
|
|
|
+ display: flex;
|
|
|
+ gap: 16px;
|
|
|
+ padding: 0 6vw 80px;
|
|
|
+ /* margin-bottom: 24px; */
|
|
|
+}
|
|
|
+
|
|
|
+.total-card {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 16px;
|
|
|
+ padding: 20px;
|
|
|
+ box-shadow:
|
|
|
+ rgba(0, 0, 0, 0.05) 0px 1px 3px 0px,
|
|
|
+ rgba(0, 0, 0, 0) 0px 0px 0px 0px,
|
|
|
+ rgba(0, 0, 0, 0.05) 0px 1px 2px 0px,
|
|
|
+ rgba(0, 0, 0, 0.05) 0px 2px 4px -1px,
|
|
|
+ rgba(0, 0, 0, 0.05) 0px 4px 6px -2px;
|
|
|
+ transition:
|
|
|
+ transform 0.2s ease,
|
|
|
+ box-shadow 0.2s ease;
|
|
|
+ cursor: pointer;
|
|
|
+ /* border: 1px solid #e5e7eb; */
|
|
|
+ /* border-top: solid 5px #02409b; */
|
|
|
+}
|
|
|
+
|
|
|
+.total-card:hover {
|
|
|
+ transform: translateY(-4px);
|
|
|
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.card-icon {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 12px;
|
|
|
+ background: #f9f9f9;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.card-icon svg {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ color: var(--primary-color);
|
|
|
+}
|
|
|
+
|
|
|
+.card-content {
|
|
|
+ flex: 1;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.card-title {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #6b7280;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.card-number {
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #111827;
|
|
|
+}
|
|
|
+
|
|
|
+.card-extra {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #10b981;
|
|
|
+ margin-top: 8px;
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+</style>
|