天气服务1.0

main
cc 2025-01-02 22:57:51 +08:00
parent b9869bbc6b
commit f69590b0c6
32 changed files with 1426 additions and 0 deletions

3
.gitignore Normal file
View File

@ -0,0 +1,3 @@
log/
weather.pp
weather

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"marscode.chatLanguage": "cn"
}

112
db/db.go Normal file
View File

@ -0,0 +1,112 @@
package db
import (
"cc/util/log"
"github.com/jmoiron/sqlx"
)
var (
DB *sqlx.DB
// DBPath string = "file:weather.pp?_foreign_keys=1&&_journal_mode=WAL&&mode=rwc"
DBPath string = "file:weather.pp?_foreign_keys=1"
)
func init() {
var err error
DB, err = NewSQLiteDB(DBPath)
if err != nil {
log.L.Fatalf("数据库连接失败: %v", err)
}
if !IsDBInitialized(DB) {
log.L.Info("数据库未初始化,正在初始化...")
createTables()
initData()
}
}
// 创建表
func createTables() {
// 创建天气类型表
weatherTypeTable := `
CREATE TABLE IF NOT EXISTS weather_types (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
description TEXT NOT NULL
);`
// 创建天气表
weatherTable := `
CREATE TABLE IF NOT EXISTS weathers (
project_id INTEGER PRIMARY KEY,
value TEXT NOT NULL,
update_at TEXT NOT NULL,
FOREIGN KEY(project_id) REFERENCES projects(id)
);`
// 创建位置表
localtionTable := `
CREATE TABLE IF NOT EXISTS localtions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
code TEXT NOT NULL
);`
// 创建项目表
projectTable := `
CREATE TABLE IF NOT EXISTS projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
code TEXT NOT NULL,
user TEXT NOT NULL,
description TEXT NOT NULL,
localtion_id INTEGER NOT NULL,
weather_type_id INTEGER NOT NULL,
update_frequency INTEGER NOT NULL,
dev BOOLEAN NOT NULL,
FOREIGN KEY(localtion_id) REFERENCES localtions(id),
FOREIGN KEY(weather_type_id) REFERENCES weather_types(id)
);`
// 创建表
tables := []string{weatherTypeTable, weatherTable, localtionTable, projectTable}
for _, table := range tables {
_, err := DB.Exec(table)
if err != nil {
log.L.Fatalf("创建表失败: %v", err)
}
}
}
// 初始化数据
func initData() {
// 初始化天气类型
weatherTypes := map[int][]string{
1: {"now", "实时天气"},
3: {"3d", "3天预报"},
7: {"7d", "7天预报"},
10: {"10d", "10天预报"},
15: {"15d", "15天预报"},
30: {"30d", "30天预报"},
24: {"24h", "24小时预报"},
72: {"72h", "72小时预报"},
168: {"168h", "168小时预报"},
}
for id, v := range weatherTypes {
_, err := DB.Exec("INSERT INTO weather_types (id, name, description) VALUES (?,?,?)", id, v[0], v[1])
if err != nil {
log.L.Errorf("初始化天气类型失败: %v", err)
}
}
// 初始化位置
localtions := map[string]string{
"西安": "101010100",
"上海": "101020100",
}
for name, code := range localtions {
_, err := DB.Exec("INSERT INTO localtions (name, code) VALUES (?,?)", name, code)
if err != nil {
log.L.Errorf("初始化位置失败: %v", err)
}
}
}

87
db/model/localtion.go Normal file
View File

@ -0,0 +1,87 @@
package model
import (
"cc/db"
"errors"
)
// Localtion 位置
type Localtion struct {
ID int `db:"id" json:"id"` // 位置ID
Name string `db:"name" json:"name"` // 位置名称
Code string `db:"code" json:"code"` // 位置编码
}
// GetAll 获取所有位置
func (loc *Localtion) GetAll() (rv []Localtion, rer error) {
sql := "SELECT * FROM localtions"
rer = db.DB.Select(&rv, sql)
return
}
// GetLocaltionByID 根据ID获取位置
func (loc *Localtion) GetLocaltionByID() (rer error) {
sql := "SELECT * FROM localtions WHERE id =?"
return db.DB.Get(loc, sql, loc.ID)
}
// CreateLocaltion 创建位置
func (loc *Localtion) CreateLocaltion() (rer error) {
// 检查位置名称是否存在
var count int
sql := "SELECT COUNT(*) FROM localtions WHERE name=?"
err := db.DB.Get(&count, sql, loc.Name)
if err != nil {
return err
}
if count > 0 {
return errors.New("位置名称已存在")
}
// 检查位置编码是否存在
sql = "SELECT COUNT(*) FROM localtions WHERE code=?"
err = db.DB.Get(&count, sql, loc.Code)
if err != nil {
return err
}
if count > 0 {
return errors.New("位置编码已存在")
}
// 插入数据
sql = "INSERT INTO localtions (name, code) VALUES (?, ?)"
_, rer = db.DB.Exec(sql, loc.Name, loc.Code)
return
}
// UpdateLocaltion 更新位置
func (loc *Localtion) UpdateLocaltion() (rer error) {
// 检查位置名称是否存在
var count int
sql := "SELECT COUNT(*) FROM localtions WHERE name=? AND id!=?"
err := db.DB.Get(&count, sql, loc.Name, loc.ID)
if err != nil {
return err
}
if count > 0 {
return errors.New("位置名称已存在")
}
// 检查位置编码是否存在
sql = "SELECT COUNT(*) FROM localtions WHERE code=? AND id!=?"
err = db.DB.Get(&count, sql, loc.Code, loc.ID)
if err != nil {
return err
}
if count > 0 {
return errors.New("位置编码已存在")
}
// 更新数据
sql = "UPDATE localtions SET name=?, code=? WHERE id=?"
_, rer = db.DB.Exec(sql, loc.Name, loc.Code, loc.ID)
return
}
// DeleteLocaltion 删除位置
func (loc *Localtion) DeleteLocaltion() (rer error) {
sql := "DELETE FROM localtions WHERE id=?"
_, rer = db.DB.Exec(sql, loc.ID)
return
}

