Browse Source

数据标准图谱展示

master
siyaqi 3 weeks ago
parent
commit
40a0307309
  1. 15
      vue-fastapi-backend/module_admin/controller/datastd_controller.py
  2. 12
      vue-fastapi-backend/module_admin/dao/datastd_dao.py
  3. 80
      vue-fastapi-backend/module_admin/service/datastd_service.py
  4. 1
      vue-fastapi-frontend/package.json
  5. 7
      vue-fastapi-frontend/src/api/datastd/std.js
  6. 152
      vue-fastapi-frontend/src/views/datastd/stdcode/codeStdMap.vue
  7. 15
      vue-fastapi-frontend/src/views/datastd/stdcode/index.vue
  8. 564
      vue-fastapi-frontend/src/views/datastd/stdcode/treeNodeg6.vue

15
vue-fastapi-backend/module_admin/controller/datastd_controller.py

@ -466,4 +466,17 @@ async def change_std_main_onum(
):
delete_std_main_result = await DataStdService.change_std_main_onum(query_db, edit_std_main.id,edit_std_main.sys_id)
logger.info(delete_std_main_result.message)
return ResponseUtil.success(msg=delete_std_main_result.message)
return ResponseUtil.success(msg=delete_std_main_result.message)
# 标准代码映射图谱
@datastdController.get(
'/stdcode/code/mapstdlist/{id}', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('datastd:stdcode:code:list'))]
)
async def get_code_std_map_list(
request: Request,
id: str,
query_db: AsyncSession = Depends(get_db),
):
code_page_query_result = await DataStdService.get_code_std_map_list_services(query_db, id)
logger.info('获取列配置列表成功')
return ResponseUtil.success(data=code_page_query_result)

12
vue-fastapi-backend/module_admin/dao/datastd_dao.py

@ -254,7 +254,13 @@ class DataStdDao:
@classmethod
async def delete_std_dict(cls, db: AsyncSession, Id: str):
await db.execute(delete(DataStdDict).where(DataStdDict.id == Id))
@classmethod
async def get_std_dict_list_all(cls, db: AsyncSession, query_object: DataStdDict):
filters = []
if query_object.std_code:
filters.append(DataStdDict.std_code.like(f"%{query_object.std_code}%"))
query = select(DataStdDict).where(*filters).order_by(desc(DataStdDict.create_time))
return await PageUtil.paginate(db, query, 0, 0, False)
@classmethod
async def update_std_dict(cls, db: AsyncSession, update_data: DataStdDictModel):
@ -279,6 +285,7 @@ class DataStdDao:
DataStdDict.dict_name == query_object.dict_name if query_object.dict_name else True,
DataStdDict.dict_num == query_object.dict_num if query_object.dict_num else True,
DataStdDict.dict_status == query_object.dict_status if query_object.dict_status else True,
DataStdDict.std_code == query_object.std_code if query_object.std_code else True,
DataStdDict.sys_id == query_object.sys_id if query_object.sys_id else True,
DataStdDict.dict_type == query_object.dict_type if query_object.dict_type else True,
)
@ -684,6 +691,8 @@ class DataStdDao:
filters.append(DataStdMain.std_code.like(f"%{query_object.std_code}%"))
if query_object.sys_id:
filters.append(DataStdMain.sys_id == query_object.sys_id)
if query_object.code_id:
filters.append(DataStdMain.code_id == query_object.code_id)
if query_object.std_type:
filters.append(DataStdMain.std_type == query_object.std_type)
if query_object.std_status:
@ -720,6 +729,7 @@ class DataStdDao:
DataStdMain.std_num == query_object.std_num if query_object.std_num else True,
DataStdMain.sys_id == query_object.sys_id if query_object.sys_id else True,
DataStdMain.std_type == query_object.std_type if query_object.std_type else True,
DataStdMain.code_id == query_object.code_id if query_object.code_id else True,
DataStdMain.std_status == query_object.std_status if query_object.std_status else True
)
)

80
vue-fastapi-backend/module_admin/service/datastd_service.py

