137 lines
3.5 KiB
JavaScript
137 lines
3.5 KiB
JavaScript
const {createApp,onMounted,ref} = Vue
|
||
createApp({
|
||
setup(){
|
||
const apiBase = ref(window.location.origin || "http://localhost:8000")
|
||
const stationHash = ref("")
|
||
const aiText = ref("")
|
||
const placeholder = ref("在左侧列表中选择驿来特场站,点击“查看价差”加载24小时分时电价与竞品对比,再点击“AI价差分析”获取模型给出的策略建议。")
|
||
const loading = ref(false)
|
||
const aiLoading = ref(false)
|
||
const stations = ref([])
|
||
const searchKeyword = ref("")
|
||
const selectedStation = ref(null)
|
||
const priceTableColumns = ref([])
|
||
const priceTableRows = ref([])
|
||
let chartInstance = null
|
||
let es = null
|
||
const initChart = () => {
|
||
const dom = document.getElementById("chart")
|
||
if (dom && !chartInstance) {
|
||
chartInstance = echarts.init(dom)
|
||
}
|
||
}
|
||
const loadStations = async () => {
|
||
try{
|
||
const url = apiBase.value + "/api/ylt/stations"
|
||
const params = searchKeyword.value ? {params:{q:searchKeyword.value}} : {}
|
||
const res = await axios.get(url,params)
|
||
stations.value = Array.isArray(res.data) ? res.data : []
|
||
if (!selectedStation.value && stations.value.length > 0) {
|
||
selectStation(stations.value[0])
|
||
}
|
||
}catch(e){
|
||
console.error(e)
|
||
}
|
||
}
|
||
const buildPriceTable = data => {
|
||
const cols = []
|
||
cols.push("时段")
|
||
cols.push("驿来特")
|
||
data.competitors.forEach(c => {
|
||
cols.push(c.operator)
|
||
})
|
||
priceTableColumns.value = cols
|
||
const rows = []
|
||
for (let i = 0; i < data.hours.length; i++) {
|
||
const row = []
|
||
row.push(data.hours[i] + ":00")
|
||
row.push(data.ylt.series[i])
|
||
data.competitors.forEach(c => {
|
||
row.push(c.series[i])
|
||
})
|
||
rows.push(row)
|
||
}
|
||
priceTableRows.value = rows
|
||
}
|
||
const loadComparison = async () => {
|
||
if (!stationHash.value) return
|
||
loading.value = true
|
||
try{
|
||
const url = apiBase.value + "/api/ylt/pricing/comparison/" + stationHash.value
|
||
const res = await axios.get(url)
|
||
const data = res.data
|
||
const hours = data.hours.map(h => h + ":00")
|
||
const series = []
|
||
series.push({
|
||
name:"驿来特",
|
||
type:"line",
|
||
smooth:true,
|
||
data:data.ylt.series
|
||
})
|
||
data.competitors.forEach(c=>{
|
||
series.push({
|
||
name:c.operator,
|
||
type:"line",
|
||
smooth:true,
|
||
data:c.series
|
||
})
|
||
})
|
||
buildPriceTable(data)
|
||
const option = {
|
||
tooltip:{trigger:"axis"},
|
||
legend:{data:series.map(s=>s.name),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
|
||
}
|
||
initChart()
|
||
chartInstance.setOption(option)
|
||
}catch(e){
|
||
console.error(e)
|
||
}finally{
|
||
loading.value = false
|
||
}
|
||
}
|
||
const selectStation = s => {
|
||
selectedStation.value = s
|
||
stationHash.value = s.station_hash
|
||
loadComparison()
|
||
}
|
||
const startAiStream = () => {
|
||
if (!selectedStation.value || !stationHash.value) return
|
||
if (es) {
|
||
es.close()
|
||
es = null
|
||
}
|
||
aiText.value = ""
|
||
aiLoading.value = true
|
||
const url = apiBase.value + "/api/ylt/pricing/comparison/" + stationHash.value + "/sse"
|
||
es = new EventSource(url)
|
||
es.onmessage = ev => {
|
||
aiText.value += ev.data
|
||
}
|
||
es.onerror = () => {
|
||
aiLoading.value = false
|
||
if (es) {
|
||
es.close()
|
||
es = null
|
||
}
|
||
}
|
||
}
|
||
onMounted(()=>{
|
||
initChart()
|
||
loadStations()
|
||
})
|
||
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 {stationHash,aiText,placeholder,loading,aiLoading,stations,searchKeyword,selectedStation,priceTableColumns,priceTableRows,loadStations,loadComparison,selectStation,startAiStream,formatCell}
|
||
}
|
||
}).mount("#app")
|