This commit is contained in:
chenwu 2025-03-21 16:11:03 +08:00
parent f65ab820c1
commit c23b6ca0cb
7 changed files with 148 additions and 13 deletions

36
app.py
View File

@ -1,6 +1,7 @@
from flask import Flask, render_template, jsonify, request
import json
import os
import requests
from model_connector import ModelConnector
from dax_parser import DaxParser
@ -56,6 +57,41 @@ def get_call_graph():
except Exception as e:
return jsonify({'success': False, 'message': str(e)})
@app.route('/format_dax', methods=['POST'])
def format_dax():
"""Proxy for DAX formatter service."""
try:
dax_code = request.json.get('daxCode')
if not dax_code:
return jsonify({'success': False, 'message': 'No DAX code provided'})
# 调用新的DAX格式化API
payload = {
'dax': dax_code,
'callerApp': 'https://www.daxformatter.com/',
'callerVersion': '0.5.3',
'listSeparator': ',',
'decimalSeparator': '.',
'maxLineLength': 0
}
response = requests.post('https://daxformatter.azurewebsites.net/api/DaxTokenFormat/',
json=payload)
if response.status_code != 200:
return jsonify({'success': False, 'message': 'DAX formatting service error'})
# 解析返回的JSON
formatted_data = response.json()
# 检查是否有错误
if formatted_data.get('errors') and len(formatted_data['errors']) > 0:
return jsonify({'success': False, 'message': 'DAX formatting error: ' + str(formatted_data['errors'])})
return jsonify({'success': True, 'formattedTokens': formatted_data['formatted']})
except Exception as e:
return jsonify({'success': False, 'message': str(e)})
if __name__ == '__main__':
app.run(debug=True)

View File

@ -1,5 +1,5 @@
from sys import path
path.append('C:\\Users\\ChenwuServise\\OneDrive - AZCollaboration\\Desktop\\GIT\\PBI-Measure-CallGraph\\MSNET')
path.append('C:\\Users\\Chenw\\Documents\\Trae\\PBI-Measure-CallGraph\\MSNET')
import pyadomd
import pandas as pd

View File

@ -1,3 +1,5 @@
Flask==2.3.3
pyodbc==4.0.39
pandas==2.2.3
requests==2.31.0
beautifulsoup4==4.12.2

View File

@ -0,0 +1,41 @@
/* DAX语法高亮样式 */
#measure-expression {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background-color: #f8f8f8;
padding: 10px;
border-radius: 4px;
overflow: auto;
line-height: 1.5;
white-space: pre-wrap;
}
/* 关键字 */
.dax-keyword {
color: #0000ff;
font-weight: bold;
}
/* 函数 */
.dax-function {
color: #795e26;
}
/* 括号 */
.dax-parenthesis {
color: #000000;
}
/* 数字 */
.dax-number {
color: #098658;
}
/* 字符串 */
.dax-string {
color: #a31515;
}
/* 普通文本 */
.dax-normal {
color: #000000;
}

View File

@ -5,6 +5,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>
@ -13,31 +15,85 @@
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', {
// 调用后端API进行格式化
const response = await fetch('/format_dax', {
method: 'POST',
body: formData
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ daxCode: daxCode })
});
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;
const result = await response.json();
measureExpression.textContent = formattedDax;
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>