初始化
This commit is contained in:
135
src/views/plugin/charts/antv/modules/antv-flow.vue
Normal file
135
src/views/plugin/charts/antv/modules/antv-flow.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<script setup lang="tsx">
|
||||
import { shallowRef, useTemplateRef, watch } from 'vue';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import { vResizeObserver } from '@vueuse/components';
|
||||
import type { CustomBehaviorOption, Graph } from '@antv/g6';
|
||||
import { useAntFlow } from './antv-g6-flow';
|
||||
import { nodeStatus } from './status';
|
||||
import type { CustomGraphData } from './types';
|
||||
|
||||
defineOptions({ name: 'AntvFLow' });
|
||||
|
||||
interface Props {
|
||||
behaviors?: CustomBehaviorOption[];
|
||||
data: CustomGraphData;
|
||||
selected?: string;
|
||||
height?: string;
|
||||
autoFit?: 'view' | 'center';
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const containerRef = useTemplateRef('containerRef');
|
||||
const graphRef = shallowRef<Graph | null>(null);
|
||||
|
||||
// 监听容器尺寸变化,调整画布大小为图容器大小
|
||||
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 {}
|
||||
}
|
||||
}
|
||||
|
||||
function zoomOut() {
|
||||
graphRef.value?.zoomBy(0.9);
|
||||
}
|
||||
|
||||
function zoomIn() {
|
||||
graphRef.value?.zoomBy(1.1);
|
||||
}
|
||||
|
||||
function resetZoom() {
|
||||
graphRef.value?.zoomTo(1);
|
||||
graphRef.value?.fitCenter();
|
||||
}
|
||||
|
||||
function fitZoom() {
|
||||
graphRef.value?.fitView();
|
||||
graphRef.value?.fitCenter();
|
||||
}
|
||||
|
||||
watch(
|
||||
[() => props.data, () => props.selected],
|
||||
() => {
|
||||
draw();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
defineExpose({ selectNode, graph: graphRef });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<!-- canvas toolbar -->
|
||||
<div class="absolute left-0 right-0 z-1 flex items-center items-stretch justify-between">
|
||||
<ElButtonGroup size="small" class="bg-white!">
|
||||
<ElButton @click="zoomOut">
|
||||
<icon-mingcute:zoom-out-line />
|
||||
</ElButton>
|
||||
<ElButton @click="zoomIn">
|
||||
<icon-mingcute:zoom-in-line />
|
||||
</ElButton>
|
||||
<ElButton @click="resetZoom">
|
||||
<icon-icon-park-outline:equal-ratio />
|
||||
</ElButton>
|
||||
<ElButton @click="fitZoom">
|
||||
<icon-gg:ratio />
|
||||
</ElButton>
|
||||
</ElButtonGroup>
|
||||
<div class="flex-center gap-12px">
|
||||
<ElPopover placement="bottom-end" :width="200" :animated="false">
|
||||
<template #reference>
|
||||
<ElButton size="small" class="bg-white!">
|
||||
<icon-fe:question />
|
||||
</ElButton>
|
||||
</template>
|
||||
<div class="flex-col gap-8px">
|
||||
<div span="2" class="text-12px font-bold">节点图例</div>
|
||||
<ElRow>
|
||||
<ElCol v-for="(config, status) in nodeStatus" :key="status" :span="12" class="mb-8px flex-center">
|
||||
<ElTag size="small" round :bordered="false">
|
||||
<template #default>
|
||||
<icon-f7:flag-circle-fill v-if="status === 'MILESTONE'" :style="{ color: config.color }" />
|
||||
<icon-f7:circle-fill v-else :style="{ color: config.color }" />
|
||||
{{ config.type }}
|
||||
</template>
|
||||
</ElTag>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</ElPopover>
|
||||
</div>
|
||||
</div>
|
||||
<!-- canvas container -->
|
||||
<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>
|
||||
170
src/views/plugin/charts/antv/modules/antv-g6-flow.ts
Normal file
170
src/views/plugin/charts/antv/modules/antv-g6-flow.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { Graph } from '@antv/g6';
|
||||
import type { CustomBehaviorOption, IPointerEvent } from '@antv/g6';
|
||||
import type { Canvas } from '@antv/g6/lib/runtime/canvas';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { getNodeIcon, nodeStatus } from './status';
|
||||
import type { CustomEdgeData, CustomGraphData, CustomNodeData } from './types';
|
||||
|
||||
interface AntFlowConfig {
|
||||
container: string | HTMLElement | Canvas;
|
||||
data: CustomGraphData;
|
||||
behaviors?: CustomBehaviorOption[];
|
||||
autoFit?: 'view' | 'center';
|
||||
}
|
||||
|
||||
export function useAntFlow(config: AntFlowConfig) {
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
const baseColor = 'rgb(158 163 171)';
|
||||
|
||||
const { container, autoFit = 'center', data, behaviors = [] } = config;
|
||||
|
||||
const graph = new Graph({
|
||||
container,
|
||||
animation: false,
|
||||
padding: 16,
|
||||
theme: 'light',
|
||||
autoFit,
|
||||
data,
|
||||
node: {
|
||||
type: 'rect',
|
||||
|
||||
style: (node: CustomNodeData) => {
|
||||
const iconS = getNodeIcon(node);
|
||||
let labelFill = '#000000';
|
||||
if (node.taskState === 'NOT_STARTED') {
|
||||
labelFill = '#787878';
|
||||
}
|
||||
|
||||
return {
|
||||
labelText: node.name as string,
|
||||
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: CustomNodeData) => ({
|
||||
halo: true,
|
||||
haloStroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor,
|
||||
haloLineWidth: 6,
|
||||
zIndex: 2
|
||||
})
|
||||
}
|
||||
},
|
||||
edge: {
|
||||
type: 'cubic-horizontal',
|
||||
style: (node: CustomEdgeData) => ({
|
||||
curveOffset: 10,
|
||||
curvePosition: 0.5,
|
||||
stroke: node.isDeleted ? themeStore.otherColor.error : baseColor,
|
||||
lineDash: node.isDeleted ? 4 : 0
|
||||
}),
|
||||
state: {
|
||||
active: (node: CustomEdgeData) => ({
|
||||
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',
|
||||
...behaviors
|
||||
],
|
||||
plugins: [
|
||||
{
|
||||
type: 'tooltip',
|
||||
enable: (event: IPointerEvent) => event.targetType === 'node',
|
||||
getContent: (_event: IPointerEvent, items?: CustomNodeData[]) => {
|
||||
let result = '<div style="display: flex; flex-direction: column; gap: 8px;">';
|
||||
|
||||
// 弹出提示可以自定义各种内容,但是这里很奇怪,有的class不跟随unocss的样式
|
||||
items?.forEach(item => {
|
||||
result += `
|
||||
<h3 style="display: flex; align-items: center; gap: 8px;">${item.name}</h3>
|
||||
<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>
|
||||
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; row-gap: 4px;">
|
||||
<div style="display: flex; flex-direction: column;"><div style="color: rgb(156 163 175);">预计开始</div>
|
||||
<div style="font-weight: 700;">${item.startDate || '-'}</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<div style="color: rgb(156 163 175);">预计结束</div>
|
||||
<div style="font-weight: 700;">${item.endDate || '-'}</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<div style="color: rgb(156 163 175);">实际开始</div>
|
||||
<div style="font-weight: 700;">${item.actualStartDate || '-'}</div>
|
||||
</div>
|
||||
<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>';
|
||||
return result;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
graph.render();
|
||||
|
||||
return { graph };
|
||||
}
|
||||
95
src/views/plugin/charts/antv/modules/status.ts
Normal file
95
src/views/plugin/charts/antv/modules/status.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { h } from 'vue';
|
||||
import { ElTag } from 'element-plus';
|
||||
import type { TagProps } from 'element-plus';
|
||||
import type { CustomNodeData, NodeStatus } from './types';
|
||||
|
||||
interface NodeStatusConfig {
|
||||
type: string;
|
||||
color: string;
|
||||
textColor: string;
|
||||
base64: string;
|
||||
flag64: string;
|
||||
}
|
||||
|
||||
export const nodeStatus: Record<NodeStatus, NodeStatusConfig> = {
|
||||
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: CustomNodeData) {
|
||||
if (!node.status) return '';
|
||||
|
||||
const type = node.milestone ? 'flag64' : 'base64';
|
||||
|
||||
return nodeStatus[node.status][type];
|
||||
}
|
||||
|
||||
export function getNodeStatusTag(state: NodeStatus, tagProperty?: TagProps) {
|
||||
const { color, type } = nodeStatus[state] || {};
|
||||
|
||||
return h(
|
||||
ElTag,
|
||||
{
|
||||
color,
|
||||
size: 'small',
|
||||
...tagProperty
|
||||
},
|
||||
{
|
||||
default: () => type
|
||||
}
|
||||
);
|
||||
}
|
||||
28
src/views/plugin/charts/antv/modules/types.ts
Normal file
28
src/views/plugin/charts/antv/modules/types.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { EdgeData, GraphData, NodeData } from '@antv/g6';
|
||||
|
||||
export type NodeStatus =
|
||||
| 'MILESTONE'
|
||||
| 'NOT_STARTED'
|
||||
| 'DELAYED'
|
||||
| 'PAUSED'
|
||||
| 'IN_PROGRESS'
|
||||
| 'COMPLETED'
|
||||
| 'COMPLETED_EARLY'
|
||||
| 'COMPLETED_LATE';
|
||||
|
||||
export interface CustomNodeData extends NodeData {
|
||||
isDelayed?: boolean;
|
||||
isDeleted?: boolean;
|
||||
milestone?: boolean;
|
||||
status?: NodeStatus;
|
||||
}
|
||||
|
||||
export interface CustomEdgeData extends EdgeData {
|
||||
isDelayed?: boolean;
|
||||
isDeleted?: boolean;
|
||||
}
|
||||
|
||||
export interface CustomGraphData extends GraphData {
|
||||
nodes: CustomNodeData[];
|
||||
edges: CustomEdgeData[];
|
||||
}
|
||||
Reference in New Issue
Block a user