feat: add employee management, backend health check, and UI improvements
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<section class="workbench">
|
||||
<PanelHead
|
||||
v-if="showHeader"
|
||||
@@ -9,9 +9,8 @@
|
||||
|
||||
<article class="panel assistant-hero">
|
||||
<div class="assistant-visual" aria-hidden="true">
|
||||
<div class="assistant-core">
|
||||
<img class="assistant-image" :src="robotAssistant" alt="" />
|
||||
</div>
|
||||
<span class="assistant-glow"></span>
|
||||
<img class="assistant-image" :src="robotAssistant" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="assistant-copy">
|
||||
@@ -26,7 +25,6 @@
|
||||
placeholder="例如:我昨天请客户吃饭花了 860 元,还打车去了客户公司"
|
||||
@keydown.ctrl.enter.prevent="openAssistantWithDraft"
|
||||
/>
|
||||
<button type="button" class="hero-action" @click="openAssistantWithDraft">开始识别</button>
|
||||
</div>
|
||||
|
||||
<div class="assistant-tools">
|
||||
@@ -34,10 +32,10 @@
|
||||
<i class="mdi mdi-upload-outline"></i>
|
||||
<span>上传票据</span>
|
||||
</button>
|
||||
|
||||
<div class="assistant-skills">
|
||||
<span v-for="item in assistantSkills" :key="item">{{ item }}</span>
|
||||
</div>
|
||||
<button type="button" class="hero-action" @click="openAssistantWithDraft">
|
||||
<i class="mdi mdi-magnify-scan"></i>
|
||||
<span>开始识别</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
@@ -124,7 +122,7 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import PanelHead from '../shared/PanelHead.vue'
|
||||
import robotAssistant from '../../assets/robot-assistant.png'
|
||||
import robotAssistant from '../../assets/robot-helper.png'
|
||||
|
||||
defineProps({
|
||||
showHeader: { type: Boolean, default: true }
|
||||
@@ -140,8 +138,6 @@ function openAssistantWithDraft() {
|
||||
})
|
||||
}
|
||||
|
||||
const assistantSkills = ['识别报销类别', '检查缺少材料', '生成报销草稿']
|
||||
|
||||
const todoItems = [
|
||||
{
|
||||
title: '业务招待报销建议补参与人员',
|
||||
@@ -240,9 +236,9 @@ const policyItems = [
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: 164px minmax(0, 1fr);
|
||||
gap: 24px;
|
||||
padding: 24px 26px;
|
||||
grid-template-columns: 228px minmax(0, 1fr);
|
||||
gap: 18px;
|
||||
padding: 20px 24px 20px 18px;
|
||||
border: 1px solid rgba(16, 185, 129, 0.12);
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(16, 185, 129, 0.12), transparent 34%),
|
||||
@@ -275,62 +271,65 @@ const policyItems = [
|
||||
|
||||
.assistant-visual {
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 196px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
padding: 0 0 10px 8px;
|
||||
}
|
||||
|
||||
.assistant-core {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 132px;
|
||||
height: 132px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 36px;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #ecfdf5 100%);
|
||||
box-shadow:
|
||||
0 20px 44px rgba(15, 23, 42, 0.08),
|
||||
inset 0 -10px 18px rgba(16, 185, 129, 0.10);
|
||||
color: #0f9f78;
|
||||
}
|
||||
|
||||
.assistant-core::before,
|
||||
.assistant-core::after {
|
||||
.assistant-visual::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: #d1fae5;
|
||||
inset: auto auto -78px -58px;
|
||||
width: 264px;
|
||||
height: 228px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 48% 38%, rgba(255, 255, 255, 0.92) 0%, rgba(220, 252, 231, 0.84) 58%, rgba(220, 252, 231, 0) 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.assistant-core::before {
|
||||
top: -12px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
.assistant-visual::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 52px;
|
||||
bottom: 18px;
|
||||
width: 132px;
|
||||
height: 18px;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 0 0 6px rgba(16, 185, 129, 0.10);
|
||||
background: rgba(16, 185, 129, 0.14);
|
||||
filter: blur(12px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.assistant-core::after {
|
||||
top: -4px;
|
||||
width: 2px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.assistant-core .mdi {
|
||||
font-size: 68px;
|
||||
.assistant-glow {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
bottom: 22px;
|
||||
width: 176px;
|
||||
height: 176px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(255, 255, 255, 0.98) 0%, rgba(236, 253, 245, 0.9) 58%, rgba(236, 253, 245, 0) 100%);
|
||||
box-shadow: 0 24px 48px rgba(16, 185, 129, 0.12);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.assistant-image {
|
||||
width: 104px;
|
||||
height: 104px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 184px;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 12px 20px rgba(15, 23, 42, 0.12));
|
||||
object-position: left bottom;
|
||||
filter: drop-shadow(0 22px 28px rgba(15, 23, 42, 0.16));
|
||||
}
|
||||
|
||||
.assistant-copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
gap: 10px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
@@ -340,15 +339,16 @@ const policyItems = [
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(16, 185, 129, 0.10);
|
||||
color: #0f9f78;
|
||||
background: linear-gradient(135deg, rgba(16, 185, 129, 0.14), rgba(59, 130, 246, 0.12));
|
||||
color: #0f766e;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.assistant-copy h3 {
|
||||
color: #0f172a;
|
||||
font-size: 28px;
|
||||
font-size: 26px;
|
||||
line-height: 1.25;
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -356,16 +356,15 @@ const policyItems = [
|
||||
.assistant-copy p {
|
||||
max-width: 760px;
|
||||
color: #5b6b83;
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.assistant-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
min-height: 52px;
|
||||
padding: 6px 8px 6px 14px;
|
||||
min-height: 48px;
|
||||
padding: 4px 14px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.28);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
@@ -375,9 +374,9 @@ const policyItems = [
|
||||
.assistant-input textarea {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
height: 24px;
|
||||
min-height: 24px;
|
||||
max-height: 24px;
|
||||
height: 22px;
|
||||
min-height: 22px;
|
||||
max-height: 22px;
|
||||
resize: none;
|
||||
border: 0;
|
||||
padding: 1px 0;
|
||||
@@ -406,8 +405,12 @@ const policyItems = [
|
||||
}
|
||||
|
||||
.hero-action {
|
||||
height: 36px;
|
||||
padding: 0 20px;
|
||||
height: 40px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 16px;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: #fff;
|
||||
@@ -417,10 +420,26 @@ const policyItems = [
|
||||
box-shadow: 0 10px 22px rgba(16, 185, 129, 0.18);
|
||||
}
|
||||
|
||||
.hero-action .mdi,
|
||||
.ghost-action .mdi {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.hero-action span,
|
||||
.ghost-action span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.assistant-tools {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -428,39 +447,22 @@ const policyItems = [
|
||||
height: 40px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid rgba(16, 185, 129, 0.34);
|
||||
border: 1px solid rgba(15, 118, 110, 0.18);
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
color: #0f9f78;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(244, 250, 247, 0.88));
|
||||
color: #0f766e;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
||||
0 6px 14px rgba(15, 118, 110, 0.06);
|
||||
}
|
||||
|
||||
.assistant-skills {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
color: #22a06b;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.assistant-skills span {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.assistant-skills span + span::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -7px;
|
||||
top: 50%;
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
background: rgba(16, 185, 129, 0.22);
|
||||
transform: translateY(-50%);
|
||||
.ghost-action .mdi {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.workbench-grid {
|
||||
@@ -723,10 +725,28 @@ const policyItems = [
|
||||
@media (max-width: 1080px) {
|
||||
.assistant-hero {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.assistant-visual {
|
||||
justify-content: flex-start;
|
||||
min-height: 188px;
|
||||
justify-content: center;
|
||||
padding: 0 0 8px;
|
||||
}
|
||||
|
||||
.assistant-visual::before,
|
||||
.assistant-visual::after,
|
||||
.assistant-glow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.assistant-visual::before {
|
||||
inset: auto auto -82px 50%;
|
||||
}
|
||||
|
||||
.assistant-image {
|
||||
width: 176px;
|
||||
}
|
||||
|
||||
.workbench-grid {
|
||||
@@ -747,6 +767,19 @@ const policyItems = [
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.assistant-visual {
|
||||
min-height: 160px;
|
||||
}
|
||||
|
||||
.assistant-glow {
|
||||
width: 148px;
|
||||
height: 148px;
|
||||
}
|
||||
|
||||
.assistant-image {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.assistant-input textarea {
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
@@ -800,3 +833,5 @@ const policyItems = [
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -28,14 +28,23 @@
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<button class="rail-user" type="button" aria-label="打开用户菜单">
|
||||
<span class="user-avatar">张</span>
|
||||
<span class="user-copy">
|
||||
<strong>张晓明</strong>
|
||||
<span>财务管理员</span>
|
||||
</span>
|
||||
<i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div class="rail-user">
|
||||
<div class="user-menu" role="menu" aria-label="用户菜单">
|
||||
<button class="user-menu-item" type="button" @click="emit('logout')">
|
||||
<i class="mdi mdi-logout-variant"></i>
|
||||
<span>退出系统</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="user-summary" tabindex="0" aria-label="用户信息">
|
||||
<span class="user-avatar">{{ displayUser.avatar }}</span>
|
||||
<span class="user-copy">
|
||||
<strong>{{ displayUser.name }}</strong>
|
||||
<span>{{ displayUser.role }}</span>
|
||||
</span>
|
||||
<i class="mdi mdi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
@@ -44,17 +53,25 @@ import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
navItems: { type: Array, required: true },
|
||||
activeView: { type: String, required: true }
|
||||
activeView: { type: String, required: true },
|
||||
currentUser: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
name: '系统管理员',
|
||||
role: '财务管理员',
|
||||
avatar: '管'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['navigate', 'openChat'])
|
||||
const emit = defineEmits(['navigate', 'openChat', 'logout'])
|
||||
|
||||
const sidebarMeta = {
|
||||
overview: { label: '总览' },
|
||||
workbench: { label: '个人工作台' },
|
||||
requests: { label: '差旅申请/报销' },
|
||||
approval: { label: '审批中心', badge: '12' },
|
||||
chat: { label: 'AI助手' },
|
||||
chat: { label: 'AI 助手' },
|
||||
policies: { label: '知识管理' },
|
||||
audit: { label: '技能中心' },
|
||||
employees: { label: '员工管理' }
|
||||
@@ -67,6 +84,12 @@ const decoratedNavItems = computed(() =>
|
||||
badge: sidebarMeta[item.id]?.badge
|
||||
}))
|
||||
)
|
||||
|
||||
const displayUser = computed(() => ({
|
||||
name: props.currentUser?.name || '系统管理员',
|
||||
role: props.currentUser?.role || '财务管理员',
|
||||
avatar: props.currentUser?.avatar || '管'
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -77,10 +100,10 @@ const decoratedNavItems = computed(() =>
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,.98), rgba(248,251,250,.96)),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 251, 250, 0.96)),
|
||||
#fff;
|
||||
border-right: 1px solid #dbe4ee;
|
||||
box-shadow: 1px 0 0 rgba(15,23,42,.02);
|
||||
box-shadow: 1px 0 0 rgba(15, 23, 42, 0.02);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
@@ -164,13 +187,13 @@ const decoratedNavItems = computed(() =>
|
||||
}
|
||||
|
||||
.nav-btn:hover {
|
||||
background: rgba(16,185,129,.07);
|
||||
background: rgba(16, 185, 129, 0.07);
|
||||
color: #0f9f78;
|
||||
}
|
||||
|
||||
.nav-btn.active {
|
||||
background: linear-gradient(90deg, rgba(16,185,129,.16), rgba(16,185,129,.08));
|
||||
border-color: rgba(16,185,129,.10);
|
||||
background: linear-gradient(90deg, rgba(16, 185, 129, 0.16), rgba(16, 185, 129, 0.08));
|
||||
border-color: rgba(16, 185, 129, 0.1);
|
||||
color: #059669;
|
||||
box-shadow: inset 3px 0 0 #10b981;
|
||||
}
|
||||
@@ -221,25 +244,31 @@ const decoratedNavItems = computed(() =>
|
||||
}
|
||||
|
||||
.rail-user {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
min-height: 74px;
|
||||
display: grid;
|
||||
grid-template-columns: 38px minmax(0, 1fr) 22px;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 78px;
|
||||
margin: 0;
|
||||
padding: 16px 20px 18px;
|
||||
border: 0;
|
||||
border-top: 1px solid transparent;
|
||||
background: transparent;
|
||||
color: #64748b;
|
||||
text-align: left;
|
||||
transition: background 180ms var(--ease), border-color 180ms var(--ease);
|
||||
border-top: 1px solid #edf2f7;
|
||||
}
|
||||
|
||||
.rail-user:hover {
|
||||
border-top-color: #e2e8f0;
|
||||
background: rgba(255,255,255,.72);
|
||||
.user-summary {
|
||||
min-width: 0;
|
||||
min-height: 42px;
|
||||
display: grid;
|
||||
grid-template-columns: 38px minmax(0, 1fr) 18px;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 4px 0 0;
|
||||
color: #64748b;
|
||||
border-radius: 12px;
|
||||
outline: none;
|
||||
transition: background 180ms var(--ease);
|
||||
}
|
||||
|
||||
.rail-user:hover .user-summary,
|
||||
.rail-user:focus-within .user-summary {
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
@@ -250,7 +279,7 @@ const decoratedNavItems = computed(() =>
|
||||
border: 2px solid #fff;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(135deg, #0f9f78, #65d6b4);
|
||||
box-shadow: 0 6px 14px rgba(15,159,120,.18);
|
||||
box-shadow: 0 6px 14px rgba(15, 159, 120, 0.18);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
@@ -281,10 +310,88 @@ const decoratedNavItems = computed(() =>
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.rail-user .mdi {
|
||||
.user-summary .mdi {
|
||||
justify-self: end;
|
||||
color: #718096;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
transition: transform 180ms var(--ease), color 180ms var(--ease);
|
||||
}
|
||||
|
||||
.rail-user:hover .user-summary .mdi,
|
||||
.rail-user:focus-within .user-summary .mdi {
|
||||
color: #0f9f78;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: calc(100% - 6px);
|
||||
min-width: 132px;
|
||||
padding: 8px;
|
||||
border: 1px solid rgba(226, 232, 240, 0.96);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
box-shadow:
|
||||
0 16px 32px rgba(15, 23, 42, 0.10),
|
||||
0 2px 8px rgba(15, 23, 42, 0.04);
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
pointer-events: none;
|
||||
transition:
|
||||
opacity 180ms var(--ease),
|
||||
transform 180ms var(--ease),
|
||||
box-shadow 180ms var(--ease);
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.user-menu::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
bottom: -6px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-right: 1px solid rgba(226, 232, 240, 0.96);
|
||||
border-bottom: 1px solid rgba(226, 232, 240, 0.96);
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.rail-user:hover .user-menu,
|
||||
.rail-user:focus-within .user-menu {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.user-menu-item {
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
padding: 0 12px;
|
||||
border: 0;
|
||||
border-radius: 9px;
|
||||
background: transparent;
|
||||
color: #dc2626;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
transition: background 180ms var(--ease), color 180ms var(--ease);
|
||||
}
|
||||
|
||||
.user-menu-item:hover {
|
||||
background: #fff5f5;
|
||||
color: #b91c1c;
|
||||
}
|
||||
|
||||
.user-menu-item .mdi {
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
|
||||
@@ -117,6 +117,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="isEmployees">
|
||||
<div class="kpi-chips">
|
||||
<div v-for="kpi in employeeKpis" :key="kpi.label" class="kpi-chip" :style="{ '--chip-color': kpi.color }">
|
||||
<span class="chip-value">{{ kpi.value }}<small>{{ kpi.unit }}</small></span>
|
||||
<span class="chip-label">{{ kpi.label }}</span>
|
||||
<span class="chip-delta" :class="kpi.trend">{{ kpi.meta }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
@@ -130,6 +140,10 @@ const props = defineProps({
|
||||
activeView: { type: String, default: '' },
|
||||
ranges: { type: Array, default: () => [] },
|
||||
activeRange: { type: String, default: '' },
|
||||
employeeSummary: {
|
||||
type: Object,
|
||||
default: () => null
|
||||
},
|
||||
customRange: {
|
||||
type: Object,
|
||||
default: () => ({ start: '2024-07-06', end: '2024-07-12' })
|
||||
@@ -150,6 +164,7 @@ const isOverview = computed(() => props.activeView === 'overview')
|
||||
const isRequests = computed(() => props.activeView === 'requests')
|
||||
const isApproval = computed(() => props.activeView === 'approval')
|
||||
const isPolicies = computed(() => props.activeView === 'policies')
|
||||
const isEmployees = computed(() => props.activeView === 'employees')
|
||||
|
||||
const requestKpis = [
|
||||
{ label: '全部单据', value: 30, delta: '+8', trend: 'up', arrow: 'mdi mdi-arrow-up', color: '#10b981' },
|
||||
@@ -178,6 +193,51 @@ const knowledgeKpis = [
|
||||
{ label: '问答总量', value: '8,562', meta: '较上周 +321', trend: 'up', icon: 'mdi mdi-comment-text-multiple-outline', color: '#8b5cf6' },
|
||||
{ label: '知识命中率', value: '87.3%', meta: '较上周 +1.2%', trend: 'up', icon: 'mdi mdi-bullseye-arrow', color: '#f59e0b' }
|
||||
]
|
||||
|
||||
const employeeKpis = computed(() => {
|
||||
const summary = props.employeeSummary ?? {}
|
||||
const total = Number(summary.total ?? 0)
|
||||
const active = Number(summary.active ?? 0)
|
||||
const onboarding = Number(summary.onboarding ?? 0)
|
||||
const disabled = Number(summary.disabled ?? 0)
|
||||
const followUp = Number(summary.followUp ?? 0)
|
||||
const departments = Number(summary.departments ?? 0)
|
||||
|
||||
return [
|
||||
{
|
||||
label: '员工总数',
|
||||
value: total,
|
||||
unit: '人',
|
||||
meta: `覆盖 ${departments} 个部门`,
|
||||
trend: 'up',
|
||||
color: '#10b981'
|
||||
},
|
||||
{
|
||||
label: '在职账号',
|
||||
value: active,
|
||||
unit: '人',
|
||||
meta: total ? `占比 ${Math.round((active / total) * 100)}%` : '等待数据',
|
||||
trend: 'up',
|
||||
color: '#3b82f6'
|
||||
},
|
||||
{
|
||||
label: '待处理状态',
|
||||
value: onboarding + disabled,
|
||||
unit: '人',
|
||||
meta: `试用 ${onboarding} / 停用 ${disabled}`,
|
||||
trend: onboarding + disabled > 0 ? 'down' : 'up',
|
||||
color: '#f59e0b'
|
||||
},
|
||||
{
|
||||
label: '同步待处理',
|
||||
value: followUp,
|
||||
unit: '人',
|
||||
meta: followUp > 0 ? '存在待同步账号' : '资料已同步',
|
||||
trend: followUp > 0 ? 'down' : 'up',
|
||||
color: '#8b5cf6'
|
||||
}
|
||||
]
|
||||
})
|
||||
const calendarOpen = ref(false)
|
||||
const draftStart = ref(props.customRange.start)
|
||||
const draftEnd = ref(props.customRange.end)
|
||||
|
||||
Reference in New Issue
Block a user