变更数据中心静态页面完成
This commit is contained in:
@@ -248,7 +248,8 @@ const local: App.I18n.Schema = {
|
||||
home_pssr: 'PSSR监督',
|
||||
riskstatistics: '安全与风险统计',
|
||||
home_pendingchange: '待投用变更',
|
||||
home_effect: '变更投入和效果'
|
||||
home_effect: '变更投入和效果',
|
||||
home_datachangecenter: '变更数据中心'
|
||||
},
|
||||
form: {
|
||||
required: '不能为空',
|
||||
|
||||
@@ -23,6 +23,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
changestatistics: () => import("@/views/changeStatistics/index.vue"),
|
||||
docs_archives: () => import("@/views/docs/archives/index.vue"),
|
||||
docs_query: () => import("@/views/docs/query/index.vue"),
|
||||
home_datachangecenter: () => import("@/views/home/dataChangeCenter/index.vue"),
|
||||
home_effect: () => import("@/views/home/effect/index.vue"),
|
||||
home_highrisk: () => import("@/views/home/highRisk/index.vue"),
|
||||
home_highriskdetail: () => import("@/views/home/highRiskDetail/index.vue"),
|
||||
|
||||
@@ -127,6 +127,17 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
order: 1
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'home_datachangecenter',
|
||||
path: '/home/datachangecenter',
|
||||
component: 'view.home_datachangecenter',
|
||||
meta: {
|
||||
title: 'home_datachangecenter',
|
||||
i18nKey: 'route.home_datachangecenter',
|
||||
icon: '',
|
||||
order: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'home_effect',
|
||||
path: '/home/effect',
|
||||
|
||||
@@ -174,6 +174,7 @@ const routeMap: RouteMap = {
|
||||
"docs_archives": "/docs/archives",
|
||||
"docs_query": "/docs/query",
|
||||
"home": "/home",
|
||||
"home_datachangecenter": "/home/datachangecenter",
|
||||
"home_effect": "/home/effect",
|
||||
"home_highrisk": "/home/highrisk",
|
||||
"home_highriskdetail": "/home/highriskdetail",
|
||||
|
||||
Vendored
+2
@@ -56,6 +56,7 @@ declare module 'vue' {
|
||||
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||
NGi: typeof import('naive-ui')['NGi']
|
||||
NGrid: typeof import('naive-ui')['NGrid']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
@@ -141,6 +142,7 @@ declare global {
|
||||
const NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||
const NGi: typeof import('naive-ui')['NGi']
|
||||
const NGrid: typeof import('naive-ui')['NGrid']
|
||||
const NIcon: typeof import('naive-ui')['NIcon']
|
||||
const NInput: typeof import('naive-ui')['NInput']
|
||||
const NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||
const NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
|
||||
Vendored
+2
@@ -28,6 +28,7 @@ declare module "@elegant-router/types" {
|
||||
"docs_archives": "/docs/archives";
|
||||
"docs_query": "/docs/query";
|
||||
"home": "/home";
|
||||
"home_datachangecenter": "/home/datachangecenter";
|
||||
"home_effect": "/home/effect";
|
||||
"home_highrisk": "/home/highrisk";
|
||||
"home_highriskdetail": "/home/highriskdetail";
|
||||
@@ -111,6 +112,7 @@ declare module "@elegant-router/types" {
|
||||
| "changestatistics"
|
||||
| "docs_archives"
|
||||
| "docs_query"
|
||||
| "home_datachangecenter"
|
||||
| "home_effect"
|
||||
| "home_highrisk"
|
||||
| "home_highriskdetail"
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { getColorWithOpacity } from "@/utils/common";
|
||||
import ColumnChart from './modules/columnChart.vue';
|
||||
import RingChart from "./modules/ringChart.vue";
|
||||
import RingChart2 from "./modules/ringChart2.vue";
|
||||
|
||||
const appStore = useAppStore();
|
||||
const themeStore = useThemeStore();
|
||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||
|
||||
const emit = defineEmits<{ go: [v: string, preset?: string]; openChange: [c: any] }>();
|
||||
|
||||
const range = ref("近一年");
|
||||
const rangeOptions = [
|
||||
{label: "近一年", value: "近一年"},
|
||||
{label: "近半年", value: "近半年"},
|
||||
{label: "近三个月", value: "近三个月"},
|
||||
{label: "近一个月", value: "近一个月"},
|
||||
];
|
||||
|
||||
const changeData = ref([
|
||||
{
|
||||
name: '一车间',
|
||||
value: 42,
|
||||
},
|
||||
{
|
||||
name: '二车间',
|
||||
value: 35,
|
||||
},
|
||||
{
|
||||
name: '三车间',
|
||||
value: 28,
|
||||
},
|
||||
{
|
||||
name: '供应部',
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
name: '质量部',
|
||||
value: 9,
|
||||
},
|
||||
]);
|
||||
|
||||
const DEPT_ACCEPT = [
|
||||
{ name: "工艺", value: 58 },
|
||||
{ name: "设备", value: 41 },
|
||||
{ name: "管理", value: 27 },
|
||||
];
|
||||
const ACCEPT_COLORS = ["#2080f0", "#faad14", "#52c41a"];
|
||||
|
||||
const DEPT_ACCEPT2 = [
|
||||
{ name: "完全达到", value: 13, money: 61.2, rate: 68 },
|
||||
{ name: "基本达到", value: 4, money: 19.8, rate: 21 },
|
||||
{ name: "未达到", value: 2, money: 5.4, rate: 11 },
|
||||
];
|
||||
const ACCEPT_COLORS2 = ["#52c41a", "#faad14", "#ff4d4f"];
|
||||
|
||||
const residualHigh = ref<{id: string, title: string}>({id:'MOC-2026-R01-0035',title:'R-201 反应釜搅拌器电机更换(55kW→75kW 防爆电机)'});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<!-- 我的工作台 -->
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<p class="text-sm font-bold text-slate-800">全厂变更数据中心</p>
|
||||
<p class="text-[11px] text-slate-400 mt-[1px]">时间相关数据统一在此查询 · 统计时段</p>
|
||||
<NSelect v-model:value="range" :options="rangeOptions" size="tiny" class="w-28" />
|
||||
<NButton ghost size="small" class="ml-auto text-xs">导出</NButton>
|
||||
</div>
|
||||
</NCard>
|
||||
<!-- 卡片数据 -->
|
||||
<NGrid cols="s:1 m:2 l:4" responsive="screen" :x-gap="gap" :y-gap="16"
|
||||
:style="{
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor, 0.2),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning, 0.2),
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--success-bg': getColorWithOpacity(themeStore.otherColor.success, 0.2),
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error, 0.2),
|
||||
}"
|
||||
>
|
||||
<NGi>
|
||||
<div
|
||||
class="h-100% flex-1 flex items-center gap-3 bg-white px-16px py-12px cursor-pointer transition hover:-translate-y-1"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
@click="emit('go', 'tasks')"
|
||||
>
|
||||
<span class="shrink-0 rounded-lg p-2.5 bg-[var(--theme-bg)]">
|
||||
<Icon icon="akar-icons:file" class="size-24px text-[--theme-color]" />
|
||||
</span>
|
||||
<div class="flex flex-col">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="126"
|
||||
class="text-26px font-600"
|
||||
/>
|
||||
<p class="text-[11px] font-semibold text-slate-400">变更总数 · {{ range }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<div
|
||||
class="h-100% flex-1 flex items-center gap-3 bg-white px-16px py-12px cursor-pointer transition hover:-translate-y-1"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
@click="emit('go', 'tasks')"
|
||||
>
|
||||
<span class="shrink-0 rounded-lg p-2.5 bg-[var(--warning-bg)]">
|
||||
<Icon icon="lucide:shield-check" class="size-24px text-[--warning-color]" />
|
||||
</span>
|
||||
<div class="flex flex-col">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="18"
|
||||
class="text-26px font-600"
|
||||
/>
|
||||
<p class="text-[11px] font-semibold text-slate-400">重要变更数量 · {{ range }} · 占比 14%</p>
|
||||
</div>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<div
|
||||
class="h-100% flex-1 flex items-center gap-3 bg-white px-16px py-12px cursor-pointer transition hover:-translate-y-1"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
@click="emit('go', 'tasks')"
|
||||
>
|
||||
<span class="shrink-0 rounded-lg p-2.5 bg-[var(--warning-bg)]">
|
||||
<Icon icon="lucide:shield-check" class="size-24px text-[--warning-color]" />
|
||||
</span>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="4"
|
||||
class="text-26px font-600 text-[var(--error-color)]"
|
||||
/>
|
||||
<p class="text-26px font-600 text-[var(--error-color)]"> 高 /</p>
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="11"
|
||||
class="text-26px font-600 text-[var(--error-color)]"
|
||||
/><p class="text-26px font-600 text-[var(--error-color)]"> 中</p>
|
||||
</div>
|
||||
<p class="text-[11px] font-semibold text-slate-400">变更新增风险 · 剩余高风险 1 · 剩余中风险 6</p>
|
||||
</div>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<div
|
||||
class="h-100% flex-1 flex items-center gap-3 bg-white px-16px py-12px cursor-pointer transition hover:-translate-y-1"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
@click="emit('go', 'tasks')"
|
||||
>
|
||||
<span class="shrink-0 rounded-lg p-2.5 bg-[var(--success-bg)]">
|
||||
<Icon icon="material-symbols:check-circle-outline" class="size-24px text-[--success-color]" />
|
||||
</span>
|
||||
<div class="flex flex-col">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="86.4"
|
||||
class="text-26px font-600"
|
||||
/>
|
||||
<p class="text-[11px] font-semibold text-slate-400">验收投入合计 · 已验收 19 起 · 完全达标率 68%</p>
|
||||
</div>
|
||||
</div>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid
|
||||
:x-gap="gap" :y-gap="16" responsive="screen" item-responsive
|
||||
:style="{
|
||||
'--theme-color':themeStore.themeColor
|
||||
}"
|
||||
>
|
||||
<NGi span="24 s:24 m:24 l:14">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<div class="flex items-center mb-3 gap-2">
|
||||
<Icon icon="akar-icons:file" class="size-16px text-[--theme-color]" />
|
||||
<p class="text-13px font-700 text-#64749a">各车间变更数量</p>
|
||||
<p class="text-11px text-#94a3b8 mt-2px">{{range}} · 按申请部门</p>
|
||||
</div>
|
||||
<ColumnChart :data="changeData" style="height: 100%;" />
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:10">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<div class="flex items-center mb-3 gap-2">
|
||||
<Icon icon="akar-icons:file" class="size-16px text-[--theme-color]" />
|
||||
<p class="text-13px font-700 text-#64749a">变更类型分布</p>
|
||||
<p class="text-11px text-#94a3b8 mt-2px">{{range}} · 工艺 / 设备 / 管理</p>
|
||||
</div>
|
||||
<RingChart :data="DEPT_ACCEPT" :colors="ACCEPT_COLORS" :range="range" />
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid
|
||||
:x-gap="gap" :y-gap="16" responsive="screen" item-responsive
|
||||
:style="{
|
||||
'--error-color':themeStore.otherColor.error,
|
||||
'--warning-color':themeStore.otherColor.warning,
|
||||
'--success-color':themeStore.otherColor.success,
|
||||
'--theme-color':themeStore.themeColor
|
||||
}"
|
||||
>
|
||||
<NGi span="24 s:24 m:24 l:10">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<div class="flex items-center mb-3 gap-2">
|
||||
<Icon icon="lucide:shield-alert" class="size-16px text-[--theme-color]" />
|
||||
<p class="text-13px font-700 text-#64749a">风险增量与管控</p>
|
||||
<p class="text-11px text-#94a3b8 mt-2px">{{range}} · 变更新增风险与管控落实</p>
|
||||
</div>
|
||||
<div class="space-y-2.5">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="rounded-lg bg-red-50 px-3 py-2">
|
||||
<div class="text-[11px] text-[var(--error-color)]">新增固有高风险项</div>
|
||||
<div class="text-xl font-bold text-[var(--error-color)]">4</div>
|
||||
</div>
|
||||
<div class="rounded-lg bg-amber-50 px-3 py-2">
|
||||
<div class="text-[11px] text-[var(--warning-color)]">新增中风险项</div>
|
||||
<div class="text-xl font-bold text-[var(--warning-color)]">11</div>
|
||||
</div>
|
||||
<div class="rounded-lg bg-slate-50 px-3 py-2">
|
||||
<div class="text-[11px] text-slate-500">剩余高风险项</div>
|
||||
<div class="text-xl font-bold text-slate-800">1</div>
|
||||
</div>
|
||||
<div class="rounded-lg bg-slate-50 px-3 py-2">
|
||||
<div class="text-[11px] text-slate-500">剩余中风险项</div>
|
||||
<div class="text-xl font-bold text-slate-800">6</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex justify-between text-[11px] text-slate-500">
|
||||
<span>管控措施落实率</span>
|
||||
<span class="font-semibold text-[var(--success-color)]">96%</span>
|
||||
</div>
|
||||
<div class="mt-1 h-2 w-full rounded-full bg-slate-100">
|
||||
<div class="h-2 rounded-full bg-[var(--success-color)]" style="width: 96%" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="residualHigh.id" @click="emit('openChange', residualHigh)"
|
||||
class="cursor-pointer w-full rounded-lg border border-red-100 bg-[#FFF2F0] px-3 py-2 text-left transition hover:border-red-300">
|
||||
<span class="block text-[11px] font-medium text-[var(--error-color)]">剩余高风险 · 措施落实中</span>
|
||||
<span class="mt-0.5 block truncate text-xs font-medium text-slate-800">{{ residualHigh.title }}</span>
|
||||
<span class="mt-0.5 block text-[11px] text-slate-400">{{ residualHigh.id }} · 电机吊装作业管控措施执行跟踪</span>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:14">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<div class="flex items-center mb-3 gap-2">
|
||||
<Icon icon="material-symbols:check-circle-outline" class="size-16px text-[--theme-color]" />
|
||||
<p class="text-13px font-700 text-#64749a">变更投入和效果</p>
|
||||
<p class="text-11px text-#94a3b8 mt-2px">{{range}} · 支持查询验收明细</p>
|
||||
</div>
|
||||
<RingChart2 :data="DEPT_ACCEPT2" :colors="ACCEPT_COLORS2" style="height: 210px;" />
|
||||
<div class="flex items-center justify-between border-slate-200 pt-1.5">
|
||||
<span class="text-[11px] text-slate-400">投入合计(变更材料和实施费) · 完全达到率 68%</span>
|
||||
<span class="text-xs font-bold text-[var(--theme-color)]">86.4 万元</span>
|
||||
</div>
|
||||
<div @click="emit('go', 'invest')"
|
||||
class="cursor-pointer mt-3 flex w-full items-center justify-center gap-1 rounded-lg border border-dashed py-2 text-[11px] text-slate-400 transition hover:border-[#6E93C6] hover:text-[#1D4E9C]">
|
||||
验收明细(名称 / 日期链 / 费用 / 结论)见左边栏「变更效果跟踪」<ChevronRight class="h-3 w-3" />
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useEcharts } from '@/hooks/common/echarts';
|
||||
|
||||
defineOptions({
|
||||
name: 'RingChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data: { name: string; value: number; }[]; }>();
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show:false,
|
||||
bottom: '20%',
|
||||
left: 'center',
|
||||
icon: 'circle',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemStyle: {
|
||||
borderWidth: 0
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: "5%",
|
||||
left: "5%",
|
||||
right: "5%",
|
||||
bottom: "5%",
|
||||
},
|
||||
calculable: true,
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
boundaryGap: true, // 新增,固定柱子位置
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
splitArea: { show: false },
|
||||
data: [] as string[],
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
show: false,
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: "bar",
|
||||
barWidth: 45,
|
||||
barGap: "10%",
|
||||
color: "#2080f0",
|
||||
label: { show: true, position: 'top',color: '#333',fontWeight: 'bold' },
|
||||
data: [] as number[],
|
||||
},
|
||||
]
|
||||
}));
|
||||
|
||||
function init() {
|
||||
updateOptions(opts => {
|
||||
let allMonth = props.data.map((item:any) => item.name);
|
||||
let values = props.data.map((item:any) => item.value);
|
||||
opts.xAxis[0].data = allMonth;
|
||||
opts.series[0].data = values;
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="domRef" class="w-full h-220px overflow-hidden"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useEcharts } from '@/hooks/common/echarts';
|
||||
|
||||
defineOptions({
|
||||
name: 'RingChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data?: { name: string; value: number }[]; colors?: string[]; range?: string }>();
|
||||
const range = ref("近一年");
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
bottom: 0,
|
||||
left: 'center',
|
||||
icon: 'circle',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemStyle: {
|
||||
borderWidth: 0
|
||||
},
|
||||
},
|
||||
title: {
|
||||
text: `{a|126}\n{b|${range.value}}`,
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 24,
|
||||
color: '#333',
|
||||
fontWeight: 800,
|
||||
align: 'center',
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
b: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
align: 'center',
|
||||
verticalAlign: 'middle',
|
||||
fontWeight: 500,
|
||||
padding: [5, 0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
left: 'center',
|
||||
top: '35%',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
color: ['#5da8ff', '#8e9dff', '#fedc69', '#26deca'],
|
||||
radius: ['45%', '65%'],
|
||||
center: ['50%', '45%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'outside',
|
||||
formatter: '{b}\n{c} ({d}%)',
|
||||
fontSize: 12,
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 10,
|
||||
length2: 10
|
||||
},
|
||||
data: [] as { name: string; value: number }[]
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
function init() {
|
||||
updateOptions(opts => {
|
||||
range.value = props.range || "近一年";
|
||||
opts.series[0].data = props.data || [];
|
||||
opts.series[0].color = props.colors || [];
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="domRef" class="w-full h-220px overflow-hidden"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useEcharts } from '@/hooks/common/echarts';
|
||||
|
||||
defineOptions({
|
||||
name: 'RingChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data?: { name: string; value: number; money: number; rate: number }[]; colors?: string[]; range?: string }>();
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: '0%',
|
||||
top: 'center',
|
||||
icon: 'circle',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemStyle: {
|
||||
borderWidth: 0
|
||||
},
|
||||
textStyle: {
|
||||
rich: {
|
||||
name: {
|
||||
width: 50,
|
||||
},
|
||||
count: {
|
||||
width: 80,
|
||||
align: 'right',
|
||||
fontWeight: 600,
|
||||
},
|
||||
rate: {
|
||||
align: 'left',
|
||||
},
|
||||
money: {
|
||||
width: 80,
|
||||
align: 'right',
|
||||
fontWeight: 600,
|
||||
},
|
||||
}
|
||||
},
|
||||
formatter: function (name: string) {
|
||||
var info = props.data?.find((item: { name: string }) => item.name === name);
|
||||
console.group(info)
|
||||
if(info){
|
||||
return '{name|'+name+'} {count|'+(info.value)+' 起}{rate|'+(info.rate)+' %} {money|'+(info.money)+' 万元}';
|
||||
}else{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: `{a|19}\n{b|已验收}`,
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 24,
|
||||
color: '#333',
|
||||
fontWeight: 800,
|
||||
align: 'center',
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
b: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
align: 'center',
|
||||
verticalAlign: 'middle',
|
||||
fontWeight: 500,
|
||||
padding: [5, 0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
left: '32%',
|
||||
top: '35%',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
color: ['#5da8ff', '#8e9dff', '#fedc69', '#26deca'],
|
||||
radius: ['50%', '70%'],
|
||||
center: ['35%', '45%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'outside',
|
||||
formatter: '{b}\n{c} ({d}%)',
|
||||
fontSize: 12,
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 10,
|
||||
length2: 10
|
||||
},
|
||||
data: [] as { name: string; value: number }[]
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
function init() {
|
||||
updateOptions(opts => {
|
||||
opts.series[0].data = props.data || [];
|
||||
opts.series[0].color = props.colors || [];
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="domRef" class="w-full h-220px overflow-hidden"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user