Files
wasm-go/web/index.html
lychang 8a15a1bdf4 update
2026-05-28 22:19:21 +08:00

1153 lines
44 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="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WASM企业分析工具套件</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
}
.container {
background-color: white;
border-radius: 15px;
padding: 40px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
margin-top: 20px;
}
header {
text-align: center;
margin-bottom: 40px;
}
h1 {
color: #2c3e50;
font-size: 2.5em;
margin-bottom: 10px;
}
.subtitle {
color: #7f8c8d;
font-size: 1.2em;
margin-bottom: 30px;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin: 40px 0;
}
.feature-card {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
text-align: center;
transition: transform 0.3s ease;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2.5em;
margin-bottom: 15px;
display: block;
}
.feature-title {
font-size: 1.3em;
color: #2c3e50;
margin-bottom: 10px;
}
.feature-desc {
color: #7f8c8d;
}
.section {
margin: 30px 0;
padding: 25px;
background: #e3f2fd;
border-radius: 10px;
}
label {
display: block;
margin-bottom: 12px;
font-weight: bold;
color: #34495e;
font-size: 1.1em;
}
input[type="text"], textarea, input[type="file"] {
width: 100%;
padding: 12px;
border: 2px solid #bbdefb;
border-radius: 8px;
font-size: 16px;
box-sizing: border-box;
transition: border-color 0.3s;
margin-bottom: 15px;
}
input[type="text"]:focus, textarea:focus {
outline: none;
border-color: #64b5f6;
}
button {
background: linear-gradient(45deg, #2196F3, #21CBF3);
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
margin-right: 10px;
margin-top: 10px;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(33, 150, 243, 0.4);
}
button:disabled {
background: #b0bec5;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.result-section {
margin-top: 20px;
padding: 20px;
background-color: #e8f5e9;
border-radius: 10px;
display: none;
}
.result-section.show {
display: block;
animation: fadeIn 0.5s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.result-item {
margin-bottom: 15px;
padding: 15px;
background-color: white;
border-radius: 8px;
border-left: 5px solid #4caf50;
}
.loading {
text-align: center;
padding: 20px;
display: none;
}
.loading.show {
display: block;
}
.error {
color: #f44336;
background-color: #ffebee;
padding: 15px;
border-radius: 8px;
margin-top: 15px;
display: none;
}
.error.show {
display: block;
}
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
border-radius: 8px 8px 0 0;
}
.tab button {
background: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 17px;
margin: 0;
box-shadow: none;
}
.tab button:hover {
background-color: #ddd;
}
.tab button.active {
background-color: #2196F3;
color: white;
}
.tabcontent {
display: none;
padding: 20px;
border: 1px solid #ccc;
border-top: none;
border-radius: 0 0 8px 8px;
background-color: white;
}
.config-btn {
background: inherit;
border: 1px solid #ccc;
border-radius: 8px;
padding: 10px 15px;
cursor: pointer;
font-size: 16px;
margin-left: 10px;
box-shadow: none;
}
.config-btn:hover {
background-color: #ddd;
}
.config-panel {
display: none;
background-color: white;
border: 1px solid #ccc;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.config-panel.active {
display: block;
}
footer {
text-align: center;
margin-top: 40px;
color: #95a5a6;
font-size: 0.9em;
}
.json-output {
background: rgba(0, 0, 0, 0.3);
padding: 15px;
border-radius: 5px;
font-family: monospace;
white-space: pre-wrap;
word-break: break-word;
max-height: 400px;
overflow-y: auto;
}
.config-btn {
background: rgba(255, 255, 255, 0.2);
color: white;
border: none;
padding: 10px 15px;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
transition: background 0.3s;
}
.config-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
.config-panel {
display: none;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
.config-panel.active {
display: block;
}
.prompt-description, .prompt-input-section, .prompt-params-section,
.prompt-expected-section, .prompt-result-section, .prompt-usage {
margin-bottom: 25px;
padding: 20px;
background-color: white;
border-radius: 10px;
border-left: 5px solid #2196F3;
}
.prompt-description h4, .prompt-params-section h4,
.prompt-expected-section h4, .prompt-result-section h4, .prompt-usage h4 {
margin-top: 0;
color: #2c3e50;
font-size: 1.1em;
}
.prompt-description p {
color: #7f8c8d;
line-height: 1.6;
}
.param-note {
font-size: 0.9em;
color: #95a5a6;
margin-top: 10px;
}
.prompt-result-section {
display: none;
border-left-color: #4caf50;
}
.prompt-result-section.show {
display: block;
animation: fadeIn 0.5s;
}
.prompt-usage ul {
margin: 0;
padding-left: 20px;
color: #7f8c8d;
}
.prompt-usage li {
margin-bottom: 8px;
}
select {
width: 100%;
padding: 12px;
border: 2px solid #bbdefb;
border-radius: 8px;
font-size: 16px;
box-sizing: border-box;
margin-bottom: 15px;
background-color: white;
}
select:focus {
outline: none;
border-color: #64b5f6;
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
.tab button {
padding: 10px 12px;
font-size: 14px;
}
h1 {
font-size: 1.8em;
}
}
</style>
</head>
<body>
<header>
<h1>🚀 Excel转JSON工具</h1>
<p class="subtitle">基于WebAssembly的多功能企业数据分析平台</p>
</header>
<div class="container">
<!-- 顶部导航栏 -->
<div class="navbar">
<h1>🚀 Excel转JSON工具</h1>
<!-- LLM配置按钮 -->
<button id="llmConfigBtn" class="config-btn" onclick="toggleLLMConfig()">⚙️ LLM配置</button>
</div>
<!-- LLM配置面板 -->
<div id="llmConfigPanel" class="config-panel">
<div class="section">
<h3>🤖 LLM配置</h3>
<label for="llmProviderSelect">Provider:</label>
<select id="llmProviderSelect">
<option value="default">default</option>
<option value="ollama">Ollama</option>
<option value="openai">OpenAI</option>
</select>
<label for="llmBaseUrlInput">Base URL:</label>
<input type="text" id="llmBaseUrlInput" placeholder="https://api.deepseek.com" value="">
<label for="llmModelInput">Model:</label>
<input type="text" id="llmModelInput" placeholder="deepseek-v4-flash" value="">
<label for="llmApiKeyInput">API Key:</label>
<input type="password" id="llmApiKeyInput" placeholder="输入API密钥(如果需要)">
<button id="saveLlmConfigBtn" class="btn">💾 保存配置</button>
<button id="closeLlmConfigBtn" class="btn cancel-btn" onclick="toggleLLMConfig()">❌ 关闭</button>
</div>
</div>
<!-- 标签页导航 -->
<div class="tab">
<button class="tablinks active" onclick="openTab(event, 'company')">企业行业分析</button>
<button class="tablinks" onclick="openTab(event, 'excel')">Excel解析</button>
<button class="tablinks" onclick="openTab(event, 'llm')">AI分析</button>
<button class="tablinks" onclick="openTab(event, 'prompt')">Prompt管理</button>
<button class="tablinks" onclick="openTab(event, 'tax')">税务健康</button>
</div>
<!-- 企业行业分析标签页 -->
<div id="company" class="tabcontent" style="display: block;">
<div class="section">
<label for="companyName">🔍 请输入企业全称:</label>
<input type="text" id="companyName" placeholder="例如:深圳市致远速联信息技术有限公司" value="深圳市致远速联信息技术有限公司">
<button id="analyzeCompanyBtn" disabled>分析企业行业</button>
</div>
</div>
<!-- Excel解析标签页 -->
<div id="excel" class="tabcontent">
<div class="section">
<label for="excelFile">📁 请选择Excel文件:</label>
<input type="file" id="excelFile" accept=".xlsx,.xls">
<button id="parseExcelBtn" disabled>解析Excel文件</button>
</div>
</div>
<!-- AI分析标签页 -->
<div id="llm" class="tabcontent">
<div class="section">
<label for="llmPrompt">💬 请输入分析提示:</label>
<textarea id="llmPrompt" rows="4" placeholder="请输入您想要分析的内容...">请分析以下企业数据并给出建议</textarea>
<button id="callLLMBtn" disabled>调用AI分析</button>
</div>
</div>
<!-- Prompt管理标签页 -->
<div id="prompt" class="tabcontent">
<div class="section">
<h3>📝 getPrompt 方法功能展示</h3>
<div class="prompt-description">
<h4>功能描述</h4>
<p>getPrompt 方法用于根据指定的财务报表周期获取对应的提示词模板。系统支持多种周期类型,包括季度(Q1-Q3)和年度报告,每种周期对应专门设计的财务分析提示词,用于指导大模型进行税务健康评估数据转换。</p>
</div>
<div class="prompt-input-section">
<label for="promptPeriodSelect">📅 选择财务周期:</label>
<select id="promptPeriodSelect">
<option value="Q1">Q1 (第一季度)</option>
<option value="第一季度">第一季度</option>
<option value="Q2">Q2 (第二季度)</option>
<option value="第二季度">第二季度</option>
<option value="Q3">Q3 (第三季度)</option>
<option value="第三季度">第三季度</option>
<option value="年度">年度</option>
</select>
</div>
<div class="prompt-params-section">
<h4>📋 输入参数示例</h4>
<div class="json-output" style="background: #fff3e0; border: 1px solid #ff9800; color: #e65100;">
{"period": "Q1"}
</div>
<p class="param-note">参数说明: period 为字符串类型,支持的值包括 Q1、第一季度、Q2、第二季度、Q3、第三季度、年度</p>
</div>
<div class="prompt-expected-section">
<h4>🎯 预期输出结果</h4>
<div class="json-output" style="background: #e8f5e9; border: 1px solid #4caf50; color: #2e7d32;">
{"prompt": "根据选择的周期返回对应的提示词模板", "period": "所选周期"}
</div>
<p class="param-note">返回格式: JSON对象,包含 prompt(提示词内容) 和 period(所选周期) 字段</p>
</div>
<button id="getPromptBtn" disabled>🚀 获取提示词</button>
<div class="prompt-result-section" id="promptResultSection">
<h4>✅ 实际执行结果</h4>
<div id="promptResultContent"></div>
</div>
<div class="prompt-usage">
<h4>📖 使用说明</h4>
<ul>
<li>1. 从下拉菜单中选择一个财务周期</li>
<li>2. 点击「获取提示词」按钮执行 getPrompt 方法</li>
<li>3. 在下方「实际执行结果」区域查看返回的提示词内容</li>
<li>4. 如果选择了不支持的周期,系统会返回错误信息</li>
</ul>
</div>
</div>
</div>
<!-- 税务健康标签页 -->
<div id="tax" class="tabcontent">
<div class="section">
<h3>📊 税务健康评估参数</h3>
<label for="companyNameInput">🏢 企业名称:</label>
<input type="text" id="companyNameInput" placeholder="请输入企业全称" value="企业名称">
<label for="periodInput">📅 测评周期:</label>
<select id="periodInput">
<option value="Q1">第一季度</option>
<option value="Q2">第二季度</option>
<option value="Q3">第三季度</option>
<option value="Q4">第四季度</option>
<option value="年度">年度</option>
</select>
<label for="yearInput">📅 报告期:</label>
<input type="number" id="yearInput" placeholder="年份" value="2021" min="1900" max="2022">
<label for="citInput">💰 企业所得税应纳税额合计 (万元):</label>
<input type="number" id="citInput" placeholder="单位:万元" value="100.0" step="0.01">
<label for="vatInput">💰 增值税应纳税额合计 (万元):</label>
<input type="number" id="vatInput" placeholder="单位:万元" value="50.0" step="0.01">
<label for="inputVatInput">💰 增值税进项税额 (万元):</label>
<input type="number" id="inputVatInput" placeholder="单位:万元" value="30.0" step="0.01">
<label for="outputVatInput">💰 增值税销项税额 (万元):</label>
<input type="number" id="outputVatInput" placeholder="单位:万元" value="80.0" step="0.01">
<label for="preCitInput">💰 上一期企业所得税应纳税额合计 (万元):</label>
<input type="number" id="preCitInput" placeholder="单位:万元" value="90.0" step="0.01">
<label for="preVatInput">💰 上一期增值税应纳税额合计 (万元):</label>
<input type="number" id="preVatInput" placeholder="单位:万元" value="45.0" step="0.01">
<label for="preInputVatInput">💰 上一期增值税进项税额 (万元):</label>
<input type="number" id="preInputVatInput" placeholder="单位:万元" value="25.0" step="0.01">
<label for="preOutputVatInput">💰 上一期增值税销项税额 (万元):</label>
<input type="number" id="preOutputVatInput" placeholder="单位:万元" value="70.0" step="0.01">
<label for="excelFileInput">📁 上传Excel财务报表 (可选):</label>
<input type="file" id="excelFileInput" accept=".xlsx,.xls">
<label for="taxJsonInput">📄 或者直接粘贴JSON数据:</label>
<textarea id="taxJsonInput" rows="4" placeholder='粘贴财务报表JSON数据'>{"LC0000003E_T0I0331": 741213833.14, "LC0000003E_T0I0101": 578064138.06}</textarea>
<button id="submitTaxBtn" disabled>提交税务评估</button>
<button id="queryResultBtn" disabled style="background: linear-gradient(45deg, #4CAF50, #8BC34A);">查询评估结果</button>
<div style="margin-top: 15px;">
<label for="orderNoInput">📋 订单号 (用于查询):</label>
<input type="text" id="orderNoInput" placeholder="输入订单号查询结果">
</div>
</div>
</div>
<div class="loading" id="loading">
<p>🔄 正在处理请求...请稍候</p>
</div>
<div class="error" id="error"></div>
<div class="result-section" id="resultSection">
<h2>📊 分析结果</h2>
<div id="resultContent"></div>
</div>
</div>
<footer>
<p>Powered by WebAssembly & Go | 企业分析工具套件 v1.0</p>
</footer>
<!-- 加载WASM运行时 -->
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
// WASM加载完成后启用所有按钮
document.getElementById('analyzeCompanyBtn').disabled = false;
document.getElementById('parseExcelBtn').disabled = false;
document.getElementById('callLLMBtn').disabled = false;
document.getElementById('getPromptBtn').disabled = false;
document.getElementById('submitTaxBtn').disabled = false;
document.getElementById('queryResultBtn').disabled = false;
console.log('WASM模块加载完成');
}).catch((err) => {
console.error('WASM加载失败:', err);
showError('WASM模块加载失败: ' + err.message);
});
// 获取DOM元素
const analyzeCompanyBtn = document.getElementById('analyzeCompanyBtn');
const parseExcelBtn = document.getElementById('parseExcelBtn');
const callLLMBtn = document.getElementById('callLLMBtn');
const companyNameInput = document.getElementById('companyName');
const excelFileInput = document.getElementById('excelFile');
const llmPromptInput = document.getElementById('llmPrompt');
const resultSection = document.getElementById('resultSection');
const resultContent = document.getElementById('resultContent');
const loadingDiv = document.getElementById('loading');
const errorDiv = document.getElementById('error');
// 企业行业分析按钮事件
analyzeCompanyBtn.addEventListener('click', async () => {
const companyName = companyNameInput.value.trim();
if (!companyName) {
showError('请输入企业名称');
return;
}
showLoading(true);
hideError();
resultSection.classList.remove('show');
try {
// 获取当前LLM配置
const llmConfig = getCurrentLLMConfig();
const result = await window.analyzeCompanyIndustryAsync(companyName, JSON.stringify(llmConfig));
if (result && result.error) {
showError(result.error);
} else {
displayResults('企业行业分析结果', result);
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('分析过程中发生错误: ' + errorMsg);
} finally {
showLoading(false);
}
});
// Excel解析按钮事件
parseExcelBtn.addEventListener('click', async () => {
const file = excelFileInput.files[0];
if (!file) {
showError('请选择一个Excel文件');
return;
}
showLoading(true);
hideError();
resultSection.classList.remove('show');
try {
// 读取文件为ArrayBuffer
const arrayBuffer = await file.arrayBuffer();
// 调用WASM中的解析函数
const result = await window.parseExcelAsync(arrayBuffer);
if (result && result.error) {
showError(result.error);
} else {
displayResults('Excel解析结果', result);
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('解析Excel过程中发生错误: ' + errorMsg);
} finally {
showLoading(false);
}
});
// AI分析按钮事件
callLLMBtn.addEventListener('click', async () => {
const prompt = llmPromptInput.value.trim();
if (!prompt) {
showError('请输入分析提示');
return;
}
showLoading(true);
hideError();
resultSection.classList.remove('show');
try {
// 获取当前LLM配置
const llmConfig = getCurrentLLMConfig();
// 调用大模型
const result = await window.callLLMAsync(prompt, JSON.stringify(llmConfig));
if (result && result.error) {
showError('调用大模型失败: ' + result.error);
} else {
// 显示结果
displayResults('大模型调用结果', result);
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('AI分析过程中发生错误: ' + errorMsg);
} finally {
showLoading(false);
}
});
// 税务健康提交按钮事件
const submitTaxBtn = document.getElementById('submitTaxBtn');
const queryResultBtn = document.getElementById('queryResultBtn');
const taxCompanyNameInput = document.getElementById('companyNameInput');
const periodInput = document.getElementById('periodInput');
const yearInput = document.getElementById('yearInput');
const citInput = document.getElementById('citInput');
const vatInput = document.getElementById('vatInput');
const inputVatInput = document.getElementById('inputVatInput');
const outputVatInput = document.getElementById('outputVatInput');
const preCitInput = document.getElementById('preCitInput');
const preVatInput = document.getElementById('preVatInput');
const preInputVatInput = document.getElementById('preInputVatInput');
const preOutputVatInput = document.getElementById('preOutputVatInput');
const taxExcelFileInput = document.getElementById('excelFileInput');
const taxJsonInput = document.getElementById('taxJsonInput');
const orderNoInput = document.getElementById('orderNoInput');
submitTaxBtn.addEventListener('click', async () => {
// 收集所有输入的参数
const companyName = taxCompanyNameInput.value.trim();
const period = periodInput.value;
const year = yearInput.value;
const cit = parseFloat(citInput.value) || 0;
const vat = parseFloat(vatInput.value) || 0;
const inputVat = parseFloat(inputVatInput.value) || 0;
const outputVat = parseFloat(outputVatInput.value) || 0;
const preCit = parseFloat(preCitInput.value) || 0;
const preVat = parseFloat(preVatInput.value) || 0;
const preInputVat = parseFloat(preInputVatInput.value) || 0;
const preOutputVat = parseFloat(preOutputVatInput.value) || 0;
const jsonData = taxJsonInput.value.trim();
if (!companyName) {
showError('请输入企业名称');
return;
}
if (!year || isNaN(year)) {
showError('请输入有效的年份');
return;
}
showLoading(true);
hideError();
resultSection.classList.remove('show');
try {
// 构建请求数据
let requestData = {
req_no: Date.now().toString(),
company_name: companyName,
period: period,
year: year.toString(),
cit: cit,
vat: vat,
input_vat: inputVat,
output_vat: outputVat,
pre_cit: preCit,
pre_vat: preVat,
pre_input_vat: preInputVat,
pre_output_vat: preOutputVat
};
// 处理Excel文件或JSON数据
if (taxExcelFileInput.files.length > 0) {
// 如果用户选择了Excel文件,需要先解析它并通过LLM转换为JSON
const file = taxExcelFileInput.files[0];
const arrayBuffer = await file.arrayBuffer();
// 获取期间参数
const period = periodInput.value;
// 获取当前LLM配置
const llmConfig = getCurrentLLMConfig();
// 使用新的函数将Excel数据通过LLM转换为JSON格式,传入期间参数和配置
const conversionResult = await window.convertExcelToJsonViaLLM(arrayBuffer, period, JSON.stringify(llmConfig));
// 检查转换结果是否包含错误
if (conversionResult && conversionResult.error) {
showError('Excel转JSON过程中发生错误: ' + conversionResult.error);
return;
}
if (conversionResult && conversionResult.error) {
showError('Excel转JSON过程中发生错误: ' + conversionResult.error);
return;
}
// 优先使用转换后的JSON数据
if (conversionResult.json_data) {
requestData.data = conversionResult.json_data;
} else if (conversionResult.parsed_json) {
// 如果有解析后的JSON字符串,尝试解析它
try {
requestData.data = JSON.parse(conversionResult.parsed_json);
} catch (e) {
console.warn('无法解析LLM返回的JSON,使用原始响应:', e);
// 如果解析失败,使用原始响应作为数据
requestData.data = conversionResult;
}
} else {
showError('Excel转JSON失败,未获得有效数据');
return;
}
} else if (jsonData) {
// 如果提供了JSON数据
try {
const parsedData = JSON.parse(jsonData);
requestData.data = parsedData;
} catch (e) {
showError('JSON数据格式不正确: ' + e.message);
return;
}
} else {
showError('请上传Excel文件或提供JSON数据');
return;
}
// 首先调用税务健康API获取订单号
const result = await window.callTaxHealthAsync(JSON.stringify(requestData));
if (result && result.error) {
showError(result.error);
return;
}
// 显示初始结果并开始轮询
displayResults('税务健康评估提交结果', result);
// 自动填充订单号到查询框
if (result.order_no) {
orderNoInput.value = result.order_no;
// 开始轮询查询结果
console.log('开始轮询查询结果...');
let attempts = 0;
const maxAttempts = 60; // 最多轮询60次
const pollForResult = async () => {
if (attempts >= maxAttempts) {
console.log('轮询超时');
return;
}
try {
const pollResult = await window.queryTaxResultAsync(result.order_no);
if (pollResult && pollResult.error) {
showError('查询结果时发生错误: ' + pollResult.error);
return;
}
const queryResponse = pollResult.query_response;
console.log(`轮询结果 - 状态码: ${queryResponse.code}, 订单状态: ${queryResponse.data.status}`);
// 根据状态码判断处理结果
switch (queryResponse.data.status) {
case 99: // 执行成功
console.log('税务评估已完成!');
displayResults('税务评估最终结果', pollResult);
// 显示结果文件地址
if (queryResponse.data.detail && queryResponse.data.detail.files) {
console.log('结果文件地址:', queryResponse.data.detail.files);
}
return;
case 0: // 正在执行
console.log(`任务仍在处理中... (${attempts + 1}/${maxAttempts})`);
attempts++;
setTimeout(pollForResult, 5000); // 5秒后再次查询
break;
case -1: // 无效订单
showError(`订单无效: ${queryResponse.data.detail?.error || '未知错误'}`);
return;
case 98: // 执行失败
showError(`任务执行失败: ${queryResponse.data.detail?.error || '未知错误'}`);
return;
default:
console.log(`未知状态码: ${queryResponse.data.status}`);
attempts++;
setTimeout(pollForResult, 5000);
break;
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('轮询过程中发生错误: ' + errorMsg);
}
};
// 开始轮询
setTimeout(pollForResult, 5000);
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('税务健康评估过程中发生错误: ' + errorMsg);
} finally {
showLoading(false);
}
});
// 查询税务评估结果按钮事件
queryResultBtn.addEventListener('click', async () => {
const orderNo = orderNoInput.value.trim();
if (!orderNo) {
showError('请输入订单号');
return;
}
showLoading(true);
hideError();
resultSection.classList.remove('show');
try {
const result = await window.queryTaxResultAsync(orderNo);
if (result && result.error) {
showError(result.error);
} else {
displayResults('税务评估查询结果', result);
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('查询税务评估结果过程中发生错误: ' + errorMsg);
} finally {
showLoading(false);
}
});
// getPrompt按钮事件
const getPromptBtn = document.getElementById('getPromptBtn');
const promptPeriodSelect = document.getElementById('promptPeriodSelect');
const promptResultSection = document.getElementById('promptResultSection');
const promptResultContent = document.getElementById('promptResultContent');
getPromptBtn.addEventListener('click', async () => {
const period = promptPeriodSelect.value;
showLoading(true);
hideError();
promptResultSection.classList.remove('show');
try {
const result = await window.getPrompt(period);
if (result && result.error) {
showError(result.error);
} else {
let html = '<div class="json-output" style="background: #e8f5e9; border: 1px solid #4caf50;">';
html += '<strong>周期:</strong> ' + result.period + '<br><br>';
html += '<strong>提示词内容:</strong><br>';
html += '<pre style="white-space: pre-wrap; word-break: break-word;">' + result.prompt + '</pre>';
html += '</div>';
promptResultContent.innerHTML = html;
promptResultSection.classList.add('show');
}
} catch (error) {
const errorMsg = error.error || error.message || JSON.stringify(error);
showError('获取提示词失败: ' + errorMsg);
} finally {
showLoading(false);
}
});
// 显示加载状态
function showLoading(show) {
if (show) {
loadingDiv.classList.add('show');
// 禁用所有按钮以防止重复点击
analyzeCompanyBtn.disabled = true;
parseExcelBtn.disabled = true;
callLLMBtn.disabled = true;
getPromptBtn.disabled = true;
submitTaxBtn.disabled = true;
queryResultBtn.disabled = true;
} else {
loadingDiv.classList.remove('show');
// 重新启用按钮(但保持初始状态由WASM加载决定)
// 这里简单地重新启用
setTimeout(() => {
analyzeCompanyBtn.disabled = false;
parseExcelBtn.disabled = false;
callLLMBtn.disabled = false;
getPromptBtn.disabled = false;
submitTaxBtn.disabled = false;
queryResultBtn.disabled = false;
}, 100);
}
}
// 显示错误信息
function showError(message) {
errorDiv.textContent = message;
errorDiv.classList.add('show');
}
// 隐藏错误信息
function hideError() {
errorDiv.classList.remove('show');
}
// 显示结果
function displayResults(title, result) {
if (!result) {
showError('未能获取分析结果');
return;
}
let html = `<div class="result-item"><h3>${title}</h3>`;
// 格式化输出结果
html += '<pre>' + JSON.stringify(result, null, 2) + '</pre>';
html += '</div>';
resultContent.innerHTML = html;
resultSection.classList.add('show');
}
// 切换LLM配置面板显示/隐藏
function toggleLLMConfig() {
const panel = document.getElementById('llmConfigPanel');
const isActive = panel.classList.contains('active');
if (isActive) {
panel.classList.remove('active');
} else {
panel.classList.add('active');
}
}
// 保存LLM配置
document.addEventListener('DOMContentLoaded', function() {
const saveLlmConfigBtn = document.getElementById('saveLlmConfigBtn');
if (saveLlmConfigBtn) {
saveLlmConfigBtn.addEventListener('click', function() {
const provider = document.getElementById('llmProviderSelect').value;
const baseUrl = document.getElementById('llmBaseUrlInput').value;
const model = document.getElementById('llmModelInput').value;
const apiKey = document.getElementById('llmApiKeyInput').value;
// 保存配置到localStorage
const llmConfig = {
provider: provider,
base_url: baseUrl,
model: model,
api_key: apiKey
};
localStorage.setItem('llmConfig', JSON.stringify(llmConfig));
alert('LLM配置已保存!');
});
}
});
// 从localStorage加载LLM配置
function loadLLMConfig() {
const savedConfig = localStorage.getItem('llmConfig');
if (savedConfig) {
try {
const config = JSON.parse(savedConfig);
if (document.getElementById('llmProviderSelect')) {
document.getElementById('llmProviderSelect').value = config.provider || 'default';
}
if (document.getElementById('llmBaseUrlInput')) {
document.getElementById('llmBaseUrlInput').value = config.base_url || '';
}
if (document.getElementById('llmModelInput')) {
document.getElementById('llmModelInput').value = config.model || '';
}
if (document.getElementById('llmApiKeyInput')) {
document.getElementById('llmApiKeyInput').value = config.api_key || '';
}
} catch (e) {
console.error('加载LLM配置失败:', e);
}
}
}
// 在页面加载完成后初始化LLM配置
document.addEventListener('DOMContentLoaded', function() {
loadLLMConfig();
});
// 获取当前LLM配置
function getCurrentLLMConfig() {
const savedConfig = localStorage.getItem('llmConfig');
if (savedConfig) {
try {
return JSON.parse(savedConfig);
} catch (e) {
console.error('解析LLM配置失败:', e);
}
}
// 返回默认配置
return {
provider: 'default',
base_url: '',
model: '',
api_key: ''
};
}
// 标签页功能
function openTab(evt, tabName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(tabName).style.display = "block";
evt.currentTarget.className += " active";
}
// 回车键触发当前活动标签页的分析
document.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
const activeTab = document.querySelector('.tabcontent[style*="block"]');
if (activeTab.id === 'company') {
analyzeCompanyBtn.click();
} else if (activeTab.id === 'llm') {
callLLMBtn.click();
} else if (activeTab.id === 'tax') {
submitTaxBtn.click();
}
}
});
</script>
</body>
</html>