Files
workspace/code/fms/fms-vue/src/views/DashboardView.vue
T
2026-07-15 22:12:23 +08:00

219 lines
4.6 KiB
Vue

<script setup>
import {
CheckCircleOutlined,
ClockCircleOutlined,
DollarOutlined,
FileTextOutlined,
PlusOutlined,
} from "@antdv-next/icons";
const metrics = [
{ label: "今日新增", value: "0", tone: "blue", icon: FileTextOutlined },
{ label: "待处理", value: "0", tone: "amber", icon: ClockCircleOutlined },
{ label: "本月应收", value: "¥ 0.00", tone: "green", icon: DollarOutlined },
{ label: "本月完成", value: "0", tone: "gray", icon: CheckCircleOutlined },
];
const columns = [
{ title: "单据编号", dataIndex: "id", key: "id" },
{ title: "客户名称", dataIndex: "customer", key: "customer" },
{ title: "业务状态", dataIndex: "status", key: "status" },
{ title: "更新时间", dataIndex: "updatedAt", key: "updatedAt" },
];
</script>
<template>
<div class="dashboard">
<section class="metric-grid" aria-label="业务概览">
<article v-for="item in metrics" :key="item.label" class="metric-card">
<div class="metric-card__copy">
<span>{{ item.label }}</span>
<strong>{{ item.value }}</strong>
</div>
<div class="metric-card__icon" :class="`metric-card__icon--${item.tone}`">
<component :is="item.icon" />
</div>
</article>
</section>
<section class="dashboard-grid">
<div class="panel work-panel">
<div class="panel__header">
<div>
<h2>待办业务</h2>
<span>最近更新</span>
</div>
<a-button type="primary">
<template #icon><PlusOutlined /></template>
新建业务
</a-button>
</div>
<a-table
:columns="columns"
:data-source="[]"
:pagination="false"
size="middle"
:scroll="{ x: 620 }"
/>
</div>
<div class="panel quick-panel">
<div class="panel__header">
<div>
<h2>快捷入口</h2>
<span>常用操作</span>
</div>
</div>
<nav class="quick-links">
<router-link to="/business/orders">
<FileTextOutlined />
<span>业务单据</span>
</router-link>
<router-link to="/fees/receivable">
<DollarOutlined />
<span>应收费用</span>
</router-link>
<router-link to="/reports/operations">
<CheckCircleOutlined />
<span>运营报表</span>
</router-link>
</nav>
</div>
</section>
</div>
</template>
<style lang="scss" scoped>
.dashboard {
display: grid;
gap: 8px;
}
.metric-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
}
.metric-card {
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
border: 1px solid var(--fms-border);
border-radius: 4px;
background: var(--fms-surface);
&__copy {
display: flex;
min-width: 0;
flex-direction: column;
span {
color: var(--fms-text-secondary);
font-size: 12px;
}
strong {
margin-top: 4px;
overflow: hidden;
color: var(--fms-text);
font-size: 19px;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
}
&__icon {
display: grid;
flex: none;
width: 34px;
height: 34px;
place-items: center;
border-radius: 4px;
font-size: 17px;
&--blue {
background: #e6f4ff;
color: #1677ff;
}
&--amber {
background: #fff7e6;
color: #d46b08;
}
&--green {
background: #f0f9eb;
color: #389e0d;
}
&--gray {
background: #f2f3f5;
color: #4e5969;
}
}
}
.dashboard-grid {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr);
gap: 8px;
}
.panel {
min-width: 0;
border: 1px solid var(--fms-border);
border-radius: 4px;
background: var(--fms-surface);
&__header {
display: flex;
min-height: 46px;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 7px 10px;
border-bottom: 1px solid var(--fms-border);
h2 {
margin: 0;
color: var(--fms-text);
font-size: 13px;
}
span {
color: var(--fms-text-secondary);
font-size: 11px;
}
}
}
.work-panel :deep(.ant-table-wrapper) {
padding: 0 2px 2px;
}
.quick-links {
display: grid;
padding: 4px;
a {
display: flex;
min-height: 36px;
align-items: center;
gap: 8px;
padding: 5px 7px;
border-radius: 3px;
color: var(--fms-text);
font-size: 12px;
&:hover {
background: var(--fms-hover);
color: #1677ff;
}
}
}
</style>