diff --git a/.gitignore b/.gitignore
index 0d9072a..70e2830 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,4 +48,5 @@ extend/base/common/command/curd/migrate_output.php
/source/**/.vscode
.trae/documents/
/docker-dev/
-/.sisyphus
\ No newline at end of file
+/.sisyphus
+/.omo
\ No newline at end of file
diff --git a/extend/base/common/tpl/think_exception_debug.tpl b/extend/base/common/tpl/think_exception_debug.tpl
index 0de36d0..a3a3567 100644
--- a/extend/base/common/tpl/think_exception_debug.tpl
+++ b/extend/base/common/tpl/think_exception_debug.tpl
@@ -322,6 +322,13 @@ if (!function_exists('echo_value')) {
margin-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 {
display: inline-flex;
align-items: center;
@@ -372,25 +379,55 @@ if (!function_exists('echo_value')) {
}
#markdown-preview {
display: none;
- padding: 20px;
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: 45%;
+ height: 100%;
background: #fff;
- position: relative;
- margin-top: 20px;
- border: 1px solid #ddd;
- border-radius: 4px;
+ border-left: 1px solid #ddd;
+ box-shadow: -4px 0 16px rgba(0,0,0,0.12);
+ z-index: 99998;
+ 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 {
white-space: pre-wrap;
word-break: break-word;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 13px;
- background: #f8f9fa;
- padding: 15px;
- border-radius: 4px;
- border: 1px solid #e8e8e8;
+ background: #fff;
+ padding: 20px;
+ margin: 0;
+ border: none;
+ border-radius: 0;
color: #333;
- max-height: 600px;
+ height: calc(100% - 49px);
overflow: auto;
+ box-sizing: border-box;
}
@@ -517,6 +554,7 @@ if (!function_exists('echo_value')) {
+ 0字
@@ -526,8 +564,12 @@ if (!function_exists('echo_value')) {
-
+
@@ -634,21 +676,24 @@ if (!function_exists('echo_value')) {
" . 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";
}
-// Location
-if (isset($file) && isset($line)) {
- $fileEscaped = str_replace('\\', '\\\\', $file);
- $md = "## \u51fa\u9519\u4f4d\u7f6e\n- **File:** `{$fileEscaped}`\n- **Line:** `{$line}`\n\n";
- echo 'mdFragments.location = ' . json_encode($md, JSON_UNESCAPED_UNICODE) . ";\n";
+// Location (from first trace)
+if (isset($traces) && is_array($traces) && !empty($traces)) {
+ $firstTrace = $traces[0];
+ if (isset($firstTrace['file']) && isset($firstTrace['line'])) {
+ $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)
if (isset($traces) && is_array($traces)) {
foreach ($traces as $index => $trace) {
- $md = "## \u5f02\u5e38 #{$index}\n";
+ $md = "## 异常 #{$index}\n";
if (isset($trace['message'])) {
$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";
}
if (!empty($trace['trace'])) {
- $md .= "### \u8c03\u7528\u6808\n";
+ $md .= "### 调用栈\n";
$count = 0;
$total = count($trace['trace']);
foreach ($trace['trace'] as $i => $item) {
if ($count >= 20) {
- $md .= "... (\u5171 {$total} \u5c42\uff0c\u5df2\u622a\u65ad)\n";
+ $md .= "... (共 {$total} 层,已截断)\n";
break;
}
$func = $item['function'] ?? 'unknown';
@@ -684,7 +729,7 @@ if (isset($traces) && is_array($traces)) {
if (isset($traces) && is_array($traces)) {
foreach ($traces as $index => $trace) {
if (!empty($trace['source'])) {
- $md = "### \u6e90\u7801\u7247\u6bb5\n```php\n";
+ $md = "### 源码片段\n```php\n";
foreach ((array) $trace['source']['source'] as $key => $value) {
$lineNum = $key + $trace['source']['first'];
$marker = ($trace['line'] === $lineNum) ? ' >>>' : '';
@@ -699,7 +744,7 @@ if (isset($traces) && is_array($traces)) {
// Exception Data
if (isset($datas) && is_array($datas)) {
$hasData = false;
- $md = "## \u5f02\u5e38\u6570\u636e\n";
+ $md = "## 异常数据\n";
foreach ($datas as $label => $value) {
if (!empty($value)) {
$hasData = true;
@@ -761,10 +806,14 @@ if (isset($tables) && is_array($tables)) {
}
restoreCheckboxState();
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"]');
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) {}
}
+ // 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
function updateDisabledState() {
// Exception data
@@ -863,20 +925,20 @@ if (isset($tables) && is_array($tables)) {
window.copyToClipboard = function() {
var content = generateMarkdown();
if (!content.trim()) {
- alert('\u8bf7\u81f3\u5c11\u52fe\u9009\u4e00\u4e2a\u5185\u5bb9\u9009\u9879');
+ alert('请至少勾选一个内容选项');
return;
}
var btn = document.getElementById('btn-copy');
if (navigator.clipboard) {
navigator.clipboard.writeText(content).then(function() {
- btn.textContent = '\u5df2\u590d\u5236';
+ btn.textContent = '已复制';
btn.classList.add('copied');
setTimeout(function() {
- btn.textContent = '\u590d\u5236\u7ed9AI';
+ btn.textContent = '复制给AI';
btn.classList.remove('copied');
}, 2000);
}, function(err) {
- alert('\u590d\u5236\u5931\u8d25: ' + err);
+ alert('复制失败: ' + err);
});
} else {
var textarea = document.createElement('textarea');
@@ -887,14 +949,14 @@ if (isset($tables) && is_array($tables)) {
textarea.select();
try {
document.execCommand('copy');
- btn.textContent = '\u5df2\u590d\u5236';
+ btn.textContent = '已复制';
btn.classList.add('copied');
setTimeout(function() {
- btn.textContent = '\u590d\u5236\u7ed9AI';
+ btn.textContent = '复制给AI';
btn.classList.remove('copied');
}, 2000);
} catch (err) {
- alert('\u590d\u5236\u5931\u8d25');
+ alert('复制失败');
}
document.body.removeChild(textarea);
}
@@ -909,11 +971,11 @@ if (isset($tables) && is_array($tables)) {
var content = generateMarkdown();
document.getElementById('markdown-content').textContent = content;
preview.style.display = 'block';
- btn.textContent = '\u5173\u95ed\u9884\u89c8';
+ btn.textContent = '关闭预览';
btn.classList.add('active');
} else {
preview.style.display = 'none';
- btn.textContent = '\u9884\u89c8';
+ btn.textContent = '预览';
btn.classList.remove('active');
}
};
@@ -923,13 +985,14 @@ if (isset($tables) && is_array($tables)) {
var btn = document.getElementById('btn-path');
if (currentPathMode === 'simple') {
currentPathMode = 'full';
- btn.textContent = '\u8def\u5f84:\u5b8c\u6574';
+ btn.textContent = '路径:完整';
btn.classList.add('active');
} else {
currentPathMode = 'simple';
- btn.textContent = '\u8def\u5f84:\u7b80\u7565';
+ btn.textContent = '路径:简洁';
btn.classList.remove('active');
}
+ updatePreviewIfOpen();
};
})();