104
db/model/project.go Normal file
View File

@ -0,0 +1,104 @@
package model
import (
"cc/db"
"errors"
"math/rand"
)
// Project 项目
type Project struct {
ID int `db:"id" json:"id"` // 项目ID
Name string `db:"name" json:"name"` // 项目名称
Code int `db:"code" json:"code"` // 项目编码
User string `db:"user" json:"user"` // 项目用户
Description string `db:"description" json:"description"` // 项目描述
UpdateFrequency int `db:"update_frequency" json:"update_frequency"` // 更新频率
LocaltionID int `db:"localtion_id" json:"localtion_id"` // 项目位置ID
WeatherTypeID int `db:"weather_type_id" json:"weather_type_id"` // 天气类型ID
Dev bool `db:"dev" json:"dev"` // 是否为开发模式
}
// GetAll 获取所有项目
func (pro *Project) GetAll() (rv []Project, rer error) {
sql := "SELECT * FROM projects"
rer = db.DB.Select(&rv, sql)
return
}
// GetProjectByID 通过项目ID获取项目
func (pro *Project) GetProjectByID() (rer error) {
sql := "SELECT * FROM projects WHERE id =?"
return db.DB.Get(pro, sql, pro.ID)
}
// GetProjectByCode 通过项目代码获取项目
func (pro *Project) GetProjectByCode() (rer error) {
sql := "SELECT * FROM projects WHERE code =?"
return db.DB.Get(pro, sql, pro.Code)
}
// CreateProject 创建项目
func (pro *Project) CreateProject() (rer error) {
// 判断是否存在相同的项目名称和天气类型
var count int
err := db.DB.Get(&count, "SELECT COUNT(*) FROM projects WHERE name =? AND weather_type_id =?", pro.Name, pro.WeatherTypeID)
if err != nil {
return err
}
if count > 0 {
return errors.New("已存在相同配置")
}
// 判断项目代码当前项目代码不为0时必须是4位数字
if pro.Code != 0 {
if pro.Code < 1000 || pro.Code > 9999 {
return errors.New("项目代码必须是4位数字")
}
err := db.DB.Get(&count, "SELECT COUNT(*) FROM projects WHERE code =?", pro.Code)
if err != nil {
return err
}
if count > 0 {
return errors.New("项目代码已存在,请重新输入,或者将项目代码设置为0,系统将随机生成一个4位数字的项目代码")
}
} else {
// 随机生成一个4位数字的项目代码
for {
pro.Code = rand.Intn(9000) + 1000
err := db.DB.Get(&count, "SELECT COUNT(*) FROM projects WHERE code =?", pro.Code)
if err != nil {
return err
}
if count == 0 {
break
}
}
}
// 更新频率为0时设置为60分钟
if pro.UpdateFrequency == 0 {
pro.UpdateFrequency = 60
}
// 插入数据
sql := "INSERT INTO projects (name, code, user, description, update_frequency, localtion_id, weather_type_id, dev) VALUES (?,?,?,?,?,?,?,?)"
_, rer = db.DB.Exec(sql, pro.Name, pro.Code, pro.User, pro.Description, pro.UpdateFrequency, pro.LocaltionID, pro.WeatherTypeID, pro.Dev)
return
}
// UpdateProject 更新项目
func (pro *Project) UpdateProject() (rer error) {
// 更新频率为0时设置为60分钟
if pro.UpdateFrequency == 0 {
pro.UpdateFrequency = 60
}
// 更新数据
sql := "UPDATE projects SET name=?, user=?, description=?, update_frequency=?, localtion_id=?, weather_type_id=?, dev=? WHERE id=?"
_, rer = db.DB.Exec(sql, pro.Name, pro.User, pro.Description, pro.UpdateFrequency, pro.LocaltionID, pro.WeatherTypeID, pro.Dev, pro.ID)
return
}
// DeleteProject 删除项目
func (pro *Project) DeleteProject() (rer error) {
sql := "DELETE FROM projects WHERE id=?"
_, rer = db.DB.Exec(sql, pro.ID)
return
}

38
db/model/weather.go Normal file
View File

@ -0,0 +1,38 @@
package model
import (
"cc/db"
"encoding/json"
)
// Weather 天气
type Weather struct {
ProjectID int `db:"project_id" json:"project_id"` // 项目ID
UpdateAt string `db:"update_at" json:"update_at"` // 更新时间
Value json.RawMessage `db:"value" json:"value"` // 天气信息
}
// GetWeather 获取天气
func (w *Weather) GetWeather() (rer error) {
sql := "SELECT * FROM weathers WHERE project_id =?"
return db.DB.Get(w, sql, w.ProjectID)
}
// UpdateWeather 更新天气
func (w *Weather) UpdateWeather() (rer error) {
// 如果不存在则创建
var count int
err := db.DB.Get(&count, "SELECT COUNT(*) FROM weathers WHERE project_id =?", w.ProjectID)
if err != nil {
return err
}
if count == 0 {
sql := "INSERT INTO weathers (project_id, update_at, value) VALUES (?, ?, ?)"
_, rer = db.DB.Exec(sql, w.ProjectID, w.UpdateAt, w.Value)
return
}
// 更新天气
sql := "UPDATE weathers SET update_at =?, value =? WHERE project_id =?"
_, rer = db.DB.Exec(sql, w.UpdateAt, w.Value, w.ProjectID)
return
}

