144 lines
6.6 KiB
HTML
144 lines
6.6 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Power BI Measure Call Graph</title>
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||
<!-- D3.js for visualization -->
|
||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||
<script>
|
||
async function formatDAX() {
|
||
const measureExpression = document.getElementById('measure-expression');
|
||
const daxCode = measureExpression.textContent;
|
||
|
||
try {
|
||
const formData = new FormData();
|
||
formData.append('fx', daxCode);
|
||
formData.append('r', 'US');
|
||
|
||
const response = await fetch('https://www.daxformatter.com', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error('格式化请求失败');
|
||
}
|
||
|
||
const result = await response.text();
|
||
// 解析返回的HTML,提取格式化后的DAX代码
|
||
const parser = new DOMParser();
|
||
const doc = parser.parseFromString(result, 'text/html');
|
||
const formattedDax = doc.querySelector('#formatted-dax').textContent;
|
||
|
||
measureExpression.textContent = formattedDax;
|
||
} catch (error) {
|
||
console.error('格式化DAX时出错:', error);
|
||
alert('格式化DAX时出错,请检查网络连接或稍后重试');
|
||
}
|
||
}
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<header>
|
||
<h1>Power BI Measure Call Graph</h1>
|
||
</header>
|
||
|
||
<div class="connection-panel">
|
||
<h2>Connect to Analysis Services</h2>
|
||
<div class="connection-form">
|
||
<div class="form-group">
|
||
<label for="server">Server:</label>
|
||
<input type="text" id="server" placeholder="localhost">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="database">Database:</label>
|
||
<input type="text" id="database" placeholder="AdventureWorks">
|
||
</div>
|
||
</div>
|
||
<button id="connect-btn">Connect</button>
|
||
<div id="connection-status"></div>
|
||
</div>
|
||
|
||
<div class="main-content">
|
||
<div class="visualization-container">
|
||
<div class="controls">
|
||
<button id="reset-btn">Reset View</button>
|
||
<div class="search-box">
|
||
<input type="text" id="search-input" placeholder="search...">
|
||
<div id="search-results" class="search-results"></div>
|
||
</div>
|
||
</div>
|
||
<div id="graph-container"></div>
|
||
<div id="graph-container-detail">
|
||
<h3>Selected Measure Details</h3>
|
||
<button id="reset-detail-btn" class="reset-btn" title="Reset view">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0z"></path>
|
||
<path d="M17 12H7"></path>
|
||
<path d="M12 17V7"></path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
setTimeout(function() {
|
||
const resetDetailBtn = document.getElementById('reset-detail-btn');
|
||
if (resetDetailBtn) {
|
||
resetDetailBtn.click();
|
||
}
|
||
}, 800);
|
||
|
||
// 添加一个MutationObserver来监视图表内容变化
|
||
const detailContainer = document.getElementById('graph-container-detail');
|
||
if (detailContainer) {
|
||
const observer = new MutationObserver(function(mutations) {
|
||
const hasContentChanges = mutations.some(mutation =>
|
||
mutation.type === 'childList' &&
|
||
(mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)
|
||
);
|
||
|
||
if (hasContentChanges) {
|
||
setTimeout(function() {
|
||
const resetDetailBtn = document.getElementById('reset-detail-btn');
|
||
if (resetDetailBtn) {
|
||
resetDetailBtn.click();
|
||
}
|
||
}, 500);
|
||
}
|
||
});
|
||
|
||
observer.observe(detailContainer, {
|
||
childList: true,
|
||
subtree: true
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
</div>
|
||
<div class="resize-handle"></div>
|
||
<div class="measure-details">
|
||
<h2>Measure Details</h2>
|
||
<div id="measure-name"></div>
|
||
<div class="measure-controls">
|
||
<button id="format-btn" class="format-btn" onclick="formatDAX()">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
|
||
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
|
||
</svg>
|
||
格式化 DAX
|
||
</button>
|
||
</div>
|
||
<pre id="measure-expression"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="{{ url_for('static', filename='js/graph.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='js/resize.js') }}"></script>
|
||
</body>
|
||
</html>
|