'commit'
This commit is contained in:
@@ -13,6 +13,9 @@ from Tools.T6_Export import export_excel, DorisExcelExporter, extract_hourly_pri
|
||||
import tempfile
|
||||
import os
|
||||
import zipfile
|
||||
import subprocess
|
||||
from pydantic import BaseModel
|
||||
from starlette.background import BackgroundTask
|
||||
from Model.YltAnalyticsModel import (
|
||||
StationBase,
|
||||
CompetitorStation,
|
||||
@@ -95,6 +98,55 @@ async def export_prices_zip():
|
||||
)
|
||||
|
||||
|
||||
class AiReportRequest(BaseModel):
|
||||
content: str
|
||||
|
||||
|
||||
@router.post("/api/export/ai-report-docx")
|
||||
async def export_ai_report_docx(req: AiReportRequest):
|
||||
content = req.content
|
||||
if not content:
|
||||
raise HTTPException(status_code=400, detail="Content is empty")
|
||||
|
||||
# Create temp markdown file
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False, encoding="utf-8") as tmp_md:
|
||||
tmp_md.write(content)
|
||||
tmp_md_path = tmp_md.name
|
||||
|
||||
output_docx_path = tmp_md_path.replace(".md", ".docx")
|
||||
|
||||
# Check template
|
||||
template_path = "static/template/templates.docx"
|
||||
cmd = ['pandoc', '-s', tmp_md_path, '-o', output_docx_path, '--resource-path=static']
|
||||
|
||||
# Only add reference doc if it exists, but the user requested it specifically.
|
||||
# We'll check if it exists, if not, we might fail or warn, but let's try to include it if possible.
|
||||
if os.path.exists(template_path):
|
||||
cmd.extend(['--reference-doc', template_path])
|
||||
|
||||
try:
|
||||
subprocess.run(cmd, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Clean up
|
||||
if os.path.exists(tmp_md_path):
|
||||
os.remove(tmp_md_path)
|
||||
raise HTTPException(status_code=500, detail=f"Pandoc conversion failed: {str(e)}")
|
||||
|
||||
def cleanup():
|
||||
if os.path.exists(tmp_md_path):
|
||||
os.remove(tmp_md_path)
|
||||
if os.path.exists(output_docx_path):
|
||||
os.remove(output_docx_path)
|
||||
|
||||
return FileResponse(
|
||||
output_docx_path,
|
||||
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
filename="AI分析报告.docx",
|
||||
background=BackgroundTask(cleanup)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@router.get("/api/ai/pricing/strategy-summary")
|
||||
async def ai_pricing_strategy_summary():
|
||||
async def generate_stream():
|
||||
|
||||
Binary file not shown.
@@ -278,6 +278,42 @@ body {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* Markdown Table Styling in AI Result */
|
||||
.ai-result table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0;
|
||||
font-size: 13px;
|
||||
background-color: var(--card-bg); /* Use card bg to distinguish from ai-box bg */
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 6px;
|
||||
overflow: hidden; /* For rounded corners on table */
|
||||
}
|
||||
|
||||
.ai-result th,
|
||||
.ai-result td {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--card-border); /* Explicit border color */
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ai-result th {
|
||||
background-color: rgba(15, 23, 42, 0.8);
|
||||
color: var(--text-secondary);
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.ai-result tr:nth-child(even) {
|
||||
background-color: rgba(255, 255, 255, 0.02); /* Slight zebra striping */
|
||||
}
|
||||
|
||||
.ai-result tr:hover td {
|
||||
background-color: var(--table-row-hover);
|
||||
}
|
||||
|
||||
/* Custom Scrollbar Webkit */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
|
||||
@@ -15,9 +15,13 @@
|
||||
<div class="dashboard-title">⚡ 充电站电价分析驾驶舱</div>
|
||||
<div class="controls">
|
||||
<button class="btn-primary" @click="exportAllPrices" :disabled="exporting">
|
||||
<span v-if="!exporting">📊 一键导出分析报告</span>
|
||||
<span v-if="!exporting">📊 导出分时段电价表</span>
|
||||
<span v-else>⏳ 导出中...</span>
|
||||
</button>
|
||||
<button class="btn-primary" @click="exportAiReport" :disabled="exportingReport || !aiText" :title="!aiText ? '请先生成AI分析报告' : ''">
|
||||
<span v-if="!exportingReport">📑 导出分析报告</span>
|
||||
<span v-else>⏳ 生成中...</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ const aiText = ref("")
|
||||
const placeholder = ref("点击左侧按钮查询四家供应商最新24小时分时电价,再使用右侧AI综合分析功能对各司定价策略进行对比。")
|
||||
const loading = ref(false)
|
||||
const exporting = ref(false)
|
||||
const exportingReport = ref(false)
|
||||
const aiLoading = ref(false)
|
||||
const aiBoxRef = ref(null)
|
||||
const priceTableRows = ref([])
|
||||
@@ -122,6 +123,35 @@ exporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const exportAiReport = async () => {
|
||||
if (!aiText.value) {
|
||||
alert("请先生成AI分析报告")
|
||||
return
|
||||
}
|
||||
try {
|
||||
exportingReport.value = true
|
||||
const res = await axios.post(apiBase.value + "/api/export/ai-report-docx", {
|
||||
content: aiText.value
|
||||
}, {responseType: "blob"})
|
||||
|
||||
const blob = new Blob([res.data], {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"})
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement("a")
|
||||
a.href = url
|
||||
a.download = "AI分析报告.docx"
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
alert("导出失败,请检查是否安装Pandoc")
|
||||
} finally {
|
||||
exportingReport.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const startAiAnalysis = async () => {
|
||||
if (aiLoading.value) return
|
||||
aiText.value = ""
|
||||
@@ -210,6 +240,6 @@ const getPriceColor = (price) => {
|
||||
return '#f1f5f9' // Slate-100
|
||||
}
|
||||
|
||||
return {apiBase,operators,aiText,placeholder,loading,exporting,aiLoading,priceTableRows,loadAllOperatorsPrices,exportAllPrices,startAiAnalysis,formatCell,getPriceColor,renderedAiText,aiBoxRef}
|
||||
return {apiBase,operators,aiText,placeholder,loading,exporting,exportingReport,aiLoading,priceTableRows,loadAllOperatorsPrices,exportAllPrices,exportAiReport,startAiAnalysis,formatCell,getPriceColor,renderedAiText,aiBoxRef}
|
||||
}
|
||||
}).mount("#app")
|
||||
|
||||
BIN
static/templates/templates.docx
Normal file
BIN
static/templates/templates.docx
Normal file
Binary file not shown.
Reference in New Issue
Block a user