22
db/model/weather_type.go Normal file
View File

@ -0,0 +1,22 @@
package model
import "cc/db"
type WeatherType struct {
Id int `db:"id" json:"id"` // 天气类型ID
Name string `db:"name" json:"name"` // 天气类型名称
Description string `db:"description" json:"description"` // 天气类型描述
}
// GetAll 获取所有天气类型
func (w *WeatherType) GetAll() (rv []WeatherType, rer error) {
sql := "SELECT * FROM weather_types"
rer = db.DB.Select(&rv, sql)
return
}
// GetWeatherTypeByID 根据ID获取天气类型
func (w *WeatherType) GetWeatherTypeByID() (rer error) {
sql := "SELECT * FROM weather_types WHERE id =?"
return db.DB.Get(w, sql, w.Id)
}

24
db/sqlite.go Normal file
View File

@ -0,0 +1,24 @@
package db
import (
"github.com/jmoiron/sqlx"
_ "github.com/mattn/go-sqlite3"
)
func NewSQLiteDB(Path string) (db *sqlx.DB, rer error) {
db, rer = sqlx.Open("sqlite3", Path)
if rer != nil {
return
}
rer = db.Ping()
return
}
func IsDBInitialized(db *sqlx.DB) bool {
var count int
err := db.Get(&count, "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='localtions';")
if err != nil {
return false
}
return count > 0
}

30
go.mod Normal file
View File

@ -0,0 +1,30 @@
module cc
go 1.23.1
require (
git.shikicc.com/golang/kit v0.0.6
github.com/gofiber/contrib/fiberzap/v2 v2.1.4
github.com/gofiber/fiber/v2 v2.52.6
github.com/jmoiron/sqlx v1.4.0
github.com/mattn/go-sqlite3 v1.14.24
)
require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/tinylib/msgp v1.2.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.55.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/sys v0.28.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
)

62
go.sum Normal file
View File

@ -0,0 +1,62 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.shikicc.com/golang/kit v0.0.6 h1:4/G3Ajsgw8bET2W2SrMG5hCh94zrh/jZR/Md8QbxG4s=
git.shikicc.com/golang/kit v0.0.6/go.mod h1:rDoS4olD/rogB7sKzzFBBR7MF8WsXUcrzaaeDFFQgyQ=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/gofiber/contrib/fiberzap/v2 v2.1.4 h1:GCtCQnT4Cr9az4qab2Ozmqsomkxm4Ei86MfKk/1p5+0=
github.com/gofiber/contrib/fiberzap/v2 v2.1.4/go.mod h1:PkdXgUzw+oj4m6ksfKJ0Hs3H7iPhwvhfI4b2LSA9hhA=
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po=
github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

11
log/info Normal file
View File

@ -0,0 +1,11 @@
[2025-01-01 19:11:28] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 12:35:28] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 12:42:25] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 12:44:26] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 13:57:55] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 14:17:40] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 14:32:17] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 14:33:49] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 14:36:33] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 14:37:47] [INFO] 数据库未初始化,正在初始化...
[2025-01-02 14:39:59] [INFO] 数据库未初始化,正在初始化...

117
log/web_info Normal file
View File

