97 lines
3.1 KiB
Vue
97 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, ref } from "vue";
|
|
import { ElMessage } from "element-plus";
|
|
import { getDashboard } from "@/api/client";
|
|
import { leadStatusLabel } from "@/lib/leads";
|
|
import type { Dashboard } from "@/types";
|
|
|
|
const data = ref<Dashboard | null>(null);
|
|
const loading = ref(true);
|
|
const error = ref("");
|
|
|
|
async function load() {
|
|
loading.value = true;
|
|
error.value = "";
|
|
try {
|
|
data.value = await getDashboard();
|
|
} catch (err) {
|
|
error.value = err instanceof Error ? err.message : "仪表盘加载失败";
|
|
ElMessage.error(error.value);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
const formatDate = (value?: string | null) => {
|
|
if (!value) return "未填写";
|
|
const date = new Date(value);
|
|
return Number.isNaN(date.valueOf())
|
|
? value
|
|
: new Intl.DateTimeFormat("zh-CN", {
|
|
dateStyle: "medium",
|
|
timeStyle: "short",
|
|
}).format(date);
|
|
};
|
|
|
|
onMounted(load);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page-stack">
|
|
<div class="page-intro">
|
|
<div>
|
|
<p class="eyebrow">TODAY / SNAPSHOT</p>
|
|
<h2>运营概览</h2>
|
|
<p>快速查看当前内容和需求线索的状态。</p>
|
|
</div>
|
|
<el-button :loading="loading" @click="load">刷新数据</el-button>
|
|
</div>
|
|
<el-alert v-if="error" :title="error" type="error" show-icon :closable="false" />
|
|
<div v-if="loading" class="loading-grid">
|
|
<el-skeleton v-for="item in 2" :key="item" animated />
|
|
</div>
|
|
<template v-else-if="data">
|
|
<div class="metric-grid">
|
|
<el-card shadow="never" class="metric-card">
|
|
<span>待处理线索</span>
|
|
<strong>{{ data.stats.newLeadCount }}</strong>
|
|
<small>需要及时跟进</small>
|
|
</el-card>
|
|
<el-card shadow="never" class="metric-card accent">
|
|
<span>全部线索</span>
|
|
<strong>{{ data.stats.leadCount }}</strong>
|
|
<small>持续沉淀中的需求</small>
|
|
</el-card>
|
|
</div>
|
|
<el-card shadow="never" class="panel-card">
|
|
<template #header>
|
|
<div class="panel-heading">
|
|
<span>最近线索</span>
|
|
<el-tag type="info" effect="plain">最多 5 条</el-tag>
|
|
</div>
|
|
</template>
|
|
<el-empty v-if="!data.recentLeads.length" description="暂无线索" />
|
|
<el-table v-else :data="data.recentLeads" stripe>
|
|
<el-table-column label="联系人">
|
|
<template #default="{ row }">
|
|
{{ row.contactName || "未填写联系人" }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="phone" label="联系方式" />
|
|
<el-table-column prop="destination" label="目的地" />
|
|
<el-table-column label="状态">
|
|
<template #default="{ row }">
|
|
{{ leadStatusLabel(row.status) }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="提交时间">
|
|
<template #default="{ row }">
|
|
{{ formatDate(row.createdAt) }}
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
</template>
|
|
</div>
|
|
</template>
|