@ -833,4 +833,82 @@ class DataStdService:
await query_db.rollback()
raise e
else:
raise ServiceException(message='传入标准ID为空')
raise ServiceException(message='传入标准ID为空')
@classmethod
async def get_code_std_map_list_services(cls, query_db: AsyncSession, id: str):
# 查询 A 表(t_datastd_main)
check_model = DataStdMainModel()
check_model.code_id = id
main_list = await DataStdDao.get_std_main_list_all(query_db, check_model)
stdCode=await DataStdDao.get_std_code_by_id(query_db, id)
if not main_list:
return {"tableData": [], "children": []} # 如果 A 表没有数据,返回空结构
table_data = [] # 存储表格数据
children = [] # 存储图谱数据
for main in main_list:
# 查询 B 表(t_datastd_dict),通过 A 表的 id 匹配 std_code
dict_model = DataStdDictModel()
dict_model.std_code = main.get('id') # 使用 get() 方法访问字段
dict_list = await DataStdDao.get_std_dict_list_all(query_db, dict_model)
# 组织表格数据
if dict_list:
for dict_item in dict_list:
table_data.append({
"codeNum": stdCode.code_num, # 使用 get() 方法访问字段
"codeName": stdCode.code_name, # 使用 get() 方法访问字段
"stdNum": main.get('stdNum'), # 使用 get() 方法访问字段
"stdName": main.get('stdName'), # 使用 get() 方法访问字段
"stdCode": main.get('stdCode'), # 使用 get() 方法访问字段
"dictNum": dict_item.get('dictNum'), # 使用 get() 方法访问字段
"dictName": dict_item.get('dictName'), # 使用 get() 方法访问字段
"dictCode": dict_item.get('dictCode'), # 使用 get() 方法访问字段
})
else :
table_data.append({
"codeNum": stdCode.code_num, # 使用 get() 方法访问字段
"codeName": stdCode.code_name, # 使用 get() 方法访问字段
"stdNum": main.get('stdNum'), # 使用 get() 方法访问字段
"stdName": main.get('stdName'), # 使用 get() 方法访问字段
"stdCode": main.get('stdCode'), # 使用 get() 方法访问字段
"dictNum": "", # 使用 get() 方法访问字段
"dictName":"", # 使用 get() 方法访问字段
"dictCode": "", # 使用 get() 方法访问字段
})
# 组织图谱数据(A 表作为父节点)
node = {
"id": f"node_{main.get('id')}", # 使用 get() 方法访问字段
"name": main.get('stdName'), # 使用 get() 方法访问字段
"label": main.get('stdCode'), # 使用 get() 方法访问字段
"rate": 1.0,
"status": "B",
"currency": main.get('stdNum'), # 使用 get() 方法访问字段
"variableValue": "标准",
"variableUp": True,
"children": [],
}
# B 表数据作为子节点
for dict_item in dict_list:
node["children"].append({
"id": f"dict_{dict_item.get('id')}", # 使用 get() 方法访问字段
"name": dict_item.get('dictName'), # 使用 get() 方法访问字段
"label": dict_item.get('dictCode'), # 使用 get() 方法访问字段
"rate": 1.0,
"status": "R",
"currency": dict_item.get('dictNum'), # 使用 get() 方法访问字段
"variableValue": "词典",
"variableUp": True,
})
children.append(node)
return {
"tableData": table_data,
"children": children
}

1
vue-fastapi-frontend/package.json

@ -34,6 +34,7 @@
"element-plus": "2.8.0",
"file-saver": "2.0.5",
"fuse.js": "6.6.2",
"insert-css": "^2.0.0",
"js-cookie": "3.0.5",
"js-md5": "^0.8.3",
"jsencrypt": "3.3.2",

7
vue-fastapi-frontend/src/api/datastd/std.js

