fix: align dashboard lead presentation
This commit is contained in:
18
WonderQ-Admin-UI-Vue/src/pages/DashboardPage.test.ts
Normal file
18
WonderQ-Admin-UI-Vue/src/pages/DashboardPage.test.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { readFile } from "node:fs/promises";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("DashboardPage lead presentation", () => {
|
||||||
|
it("uses the same labels and date formatting as the leads page", async () => {
|
||||||
|
const source = await readFile(
|
||||||
|
fileURLToPath(new URL("./DashboardPage.vue", import.meta.url)),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(source).toContain('import { leadStatusLabel } from "@/lib/leads";');
|
||||||
|
expect(source).toContain('const formatDate = (value?: string | null) =>');
|
||||||
|
expect(source).toContain('row.contactName || "未填写联系人"');
|
||||||
|
expect(source).toContain("leadStatusLabel(row.status)");
|
||||||
|
expect(source).toContain("formatDate(row.createdAt)");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { getDashboard } from "@/api/client";
|
import { getDashboard } from "@/api/client";
|
||||||
|
import { leadStatusLabel } from "@/lib/leads";
|
||||||
import type { Dashboard } from "@/types";
|
import type { Dashboard } from "@/types";
|
||||||
|
|
||||||
const data = ref<Dashboard | null>(null);
|
const data = ref<Dashboard | null>(null);
|
||||||
@@ -11,19 +12,85 @@ const error = ref("");
|
|||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
error.value = "";
|
error.value = "";
|
||||||
try { data.value = await getDashboard(); } catch (err) { error.value = err instanceof Error ? err.message : "仪表盘加载失败"; ElMessage.error(error.value); } finally { loading.value = false; }
|
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);
|
onMounted(load);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page-stack">
|
<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>
|
<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" />
|
<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>
|
<div v-if="loading" class="loading-grid">
|
||||||
|
<el-skeleton v-for="item in 2" :key="item" animated />
|
||||||
|
</div>
|
||||||
<template v-else-if="data">
|
<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>
|
<div class="metric-grid">
|
||||||
<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 prop="contactName" label="联系人" /><el-table-column prop="phone" label="联系方式" /><el-table-column prop="destination" label="目的地" /><el-table-column prop="status" label="状态" /><el-table-column prop="createdAt" label="提交时间" /></el-table></el-card>
|
<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>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user