@ -0,0 +1,117 @@
[2025-01-01 19:11:56] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/0033", "protocol": "http", "ip": "10.10.10.31", "latency": "861.559µs", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}
[2025-01-01 19:14:02] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/0033", "protocol": "http", "ip": "10.10.10.31", "latency": "390.925µs", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}
[2025-01-01 19:14:31] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/0033", "protocol": "http", "ip": "10.10.10.31", "latency": "486.374µs", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}
[2025-01-01 19:15:21] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/0033", "protocol": "http", "ip": "10.10.10.31", "latency": "184.637µs", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}
[2025-01-01 19:15:23] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/0033", "protocol": "http", "ip": "10.10.10.31", "latency": "199.286µs", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}
[2025-01-01 19:17:06] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/0033", "protocol": "http", "ip": "10.10.10.31", "latency": "685.22µs", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}
[2025-01-02 12:37:01] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/6143", "protocol": "http", "ip": "10.10.10.31", "latency": "294.391µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:37:35] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "258.253µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:37:54] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "6.59407ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:37:59] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "200.805µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:30] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "254.377µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:33] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "167.144µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:40] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "190.578µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:44] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "7.321563ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:48] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "215.955µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:53] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "7.433112ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:42:55] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "211.919µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:44:33] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "272.261µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:44:36] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "9.664442ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:44:37] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "187.402µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:44:41] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "221.306µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:44:43] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "7.777277ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:44:45] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "217.447µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:45:42] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/localtion/2", "protocol": "http", "ip": "10.10.10.31", "latency": "5.95115ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:45:45] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/localtion/2", "protocol": "http", "ip": "10.10.10.31", "latency": "282.711µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:45:46] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/localtion/2", "protocol": "http", "ip": "10.10.10.31", "latency": "301.948µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:45:47] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/localtion/2", "protocol": "http", "ip": "10.10.10.31", "latency": "259.358µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:45:56] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "201.158µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:45:57] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "149.54µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:46:20] [INFO] Success {"status": 200, "method": "DELETE", "path": "/api/localtion/3", "protocol": "http", "ip": "10.10.10.31", "latency": "6.073141ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:46:27] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "170.13µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:46:34] [INFO] Success {"status": 200, "method": "POST", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "210.967µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:47:11] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "266.07µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:47:37] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/2977", "protocol": "http", "ip": "10.10.10.31", "latency": "203.612µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:48:00] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "5.957308ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:48:11] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "168.577µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 12:48:13] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "169.73µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:58:00] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "271.03µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:58:18] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/2977", "protocol": "http", "ip": "10.10.10.31", "latency": "146.255µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:58:20] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/2977", "protocol": "http", "ip": "10.10.10.31", "latency": "132.428µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:58:23] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/2977", "protocol": "http", "ip": "10.10.10.31", "latency": "180.108µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:58:26] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "132.429µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:58:45] [INFO] Success {"status": 200, "method": "GET", "path": "/api/localtion", "protocol": "http", "ip": "10.10.10.31", "latency": "165.362µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 13:59:05] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "139.623µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:01:22] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "100.069µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:01:54] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "26.189µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:02:18] [INFO] Success {"status": 200, "method": "POST", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "306.087µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:05:20] [INFO] Success {"status": 200, "method": "POST", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "156.755µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:16:37] [INFO] Success {"status": 200, "method": "POST", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "279.27µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:16:38] [INFO] Success {"status": 200, "method": "POST", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "317.023µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:16:52] [INFO] Success {"status": 200, "method": "POST", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "177.116µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:17:42] [INFO] Success {"status": 200, "method": "POST", "path": "/api/weather/types", "protocol": "http", "ip": "10.10.10.31", "latency": "347.31µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:18:02] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "312.112µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:18:12] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "187.847µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:18:45] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "6.345588ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:20:52] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "453.018µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:21:09] [INFO] Success {"status": 200, "method": "DELETE", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "41.258µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:21:20] [INFO] Success {"status": 200, "method": "DELETE", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "33.814µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:24:56] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "269.53µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:25:44] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "135.657µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:26:11] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "332.409µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:26:54] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "261.663µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:28:11] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "319.404µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:28:41] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "312.601µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:32:25] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "7.880342ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:32:30] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "183.968µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:32:34] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "165.132µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:32:45] [INFO] Success {"status": 200, "method": "DELETE", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "88.607µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:33:55] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "13.07987ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:33:58] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "6.922872ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:34:05] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "214.775µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:34:07] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "188.356µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:36:38] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "6.632361ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:36:45] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/3002", "protocol": "http", "ip": "10.10.10.31", "latency": "223.382µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:36:52] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project/3002", "protocol": "http", "ip": "10.10.10.31", "latency": "182.184µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:02] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "157.126µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:11] [INFO] Success {"status": 200, "method": "PUT", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "9.599906ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:22] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "194.136µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:23] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "150.103µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:29] [INFO] Success {"status": 200, "method": "DELETE", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "6.156992ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:32] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "160.543µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:35] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "6.655493ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:37:52] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "9.692681ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:38:01] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/2426", "protocol": "http", "ip": "10.10.10.31", "latency": "165.037576ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:38:05] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/2426", "protocol": "http", "ip": "10.10.10.31", "latency": "39.928172ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:38:06] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/2426", "protocol": "http", "ip": "10.10.10.31", "latency": "41.064915ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:38:07] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/2426", "protocol": "http", "ip": "10.10.10.31", "latency": "42.155822ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:38:08] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/2426", "protocol": "http", "ip": "10.10.10.31", "latency": "40.147544ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:12] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "10.894672ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:26] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "10.371355ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:28] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "6.659095ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:29] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "20.576789ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:31] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "6.556924ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:32] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "6.679473ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:37] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "251.754µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:50] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "156.228978ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:40:59] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "42.464346ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:41:03] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "39.912975ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:41:52] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "139.313879ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:41:53] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "36.423922ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:43:15] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "151.524839ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:43:17] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "39.584616ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:43:18] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "39.211161ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:43:19] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "38.165661ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:43:20] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "38.649042ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:44:06] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "151.430289ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:44:08] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "40.111296ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:44:09] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "39.638676ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:45:40] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "143.712593ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:45:41] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "207.35µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:45:42] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "245.492µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:45:43] [INFO] Success {"status": 200, "method": "GET", "path": "/api/weather/7127", "protocol": "http", "ip": "10.10.10.31", "latency": "241.755µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:48:26] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "423.669µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:48:28] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "159.64µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:48:34] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "10.289775ms", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:48:35] [INFO] Success {"status": 200, "method": "POST", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "170.822µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 22:48:38] [INFO] Success {"status": 200, "method": "GET", "path": "/api/project", "protocol": "http", "ip": "10.10.10.31", "latency": "252.726µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}

2
log/web_warn Normal file
View File