@ -47,6 +47,13 @@ export function getStdCodeItem(rowId) {
method: 'get'
})
}
// 查询标准代码项详情
export function getStdCodeMap(rowId) {
return request({
url: '/default-api/datastd/stdcode/code/mapstdlist/' + parseStrEmpty(rowId),
method: 'get'
})
}
// 新增标准代码
export function addStdCode(data) {

152
vue-fastapi-frontend/src/views/datastd/stdcode/codeStdMap.vue

@ -0,0 +1,152 @@
<template>
<el-tabs v-model="activeName" style="margin-top: 8px">
<el-tab-pane label="图谱" name="1">
<treeNodeg6 ref="treeGraph" :mockData="mockData" />
</el-tab-pane>
<el-tab-pane label="表格" name="2">
<el-table
v-loading="loading"
:data="tableData"
@selection-change="handleSelectionChange"
border
style="width: 100%"
>
<el-table-column label="代码编号" align="center" prop="codeNum" />
<el-table-column label="代码名称" align="center" prop="codeName" />
<el-table-column label="引用标准编号" align="center" prop="stdNum" />
<el-table-column label="引用标准英文名" align="center" prop="stdCode" />
<el-table-column label="引用标准中文名" align="center" prop="stdName" />
<el-table-column label="引用字典编号" align="center" prop="dictNum" />
<el-table-column label="引用字典英文名" align="center" prop="dictCode" />
<el-table-column label="引用字典中文名" align="center" prop="dictName" />
</el-table>
</el-tab-pane>
</el-tabs>
</template>
<script setup>
import { ref, onMounted, nextTick } from "vue";
import { getStdCodeMap } from "@/api/datastd/std";
import treeNodeg6 from "./treeNodeg6.vue";
const activeName = ref("1"); //
const treeGraph = ref(null);
const tableData = ref([]);
const selections = ref([]);
const loading = ref(false);
const props = defineProps({
rowData: {
type: Object,
required: false
}
});
// mocked data
const mockData = ref({
id: "g1",
name: props.rowData.codeName,
count: 123456,
label: props.rowData.codeNum,
rate: 1.0,
status: "G",
variableValue: "代码",
variableUp: true,
children:[]
// children: [
// {
// id: "g12",
// name: "",
// count: 123456,
// label: "iss_ins_type",
// rate: 1.0,
// status: "R",
// currency: "xx001",
// variableValue: "",
// variableUp: true,
// children: [
// {
// id: "g121",
// name: "",
// collapsed: true,
// count: 123456,
// label: "iss_ins_type",
// rate: 1.0,
// status: "B",
// currency: "xx002",
// variableValue: "",
// variableUp: true,
// },
// ],
// },
// {
// id: "g13",
// name: "",
// label: "issr_no",
// rate: 1,
// status: "R",
// currency: "xx002",
// variableValue: "",
// variableUp: true,
// },
// ],
});
//
const getList = async () => {
loading.value = true;
try {
const response = await listStdCodemap();
tableData.value = response.rows || [];
} finally {
loading.value = false;
}
};
const handleSelectionChange = (selection) => {
selections.value = selection;
};
//
onMounted(() => {
nextTick(() => {
getStdCodeMap(props.rowData.id).then(response => {
mockData.value.children = response.data.children;
tableData.value = response.data.tableData;
if (treeGraph.value) {
treeGraph.value.refreshGraph();
}
});
});
});
</script>
<style scoped>
.app-container {
padding: 20px;
}
.query-form-container {
margin-bottom: 20px;
}
.el-table .el-input {
width: 100%;
}
.form-container {
margin-bottom: 20px;
}
.info-text {
font-size: 18px;
line-height: 1.6;
color: #333;
font-weight: 500;
display: inline-block;
width: 100%;
}
</style>

15
vue-fastapi-frontend/src/views/datastd/stdcode/index.vue

@ -110,7 +110,7 @@
<el-link
type="primary"
:underline="true"
@click="handleCodeClick(scope.row)"
@click="handleMapCodeStdClick(scope.row)"
style="cursor: pointer"
>
查看
@ -164,6 +164,11 @@
<code-map ref="showMapCodeDialog" v-if="mapVisible" :codeId="codeMapId"/>
</el-dialog>
<el-dialog v-model="mapStdVisible" width="1200px">
<!-- 引入第三个页面组件 -->
<code-std-map ref="showMapCodeStdDialog" :rowData="selectedRow" v-if="mapStdVisible" />
</el-dialog>
</div>
</template>
@ -175,7 +180,7 @@ import { ElLink } from 'element-plus';
import CodeItem from './codeItem.vue'; //
import codeItemCommon from './codeItemCommon.vue'; //
import codeMap from './codeMap'; //
import codeStdMap from './codeStdMap.vue';
const { proxy } = getCurrentInstance();
const { std_code_status,std_code_appr } = proxy.useDict("std_code_status","std_code_appr");
@ -245,6 +250,7 @@ const getList = async () => {
};
const codeVisible = ref(false);
const mapVisible = ref(false);
const mapStdVisible = ref(false);
const codeMapId = ref(null);
//
@ -257,6 +263,11 @@ const handleMapCodeClick = (row) => {
codeMapId.value=row.id
mapVisible.value = true;
};
const handleMapCodeStdClick = (row) => {
selectedRow.value=row
mapStdVisible.value = true;
};
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);

