- 新增 queryISIMSRoomBuyRecord 充值记录获取 + 10分钟缓存 - 日耗电 = 剩余变化 + 当天充值电量(电价0.535元/度) - 月度汇总增加充值次数/电量/金额 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
119 lines
3.3 KiB
Go
119 lines
3.3 KiB
Go
package main
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// buy_records.go - 充值/缴费记录获取与缓存
|
||
// 接口: POST /app/electric/queryISIMSRoomBuyRecord
|
||
// 返回每笔充值记录(金额/类型/时间),用于精确计算日耗电
|
||
|
||
// buyRecord 单笔充值记录
|
||
type buyRecord struct {
|
||
Date string `json:"date"` // 充值日期 YYYY-MM-DD
|
||
Money float64 `json:"money"` // 充值金额(元)
|
||
Kwh float64 `json:"kwh"` // 换算电量(度) = money / price
|
||
Type string `json:"type"` // 现金充值 / 下发补助
|
||
Detail string `json:"detail"` // 完整时间 YYYY-M-D H:M:S
|
||
}
|
||
|
||
// 充值记录缓存
|
||
var (
|
||
buyRecordsCache []buyRecord
|
||
buyRecordsTime int64
|
||
)
|
||
|
||
// queryBuyRecords 获取某房间的充值记录(需 application 域 shiroJID)
|
||
func queryBuyRecords(shiroJID string, room *roomInfo) ([]buyRecord, error) {
|
||
price := unitPrice()
|
||
s := newXfSession(shiroJID)
|
||
body := fmt.Sprintf("areaId=%s&buildingCode=%s&floorCode=%s&roomCode=%s&mdtype=room&platform=%s",
|
||
room.AreaID, room.BuildingCode, room.FloorCode, room.RoomCode, xfPlatform)
|
||
b, _, err := s.postForm("https://application.xiaofubao.com/app/electric/queryISIMSRoomBuyRecord",
|
||
body, "https://application.xiaofubao.com/")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var res struct {
|
||
StatusCode flexInt `json:"statusCode"`
|
||
Rows []struct {
|
||
DateTime string `json:"datetime"` // "2026-8-23 0:45:49"
|
||
BuyType string `json:"buytype"` // 现金充值 / 下发补助
|
||
BuyUsing string `json:"buyusingtpe"` // 照明用电
|
||
Money string `json:"money"` // "40.00"
|
||
} `json:"rows"`
|
||
}
|
||
if err := json.Unmarshal(b, &res); err != nil {
|
||
return nil, err
|
||
}
|
||
if res.StatusCode != 0 {
|
||
return nil, fmt.Errorf("queryISIMSRoomBuyRecord 失败: %s", string(b))
|
||
}
|
||
|
||
var records []buyRecord
|
||
for _, r := range res.Rows {
|
||
var money float64
|
||
fmt.Sscanf(r.Money, "%f", &money)
|
||
rec := buyRecord{
|
||
Date: datePart(r.DateTime),
|
||
Money: round2(money),
|
||
Kwh: round2(money / price),
|
||
Type: r.BuyType,
|
||
Detail: r.DateTime,
|
||
}
|
||
records = append(records, rec)
|
||
}
|
||
return records, nil
|
||
}
|
||
|
||
// getBuyRecordsCached 获取充值记录(带缓存,10 分钟有效)
|
||
func getBuyRecordsCached(shiroJID string, room *roomInfo) ([]buyRecord, error) {
|
||
if buyRecordsCache != nil && time.Now().Unix()-buyRecordsTime < 600 {
|
||
return buyRecordsCache, nil
|
||
}
|
||
recs, err := queryBuyRecords(shiroJID, room)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
buyRecordsCache = recs
|
||
buyRecordsTime = time.Now().Unix()
|
||
return recs, nil
|
||
}
|
||
|
||
// rechargeKwhByDate 生成 map[date] -> 当天充值电量(度)
|
||
func rechargeKwhByDate(records []buyRecord) map[string]float64 {
|
||
m := map[string]float64{}
|
||
for _, r := range records {
|
||
m[r.Date] = round2(m[r.Date] + r.Kwh)
|
||
}
|
||
return m
|
||
}
|
||
|
||
// unitPrice 电价(元/度),默认 0.535,可用 XF_PRICE 环境变量覆盖
|
||
func unitPrice() float64 {
|
||
if v := envOr("XF_PRICE", ""); v != "" {
|
||
var p float64
|
||
if _, err := fmt.Sscanf(v, "%f", &p); err == nil && p > 0 {
|
||
return p
|
||
}
|
||
}
|
||
return 0.535
|
||
}
|
||
|
||
// datePart 从 "2026-8-23 0:45:49" 提取 "2026-08-23"
|
||
func datePart(dt string) string {
|
||
parts := strings.SplitN(dt, " ", 2)
|
||
if len(parts) == 0 {
|
||
return dt
|
||
}
|
||
// 规范化月份/日补零
|
||
ymd := strings.Split(parts[0], "-")
|
||
if len(ymd) != 3 {
|
||
return parts[0]
|
||
}
|
||
return fmt.Sprintf("%s-%02s-%02s", ymd[0], ymd[1], ymd[2])
|
||
}
|