@ -0,0 +1,2 @@
[2025-01-02 12:45:15] [WARN] Client error {"status": 401, "method": "PUT", "path": "/api/localtion/2", "protocol": "http", "ip": "10.10.10.31", "latency": "17.994µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}
[2025-01-02 14:20:57] [WARN] Client error {"status": 401, "method": "DELETE", "path": "/api/project/1", "protocol": "http", "ip": "10.10.10.31", "latency": "14.336µs", "ua": "PostmanRuntime-ApipostRuntime/1.1.0"}

29
qweather/get.go Normal file
View File

@ -0,0 +1,29 @@
package qweather
import (
"encoding/json"
"io"
"net/http"
)
// 获取天气
func Get(location_id, weather_type_id int, dev bool) (json.RawMessage, error) {
// 生成url
url, err := makeURL(dev, location_id, weather_type_id)
if err != nil {
return nil, err
}
// 发送请求, 获取数据
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 读取数据
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// 返回数据
return body, nil
}

50
qweather/url.go Normal file
View File

@ -0,0 +1,50 @@
package qweather
import (
"cc/db/model"
)
var (
// 开发者密钥
c_DEVKEY = "ecac5888fd314a5d883c0f9126145969"
// 生产环境密钥
c_PROKEY = "ecac5888fd314a5d883c0f9126145969"
// 开发环境url
c_DEVURL = "https://devapi.qweather.com/"
// 生产环境url
c_PROURL = "https://api.qweather.com/"
// 版本号
c_VERSION = "v7/weather/"
)
// makeURL 生成url
func makeURL(dev bool, location_id, weather_type_id int) (rv string, rer error) {
// 获取位置信息
localtion := model.Localtion{ID: location_id}
err := localtion.GetLocaltionByID()
if err != nil {
return "", err
}
// 获取天气类型
weatherType := model.WeatherType{Id: weather_type_id}
err = weatherType.GetWeatherTypeByID()
if err != nil {
return "", err
}
if dev {
rv = c_DEVURL
} else {
rv = c_PROURL
}
rv += c_VERSION
rv += weatherType.Name
rv += "?key="
if dev {
rv += c_DEVKEY
} else {
rv += c_PROKEY
}
rv += "&location="
rv += localtion.Code
return
}

63
util/log/log.go Normal file
View File

@ -0,0 +1,63 @@
package log
import (
"git.shikicc.com/golang/kit/log/zaplog"
)
var L = zaplog.New(zaplog.Config{
Mode: zaplog.Debug,
DebugLog: zaplog.LogFileConfig{
Filename: "log/debug",
FileSize_MB: 1,
FileBackup: 3,
},
InfoLog: zaplog.LogFileConfig{
Filename: "log/info",
FileSize_MB: 1,
FileBackup: 3,
},
WarnLog: zaplog.LogFileConfig{
Filename: "log/warn",
FileSize_MB: 1,
FileBackup: 3,
},
ErrorLog: zaplog.LogFileConfig{
Filename: "log/error",
FileSize_MB: 1,
FileBackup: 3,
},
FatalLog: zaplog.LogFileConfig{
Filename: "log/fatal",
FileSize_MB: 1,
FileBackup: 3,
},
})
var W = zaplog.New(zaplog.Config{
Mode: zaplog.Debug,
DebugLog: zaplog.LogFileConfig{
Filename: "log/web_debug",
FileSize_MB: 1,
FileBackup: 3,
},
InfoLog: zaplog.LogFileConfig{
Filename: "log/web_info",
FileSize_MB: 1,
FileBackup: 3,
},
WarnLog: zaplog.LogFileConfig{
Filename: "log/web_warn",
FileSize_MB: 1,
FileBackup: 3,
},
ErrorLog: zaplog.LogFileConfig{
Filename: "log/web_error",
FileSize_MB: 1,
FileBackup: 3,
},
FatalLog: zaplog.LogFileConfig{
Filename: "log/web_fatal",
FileSize_MB: 1,
FileBackup: 3,
},
})

BIN
weather Executable file

Binary file not shown.

11
weather.go Normal file
View File

@ -0,0 +1,11 @@
package main
import (
"cc/db"
"cc/web"
)
func main() {
defer db.DB.Close()
web.Go()
}

BIN
weather.pp Normal file

Binary file not shown.

View File

@ -0,0 +1,82 @@
package api
import (
"cc/db/model"
"cc/web/util/response"
"github.com/gofiber/fiber/v2"
)
// GetLocaltions 获取所有地点
func GetLocaltions(c *fiber.Ctx) error {
loc := model.Localtion{}
// 获取所有地点
localtions, err := loc.GetAll()
if err != nil {
return response.Error(c, response.InternalServerError, "获取地点失败: "+err.Error())
}
// 返回地点
return response.Ok(c, localtions)
}
// CreateLocaltion 创建地点
func CreateLocaltion(c *fiber.Ctx) error {
loc := model.Localtion{}
// 解析参数
err := c.BodyParser(&loc)
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 创建地点
err = loc.CreateLocaltion()
if err != nil {
return response.Error(c, response.InternalServerError, "创建地点失败: "+err.Error())
}
// 返回地点
return response.Ok(c, loc)
}
// UpdateLocaltion 更新地点
func UpdateLocaltion(c *fiber.Ctx) error {
// 获取地点id
id, err := c.ParamsInt("id")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取地点
loc := model.Localtion{
ID: id,
}
// 解析参数
err = c.BodyParser(&loc)
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 更新地点
err = loc.UpdateLocaltion()
if err != nil {
return response.Error(c, response.InternalServerError, "更新地点失败: "+err.Error())
}
// 返回地点
return response.Ok(c, loc)
}
// DeleteLocaltion 删除地点
func DeleteLocaltion(c *fiber.Ctx) error {
// 获取地点id
id, err := c.ParamsInt("id")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取地点
loc := model.Localtion{
ID: id,
}
// 删除地点
err = loc.DeleteLocaltion()
if err != nil {
return response.Error(c, response.InternalServerError, "删除地点失败: "+err.Error())
}
// 返回地点
return response.Ok(c, "删除地点成功")
}

View File

@ -0,0 +1,19 @@
package localtion
import (
"cc/web/app/localtion/api"
"github.com/gofiber/fiber/v2"
)
// AddRouter 添加路由
func AddRouter(r fiber.Router) {
// 获取所有地点
r.Get("localtion", api.GetLocaltions)
// 创建地点
r.Post("localtion", api.CreateLocaltion)
// 更新地点
r.Put("localtion/:id", api.UpdateLocaltion)
// 删除地点
r.Delete("localtion/:id", api.DeleteLocaltion)
}

View File

@ -0,0 +1,122 @@
package api
import (
"cc/db/model"
"cc/web/util/response"
"github.com/gofiber/fiber/v2"
)
// GetProjects 获取所有项目
func GetProjects(c *fiber.Ctx) error {
pro := model.Project{}
// 获取所有项目
projects, err := pro.GetAll()
if err != nil {
return response.Error(c, response.InternalServerError, "获取项目失败: "+err.Error())
}
// 返回项目
return response.Ok(c, projects)
}
// GetProjectByID 通过项目ID获取项目
func GetProjectByID(c *fiber.Ctx) error {
// 获取项目ID
id, err := c.ParamsInt("id")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取项目
pro := model.Project{
ID: id,
}
// 通过项目ID获取项目
err = pro.GetProjectByID()
if err != nil {
return response.Error(c, response.InternalServerError, "获取项目失败: "+err.Error())
}
// 返回项目
return response.Ok(c, pro)
}
// GetProjectByCode 通过项目代码获取项目
func GetProjectByCode(c *fiber.Ctx) error {
// 获取项目代码
code, err := c.ParamsInt("code")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取项目
pro := model.Project{
Code: code,
}
// 通过项目代码获取项目
err = pro.GetProjectByCode()
if err != nil {
return response.Error(c, response.InternalServerError, "获取项目失败: "+err.Error())
}
// 返回项目
return response.Ok(c, pro)
}
// CreateProject 创建项目
func CreateProject(c *fiber.Ctx) error {
pro := model.Project{}
// 解析参数
err := c.BodyParser(&pro)
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 创建项目
err = pro.CreateProject()
if err != nil {
return response.Error(c, response.InternalServerError, "创建项目失败: "+err.Error())
}
// 返回项目
return response.Ok(c, pro)
}
// UpdateProject 更新项目
func UpdateProject(c *fiber.Ctx) error {
// 获取项目代码
id, err := c.ParamsInt("id")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取项目
pro := model.Project{
ID: id,
}
// 解析参数
err = c.BodyParser(&pro)
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 更新项目
err = pro.UpdateProject()
if err != nil {
return response.Error(c, response.InternalServerError, "更新项目失败: "+err.Error())
}
// 返回项目
return response.Ok(c, pro)
}
// DeleteProject 删除项目
func DeleteProject(c *fiber.Ctx) error {
// 获取项目代码
id, err := c.ParamsInt("id")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取项目
pro := model.Project{
ID: id,
}
// 删除项目
err = pro.DeleteProject()
if err != nil {
return response.Error(c, response.InternalServerError, "删除项目失败: "+err.Error())
}
// 返回项目
return response.Ok(c, "删除成功")
}

View File

@ -0,0 +1,23 @@
package project
import (
"cc/web/app/project/api"
"github.com/gofiber/fiber/v2"
)
// AddRouter 添加路由
func AddRouter(r fiber.Router) {
// 获取所有项目
r.Get("project", api.GetProjects)
// 通过项目ID获取项目
r.Get("project/:id", api.GetProjectByID)
// 通过项目编码获取项目
r.Post("project/:code", api.GetProjectByCode)
// 创建项目
r.Post("project", api.CreateProject)
// 更新项目
r.Put("project/:id", api.UpdateProject)
// 删除项目
r.Delete("project/:id", api.DeleteProject)
}

View File

@ -0,0 +1,69 @@
package api
import (
"cc/db/model"
"cc/qweather"
"cc/web/util/response"
"time"
"github.com/gofiber/fiber/v2"
)
func GetWeatherByCode(c *fiber.Ctx) error {
// 获取项目代码
code, err := c.ParamsInt("code")
if err != nil {
return response.Error(c, response.BadRequest, "参数错误")
}
// 获取项目信息
project := model.Project{Code: code}
err = project.GetProjectByCode()
if err != nil {
return response.Error(c, response.InternalServerError, "获取项目信息失败: "+err.Error())
}
// 获取天气缓存
weather := model.Weather{ProjectID: project.ID}
weather.GetWeather()
// 判断是否需要更新
var flag bool
// 检查天气缓存是否为空
if weather.Value == nil {
flag = true
} else {
// 检查天气缓存是否过期
update, err := time.Parse("2006-01-02 15:04:05", weather.UpdateAt)
if err != nil {
return response.Error(c, response.InternalServerError, "解析时间失败: "+err.Error())
}
// 更新时间与当前时间差大于更新频率则更新
if time.Since(update) > time.Duration(project.UpdateFrequency)*time.Minute {
flag = true
}
}
if flag {
// 更新天气
// 获取天气
weather.UpdateAt = time.Now().Local().Format("2006-01-02 15:04:05")
weather.Value, err = qweather.Get(project.LocaltionID, project.WeatherTypeID, project.Dev)
if err != nil {
return response.Error(c, response.InternalServerError, "获取天气失败: "+err.Error())
}
// 更新天气缓存
err = weather.UpdateWeather()
if err != nil {
return response.Error(c, response.InternalServerError, "更新天气缓存失败: "+err.Error())
}
}
return response.Ok(c, weather)
}
// 获取天气类型
func GetWeatherType(c *fiber.Ctx) error {
// 获取天气类型
weatherType := model.WeatherType{}
weatherTypes, err := weatherType.GetAll()
if err != nil {
return response.Error(c, response.InternalServerError, "获取天气类型失败: "+err.Error())
}
return response.Ok(c, weatherTypes)
}

View File

@ -0,0 +1,17 @@
package weather
import (
"cc/web/app/weather/api"
"cc/web/middleware"
"github.com/gofiber/fiber/v2"
)
// AddRouter 添加路由
func AddRouter(r fiber.Router) {
// 通过code获取实时天气
r.Use(middleware.Limiter())
r.Get("weather/:code", api.GetWeatherByCode)
// 获取天气类型
r.Post("weather/types", api.GetWeatherType)
}

19
web/middleware/limiter.go Normal file
View File

@ -0,0 +1,19 @@
package middleware
import (
"cc/web/util/response"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/limiter"
)
func Limiter() func(*fiber.Ctx) error {
return limiter.New(limiter.Config{
Max: 1,
Expiration: time.Second,
LimitReached: func(c *fiber.Ctx) error {
return response.Error(c, response.TooManyRequests, "请求过多")
},
})
}

28
web/middleware/log.go Normal file
View File

@ -0,0 +1,28 @@
package middleware
import (
"cc/util/log"
"github.com/gofiber/contrib/fiberzap/v2"
"github.com/gofiber/fiber/v2"
)
func Log() func(*fiber.Ctx) error {
return fiberzap.New(fiberzap.Config{
Logger: log.W.Desugar(),
Fields: []string{
"status",
"method",
"path",
"protocol",
"ip",
"latency",
"ua",
},
Messages: []string{
"Server error",
"Client error",
"Success ",
},
})
}

106
web/util/request/code.go Normal file
View File

@ -0,0 +1,106 @@
package request
// rcud 0123
const (
/***** 用户接口 *****/
QueryUser ActionNum = 90000 // 用户查询
CreateUser ActionNum = 90100 // 用户新增
UpdateUser ActionNum = 90200 // 用户修改
UpdateUserPassword ActionNum = 90201 // 用户密码修改
DeleteUser ActionNum = 90300 // 用户删除
/***** 登录接口 *****/
LoginStatus ActionNum = 50000 // 登录状态
Logout ActionNum = 50002 // 登出请求
/***** 系统接口 *****/
QueryInfo ActionNum = 57000 // 查询信息
QueryNet ActionNum = 57001 // 查询网络
QueryCom ActionNum = 57002 // 查询串口
UpdateNet ActionNum = 57201 // 更新网络
Reboot ActionNum = 57202 // 重启网关
/***** 模板接口 *****/
QueryAllTemplates ActionNum = 53000 // 查询模板
CreateTemplate ActionNum = 53100 // 新增模板
UpdateTemplate ActionNum = 53200 // 更新模板
DeleteTemplate ActionNum = 53300 // 删除模板
QueryTemplateSupportType ActionNum = 53001 // 查询支持的模板类型
/***** 模板点位接口 *****/
QueryTemplatePoint ActionNum = 53010 // 查询模板下的点位
CreateTemplatePoint ActionNum = 53110 // 新增模板下的点位
UpdateTemplatePoint ActionNum = 53210 // 更新模板下的点位
DeleteTemplatePoint ActionNum = 53310 // 删除模板下的点位
ExportTemplatePoint ActionNum = 53211 // 导出模板下的点位
ImportTemplatePoint ActionNum = 53212 // 导入模板下的点位
QueryTemplatePointSupportType ActionNum = 53011 // 查询支持的点位类型
QueryDLT645TemplatePointSupportType ActionNum = 53012 // 查询支持的点位类型
QueryModbusTemplatePoint ActionNum = 53020 // 查询MODBUS模板下的点位
CreateModbusTemplatePoint ActionNum = 53120 // 新增MODBUS模板下的点位
QueryDLT6452007TemplatePoint ActionNum = 53021 // 查询DLT6452007模板下的点位
CreateDLT6452007TemplatePoint ActionNum = 53121 // 新增DLT6452007模板下的点位
/***** 驱动接口 *****/
QueryDriver ActionNum = 54000 // 查询驱动
CreateDriver ActionNum = 54100 // 增加驱动
UpdateDriver ActionNum = 54200 // 更新驱动
DeleteDriver ActionNum = 54300 // 删除驱动
StartDriver ActionNum = 54400 // 启动驱动
StopDriver ActionNum = 54500 // 停止驱动
QueryDriverSupportType ActionNum = 54001 // 查询支持的驱动类型
QueryDriverSupportTemplateType ActionNum = 54002 // 查询驱动类型支持的模板列表
QueryDriverSupportStatus ActionNum = 54003 // 查询支持的驱动状态
QueryDriverInfo ActionNum = 54004 // 查询驱动详情
QueryDriverConfig ActionNum = 54005 // 查询驱动配置
ResetDriverInfoCount ActionNum = 54201 // 重置驱动详情的通信统计
UpdateDriverConfig ActionNum = 54202 // 更新驱动配置
/***** 驱动设备接口 *****/
QueryDriverDevice ActionNum = 54010 // 查询驱动下的设备
CreateDriverDevice ActionNum = 54110 // 增加驱动下的设备
UpdateDriverDevice ActionNum = 54210 // 更新驱动下的设备
DeleteDriverDevice ActionNum = 54310 // 删除驱动下的设备
ExportDriverDevice ActionNum = 54211 // 导出驱动下的设备
ImportDriverDevice ActionNum = 54212 // 导入驱动下的设备
/***** 实时数据接口 *****/
PointGet ActionNum = 56000 // 获取点位
PointSet ActionNum = 56001 // 点位写值
PointHistoryEnable ActionNum = 56002 // 启用历史记录
PointHistoryDisable ActionNum = 56003 // 禁用历史记录
PointHistorySetMax ActionNum = 56004 // 设置历史记录最大数量
PointHistoryClear ActionNum = 56005 // 清空历史记录
PointHistoryExport ActionNum = 56006 // 导出历史记录
PointResetHealth ActionNum = 56007 // 重置健康信息
DeviceGet ActionNum = 56100 // 获取设备
DeviceEnable ActionNum = 56101 // 启用设备
DeviceDisable ActionNum = 56102 // 禁用设备
DriverGet ActionNum = 56200 // 获取驱动
DriverStart ActionNum = 56201 // 启动驱动
DriverStop ActionNum = 56202 // 停止驱动
DriverResetHealth ActionNum = 56203 // 重置健康信息
)
type ActionNum uint64

View File

@ -0,0 +1 @@
package request

109
web/util/response/code.go Normal file
View File

@ -0,0 +1,109 @@
package response
const (
Success ResponseCode = 0
NoContent ResponseCode = 204
BadRequest ResponseCode = 400
Unauthorized ResponseCode = 401
TooManyRequests ResponseCode = 429
InternalServerError ResponseCode = 500
InvalidUserName ResponseCode = 40101
InvalidUserPassword ResponseCode = 40102
DBFailure ResponseCode = 50001
InvalidActionNum ResponseCode = 52000
InvalidBody ResponseCode = 1002
DataNotExist ResponseCode = 2002
DataIsExist ResponseCode = 2003
InvalidUserID ResponseCode = 3001
InvalidUserToken ResponseCode = 3004
InvalidUserRole ResponseCode = 3005
InvalidUserStatus ResponseCode = 3006
InvalidTemplateType ResponseCode = 60001
TemplateInUse ResponseCode = 60002
InvalidDriverType ResponseCode = 61001
DriverIsRun ResponseCode = 61002
ErrDataPointWrite ResponseCode = 7001
)
type ResponseCode uint32
func (r ResponseCode) String() string {
switch r {
case Success:
return "请求成功"
case NoContent:
return "无内容"
case BadRequest:
return "错误请求"
case Unauthorized:
return "未授权"
case TooManyRequests:
return "请求过多"
case InternalServerError:
return "服务器内部错误"
case DBFailure:
return "数据库操作失败"
case InvalidUserName:
return "无效的用户名"
case InvalidUserPassword:
return "无效的用户密码"
case InvalidActionNum:
return "无效的请求动作"
///////////////////////////////////////
// 1001-1003
case InvalidBody:
return "无效的请求体"
// 2001-2999 数据库相关
case DataNotExist:
return "数据不存在"
case DataIsExist:
return "数据已存在"
// 3001-3999 用户相关
case InvalidUserID:
return "无效的用户ID"
case InvalidUserToken:
return "无效的用户token"
case InvalidUserRole:
return "无效的用户权限"
case InvalidUserStatus:
return "无效的用户状态"
case InvalidTemplateType:
return "无效的模板类型"
case TemplateInUse:
return "模板使用中"
case InvalidDriverType:
return "无效的驱动类型"
case DriverIsRun:
return "驱动运行中"
// 96001
default:
return "未知的响应码"
}
}

View File

@ -0,0 +1,27 @@
package response
import "github.com/gofiber/fiber/v2"
type ResponseData struct {
Code ResponseCode `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
func Ok(c *fiber.Ctx, data interface{}) error {
ret := ResponseData{
Code: Success,
Message: Success.String(),
Data: data,
}
return c.JSON(ret)
}
func Error(c *fiber.Ctx, errCode ResponseCode, data interface{}) error {
ret := ResponseData{
Code: errCode,
Message: errCode.String(),
Data: data,
}
return c.JSON(ret)
}

36
web/web.go Normal file
View File

@ -0,0 +1,36 @@
package web
import (
"cc/web/app/localtion"
"cc/web/app/project"
"cc/web/app/weather"
"cc/web/middleware"
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/basicauth"
)
// Go 启动web服务
func Go() {
app := fiber.New(fiber.Config{
ServerHeader: "weather",
AppName: "天气服务",
})
app.Use(middleware.Log())
r := app.Group("api") // 路由组
weather.AddRouter(r) // 天气接口
app.Use(basicauth.New(basicauth.Config{
Users: map[string]string{
"weather": "lweather",
},
}))
project.AddRouter(r) // 项目接口
localtion.AddRouter(r) // 地点接口
if err := app.Listen(":52001"); err != nil {
log.Panic("[web]端口监听失败:", err)
}
}