mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-23 20:06:37 +08:00
feat(projects): add antv g6 example
This commit is contained in:
parent
a6545265ac
commit
0c0d606ae5
@ -49,6 +49,7 @@
|
||||
"dependencies": {
|
||||
"@antv/data-set": "0.11.8",
|
||||
"@antv/g2": "5.2.5",
|
||||
"@antv/g6": "^5.0.26",
|
||||
"@better-scroll/core": "2.5.1",
|
||||
"@iconify/vue": "4.1.2",
|
||||
"@sa/alova": "workspace:*",
|
||||
@ -57,6 +58,7 @@
|
||||
"@sa/hooks": "workspace:*",
|
||||
"@sa/materials": "workspace:*",
|
||||
"@sa/utils": "workspace:*",
|
||||
"@vueuse/components": "^11.1.0",
|
||||
"@vueuse/core": "11.1.0",
|
||||
"clipboard": "2.0.11",
|
||||
"dayjs": "1.11.13",
|
||||
|
589
pnpm-lock.yaml
589
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -199,6 +199,7 @@ const local: App.I18n.Schema = {
|
||||
plugin_copy: 'Copy',
|
||||
plugin_charts: 'Charts',
|
||||
plugin_charts_echarts: 'ECharts',
|
||||
plugin_charts_antv: 'AntV',
|
||||
plugin_editor: 'Editor',
|
||||
plugin_editor_quill: 'Quill',
|
||||
plugin_editor_markdown: 'Markdown',
|
||||
|
@ -199,6 +199,7 @@ const local: App.I18n.Schema = {
|
||||
plugin_copy: '剪贴板',
|
||||
plugin_charts: '图表',
|
||||
plugin_charts_echarts: 'ECharts',
|
||||
plugin_charts_antv: 'AntV',
|
||||
plugin_editor: '编辑器',
|
||||
plugin_editor_quill: '富文本编辑器',
|
||||
plugin_editor_markdown: 'MD 编辑器',
|
||||
|
@ -40,6 +40,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
"multi-menu_first_child": () => import("@/views/multi-menu/first_child/index.vue"),
|
||||
"multi-menu_second_child_home": () => import("@/views/multi-menu/second_child_home/index.vue"),
|
||||
plugin_barcode: () => import("@/views/plugin/barcode/index.vue"),
|
||||
plugin_charts_antv: () => import("@/views/plugin/charts/antv/index.vue"),
|
||||
plugin_charts_echarts: () => import("@/views/plugin/charts/echarts/index.vue"),
|
||||
plugin_copy: () => import("@/views/plugin/copy/index.vue"),
|
||||
plugin_editor_markdown: () => import("@/views/plugin/editor/markdown/index.vue"),
|
||||
|
@ -405,6 +405,16 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
icon: 'mdi:chart-areaspline'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'plugin_charts_antv',
|
||||
path: '/plugin/charts/antv',
|
||||
component: 'view.plugin_charts_antv',
|
||||
meta: {
|
||||
title: 'plugin_charts_antv',
|
||||
i18nKey: 'route.plugin_charts_antv',
|
||||
icon: 'hugeicons:flow-square'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_charts_echarts',
|
||||
path: '/plugin/charts/echarts',
|
||||
|
@ -211,6 +211,7 @@ const routeMap: RouteMap = {
|
||||
"plugin": "/plugin",
|
||||
"plugin_barcode": "/plugin/barcode",
|
||||
"plugin_charts": "/plugin/charts",
|
||||
"plugin_charts_antv": "/plugin/charts/antv",
|
||||
"plugin_charts_echarts": "/plugin/charts/echarts",
|
||||
"plugin_copy": "/plugin/copy",
|
||||
"plugin_editor": "/plugin/editor",
|
||||
|
9
src/typings/components.d.ts
vendored
9
src/typings/components.d.ts
vendored
@ -22,10 +22,15 @@ declare module 'vue' {
|
||||
IconCarbonPlay: typeof import('~icons/carbon/play')['default']
|
||||
IconCarbonStop: typeof import('~icons/carbon/stop')['default']
|
||||
'IconCharm:download': typeof import('~icons/charm/download')['default']
|
||||
'IconF7:circleFill': typeof import('~icons/f7/circle-fill')['default']
|
||||
'IconF7:flagCircleFill': typeof import('~icons/f7/flag-circle-fill')['default']
|
||||
'IconFe:question': typeof import('~icons/fe/question')['default']
|
||||
'IconFileIcons:microsoftExcel': typeof import('~icons/file-icons/microsoft-excel')['default']
|
||||
'IconGg:ratio': typeof import('~icons/gg/ratio')['default']
|
||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||
'IconIc:roundPlus': typeof import('~icons/ic/round-plus')['default']
|
||||
'IconIconParkOutline:equalRatio': typeof import('~icons/icon-park-outline/equal-ratio')['default']
|
||||
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
||||
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
|
||||
IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default']
|
||||
@ -43,6 +48,8 @@ declare module 'vue' {
|
||||
IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
||||
'IconMingcute:zoomInLine': typeof import('~icons/mingcute/zoom-in-line')['default']
|
||||
'IconMingcute:zoomOutLine': typeof import('~icons/mingcute/zoom-out-line')['default']
|
||||
IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
||||
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
||||
@ -51,6 +58,7 @@ declare module 'vue' {
|
||||
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
|
||||
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
||||
NCard: typeof import('naive-ui')['NCard']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCollapse: typeof import('naive-ui')['NCollapse']
|
||||
@ -66,6 +74,7 @@ declare module 'vue' {
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||
NFlex: typeof import('naive-ui')['NFlex']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||
|
2
src/typings/elegant-router.d.ts
vendored
2
src/typings/elegant-router.d.ts
vendored
@ -65,6 +65,7 @@ declare module "@elegant-router/types" {
|
||||
"plugin": "/plugin";
|
||||
"plugin_barcode": "/plugin/barcode";
|
||||
"plugin_charts": "/plugin/charts";
|
||||
"plugin_charts_antv": "/plugin/charts/antv";
|
||||
"plugin_charts_echarts": "/plugin/charts/echarts";
|
||||
"plugin_copy": "/plugin/copy";
|
||||
"plugin_editor": "/plugin/editor";
|
||||
@ -181,6 +182,7 @@ declare module "@elegant-router/types" {
|
||||
| "multi-menu_first_child"
|
||||
| "multi-menu_second_child_home"
|
||||
| "plugin_barcode"
|
||||
| "plugin_charts_antv"
|
||||
| "plugin_charts_echarts"
|
||||
| "plugin_copy"
|
||||
| "plugin_editor_markdown"
|
||||
|
60
src/views/plugin/charts/antv/data.ts
Normal file
60
src/views/plugin/charts/antv/data.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import type { CustomGraphData } from './modules/antv-g6-flow';
|
||||
|
||||
// 日期可以自己随便设置,就是字符串展示,也可以修改为业务需要的字段
|
||||
export function getFlowDatas(): CustomGraphData {
|
||||
return {
|
||||
nodes: [
|
||||
{
|
||||
id: 'NS',
|
||||
name: 'Start',
|
||||
status: 'COMPLETED',
|
||||
startDate: '2024-10-01',
|
||||
endDate: '2024-10-07',
|
||||
actualStartDate: '2024-10-01',
|
||||
actualEndDate: '2024-10-07'
|
||||
},
|
||||
{
|
||||
id: 'N1',
|
||||
name: 'Node1',
|
||||
status: 'COMPLETED_EARLY',
|
||||
startDate: '2024-10-08',
|
||||
endDate: '2024-10-10',
|
||||
actualStartDate: '2024-10-08',
|
||||
actualEndDate: '2024-10-09',
|
||||
milestone: true
|
||||
},
|
||||
{
|
||||
id: 'N2',
|
||||
name: 'Node2',
|
||||
status: 'COMPLETED_EARLY',
|
||||
startDate: '2024-10-11',
|
||||
endDate: '2024-10-13',
|
||||
actualStartDate: '2024-10-11',
|
||||
actualEndDate: '2024-10-12'
|
||||
},
|
||||
{ id: 'N3', name: 'Node3', status: 'IN_PROGRESS', isDeleted: true },
|
||||
{ id: 'N4', name: 'Node4', status: 'COMPLETED_LATE' },
|
||||
{ id: 'N5', name: 'Node5', status: 'DELAYED', isDelayed: true, milestone: true },
|
||||
{ id: 'N6', name: 'Node6', status: 'PAUSED' },
|
||||
{ id: 'N7', name: 'Node7', status: 'NOT_STARTED' },
|
||||
{ id: 'N8', name: 'Node8', status: 'NOT_STARTED' },
|
||||
{ id: 'N9', name: 'End', status: 'NOT_STARTED' },
|
||||
{ id: 'NX', name: 'NodeX', status: 'NOT_STARTED', isDeleted: true }
|
||||
],
|
||||
edges: [
|
||||
{ id: 'E1', source: 'NS', target: 'N1' },
|
||||
{ id: 'E2', source: 'N1', target: 'N2' },
|
||||
{ id: 'E3', source: 'N1', target: 'N3', isDeleted: true },
|
||||
{ id: 'E4', source: 'N1', target: 'N4' },
|
||||
{ id: 'E5', source: 'N2', target: 'N5' },
|
||||
{ id: 'E6', source: 'N3', target: 'N5', isDeleted: true },
|
||||
{ id: 'E7', source: 'N4', target: 'N5' },
|
||||
{ id: 'E8', source: 'N5', target: 'N6' },
|
||||
{ id: 'E9', source: 'N6', target: 'N7' },
|
||||
{ id: 'E10', source: 'N6', target: 'N8' },
|
||||
{ id: 'E11', source: 'N7', target: 'N9' },
|
||||
{ id: 'EX', source: 'N8', target: 'N9' },
|
||||
{ id: 'EO', source: 'N5', target: 'NX', isDeleted: true }
|
||||
]
|
||||
};
|
||||
}
|
59
src/views/plugin/charts/antv/index.vue
Normal file
59
src/views/plugin/charts/antv/index.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<script setup lang="tsx">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import type { IPointerEvent } from '@antv/g6';
|
||||
import AntvFlow from './modules/antv-flow.vue';
|
||||
import { getFlowDatas } from './data';
|
||||
|
||||
const antvFlowRef = ref();
|
||||
const flowDatas = ref<any>({});
|
||||
const seletedNode = ref<string | undefined>('N2');
|
||||
const behaviors = [
|
||||
{
|
||||
type: 'click-select',
|
||||
enable: (event: IPointerEvent) => event.targetType === 'node',
|
||||
onClick: (event: IPointerEvent) => {
|
||||
const node = event.target as any;
|
||||
const nodeData = flowDatas.value.nodes?.find((item: any) => item.id === node.id);
|
||||
seletedNode.value = nodeData?.id;
|
||||
window.$message?.success(`选中节点:[${node?.id}]${nodeData?.name}`);
|
||||
}
|
||||
}
|
||||
];
|
||||
const hasNodeN = computed(() => flowDatas.value.nodes?.some((node: any) => node.id === 'NN'));
|
||||
|
||||
function addNode() {
|
||||
const { nodes, edges } = flowDatas.value;
|
||||
|
||||
nodes.push({ id: 'NN', name: 'New node', status: 'NOT_STARTED' });
|
||||
edges.push({ id: 'EN', source: 'N5', target: 'NN' });
|
||||
flowDatas.value = { nodes, edges };
|
||||
}
|
||||
|
||||
function removeNode(id: string) {
|
||||
const { nodes, edges } = flowDatas.value;
|
||||
// 删除node的同时,也需要删除包含NX的edge
|
||||
flowDatas.value = {
|
||||
nodes: nodes.filter((node: any) => node.id !== id),
|
||||
edges: edges.filter((edge: any) => edge.source !== id && edge.target !== id)
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
flowDatas.value = getFlowDatas();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full">
|
||||
<NCard title="AntV G6 Next" :bordered="false" class="h-full card-wrapper">
|
||||
<AntvFlow ref="antvFlowRef" :data="flowDatas" :selected="seletedNode" :behaviors="behaviors" />
|
||||
<NDivider />
|
||||
<NFlex>
|
||||
<NButton @click="seletedNode = 'N5'">选中节点N5(需要自行处理选中事件,不会触发元素点击)</NButton>
|
||||
<NButton v-if="!hasNodeN" @click="addNode">添加节点并与Node5连线</NButton>
|
||||
<NButton v-else @click="() => removeNode('NN')">删除新添加的节点</NButton>
|
||||
<NButton @click="() => removeNode('NX')">删除NodeX</NButton>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
</div>
|
||||
</template>
|
134
src/views/plugin/charts/antv/modules/antv-flow.vue
Normal file
134
src/views/plugin/charts/antv/modules/antv-flow.vue
Normal file
@ -0,0 +1,134 @@
|
||||
<script setup lang="tsx">
|
||||
import { shallowRef, watch } from 'vue';
|
||||
import { vResizeObserver } from '@vueuse/components';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import type { CustomBehaviorOption } from '@antv/g6';
|
||||
import type { CustomGraphData } from './antv-g6-flow';
|
||||
import { useAntFlow } from './antv-g6-flow';
|
||||
import { nodeStatus } from './status';
|
||||
|
||||
defineOptions({
|
||||
name: 'AntvFLow',
|
||||
inheritAttrs: false
|
||||
});
|
||||
|
||||
interface Props {
|
||||
behaviors?: CustomBehaviorOption[];
|
||||
data: CustomGraphData;
|
||||
selected?: string;
|
||||
height?: string;
|
||||
autoFit?: 'view' | 'center';
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const containerRef = shallowRef();
|
||||
const graphRef = shallowRef();
|
||||
|
||||
// 监听容器尺寸变化,调整画布大小为图容器大小
|
||||
const onContainerResize = useDebounceFn(() => {
|
||||
if (graphRef.value) {
|
||||
graphRef.value.resize();
|
||||
}
|
||||
}, 5);
|
||||
|
||||
async function draw() {
|
||||
if (graphRef.value) {
|
||||
graphRef.value.destroy();
|
||||
}
|
||||
const { graph } = useAntFlow({
|
||||
container: 'antv-flow',
|
||||
data: props.data,
|
||||
behaviors: props.behaviors,
|
||||
autoFit: props.autoFit
|
||||
});
|
||||
graphRef.value = graph;
|
||||
await selectNode();
|
||||
}
|
||||
|
||||
async function selectNode() {
|
||||
if (props.selected && graphRef.value) {
|
||||
try {
|
||||
await graphRef.value.setElementState(props.selected, 'selected');
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
[() => props.data, () => props.selected],
|
||||
() => {
|
||||
draw();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
defineExpose({ selectNode, graph: graphRef });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<!-- 画布操作栏 -->
|
||||
<div class="absolute left-0 right-0 z-1 flex items-center items-stretch justify-between">
|
||||
<NButtonGroup size="small" class="bg-white!">
|
||||
<NButton @click="graphRef.zoomBy(0.9)">
|
||||
<icon-mingcute:zoom-out-line />
|
||||
</NButton>
|
||||
<NButton @click="graphRef.zoomBy(1.1)">
|
||||
<icon-mingcute:zoom-in-line />
|
||||
</NButton>
|
||||
<NButton
|
||||
@click="
|
||||
() => {
|
||||
graphRef.zoomTo(1);
|
||||
graphRef.fitCenter();
|
||||
}
|
||||
"
|
||||
>
|
||||
<icon-icon-park-outline:equal-ratio />
|
||||
</NButton>
|
||||
<NButton
|
||||
@click="
|
||||
() => {
|
||||
graphRef.fitView();
|
||||
graphRef.fitCenter();
|
||||
}
|
||||
"
|
||||
>
|
||||
<icon-gg:ratio />
|
||||
</NButton>
|
||||
</NButtonGroup>
|
||||
<div class="flex-center gap-12px">
|
||||
<NPopover placement="bottom-end" :animated="false">
|
||||
<template #trigger>
|
||||
<NButton size="small" class="bg-white!">
|
||||
<icon-fe:question />
|
||||
</NButton>
|
||||
</template>
|
||||
<div class="flex-col gap-8px">
|
||||
<div span="2" class="text-12px font-bold">节点图例</div>
|
||||
<NGrid :cols="2" :y-gap="8" class="w-180px!">
|
||||
<NGi v-for="[key, value] in Object.entries(nodeStatus)" :key="key" class="flex-center">
|
||||
<NTag size="small" round :bordered="false">
|
||||
<template #icon>
|
||||
<icon-f7:flag-circle-fill v-if="key === 'MILESTONE'" :style="{ color: value.color }" />
|
||||
<icon-f7:circle-fill v-else :style="{ color: value.color }" />
|
||||
</template>
|
||||
{{ value.type }}
|
||||
</NTag>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
</div>
|
||||
</NPopover>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 画布 -->
|
||||
<div
|
||||
id="antv-flow"
|
||||
ref="containerRef"
|
||||
v-resize-observer="onContainerResize"
|
||||
class="w-full"
|
||||
:style="{ height: props.height || '300px' }"
|
||||
@contextmenu="event => event.preventDefault()"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
169
src/views/plugin/charts/antv/modules/antv-g6-flow.ts
Normal file
169
src/views/plugin/charts/antv/modules/antv-g6-flow.ts
Normal file
@ -0,0 +1,169 @@
|
||||
import type { CustomBehaviorOption, EdgeData, GraphData, NodeData } from '@antv/g6';
|
||||
import { Graph } from '@antv/g6';
|
||||
import type { Canvas } from '@antv/g6/lib/runtime/canvas';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { getNodeIcon, nodeStatus } from './status';
|
||||
|
||||
const baseColor = 'rgb(158 163 171)';
|
||||
|
||||
export interface CustomNodeData extends NodeData {
|
||||
isDelayed?: boolean;
|
||||
isDeleted?: boolean;
|
||||
milestone?: boolean;
|
||||
}
|
||||
|
||||
export interface CustomEdgeData extends EdgeData {
|
||||
isDelayed?: boolean;
|
||||
isDeleted?: boolean;
|
||||
}
|
||||
|
||||
export interface CustomGraphData extends GraphData {
|
||||
nodes?: CustomNodeData[];
|
||||
edges?: CustomEdgeData[];
|
||||
}
|
||||
|
||||
interface AntFlow {
|
||||
container: string | HTMLElement | Canvas;
|
||||
data: CustomGraphData;
|
||||
behaviors?: CustomBehaviorOption[];
|
||||
autoFit?: 'view' | 'center';
|
||||
}
|
||||
|
||||
export function useAntFlow(property: AntFlow) {
|
||||
const themeStore = useThemeStore();
|
||||
const otherBehaviors = property.behaviors ? property.behaviors : [];
|
||||
|
||||
const graph = new Graph({
|
||||
container: property.container,
|
||||
animation: false,
|
||||
padding: 16,
|
||||
theme: 'light',
|
||||
autoFit: property.autoFit || 'center',
|
||||
data: property.data as GraphData,
|
||||
node: {
|
||||
type: 'rect',
|
||||
|
||||
style: (node: any) => {
|
||||
const iconS = getNodeIcon(node);
|
||||
let labelFill = '#000000';
|
||||
if (node.taskState === 'NOT_STARTED') {
|
||||
labelFill = '#787878';
|
||||
}
|
||||
|
||||
return {
|
||||
labelText: node.name,
|
||||
size: [120, 26],
|
||||
radius: 99,
|
||||
fill: '#FFFFFF',
|
||||
stroke: node.isDeleted ? themeStore.otherColor.error : baseColor,
|
||||
lineDash: node.isDeleted ? 4 : 0,
|
||||
lineWidth: 1,
|
||||
labelFill,
|
||||
labelX: 2,
|
||||
labelY: 2,
|
||||
labelTextBaseline: 'middle',
|
||||
labelTextAlign: 'center',
|
||||
labelLineHeight: 13,
|
||||
labelWordWrap: true,
|
||||
labelMaxWidth: 72,
|
||||
iconSrc: iconS,
|
||||
iconWidth: 16,
|
||||
iconHeight: 16,
|
||||
iconX: -45,
|
||||
labelFontSize: 12,
|
||||
labelPlacement: 'center',
|
||||
badgeLineWidth: 6,
|
||||
badgeFontSize: 8,
|
||||
badges: [
|
||||
{ text: '延期', placement: 'top', offsetY: -11, visibility: node.isDelayed ? 'visible' : 'hidden' },
|
||||
{ text: '已删除', placement: 'bottom', offsetY: 11, visibility: node.isDeleted ? 'visible' : 'hidden' }
|
||||
],
|
||||
badgePalette: [themeStore.otherColor.error, themeStore.otherColor.error],
|
||||
ports: [{ placement: 'left' }, { placement: 'right' }]
|
||||
};
|
||||
},
|
||||
state: {
|
||||
selected: {
|
||||
lineWidth: 2,
|
||||
stroke: themeStore.themeColor,
|
||||
labelFill: themeStore.themeColor,
|
||||
halo: true,
|
||||
haloStroke: themeStore.themeColor,
|
||||
haloLineWidth: 6
|
||||
},
|
||||
active: (node: any) => ({
|
||||
halo: true,
|
||||
haloStroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor,
|
||||
haloLineWidth: 6,
|
||||
zIndex: 2
|
||||
})
|
||||
}
|
||||
},
|
||||
edge: {
|
||||
type: 'cubic-horizontal',
|
||||
style: (node: any) => ({
|
||||
curveOffset: 10,
|
||||
curvePosition: 0.5,
|
||||
stroke: node.isDeleted ? themeStore.otherColor.error : baseColor,
|
||||
lineDash: node.isDeleted ? 4 : 0
|
||||
}),
|
||||
state: {
|
||||
active: (node: any) => ({
|
||||
lineWidth: 2,
|
||||
stroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor,
|
||||
halo: true,
|
||||
haloStroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor,
|
||||
haloLineWidth: 6,
|
||||
zIndex: 2
|
||||
})
|
||||
}
|
||||
},
|
||||
layout: {
|
||||
type: 'antv-dagre',
|
||||
rankdir: 'LR',
|
||||
ranksep: 20,
|
||||
nodesep: -20,
|
||||
controlPoints: true
|
||||
},
|
||||
behaviors: [
|
||||
{
|
||||
key: 'hover-activate',
|
||||
type: 'hover-activate',
|
||||
degree: 1,
|
||||
direction: 'both'
|
||||
},
|
||||
'drag-canvas',
|
||||
...otherBehaviors
|
||||
],
|
||||
plugins: [
|
||||
{
|
||||
type: 'tooltip',
|
||||
enable: (event: any) => event.targetType === 'node',
|
||||
getContent: (_event: any, items: any) => {
|
||||
let result = '<div style="display: flex; flex-direction: column; gap: 8px;">';
|
||||
|
||||
// 弹出提示可以自定义各种内容,但是这里很奇怪,有的class不跟随uniocss的样式
|
||||
items?.forEach((item: any) => {
|
||||
result += `<h3 style="display: flex; align-items: center; gap: 8px;">${item.name}</h3>`;
|
||||
result += `<div style="display: flex;"><b>状态:</b><div style="display: flex; gap: 4px;"><img src="${getNodeIcon(item)}" /><span style="font-weight: 400 !important;">${nodeStatus[item.status as keyof typeof nodeStatus].type}</span></div></div>`;
|
||||
|
||||
result += `<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; row-gap: 4px;">`;
|
||||
result += `<div style="display: flex; flex-direction: column;"><div style="color: rgb(156 163 175);">预计开始</div><div style="font-weight: 700;">${item.startDate || '-'}</div></div>`;
|
||||
result += `<div style="display: flex; flex-direction: column;"><div style="color: rgb(156 163 175);">预计结束</div><div style="font-weight: 700;">${item.endDate || '-'}</div></div>`;
|
||||
result += `<div style="display: flex; flex-direction: column;"><div style="color: rgb(156 163 175);">实际开始</div><div style="font-weight: 700;">${item.actualStartDate || '-'}</div></div>`;
|
||||
result += `<div style="display: flex; flex-direction: column;"><div style="color: rgb(156 163 175);">实际结束</div><div style="font-weight: 700;">${item.actualEndDate || '-'}</div></div>`;
|
||||
result += `</div>`;
|
||||
});
|
||||
|
||||
result += '</div>';
|
||||
return result;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
graph.render();
|
||||
|
||||
return {
|
||||
graph
|
||||
};
|
||||
}
|
99
src/views/plugin/charts/antv/modules/status.ts
Normal file
99
src/views/plugin/charts/antv/modules/status.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { h } from 'vue';
|
||||
import type { TagProps } from 'naive-ui';
|
||||
import { NTag } from 'naive-ui';
|
||||
|
||||
export const nodeStatus = {
|
||||
MILESTONE: {
|
||||
type: '里程碑',
|
||||
color: '#5b5b5b',
|
||||
textColor: '',
|
||||
base64: '',
|
||||
flag64: ''
|
||||
},
|
||||
NOT_STARTED: {
|
||||
type: '未开始',
|
||||
color: '#CCCDD0',
|
||||
textColor: '#5b5b5b',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNDQ0NERDAiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNDQ0NERDAiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
},
|
||||
DELAYED: {
|
||||
type: '已延期',
|
||||
color: '#B81111',
|
||||
textColor: '#dccbcb',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNCODExMTEiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNCODExMTEiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
},
|
||||
PAUSED: {
|
||||
type: '已暂停',
|
||||
color: '#0E42D2',
|
||||
textColor: '#dae0f0',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiMwRTQyRDIiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiMwRTQyRDIiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
},
|
||||
IN_PROGRESS: {
|
||||
type: '进行中',
|
||||
color: '#E1BE0D',
|
||||
textColor: '#4f4304',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNFMUJFMEQiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNFMUJFMEQiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
},
|
||||
COMPLETED: {
|
||||
type: '已完成',
|
||||
color: '#33C73D',
|
||||
textColor: '#084e0c',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiMzM0M3M0QiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiMzM0M3M0QiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
},
|
||||
COMPLETED_EARLY: {
|
||||
type: '提前完成',
|
||||
color: '#CCFF99',
|
||||
textColor: '#42681d',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNDQ0ZGOTkiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNDQ0ZGOTkiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
},
|
||||
COMPLETED_LATE: {
|
||||
type: '延期完成',
|
||||
color: '#CC6699',
|
||||
textColor: '#4b092a',
|
||||
base64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNDQzY2OTkiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjgyOCAyMy45MDYtMjMuOTA2YzAtMTMuMDU1LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45NDUgNC4wOTUgMjhjMCAxMy4wNzggMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2Ii8+PC9zdmc+',
|
||||
flag64:
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgNTYgNTYiPjxwYXRoIGZpbGw9IiNDQzY2OTkiIGQ9Ik0yOCA1MS45MDZjMTMuMDU1IDAgMjMuOTA2LTEwLjg1MSAyMy45MDYtMjMuOTA2YzAtMTMuMDc4LTEwLjg3NS0yMy45MDYtMjMuOTMtMjMuOTA2QzE0Ljg5OSA0LjA5NCA0LjA5NSAxNC45MjIgNC4wOTUgMjhjMCAxMy4wNTUgMTAuODI4IDIzLjkwNiAyMy45MDYgMjMuOTA2bS05LjA3LTExLjExYy0uNTg2IDAtMS4xMDItLjUxNS0xLjEwMi0xLjA3N1YxOS44MmMwLTEuMDA4LjQ5Mi0xLjc1OCAxLjQ1My0yLjE4Yy44NDQtLjM3NCAxLjU3LS41ODUgMy4zNzUtLjU4NWM0LjI0MiAwIDYuODkgMi4wODYgMTAuODc1IDIuMDg2YzEuOTIyIDAgMi45My0uNDkzIDMuNTQtLjQ5M2MuNzk2IDAgMS40MDYuNDkzIDEuNDA2IDEuMTcydjExLjU1NWMwIDEuMDU1LS40NDYgMS43MzQtMS40NTQgMi4xOGMtLjg2Ny4zOTgtMS42MTcuNjA5LTMuMzc1LjYwOWMtNC4wNzggMC02LjY4LTIuMDYyLTEwLjg3NS0yLjA2MmMtMS40MyAwLTIuMzY3LjI4LTIuNzg5LjQ2OHY3LjE0OWMwIC41ODYtLjQ0NSAxLjA3OC0xLjA1NCAxLjA3OCIvPjwvc3ZnPg=='
|
||||
}
|
||||
};
|
||||
|
||||
export function getNodeIcon(node: any) {
|
||||
const type = node.milestone ? 'flag64' : 'base64';
|
||||
if (node.status) {
|
||||
return nodeStatus[node.status as keyof typeof nodeStatus][type];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function getNodeStatusTag(state: keyof typeof nodeStatus, tagProperty?: TagProps) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
color: { textColor: nodeStatus[state]?.textColor, color: nodeStatus[state]?.color },
|
||||
bordered: false,
|
||||
size: 'small',
|
||||
...tagProperty
|
||||
},
|
||||
{
|
||||
default: () => nodeStatus[state]?.type
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user