564
vue-fastapi-frontend/src/views/datastd/stdcode/treeNodeg6.vue

@ -0,0 +1,564 @@
<template>
<div>
<div ref="container" id="container" class="graph-container"></div>
</div>
</template>
<script>
import { onMounted, ref } from 'vue';
import G6 from '@antv/g6';
import insertCss from 'insert-css';
insertCss(`
.g6-component-tooltip {
background-color: rgba(0,0,0, 0.65);
padding: 10px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
width: fit-content;
color: #fff;
border-radius = 4px;
}
`);
// mocked data
// const mockData = {
// id: 'g1',
// name: '',
// count: 123456,
// label: 'SYS049',
// // currency: '',
// rate: 1.0,
// status: 'G',
// // variableName: 'V1',
// variableValue:'',
// variableUp: true,
// children: [
// {
// id: 'g12',
// name: '',
// count: 123456,
// label: 'iss_ins_type',
// rate: 1.0,
// status: 'R',
// currency: 'xx001',
// // variableName: 'V2',
// variableValue:'',
// variableUp: true,
// children: [
// {
// id: 'g121',
// name: '',
// collapsed: true,
// count: 123456,
// label: 'iss_ins_type',
// rate: 1.0,
// status: 'B',
// currency: 'xx002',
// variableValue:'',
// variableUp: true,
// },
// ],
// },
// {
// id: 'g13',
// name: '',
// label: 'issr_no',
// rate: 1,
// status: 'R',
// currency: 'xx002',
// // variableName: '',
// variableValue:'',
// variableUp: true,
// }
// ],
// };
const colors = {
B: '#5B8FF9',
R: '#F46649',
Y: '#EEBC20',
G: '#5BD8A6',
DI: '#A7A7A7',
};
export default {
name: 'G6TreeGraph',
props: {
// prop mockData
mockData: {
type: Object,
required: true,
},
},
setup(props) {
const container = ref(null);
let graph = null;
// // props
const propsConfig = {
data: props.mockData,
config: {
padding: [20, 50],
defaultLevel: 3,
defaultZoom: 0.8,
modes: { default: ['zoom-canvas', 'drag-canvas'] },
},
};
console.log(props.mockData,"mockDatamockDatamockData")
//
const registerFn = () => {
/** 自定义节点 **/
G6.registerNode(
'flow-rect',
{
shapeType: 'flow-rect',
draw(cfg, group) {
const {
name = '',
variableName,
variableValue,
variableUp,
label,
collapsed,
currency,
status,
rate,
} = cfg;
const grey = '#CED4D9';
const rectConfig = {
width: 202,
height: 60,
lineWidth: 1,
fontSize: 12,
fill: '#fff',
radius: 4,
stroke: grey,
opacity: 1,
};
const nodeOrigin = {
x: -rectConfig.width / 2,
y: -rectConfig.height / 2,
};
const textConfig = {
textAlign: 'left',
textBaseline: 'bottom',
};
const rect = group.addShape('rect', {
attrs: {
x: nodeOrigin.x,
y: nodeOrigin.y,
...rectConfig,
},
});
const rectBBox = rect.getBBox();
// label title
group.addShape('text', {
attrs: {
...textConfig,
x: 12 + nodeOrigin.x,
y: 20 + nodeOrigin.y,
text: name.length > 28 ? name.substr(0, 28) + '...' : name,
fontSize: 12,
opacity: 0.85,
fill: '#000',
cursor: 'pointer',
},
name: 'name-shape',
});
// price
const price = group.addShape('text', {
attrs: {
...textConfig,
x: 12 + nodeOrigin.x,
y: rectBBox.maxY - 12,
text: label,
fontSize: 16,
fill: '#000',
opacity: 0.85,
},
});
// label currency
group.addShape('text', {
attrs: {
...textConfig,
x: price.getBBox().maxX + 5,
y: rectBBox.maxY - 12,
text: currency,
fontSize: 12,
fill: '#000',
opacity: 0.75,
},
});
// percentage
const percentText = group.addShape('text', {
attrs: {
...textConfig,
x: rectBBox.maxX - 8,
y: rectBBox.maxY - 12,
// text: `${((variableValue || 0) * 100).toFixed(2)}%`,
text: variableValue,
fontSize: 12,
textAlign: 'right',
fill: colors[status],
},
});
// percentage triangle
const symbol = variableUp ? 'triangle' : 'triangle-down';
const triangle = group.addShape('marker', {
attrs: {
...textConfig,
x: percentText.getBBox().minX - 10,
y: rectBBox.maxY - 12 - 6,
symbol,
r: 6,
fill: colors[status],
},
});
// variable name
group.addShape('text', {
attrs: {
...textConfig,
x: triangle.getBBox().minX - 4,
y: rectBBox.maxY - 12,
text: variableName,
fontSize: 12,
textAlign: 'right',
fill: '#000',
opacity: 0.45,
},
});
// bottom line background
group.addShape('rect', {
attrs: {
x: nodeOrigin.x,
y: rectBBox.maxY - 4,
width: rectConfig.width,
height: 4,
radius: [0, 0, rectConfig.radius, rectConfig.radius],
fill: '#E0DFE3',
},
});
// bottom percent
group.addShape('rect', {
attrs: {
x: nodeOrigin.x,
y: rectBBox.maxY - 4,
width: rate * rectBBox.width,
height: 4,
radius: [0, 0, 0, rectConfig.radius],
fill: colors[status],
},
});
// collapse rect
if (cfg.children && cfg.children.length) {
group.addShape('rect', {
attrs: {
x: rectConfig.width / 2 - 8,
y: -8,
width: 16,
height: 16,
stroke: 'rgba(0, 0, 0, 0.25)',
cursor: 'pointer',
fill: '#fff',
},
name: 'collapse-back',
modelId: cfg.id,
});
// collapse text
group.addShape('text', {
attrs: {
x: rectConfig.width / 2,
y: -1,
textAlign: 'center',
textBaseline: 'middle',
text: collapsed ? '+' : '-',
fontSize: 16,
cursor: 'pointer',
fill: 'rgba(0, 0, 0, 0.25)',
},
name: 'collapse-text',
modelId: cfg.id,
});
}
this.drawLinkPoints(cfg, group);
return rect;
},
update(cfg, item) {
const { level, status, name } = cfg;
const group = item.getContainer();
let mask = group.find((ele) => ele.get('name') === 'mask-shape');
let maskLabel = group.find((ele) => ele.get('name') === 'mask-label-shape');
if (level === 0) {
group.get('children').forEach((child) => {
if (child.get('name')?.includes('collapse')) return;
child.hide();
});
if (!mask) {
mask = group.addShape('rect', {
attrs: {
x: -101,
y: -30,
width: 202,
height: 60,
opacity: 0,
fill: colors[status],
},
name: 'mask-shape',
});
maskLabel = group.addShape('text', {
attrs: {
fill: '#fff',
fontSize: 20,
x: 0,
y: 10,
text: name.length > 28 ? name.substr(0, 16) + '...' : name,
textAlign: 'center',
opacity: 0,
},
name: 'mask-label-shape',
});
const collapseRect = group.find((ele) => ele.get('name') === 'collapse-back');
const collapseText = group.find((ele) => ele.get('name') === 'collapse-text');
collapseRect?.toFront();
collapseText?.toFront();
} else {
mask.show();
maskLabel.show();
}
mask.animate({ opacity: 1 }, 200);
maskLabel.animate({ opacity: 1 }, 200);
return mask;
} else {
group.get('children').forEach((child) => {
if (child.get('name')?.includes('collapse')) return;
child.show();
});
mask?.animate({ opacity: 0 }, {
duration: 200,
callback: () => mask.hide(),
});
maskLabel?.animate({ opacity: 0 }, {
duration: 200,
callback: () => maskLabel.hide(),
});
}
this.updateLinkPoints(cfg, group);
},
setState(name, value, item) {
if (name === 'collapse') {
const group = item.getContainer();
const collapseText = group.find((e) => e.get('name') === 'collapse-text');
if (collapseText) {
if (!value) {
collapseText.attr({ text: '-' });
} else {
collapseText.attr({ text: '+' });
}
}
}
},
getAnchorPoints() {
return [
[0, 0.5],
[1, 0.5],
];
},
},
'rect'
);
G6.registerEdge(
'flow-cubic',
{
getControlPoints(cfg) {
let controlPoints = cfg.controlPoints;
if (!controlPoints || !controlPoints.length) {
const { startPoint, endPoint, sourceNode, targetNode } = cfg;
const { x: startX, y: startY, coefficientX, coefficientY } = sourceNode
? sourceNode.getModel()
: startPoint;
const { x: endX, y: endY } = targetNode ? targetNode.getModel() : endPoint;
let curveStart = (endX - startX) * coefficientX;
let curveEnd = (endY - startY) * coefficientY;
curveStart = curveStart > 40 ? 40 : curveStart;
curveEnd = curveEnd < -30 ? curveEnd : -30;
controlPoints = [
{ x: startPoint.x + curveStart, y: startPoint.y },
{ x: endPoint.x + curveEnd, y: endPoint.y },
];
}
return controlPoints;
},
getPath(points) {
const path = [];
path.push(['M', points[0].x, points[0].y]);
path.push([
'C',
points[1].x,
points[1].y,
points[2].x,
points[2].y,
points[3].x,
points[3].y,
]);
return path;
},
},
'single-line'
);
};
//
const initGraph = (data) => {
if (!data) {
return;
}
const { onInit, config } = propsConfig;
const tooltip = new G6.Tooltip({
offsetX: 20,
offsetY: 30,
itemTypes: ['node'],
getContent: (e) => {
const outDiv = document.createElement('div');
const nodeName = e.item.getModel().name;
let formatedNodeName = '';
for (let i = 0; i < nodeName.length; i++) {
formatedNodeName = `${formatedNodeName}${nodeName[i]}`;
if (i !== 0 && i % 20 === 0)
formatedNodeName = `${formatedNodeName}<br/>`;
}
outDiv.innerHTML = `${formatedNodeName}`;
return outDiv;
},
shouldBegin: (e) => {
if (
e.target.get('name') === 'name-shape' ||
e.target.get('name') === 'mask-label-shape'
)
return true;
return false;
},
});
graph = new G6.TreeGraph({
container: container.value,
...defaultConfig(),
...config,
plugins: [tooltip],
});
if (typeof onInit === 'function') {
onInit(graph);
}
graph.data(data);
graph.render();
const handleCollapse = (e) => {
const target = e.target;
const id = target.get('modelId');
const item = graph.findById(id);
const nodeModel = item.getModel();
nodeModel.collapsed = !nodeModel.collapsed;
graph.layout();
graph.setItemState(item, 'collapse', nodeModel.collapsed);
};
graph.on('collapse-text:click', (e) => {
handleCollapse(e);
});
graph.on('collapse-back:click', (e) => {
handleCollapse(e);
});
let currentLevel = 1;
const briefZoomThreshold = Math.max(graph.getZoom(), 0.5);
graph.on('viewportchange', (e) => {
if (e.action !== 'zoom') return;
const currentZoom = graph.getZoom();
let toLevel = currentLevel;
if (currentZoom < briefZoomThreshold) {
toLevel = 0;
} else {
toLevel = 1;
}
if (toLevel !== currentLevel) {
currentLevel = toLevel;
graph.getNodes().forEach((node) => {
graph.updateItem(node, { level: toLevel });
});
}
});
};
// container
const defaultConfig = () => {
const width = container.value.scrollWidth;
const height = container.value.scrollHeight || 500;
return {
width,
height,
modes: {
default: ['zoom-canvas', 'drag-canvas'],
},
fitView: true,
animate: true,
defaultNode: {
type: 'flow-rect',
},
defaultEdge: {
type: 'cubic-horizontal',
style: {
stroke: '#CED4D9',
},
},
layout: {
type: 'indented',
direction: 'LR',
dropCap: false,
indent: 300,
getHeight: () => 60,
},
};
};
const refreshGraph = () => {
nextTick(() => {
registerFn();
initGraph(propsConfig.data);
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!container.value || !container.value.scrollWidth || !container.value.scrollHeight)
return;
graph.changeSize(container.value.scrollWidth, container.value.scrollHeight);
}
});
};
return { container ,refreshGraph };
},
};
</script>
<style scoped>
.graph-container {
width: 100%;
height: 600px;
/* border: 1px solid #ddd; */
}
</style>
Loading…
Cancel
Save