Files
FastapiAdmin/frontend/web/src/views/dashboard/screen/modules/RealtimeSales.vue
T
zhangtao 0ce31936aa chore: 清理冗余代码与配置,优化项目结构
1.  删除无用文件与废弃代码:移除locale枚举、element-plus插件、sse路由、api token模块等
2.  简化类型导入与依赖:移除大量未使用的类型导入,统一echarts导入方式
3.  优化配置与样式:调整gitignore、样式引入顺序,新增列表动画样式
4.  修复接口与模型:修正接口返回类型、查询参数配置,更新部门模型字段
5.  优化性能与体验:添加图片懒加载,优化加载逻辑与表格渲染
6.  调整环境配置:新增并更新开发/生产环境配置文件
2026-07-23 20:49:52 +08:00

128 lines
3.0 KiB
Vue

<template>
<div class="panel p1">
<div class="panel-hd"><span class="dot accent" />实时销售分时</div>
<div ref="chartRef" class="chart-box" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import { echarts } from "@/plugins/echarts";
defineOptions({ name: "RealtimeSales" });
const chartRef = ref<HTMLDivElement>();
let chart: echarts.ECharts | null = null;
let timer = 0;
const textStyle = { color: "#94a3b8" };
const hours = [
"08:00",
"09:00",
"10:00",
"11:00",
"12:00",
"13:00",
"14:00",
"15:00",
"16:00",
"17:00",
"18:00",
"19:00",
"20:00",
];
function initChart(dom: HTMLDivElement) {
chart = echarts.init(dom);
chart.setOption({
grid: { top: 20, right: 30, bottom: 30, left: 55 },
xAxis: {
type: "category",
data: hours,
axisLine: { lineStyle: { color: "#1a2050" } },
axisLabel: { ...textStyle, rotate: 30 },
},
yAxis: {
type: "value",
name: "万元",
nameTextStyle: { color: "#94a3b8", fontSize: 11 },
splitLine: { lineStyle: { color: "#1a2050", type: "dashed" } },
axisLabel: textStyle,
},
tooltip: {
trigger: "axis" as const,
backgroundColor: "#0f143c",
borderColor: "#1a2050",
textStyle: { color: "#e0e6ff" },
},
legend: { textStyle, top: 0 },
series: [
{
name: "销售额",
type: "bar",
barWidth: "60%",
itemStyle: {
borderRadius: [4, 4, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#00d4ff" },
{ offset: 1, color: "rgba(0,212,255,0.25)" },
]),
},
data: [2.1, 3.5, 4.2, 5.8, 3.2, 2.8, 4.5, 5.1, 6.3, 8.2, 4.8, 3.2, 2.5],
},
{
name: "订单数",
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 5,
lineStyle: { color: "#f59e0b", width: 2 },
itemStyle: { color: "#f59e0b" },
data: [18, 32, 45, 52, 35, 28, 42, 48, 55, 72, 48, 35, 22],
},
],
});
}
function handleResize() {
if (chart && !chart.isDisposed()) chart.resize();
}
function tick() {
if (!chart || chart.isDisposed()) return;
const sales = hours.map(() => +(1.5 + Math.random() * 7).toFixed(1));
const orders = hours.map(() => Math.round(15 + Math.random() * 60));
chart.setOption({ series: [{ data: sales }, { data: orders }] });
}
onMounted(() => {
const el = chartRef.value;
if (!el) return;
const observer = new ResizeObserver((entries) => {
const entry = entries[0];
if (entry && entry.contentRect.width > 0 && entry.contentRect.height > 0) {
observer.disconnect();
initChart(el);
timer = window.setInterval(tick, 3500);
}
});
observer.observe(el);
window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
clearInterval(timer);
window.removeEventListener("resize", handleResize);
chart?.dispose();
});
</script>
<style scoped>
.chart-box {
flex: 1;
width: 100%;
min-height: 0;
}
</style>