PBI-Measure-CallGraph/templates/index.html
2025-03-21 16:11:03 +08:00

200 lines
8.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/dax-highlight.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 {
// 调用后端API进行格式化
const response = await fetch('/format_dax', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ daxCode: daxCode })
});
if (!response.ok) {
throw new Error('格式化请求失败');
}
const result = await response.json();
if (!result.success) {
throw new Error(result.message || '格式化失败');
}
// 处理新的格式化结果(带有标记类型的数组)
const formattedHtml = applyDaxSyntaxHighlighting(result.formattedTokens);
measureExpression.innerHTML = formattedHtml;
} catch (error) {
console.error('格式化DAX时出错:', error);
alert('格式化DAX时出错请检查网络连接或稍后重试');
}
}
// 将格式化的DAX标记转换为HTML并应用语法高亮
function applyDaxSyntaxHighlighting(formattedTokens) {
if (!formattedTokens || formattedTokens.length === 0) {
return '';
}
let html = '';
// 处理每一行的标记
formattedTokens.forEach(line => {
line.forEach(token => {
const text = token.string;
const type = token.type || 'Normal';
// 根据标记类型应用不同的CSS类
switch(type) {
case 'Keyword':
html += `<span class="dax-keyword">${escapeHtml(text)}</span>`;
break;
case 'Function':
html += `<span class="dax-function">${escapeHtml(text)}</span>`;
break;
case 'Parenthesis':
html += `<span class="dax-parenthesis">${escapeHtml(text)}</span>`;
break;
case 'Number':
html += `<span class="dax-number">${escapeHtml(text)}</span>`;
break;
case 'String':
html += `<span class="dax-string">${escapeHtml(text)}</span>`;
break;
default:
html += escapeHtml(text);
}
});
html += '\n'; // 添加换行
});
return html;
}
// 转义HTML特殊字符
function escapeHtml(text) {
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
</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>