mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-09 03:22:51 +08:00
fix(debug): 修复预览不实时更新、出错位置不生效、中文Unicode转义等问题,预览改为右侧弹出面板,增加字数统计
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -48,4 +48,5 @@ extend/base/common/command/curd/migrate_output.php
|
|||||||
/source/**/.vscode
|
/source/**/.vscode
|
||||||
.trae/documents/
|
.trae/documents/
|
||||||
/docker-dev/
|
/docker-dev/
|
||||||
/.sisyphus
|
/.sisyphus
|
||||||
|
/.omo
|
||||||
@@ -322,6 +322,13 @@ if (!function_exists('echo_value')) {
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
#char-count {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
min-width: 40px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: Consolas, monospace;
|
||||||
|
}
|
||||||
#debug-toolbar .toolbar-group label {
|
#debug-toolbar .toolbar-group label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -372,25 +379,55 @@ if (!function_exists('echo_value')) {
|
|||||||
}
|
}
|
||||||
#markdown-preview {
|
#markdown-preview {
|
||||||
display: none;
|
display: none;
|
||||||
padding: 20px;
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 45%;
|
||||||
|
height: 100%;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
position: relative;
|
border-left: 1px solid #ddd;
|
||||||
margin-top: 20px;
|
box-shadow: -4px 0 16px rgba(0,0,0,0.12);
|
||||||
border: 1px solid #ddd;
|
z-index: 99998;
|
||||||
border-radius: 4px;
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#markdown-preview .preview-header {
|
||||||
|
padding: 12px 20px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
#markdown-preview .preview-header .close-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #999;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0 4px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
#markdown-preview .preview-header .close-btn:hover {
|
||||||
|
color: #333;
|
||||||
}
|
}
|
||||||
#markdown-preview pre {
|
#markdown-preview pre {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
background: #f8f9fa;
|
background: #fff;
|
||||||
padding: 15px;
|
padding: 20px;
|
||||||
border-radius: 4px;
|
margin: 0;
|
||||||
border: 1px solid #e8e8e8;
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
color: #333;
|
color: #333;
|
||||||
max-height: 600px;
|
height: calc(100% - 49px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -517,6 +554,7 @@ if (!function_exists('echo_value')) {
|
|||||||
<label data-dynamic="env" data-env-key="Server/Request Data"><input type="checkbox" data-key="env_server"> Server</label>
|
<label data-dynamic="env" data-env-key="Server/Request Data"><input type="checkbox" data-key="env_server"> Server</label>
|
||||||
</span>
|
</span>
|
||||||
<span class="toolbar-group">
|
<span class="toolbar-group">
|
||||||
|
<span id="char-count" title="当前选中内容的字符数">0字</span>
|
||||||
<button id="btn-copy" onclick="copyToClipboard()">复制给AI</button>
|
<button id="btn-copy" onclick="copyToClipboard()">复制给AI</button>
|
||||||
<button id="btn-preview" onclick="togglePreview()">预览</button>
|
<button id="btn-preview" onclick="togglePreview()">预览</button>
|
||||||
<button id="btn-path" onclick="togglePathMode()">路径:简略</button>
|
<button id="btn-path" onclick="togglePathMode()">路径:简略</button>
|
||||||
@@ -526,8 +564,12 @@ if (!function_exists('echo_value')) {
|
|||||||
<!-- Hidden root path -->
|
<!-- Hidden root path -->
|
||||||
<div id="root-path" style="display:none;"><?php echo \think\facade\App::getRootPath(); ?></div>
|
<div id="root-path" style="display:none;"><?php echo \think\facade\App::getRootPath(); ?></div>
|
||||||
|
|
||||||
<!-- Markdown Preview -->
|
<!-- Markdown Preview (right-side slide-out panel) -->
|
||||||
<div id="markdown-preview">
|
<div id="markdown-preview">
|
||||||
|
<div class="preview-header">
|
||||||
|
<span>Markdown Preview</span>
|
||||||
|
<button class="close-btn" onclick="togglePreview()">×</button>
|
||||||
|
</div>
|
||||||
<pre id="markdown-content"></pre>
|
<pre id="markdown-content"></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -634,21 +676,24 @@ if (!function_exists('echo_value')) {
|
|||||||
<?php
|
<?php
|
||||||
// Message
|
// Message
|
||||||
if (isset($message)) {
|
if (isset($message)) {
|
||||||
$md = "# \u7cfb\u7edf\u53d1\u751f\u9519\u8bef\n\n## \u9519\u8bef\u4fe1\u606f\n> " . strip_tags((string)$message) . "\n\n";
|
$md = "# 系统发生错误\n\n## 错误信息\n> " . strip_tags((string)$message) . "\n\n";
|
||||||
echo 'mdFragments.message = ' . json_encode($md, JSON_UNESCAPED_UNICODE) . ";\n";
|
echo 'mdFragments.message = ' . json_encode($md, JSON_UNESCAPED_UNICODE) . ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Location
|
// Location (from first trace)
|
||||||
if (isset($file) && isset($line)) {
|
if (isset($traces) && is_array($traces) && !empty($traces)) {
|
||||||
$fileEscaped = str_replace('\\', '\\\\', $file);
|
$firstTrace = $traces[0];
|
||||||
$md = "## \u51fa\u9519\u4f4d\u7f6e\n- **File:** `{$fileEscaped}`\n- **Line:** `{$line}`\n\n";
|
if (isset($firstTrace['file']) && isset($firstTrace['line'])) {
|
||||||
echo 'mdFragments.location = ' . json_encode($md, JSON_UNESCAPED_UNICODE) . ";\n";
|
$fileEscaped = str_replace('\\', '\\\\', $firstTrace['file']);
|
||||||
|
$md = "## 出错位置\n- **File:** `{$fileEscaped}`\n- **Line:** `{$firstTrace['line']}`\n\n";
|
||||||
|
echo 'mdFragments.location = ' . json_encode($md, JSON_UNESCAPED_UNICODE) . ";\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call Stack (per trace)
|
// Call Stack (per trace)
|
||||||
if (isset($traces) && is_array($traces)) {
|
if (isset($traces) && is_array($traces)) {
|
||||||
foreach ($traces as $index => $trace) {
|
foreach ($traces as $index => $trace) {
|
||||||
$md = "## \u5f02\u5e38 #{$index}\n";
|
$md = "## 异常 #{$index}\n";
|
||||||
if (isset($trace['message'])) {
|
if (isset($trace['message'])) {
|
||||||
$md .= "**Message:** " . strip_tags($trace['message']) . "\n\n";
|
$md .= "**Message:** " . strip_tags($trace['message']) . "\n\n";
|
||||||
}
|
}
|
||||||
@@ -656,12 +701,12 @@ if (isset($traces) && is_array($traces)) {
|
|||||||
$md .= "**Location:** `{$trace['file']}` : {$trace['line']}\n\n";
|
$md .= "**Location:** `{$trace['file']}` : {$trace['line']}\n\n";
|
||||||
}
|
}
|
||||||
if (!empty($trace['trace'])) {
|
if (!empty($trace['trace'])) {
|
||||||
$md .= "### \u8c03\u7528\u6808\n";
|
$md .= "### 调用栈\n";
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$total = count($trace['trace']);
|
$total = count($trace['trace']);
|
||||||
foreach ($trace['trace'] as $i => $item) {
|
foreach ($trace['trace'] as $i => $item) {
|
||||||
if ($count >= 20) {
|
if ($count >= 20) {
|
||||||
$md .= "... (\u5171 {$total} \u5c42\uff0c\u5df2\u622a\u65ad)\n";
|
$md .= "... (共 {$total} 层,已截断)\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$func = $item['function'] ?? 'unknown';
|
$func = $item['function'] ?? 'unknown';
|
||||||
@@ -684,7 +729,7 @@ if (isset($traces) && is_array($traces)) {
|
|||||||
if (isset($traces) && is_array($traces)) {
|
if (isset($traces) && is_array($traces)) {
|
||||||
foreach ($traces as $index => $trace) {
|
foreach ($traces as $index => $trace) {
|
||||||
if (!empty($trace['source'])) {
|
if (!empty($trace['source'])) {
|
||||||
$md = "### \u6e90\u7801\u7247\u6bb5\n```php\n";
|
$md = "### 源码片段\n```php\n";
|
||||||
foreach ((array) $trace['source']['source'] as $key => $value) {
|
foreach ((array) $trace['source']['source'] as $key => $value) {
|
||||||
$lineNum = $key + $trace['source']['first'];
|
$lineNum = $key + $trace['source']['first'];
|
||||||
$marker = ($trace['line'] === $lineNum) ? ' >>>' : '';
|
$marker = ($trace['line'] === $lineNum) ? ' >>>' : '';
|
||||||
@@ -699,7 +744,7 @@ if (isset($traces) && is_array($traces)) {
|
|||||||
// Exception Data
|
// Exception Data
|
||||||
if (isset($datas) && is_array($datas)) {
|
if (isset($datas) && is_array($datas)) {
|
||||||
$hasData = false;
|
$hasData = false;
|
||||||
$md = "## \u5f02\u5e38\u6570\u636e\n";
|
$md = "## 异常数据\n";
|
||||||
foreach ($datas as $label => $value) {
|
foreach ($datas as $label => $value) {
|
||||||
if (!empty($value)) {
|
if (!empty($value)) {
|
||||||
$hasData = true;
|
$hasData = true;
|
||||||
@@ -761,10 +806,14 @@ if (isset($tables) && is_array($tables)) {
|
|||||||
}
|
}
|
||||||
restoreCheckboxState();
|
restoreCheckboxState();
|
||||||
updateDisabledState();
|
updateDisabledState();
|
||||||
// Auto-save on checkbox change
|
updatePreviewIfOpen();
|
||||||
|
// Auto-save on checkbox change + update preview if open
|
||||||
var checkboxes = document.querySelectorAll('#debug-toolbar input[type="checkbox"]');
|
var checkboxes = document.querySelectorAll('#debug-toolbar input[type="checkbox"]');
|
||||||
checkboxes.forEach(function(cb) {
|
checkboxes.forEach(function(cb) {
|
||||||
cb.addEventListener('change', saveCheckboxState);
|
cb.addEventListener('change', function() {
|
||||||
|
saveCheckboxState();
|
||||||
|
updatePreviewIfOpen();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,6 +856,19 @@ if (isset($tables) && is_array($tables)) {
|
|||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update preview content if preview panel is currently open
|
||||||
|
function updatePreviewIfOpen() {
|
||||||
|
var preview = document.getElementById('markdown-preview');
|
||||||
|
var content = generateMarkdown();
|
||||||
|
var countEl = document.getElementById('char-count');
|
||||||
|
if (countEl) {
|
||||||
|
countEl.textContent = content.length + '字';
|
||||||
|
}
|
||||||
|
if (preview && preview.style.display === 'block') {
|
||||||
|
document.getElementById('markdown-content').textContent = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update disabled state for env checkboxes based on data availability
|
// Update disabled state for env checkboxes based on data availability
|
||||||
function updateDisabledState() {
|
function updateDisabledState() {
|
||||||
// Exception data
|
// Exception data
|
||||||
@@ -863,20 +925,20 @@ if (isset($tables) && is_array($tables)) {
|
|||||||
window.copyToClipboard = function() {
|
window.copyToClipboard = function() {
|
||||||
var content = generateMarkdown();
|
var content = generateMarkdown();
|
||||||
if (!content.trim()) {
|
if (!content.trim()) {
|
||||||
alert('\u8bf7\u81f3\u5c11\u52fe\u9009\u4e00\u4e2a\u5185\u5bb9\u9009\u9879');
|
alert('请至少勾选一个内容选项');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var btn = document.getElementById('btn-copy');
|
var btn = document.getElementById('btn-copy');
|
||||||
if (navigator.clipboard) {
|
if (navigator.clipboard) {
|
||||||
navigator.clipboard.writeText(content).then(function() {
|
navigator.clipboard.writeText(content).then(function() {
|
||||||
btn.textContent = '\u5df2\u590d\u5236';
|
btn.textContent = '已复制';
|
||||||
btn.classList.add('copied');
|
btn.classList.add('copied');
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
btn.textContent = '\u590d\u5236\u7ed9AI';
|
btn.textContent = '复制给AI';
|
||||||
btn.classList.remove('copied');
|
btn.classList.remove('copied');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
alert('\u590d\u5236\u5931\u8d25: ' + err);
|
alert('复制失败: ' + err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var textarea = document.createElement('textarea');
|
var textarea = document.createElement('textarea');
|
||||||
@@ -887,14 +949,14 @@ if (isset($tables) && is_array($tables)) {
|
|||||||
textarea.select();
|
textarea.select();
|
||||||
try {
|
try {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
btn.textContent = '\u5df2\u590d\u5236';
|
btn.textContent = '已复制';
|
||||||
btn.classList.add('copied');
|
btn.classList.add('copied');
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
btn.textContent = '\u590d\u5236\u7ed9AI';
|
btn.textContent = '复制给AI';
|
||||||
btn.classList.remove('copied');
|
btn.classList.remove('copied');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('\u590d\u5236\u5931\u8d25');
|
alert('复制失败');
|
||||||
}
|
}
|
||||||
document.body.removeChild(textarea);
|
document.body.removeChild(textarea);
|
||||||
}
|
}
|
||||||
@@ -909,11 +971,11 @@ if (isset($tables) && is_array($tables)) {
|
|||||||
var content = generateMarkdown();
|
var content = generateMarkdown();
|
||||||
document.getElementById('markdown-content').textContent = content;
|
document.getElementById('markdown-content').textContent = content;
|
||||||
preview.style.display = 'block';
|
preview.style.display = 'block';
|
||||||
btn.textContent = '\u5173\u95ed\u9884\u89c8';
|
btn.textContent = '关闭预览';
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
} else {
|
} else {
|
||||||
preview.style.display = 'none';
|
preview.style.display = 'none';
|
||||||
btn.textContent = '\u9884\u89c8';
|
btn.textContent = '预览';
|
||||||
btn.classList.remove('active');
|
btn.classList.remove('active');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -923,13 +985,14 @@ if (isset($tables) && is_array($tables)) {
|
|||||||
var btn = document.getElementById('btn-path');
|
var btn = document.getElementById('btn-path');
|
||||||
if (currentPathMode === 'simple') {
|
if (currentPathMode === 'simple') {
|
||||||
currentPathMode = 'full';
|
currentPathMode = 'full';
|
||||||
btn.textContent = '\u8def\u5f84:\u5b8c\u6574';
|
btn.textContent = '路径:完整';
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
} else {
|
} else {
|
||||||
currentPathMode = 'simple';
|
currentPathMode = 'simple';
|
||||||
btn.textContent = '\u8def\u5f84:\u7b80\u7565';
|
btn.textContent = '路径:简洁';
|
||||||
btn.classList.remove('active');
|
btn.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
updatePreviewIfOpen();
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user