const {createApp,onMounted,ref} = Vue createApp({ setup(){ const apiBase = ref(window.location.origin || "http://localhost:8000") const operators = ref([ {label:"新电途",value:"新电途"}, {label:"特来电",value:"特来电"}, {label:"驿来特",value:"驿来特"}, {label:"艾特吉易充",value:"艾特吉易充"} ]) const selectedOperator = ref("驿来特") const aiText = ref("") const placeholder = ref("点击左侧按钮查询四家供应商最新24小时分时电价,再使用右侧AI综合分析功能对各司定价策略进行对比。") const loading = ref(false) const aiLoading = ref(false) const priceTableRows = ref([]) const hourlyPricesByOperator = ref({}) let chartInstance = null const initChart = () => { const dom = document.getElementById("chart") if (dom && !chartInstance) { chartInstance = echarts.init(dom) } } const buildPriceTable = () => { const rows = [] for (let h = 0; h < 24; h++) { const row = {hour: (h.toString().padStart(2,"0") + ":00"), values: []} operators.value.forEach(op => { const series = hourlyPricesByOperator.value[op.value] || [] const price = series[h] !== undefined ? series[h] : null row.values.push({operator: op.value, price}) }) rows.push(row) } priceTableRows.value = rows if (chartInstance) { const series = operators.value.map(op => { const seriesData = [] for (let h = 0; h < 24; h++) { const list = hourlyPricesByOperator.value[op.value] || [] seriesData.push(list[h] !== undefined ? list[h] : null) } return {name: op.label, type:"line", smooth:true, data:seriesData} }) const hours = rows.map(r => r.hour) const option = { tooltip:{trigger:"axis"}, legend:{data:operators.value.map(o=>o.label),textStyle:{color:"#e5e7eb"}}, xAxis:{type:"category",data:hours,axisLine:{lineStyle:{color:"#4b5563"}},axisLabel:{color:"#9ca3af"}}, yAxis:{type:"value",name:"元/度",axisLine:{lineStyle:{color:"#4b5563"}},axisLabel:{color:"#9ca3af"},splitLine:{lineStyle:{color:"#111827"}}}, grid:{left:40,right:20,top:30,bottom:30}, series:series } chartInstance.setOption(option) } } const loadAllOperatorsPrices = async () => { loading.value = true try{ const res = await axios.get(apiBase.value + "/api/operators/hourly-prices") if (res && res.data && Array.isArray(res.data.operators)) { const dict = {} res.data.operators.forEach(item => { dict[item.operator] = item.series || [] }) hourlyPricesByOperator.value = dict buildPriceTable() } }catch(e){ console.error(e) }finally{ loading.value = false } } const loadOperatorPrices = async () => { if (!selectedOperator.value) return await loadAllOperatorsPrices() } const exportAllPrices = async () => { try{ loading.value = true const res = await axios.get(apiBase.value + "/api/export/prices-zip",{responseType:"blob"}) const blob = new Blob([res.data],{type:"application/zip"}) const url = window.URL.createObjectURL(blob) const a = document.createElement("a") a.href = url a.download = "多供应商电价导出.zip" document.body.appendChild(a) a.click() document.body.removeChild(a) window.URL.revokeObjectURL(url) }catch(e){ console.error(e) }finally{ loading.value = false } } const startAiAnalysis = async () => { if (aiLoading.value) return aiText.value = "" aiLoading.value = true try{ const res = await axios.get(apiBase.value + "/api/ai/pricing/strategy-summary") aiText.value = res.data && res.data.summary ? res.data.summary : "" }catch(e){ console.error(e) }finally{ aiLoading.value = false } } onMounted(()=>{ initChart() loadAllOperatorsPrices() }) const formatCell = v => { if (v === null || v === undefined || v === "") return "-" if (typeof v === "number") { if (Number.isNaN(v)) return "-" return v.toFixed(2) } return v } return {apiBase,operators,selectedOperator,aiText,placeholder,loading,aiLoading,priceTableRows,loadOperatorPrices,loadAllOperatorsPrices,exportAllPrices,startAiAnalysis,formatCell} } }).mount("#app")