Bladeren bron

feat: 地图更新数据接口

HeWang 8 maanden geleden
bovenliggende
commit
40cbcb0f13

+ 43 - 0
biz/dal/mysql/map_update.go

@@ -0,0 +1,43 @@
+package mysql
+
+import (
+	"context"
+	"fmt"
+	"pji_desktop_http/biz/dal/query"
+	"pji_desktop_http/biz/model"
+)
+
+func AddMapUpdateOneRecord(ctx context.Context, record model.MapUpdate) error {
+	r := query.MapUpdate
+	err := r.WithContext(ctx).Create(&record)
+	return err
+}
+
+func QueryMapUpdateRecords(ctx context.Context, record *model.MapUpdate, pageFlag bool, page, pageSize int) ([]*model.MapUpdate, int64, error) {
+	r := query.MapUpdate
+	q := r.WithContext(ctx)
+	var records []*model.MapUpdate
+	var count int64
+	var err error
+	if record.DeviceName != "" {
+		q = q.Where(r.DeviceName.Like("%" + record.DeviceName + "%"))
+	}
+	if record.DeviceType != "" {
+		q = q.Where(r.DeviceType.Eq(record.DeviceType))
+	}
+
+	if pageFlag {
+		offset := (page - 1) * pageSize
+		records, count, err = q.Order(r.UpdateTime.Desc()).FindByPage(offset, pageSize)
+	} else {
+		records, err = q.Order(r.UpdateTime.Desc()).Find()
+	}
+
+	if err != nil {
+		fmt.Println("Query simulation records failed:", err.Error())
+		return nil, 0, err
+	}
+
+	fmt.Println("Query simulation records successfully:", len(records))
+	return records, count, err
+}

+ 6 - 0
biz/dal/mysql/simulation_test_record.go

@@ -43,6 +43,12 @@ func QuerySimulationTestRecords(ctx context.Context, record *model.SimulationTes
 	if record.AlgoImageName != "" {
 		q = q.Where(r.AlgoImageName.Like("%" + record.AlgoImageName + "%"))
 	}
+	if record.TestTime != "" {
+		q = q.Where(r.TestTime.Eq(record.TestTime))
+	}
+	if record.SceneID != "" {
+		q = q.Where(r.SceneID.Eq(record.SceneID))
+	}
 	if pageFlag {
 		offset := (page - 1) * pageSize
 		records, count, err = q.Order(r.TestTime.Desc(), r.Round.Asc()).FindByPage(offset, pageSize)

+ 37 - 32
biz/dal/query/map_update.gen.go

@@ -6,7 +6,6 @@ package query
 
 import (
 	"context"
-	"pji_desktop_http/biz/model"
 
 	"gorm.io/gorm"
 	"gorm.io/gorm/clause"
@@ -16,6 +15,8 @@ import (
 	"gorm.io/gen/field"
 
 	"gorm.io/plugin/dbresolver"
+
+	"pji_desktop_http/biz/model"
 )
 
 func newMapUpdate(db *gorm.DB, opts ...gen.DOOption) mapUpdate {
@@ -29,17 +30,18 @@ func newMapUpdate(db *gorm.DB, opts ...gen.DOOption) mapUpdate {
 	_mapUpdate.ID = field.NewString(tableName, "id")
 	_mapUpdate.MapID = field.NewString(tableName, "map_id")
 	_mapUpdate.DeviceID = field.NewString(tableName, "device_id")
+	_mapUpdate.DeviceSn = field.NewString(tableName, "device_sn")
 	_mapUpdate.DeviceName = field.NewString(tableName, "device_name")
 	_mapUpdate.DeviceType = field.NewString(tableName, "device_type")
-	_mapUpdate.OriginPgmPath = field.NewString(tableName, "origin_pgm_path")
-	_mapUpdate.PrePgmPath = field.NewString(tableName, "pre_pgm_path")
-	_mapUpdate.CurrentPgmPath = field.NewString(tableName, "current_pgm_path")
-	_mapUpdate.CumulativeUpdateRate = field.NewInt32(tableName, "cumulative_update_rate")
-	_mapUpdate.UpdateFlag = field.NewInt32(tableName, "update_flag")
-	_mapUpdate.UpdateSource = field.NewInt32(tableName, "update_source")
-	_mapUpdate.UpdateTime = field.NewTime(tableName, "update_time")
+	_mapUpdate.PrePgmURL = field.NewString(tableName, "pre_pgm_url")
+	_mapUpdate.CurrentPgmURL = field.NewString(tableName, "current_pgm_url")
+	_mapUpdate.PrePngURL = field.NewString(tableName, "pre_png_url")
+	_mapUpdate.CurrentPngURL = field.NewString(tableName, "current_png_url")
+	_mapUpdate.UpdateRate = field.NewString(tableName, "update_rate")
+	_mapUpdate.CumulativeUpdateRate = field.NewString(tableName, "cumulative_update_rate")
+	_mapUpdate.UpdateTime = field.NewString(tableName, "update_time")
 	_mapUpdate.FromSceneList = field.NewString(tableName, "from_scene_list")
-	_mapUpdate.ValidFlag = field.NewInt32(tableName, "valid_flag")
+	_mapUpdate.UpdateFlag = field.NewInt32(tableName, "update_flag")
 	_mapUpdate.CreatedAt = field.NewTime(tableName, "created_at")
 	_mapUpdate.UpdatedAt = field.NewTime(tableName, "updated_at")
 	_mapUpdate.DeletedAt = field.NewField(tableName, "deleted_at")
@@ -56,17 +58,18 @@ type mapUpdate struct {
 	ID                   field.String
 	MapID                field.String
 	DeviceID             field.String
+	DeviceSn             field.String
 	DeviceName           field.String
 	DeviceType           field.String
-	OriginPgmPath        field.String
-	PrePgmPath           field.String
-	CurrentPgmPath       field.String
-	CumulativeUpdateRate field.Int32
-	UpdateFlag           field.Int32
-	UpdateSource         field.Int32
-	UpdateTime           field.Time
+	PrePgmURL            field.String
+	CurrentPgmURL        field.String
+	PrePngURL            field.String
+	CurrentPngURL        field.String
+	UpdateRate           field.String
+	CumulativeUpdateRate field.String
+	UpdateTime           field.String
 	FromSceneList        field.String
-	ValidFlag            field.Int32
+	UpdateFlag           field.Int32
 	CreatedAt            field.Time
 	UpdatedAt            field.Time
 	DeletedAt            field.Field
@@ -89,17 +92,18 @@ func (m *mapUpdate) updateTableName(table string) *mapUpdate {
 	m.ID = field.NewString(table, "id")
 	m.MapID = field.NewString(table, "map_id")
 	m.DeviceID = field.NewString(table, "device_id")
+	m.DeviceSn = field.NewString(table, "device_sn")
 	m.DeviceName = field.NewString(table, "device_name")
 	m.DeviceType = field.NewString(table, "device_type")
-	m.OriginPgmPath = field.NewString(table, "origin_pgm_path")
-	m.PrePgmPath = field.NewString(table, "pre_pgm_path")
-	m.CurrentPgmPath = field.NewString(table, "current_pgm_path")
-	m.CumulativeUpdateRate = field.NewInt32(table, "cumulative_update_rate")
-	m.UpdateFlag = field.NewInt32(table, "update_flag")
-	m.UpdateSource = field.NewInt32(table, "update_source")
-	m.UpdateTime = field.NewTime(table, "update_time")
+	m.PrePgmURL = field.NewString(table, "pre_pgm_url")
+	m.CurrentPgmURL = field.NewString(table, "current_pgm_url")
+	m.PrePngURL = field.NewString(table, "pre_png_url")
+	m.CurrentPngURL = field.NewString(table, "current_png_url")
+	m.UpdateRate = field.NewString(table, "update_rate")
+	m.CumulativeUpdateRate = field.NewString(table, "cumulative_update_rate")
+	m.UpdateTime = field.NewString(table, "update_time")
 	m.FromSceneList = field.NewString(table, "from_scene_list")
-	m.ValidFlag = field.NewInt32(table, "valid_flag")
+	m.UpdateFlag = field.NewInt32(table, "update_flag")
 	m.CreatedAt = field.NewTime(table, "created_at")
 	m.UpdatedAt = field.NewTime(table, "updated_at")
 	m.DeletedAt = field.NewField(table, "deleted_at")
@@ -129,21 +133,22 @@ func (m *mapUpdate) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
 }
 
 func (m *mapUpdate) fillFieldMap() {
-	m.fieldMap = make(map[string]field.Expr, 17)
+	m.fieldMap = make(map[string]field.Expr, 18)
 	m.fieldMap["id"] = m.ID
 	m.fieldMap["map_id"] = m.MapID
 	m.fieldMap["device_id"] = m.DeviceID
+	m.fieldMap["device_sn"] = m.DeviceSn
 	m.fieldMap["device_name"] = m.DeviceName
 	m.fieldMap["device_type"] = m.DeviceType
-	m.fieldMap["origin_pgm_path"] = m.OriginPgmPath
-	m.fieldMap["pre_pgm_path"] = m.PrePgmPath
-	m.fieldMap["current_pgm_path"] = m.CurrentPgmPath
+	m.fieldMap["pre_pgm_url"] = m.PrePgmURL
+	m.fieldMap["current_pgm_url"] = m.CurrentPgmURL
+	m.fieldMap["pre_png_url"] = m.PrePngURL
+	m.fieldMap["current_png_url"] = m.CurrentPngURL
+	m.fieldMap["update_rate"] = m.UpdateRate
 	m.fieldMap["cumulative_update_rate"] = m.CumulativeUpdateRate
-	m.fieldMap["update_flag"] = m.UpdateFlag
-	m.fieldMap["update_source"] = m.UpdateSource
 	m.fieldMap["update_time"] = m.UpdateTime
 	m.fieldMap["from_scene_list"] = m.FromSceneList
-	m.fieldMap["valid_flag"] = m.ValidFlag
+	m.fieldMap["update_flag"] = m.UpdateFlag
 	m.fieldMap["created_at"] = m.CreatedAt
 	m.fieldMap["updated_at"] = m.UpdatedAt
 	m.fieldMap["deleted_at"] = m.DeletedAt

+ 120 - 8
biz/handler/map_service/map_service.go

@@ -3,17 +3,23 @@ package map_service
 import (
 	"archive/zip"
 	"context"
+	"encoding/json"
 	"fmt"
 	"github.com/cloudwego/hertz/pkg/app"
 	"github.com/cloudwego/hertz/pkg/protocol/consts"
+	uuid "github.com/satori/go.uuid"
 	"io"
 	"net/http"
 	"os"
 	"path/filepath"
+	"pji_desktop_http/biz/dal/mysql"
+	"pji_desktop_http/biz/model"
 	"pji_desktop_http/common/config"
 	"pji_desktop_http/common/config/c_log"
 	"pji_desktop_http/common/entity"
 	"pji_desktop_http/common/util"
+	"strconv"
+	"strings"
 )
 
 // CheckMapBufConsistency 检查请求id对应的mapBuf文件夹的一致性
@@ -94,13 +100,16 @@ func DownloadOSSFile(ctx context.Context, c *app.RequestContext) {
 }
 
 // DownloadMapZipFile 根据请求id从oss拉取并打包下载建图所需要的文件
-// @router /map/downloadmapzipfile   [GET]
+// @router /map/download/map/zip   [GET]
 func DownloadMapZipFile(ctx context.Context, c *app.RequestContext) {
 	id := c.Query("id")
-	fmt.Println(id)
+	fmt.Println("id", id)
+
+	ids := strings.Split(id, ",")
+	fmt.Println("ids", ids)
 
 	// 根据id生成用于地图更新的压缩包
-	filePath, tmpDir, err := generateMapZipById(id)
+	filePath, tmpDir, err := generateMapZipById(ids)
 	if err != nil {
 		c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
 	}
@@ -176,9 +185,10 @@ func DownloadMapBagFile(ctx context.Context, c *app.RequestContext) {
 }
 
 // 根据id生成用于地图更新的压缩包
-func generateMapZipById(id string) (file string, tmpDir string, err error) {
+func generateMapZipById(ids []string) (file string, tmpDir string, err error) {
 	// 根据id获取对应的oss文件列表
-	allFileList, err := util.GetExactedMapFileById(id)
+	allFileList, err := util.GetExactedMapFileByIds(ids)
+	fmt.Println("allFileList", allFileList)
 
 	// 过滤特定后缀的文件列表
 	mapBufFileList := util.FilterBySuffixes(allFileList, config.MapBufFiltersuffixes...)
@@ -232,8 +242,19 @@ func generateMapZipById(id string) (file string, tmpDir string, err error) {
 	// 从oss下载build_map.bag文件到 bag_folder 文件夹
 	// 过滤特定后缀的文件列表
 	buildMapBagFileList := util.FilterBySuffixes(allFileList, config.BuildMapBagFiltersuffixes...)
-	buildMapBagFile := buildMapBagFileList[0]
-	err = config.OssBucket.GetObjectToFile(buildMapBagFile, filepath.Join(bagFolderDir, filepath.Base(buildMapBagFile)))
+	fmt.Println("buildMapBagFileList", buildMapBagFileList)
+	//buildMapBagFile := buildMapBagFileList[0]
+	//err = config.OssBucket.GetObjectToFile(buildMapBagFile, filepath.Join(bagFolderDir, filepath.Base(buildMapBagFile)))
+
+	for i, file := range buildMapBagFileList {
+		fileName := "build_map" + "-" + strconv.Itoa(i) + ".bag"
+		err = config.OssBucket.GetObjectToFile(file, filepath.Join(bagFolderDir, fileName))
+		if err != nil {
+			fmt.Println("Error downloading build map file:", err)
+			return "", "", err
+		}
+	}
+
 	if err != nil {
 		fmt.Println("Error downloading Bag file:", err)
 		return "", "", err
@@ -263,7 +284,7 @@ func generateMapZipById(id string) (file string, tmpDir string, err error) {
 	c_log.GlobalLogger.Info("下载文件到origin_map_folder文件夹 - 成功")
 
 	// 创建压缩文件
-	zipPath := filepath.Join(tmpDir, "mapFile-"+id+".zip")
+	zipPath := filepath.Join(tmpDir, "mapFile-"+ids[0]+".zip")
 	zipFile, err := os.Create(zipPath)
 	if err != nil {
 		fmt.Println("Error creating ZIP file:", err)
@@ -286,6 +307,97 @@ func generateMapZipById(id string) (file string, tmpDir string, err error) {
 	return zipPath, tmpDir, nil
 }
 
+// UploadMapFile 将地图更新相关文件上传到oss
+// @router /map/upload/map [GET]
+func UploadMapFile(ctx context.Context, c *app.RequestContext) {
+	equipmentNo := c.Query("equipmentNo")
+	fmt.Println("equipmentNo", equipmentNo)
+
+	mapId := c.Query("mapId")
+	fmt.Println("mapId", mapId)
+
+	timeStamp := c.Query("timeStamp")
+	fmt.Println("timeStamp", timeStamp)
+
+	header, err := c.FormFile("file")
+	if err != nil {
+		c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
+		return
+	}
+
+	fileName := header.Filename
+	fmt.Println("filename", fileName)
+
+	ossObjectKey := config.UpdateMapOssBasePrefix + "/" + equipmentNo + "/" + mapId + "/" + timeStamp + "/" + fileName
+	fmt.Println("ossObjectKey", ossObjectKey)
+
+	f, _ := header.Open()
+	defer f.Close()
+
+	config.OssMutex.Lock()
+	err = config.OssBucket.PutObject(ossObjectKey, f)
+	config.OssMutex.Unlock()
+	if err != nil {
+		c_log.GlobalLogger.Error("程序异常退出。上传文件", fileName, "->", ossObjectKey, "出错:", err)
+		c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "上传文件失败", Details: ""})
+		return
+	}
+	c_log.GlobalLogger.Info("上传文件", fileName, "->", ossObjectKey, "成功。")
+	c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "上传文件成功", Details: ossObjectKey})
+}
+
+// AddMapUpdateRecord 添加仿真测试记录
+// @router /map/add/record [GET]
+func AddMapUpdateRecord(ctx context.Context, c *app.RequestContext) {
+	var record model.MapUpdate
+	err := c.BindAndValidate(&record)
+
+	record.ID = uuid.NewV1().String()
+	fmt.Println("record", record)
+
+	if err != nil {
+		c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
+		return
+	}
+	err = mysql.AddMapUpdateOneRecord(ctx, record)
+	if err != nil {
+		c.JSON(consts.StatusOK, entity.HttpResult{Status: false, Code: "", Message: "地图更新记录添加失败"})
+		return
+	}
+	c.JSON(consts.StatusOK, entity.HttpResult{Status: true, Code: "", Message: "地图更新记录添加成功"})
+}
+
+// QueryMapUpdateRecord 根据条件查询地图更新记录
+// @router /map/query/update/record [GET]
+func QueryMapUpdateRecord(ctx context.Context, c *app.RequestContext) {
+	var record model.MapUpdate
+	err := c.BindAndValidate(&record)
+	fmt.Println("record", record)
+
+	var pageFlag bool
+	if c.Query("page") != "" && c.Query("pageSize") != "" {
+		pageFlag = true
+	} else {
+		pageFlag = false
+	}
+
+	page, _ := strconv.Atoi(c.Query("page"))
+	pageSize, _ := strconv.Atoi(c.Query("pageSize"))
+
+	records, count, err := mysql.QueryMapUpdateRecords(ctx, &record, pageFlag, page, pageSize)
+	if err != nil {
+		c.JSON(consts.StatusOK, entity.Response{Status: false, Code: "", Message: "地图更新记录查询失败", Total: 0})
+		return
+	}
+
+	output, err := json.Marshal(records)
+	if err != nil {
+		c.JSON(consts.StatusOK, entity.Response{Status: false, Code: "", Message: "地图更新记录查询失败", Total: 0})
+		return
+	}
+	c.JSON(consts.StatusOK, entity.Response{Status: true, Code: "", Message: "地图更新查询成功", Data: string(output), Total: int(count)})
+}
+
 // 计算oss中文件列表的总大小
 func calculateTotalFileSize(fileList []string) int {
 	var totalSize int

+ 9 - 8
biz/model/map_update.go

@@ -17,17 +17,18 @@ type MapUpdate struct {
 	ID                   string         `gorm:"column:id;type:varchar(100);primaryKey" json:"id"`
 	MapID                string         `gorm:"column:map_id;type:varchar(100);not null" json:"map_id"`
 	DeviceID             string         `gorm:"column:device_id;type:varchar(100);not null" json:"device_id"`
+	DeviceSn             string         `gorm:"column:device_sn;type:varchar(100);not null" json:"device_sn"`
 	DeviceName           string         `gorm:"column:device_name;type:varchar(100);not null" json:"device_name"`
 	DeviceType           string         `gorm:"column:device_type;type:varchar(100);not null" json:"device_type"`
-	OriginPgmPath        string         `gorm:"column:origin_pgm_path;type:varchar(255);not null" json:"origin_pgm_path"`
-	PrePgmPath           string         `gorm:"column:pre_pgm_path;type:varchar(255);not null" json:"pre_pgm_path"`
-	CurrentPgmPath       string         `gorm:"column:current_pgm_path;type:varchar(255);not null" json:"current_pgm_path"`
-	CumulativeUpdateRate int32          `gorm:"column:cumulative_update_rate;type:int(11);not null" json:"cumulative_update_rate"`
-	UpdateFlag           int32          `gorm:"column:update_flag;type:int(11);not null" json:"update_flag"`
-	UpdateSource         *int32         `gorm:"column:update_source;type:int(11)" json:"update_source"`
-	UpdateTime           time.Time      `gorm:"column:update_time;type:datetime;not null" json:"update_time"`
+	PrePgmURL            string         `gorm:"column:pre_pgm_url;type:varchar(255);not null" json:"pre_pgm_url"`
+	CurrentPgmURL        string         `gorm:"column:current_pgm_url;type:varchar(255);not null" json:"current_pgm_url"`
+	PrePngURL            string         `gorm:"column:pre_png_url;type:varchar(255);not null" json:"pre_png_url"`
+	CurrentPngURL        string         `gorm:"column:current_png_url;type:varchar(255);not null" json:"current_png_url"`
+	UpdateRate           string         `gorm:"column:update_rate;type:varchar(50);not null" json:"update_rate"`
+	CumulativeUpdateRate string         `gorm:"column:cumulative_update_rate;type:varchar(50);not null" json:"cumulative_update_rate"`
+	UpdateTime           string         `gorm:"column:update_time;type:varchar(50);not null" json:"update_time"`
 	FromSceneList        *string        `gorm:"column:from_scene_list;type:varchar(255)" json:"from_scene_list"`
-	ValidFlag            int32          `gorm:"column:valid_flag;type:int(11);not null" json:"valid_flag"`
+	UpdateFlag           int32          `gorm:"column:update_flag;type:int(11);not null" json:"update_flag"`
 	CreatedAt            time.Time      `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
 	UpdatedAt            *time.Time     `gorm:"column:updated_at;type:datetime" json:"updated_at"`
 	DeletedAt            gorm.DeletedAt `gorm:"column:deleted_at;type:datetime" json:"deleted_at"`

+ 1 - 1
common/config/c_map.go

@@ -5,6 +5,6 @@ var (
 	MapBagFiltersuffixes      = []string{"map.bag"}
 	BuildMapBagFiltersuffixes = []string{"build_map.bag"}
 	OriginMapFiltersuffixes   = []string{"map.pgm", "map.yaml"}
-	SimulationFiltersuffixes  = []string{"data.zip", "map.pgm", "map.yaml", "map.bag"}
+	SimulationFiltersuffixes  = []string{"data.zip", "map.pgm", "map.yaml", "map.bag", "merged_obstacles_new.csv"}
 	DataFiltersuffixes        = []string{"data.zip"}
 )

+ 1 - 0
common/config/c_oss.go

@@ -23,6 +23,7 @@ var (
 var (
 	WorldOssBasePrefix      = "world"
 	SimulationOssBasePrefix = "simulation"
+	UpdateMapOssBasePrefix  = "update_map"
 )
 
 func InitOssConfig() {

+ 4 - 0
common/config/c_pji/c_pji.go

@@ -7,4 +7,8 @@ var (
 	SenceInfoUrl = "http://10.14.86.147:9081/open/scene/" // 内网
 
 	Token = "4773hd92ysj54paflw2jem3onyhywxt2"
+
+	mapSecretId = "bz765sfnx4wsr6axx91b09ugi56jvzqox"
+
+	mapPrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ/7TuC6YrE6wX4qIyKi7ZmGl6cyYkmTwohCsvAnUdTK1l2uX2C4/lVybgFCp4dklZZgNewDDG8jMSp1KxXVUE4TxEJQQt8g1qx0JWPs1GPz5vP67yMndLbGfm360SDLjgnEBYKcpWe65f6eAPjFXgBrwdue2kZBHqTGRB8LwweVAgMBAAECgYABZx67RxHJJA7A9cr2aXSpPU45ym36NIV8KbmP9DL6KV0qgnZA+Yj2uYN6wgQzYmUSuyfojeOfWzD516qCYoB1wJYXXL3OgDP0HLJZ6WsZfIHC4uSfIRtfepccfGDxjWTCoQHYoHMC1uWww79XjqS6bnRgXCulG7itg9SHHfO2cQJBANVuktJq/bZJFGt7tXvV1IAqJ6Cc5zS62OmAeQ7YYJJIdh9xdtW0ASGzVS6Cj5wPfXp/SsfKl9ZGfql3BaeOzhsCQQC/46qqds6ztKfIAs1uKwB7M0SjASXLmO/+4dubvkabbyT4tcSqmAdOt0RqGb7/AgE6QU/an3IdbUcl/RXpLhwPAkBF0CZsd5zHzH3Gbq+9cwNQbPmLWudx4xBiyKhQh8yG7PbecCHb40ZffKaHUSOie5qiwBJ46bbi2ypBSnJqDZczAkBMEjhtXa4yJdNCAoJoQ1nsfXWfXWwbW6UBGY7THkqlghlZE85EhwKWnSbdHRnPxH6yFoROulkl+1VyZPPTvjjXAkEAryJwhKTIYXwc+cgUhWeLY/Yehj6iuwWwOfT9UbuwjnhKgKmn2tPnwY8JJcQQ99zBhQDWizj7Z9F+LlkMR6rlxw=="
 )

+ 19 - 6
common/util/u_map.go

@@ -14,7 +14,7 @@ func ContainsKey(m *sync.Map, key string) bool {
 	return found
 }
 
-// 根据id获取解析后的地图文件列表
+// GetExactedMapFileById 根据id获取解析后的地图文件列表
 func GetExactedMapFileById(id string) (fileList []string, err error) {
 	url := c_pji.SenceOssDownUrl + id
 
@@ -63,7 +63,23 @@ func GetExactedMapFileById(id string) (fileList []string, err error) {
 	return fileList, nil
 }
 
-// 根据id获取对应的原始bag文件
+// GetExactedMapFileByIds 根据id列表获取解析后的地图文件列表
+func GetExactedMapFileByIds(ids []string) (fileList []string, err error) {
+	allFileList := make([]string, 0)
+	for i, id := range ids {
+		fileList, err := GetExactedMapFileById(id)
+		if err != nil {
+			return nil, err
+		}
+		if i != 0 {
+			fileList = FilterBySuffixes(fileList, "build_map.bag")
+		}
+		allFileList = append(allFileList, fileList...)
+	}
+	return allFileList, nil
+}
+
+// GetRosFileById 根据id获取对应的原始bag文件
 func GetRosFileById(id string) (file string, err error) {
 	url := c_pji.SenceInfoUrl + id
 
@@ -101,10 +117,7 @@ func GetRosFileById(id string) (file string, err error) {
 	}
 	// 从 data字段中提取 rosField
 	rosField, ok := dataField["rosFileId"].(string)
-	if !ok {
-		fmt.Println("ID not found or not a string")
-		return
-	}
+
 	if !ok {
 		fmt.Println("Error extracting rosFileId field")
 		return "", err

+ 1 - 1
go.mod

@@ -10,6 +10,7 @@ require (
 	github.com/google/uuid v1.6.0
 	github.com/hertz-contrib/cors v0.1.0
 	github.com/jmoiron/sqlx v1.4.0
+	github.com/satori/go.uuid v1.2.0
 	github.com/shirou/gopsutil v3.21.11+incompatible
 	github.com/sirupsen/logrus v1.9.3
 	google.golang.org/protobuf v1.34.2
@@ -49,7 +50,6 @@ require (
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/nyaruka/phonenumbers v1.0.55 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
-	github.com/satori/go.uuid v1.2.0 // indirect
 	github.com/tidwall/gjson v1.14.4 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect

+ 83 - 0
pji_client/pji client_test.go

@@ -0,0 +1,83 @@
+package pji_client_test
+
+import (
+	"pji_desktop_http/pji_client"
+	"testing"
+)
+
+func TestSendMsg(t *testing.T) {
+	// 生成测试 RSA 私钥
+	priv, err := pji_client.ParsePrivateKey("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ/7TuC6YrE6wX4qIyKi7ZmGl6cyYkmTwohCsvAnUdTK1l2uX2C4/lVybgFCp4dklZZgNewDDG8jMSp1KxXVUE4TxEJQQt8g1qx0JWPs1GPz5vP67yMndLbGfm360SDLjgnEBYKcpWe65f6eAPjFXgBrwdue2kZBHqTGRB8LwweVAgMBAAECgYABZx67RxHJJA7A9cr2aXSpPU45ym36NIV8KbmP9DL6KV0qgnZA+Yj2uYN6wgQzYmUSuyfojeOfWzD516qCYoB1wJYXXL3OgDP0HLJZ6WsZfIHC4uSfIRtfepccfGDxjWTCoQHYoHMC1uWww79XjqS6bnRgXCulG7itg9SHHfO2cQJBANVuktJq/bZJFGt7tXvV1IAqJ6Cc5zS62OmAeQ7YYJJIdh9xdtW0ASGzVS6Cj5wPfXp/SsfKl9ZGfql3BaeOzhsCQQC/46qqds6ztKfIAs1uKwB7M0SjASXLmO/+4dubvkabbyT4tcSqmAdOt0RqGb7/AgE6QU/an3IdbUcl/RXpLhwPAkBF0CZsd5zHzH3Gbq+9cwNQbPmLWudx4xBiyKhQh8yG7PbecCHb40ZffKaHUSOie5qiwBJ46bbi2ypBSnJqDZczAkBMEjhtXa4yJdNCAoJoQ1nsfXWfXWwbW6UBGY7THkqlghlZE85EhwKWnSbdHRnPxH6yFoROulkl+1VyZPPTvjjXAkEAryJwhKTIYXwc+cgUhWeLY/Yehj6iuwWwOfT9UbuwjnhKgKmn2tPnwY8JJcQQ99zBhQDWizj7Z9F+LlkMR6rlxw==")
+
+	//fmt.Println("priv", priv)
+	if err != nil {
+		panic(err)
+	}
+	secretId := "bz765sfnx4wsr6axx91b09ugi56jvzqox"
+	// 创建客户端
+	apiClient, err := pji_client.NewSysUserApiClient(priv)
+	if err != nil {
+		t.Fatalf("Failed to create client: %v", err)
+	}
+
+	paramMap := make(map[string]interface{})
+	paramMap["mapId"] = "da747cc5150741cebb186f8306ab159d"
+	paramMap["type"] = 0
+	paramMap["customAreaId"] = 334
+
+	resp, err := apiClient.JsonPostRequest("https://sitwebapi.chinapji.com/webapi/openapi/console/v1/loop/sendMsg", paramMap, secretId)
+	if err != nil {
+		t.Fatalf("Request failed: %v", err)
+	}
+
+	if resp.StatusCode() != 200 {
+		t.Errorf("Expected status code 200, got %d", resp.StatusCode())
+	}
+
+	expectedBody := `{"status": "success", "data": "123"}`
+	if string(resp.Body()) != expectedBody {
+		t.Errorf("Expected body %s, got %s", expectedBody, string(resp.Body()))
+	}
+}
+
+func TestMapList(t *testing.T) {
+	// 生成测试 RSA 私钥
+	//priv, err := pji_client.ParsePrivateKey("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ/\n7TuC6YrE6wX4qIyKi7ZmGl6cyYkmTwohCsvAnUdTK1l2uX2C4/\nlVybgFCp4dklZZgNewDDG8jMSp1KxXVUE4TxEJQQt8g1qx0JWPs1GPz5vP67yMndLbGfm360SDLjgnEBYKcpWe65f6eAPjFXgBrwdue2kZBHqTGRB8LwweVAgMBAAECgYABZx67RxHJJA7A9cr2aXSpPU45ym36NIV8KbmP9DL6KV0qgnZA+Yj2uYN6wgQzYmUSuyfojeOfWzD516qCYoB1wJYXXL3OgDP0HLJZ6WsZfIHC4uSfIRtfepccfGDxjWTCoQHYoHMC1uWww79XjqS6bnRgXCulG7itg9SHHfO2cQJBANVuktJq/\nbZJFGt7tXvV1IAqJ6Cc5zS62OmAeQ7YYJJIdh9xdtW0ASGzVS6Cj5wPfXp/\nSsfKl9ZGfql3BaeOzhsCQQC/\n46qqds6ztKfIAs1uKwB7M0SjASXLmO/+4dubvkabbyT4tcSqmAdOt0RqGb7/AgE6QU/\nan3IdbUcl/\nRXpLhwPAkBF0CZsd5zHzH3Gbq+9cwNQbPmLWudx4xBiyKhQh8yG7PbecCHb40ZffKaHUSOie5qiwBJ46bbi2ypBSnJqDZczAkBMEjhtXa4yJdNCAoJoQ1nsfXWfXWwbW6UBGY7THkqlghlZE85EhwKWnSbdHRnPxH6yFoROulkl+1VyZPPTvjjXAkEAryJwhKTIYXwc+cgUhWeLY/\nYehj6iuwWwOfT9UbuwjnhKgKmn2tPnwY8JJcQQ99zBhQDWizj7Z9F+LlkMR6rlxw==")
+	priv, err := pji_client.ParsePrivateKey("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ/7TuC6YrE6wX4qIyKi7ZmGl6cyYkmTwohCsvAnUdTK1l2uX2C4/lVybgFCp4dklZZgNewDDG8jMSp1KxXVUE4TxEJQQt8g1qx0JWPs1GPz5vP67yMndLbGfm360SDLjgnEBYKcpWe65f6eAPjFXgBrwdue2kZBHqTGRB8LwweVAgMBAAECgYABZx67RxHJJA7A9cr2aXSpPU45ym36NIV8KbmP9DL6KV0qgnZA+Yj2uYN6wgQzYmUSuyfojeOfWzD516qCYoB1wJYXXL3OgDP0HLJZ6WsZfIHC4uSfIRtfepccfGDxjWTCoQHYoHMC1uWww79XjqS6bnRgXCulG7itg9SHHfO2cQJBANVuktJq/bZJFGt7tXvV1IAqJ6Cc5zS62OmAeQ7YYJJIdh9xdtW0ASGzVS6Cj5wPfXp/SsfKl9ZGfql3BaeOzhsCQQC/46qqds6ztKfIAs1uKwB7M0SjASXLmO/+4dubvkabbyT4tcSqmAdOt0RqGb7/AgE6QU/an3IdbUcl/RXpLhwPAkBF0CZsd5zHzH3Gbq+9cwNQbPmLWudx4xBiyKhQh8yG7PbecCHb40ZffKaHUSOie5qiwBJ46bbi2ypBSnJqDZczAkBMEjhtXa4yJdNCAoJoQ1nsfXWfXWwbW6UBGY7THkqlghlZE85EhwKWnSbdHRnPxH6yFoROulkl+1VyZPPTvjjXAkEAryJwhKTIYXwc+cgUhWeLY/Yehj6iuwWwOfT9UbuwjnhKgKmn2tPnwY8JJcQQ99zBhQDWizj7Z9F+LlkMR6rlxw==")
+	//priv, err := pji_client.ParsePrivateKey("7TuC6YrE6wX4qIyKi7ZmGl6cyYkmTwohCsvAnUdTK1l2uX2C4/\nlVybgFCp4dklZZgNewDDG8jMSp1KxXVUE4TxEJQQt8g1qx0JWPs1GPz5vP67yMndLbGf\nm360SDLjgnEBYKcpWe65f6eAPjFXgBrwdue2kZBHqTGRB8LwweVAgMBAAECgYABZx6\n7RxHJJA7A9cr2aXSpPU45ym36NIV8KbmP9DL6KV0qgnZA+Yj2uYN6wgQzYmUSuyfojeO\nfWzD516qCYoB1wJYXXL3OgDP0HLJZ6WsZfIHC4uSfIRtfepccfGDxjWTCoQHYoHMC1u\nWww79XjqS6bnRgXCulG7itg9SHHfO2cQJBANVuktJq/\nbZJFGt7tXvV1IAqJ6Cc5zS62OmAeQ7YYJJIdh9xdtW0ASGzVS6Cj5wPfXp/\nSsfKl9ZGfql3BaeOzhsCQQC/\n46qqds6ztKfIAs1uKwB7M0SjASXLmO/+4dubvkabbyT4tcSqmAdOt0RqGb7/AgE6QU/\nan3IdbUcl/\nRXpLhwPAkBF0CZsd5zHzH3Gbq+9cwNQbPmLWudx4xBiyKhQh8yG7PbecCHb40ZffKa\nHUSOie5qiwBJ46bbi2ypBSnJqDZczAkBMEjhtXa4yJdNCAoJoQ1nsfXWfXWwbW6UBGY7\nTHkqlghlZE85EhwKWnSbdHRnPxH6yFoROulkl+1VyZPPTvjjXAkEAryJwhKTIYXwc+cgUh\nWeLY/\nYehj6iuwWwOfT9UbuwjnhKgKmn2tPnwY8JJcQQ99zBhQDWizj7Z9F+LlkMR6rlxw==")
+
+	//fmt.Println("priv", priv)
+	if err != nil {
+		panic(err)
+	}
+	secretId := "bz765sfnx4wsr6axx91b09ugi56jvzqox"
+	// 创建客户端
+	apiClient, err := pji_client.NewSysUserApiClient(priv)
+	if err != nil {
+		t.Fatalf("Failed to create client: %v", err)
+	}
+
+	// 测试 POST 请求
+	//paramMap := map[string]interface{}{
+	//	"name":  "test",
+	//	"value": "123",
+	//}
+
+	paramMap := map[string]string{
+		//"mapType": "0",
+	}
+	resp, err := apiClient.GetRequest("https://sitwebapi.chinapji.com/webapi/openapi/console/v1/loop/mapList", paramMap, secretId)
+
+	if err != nil {
+		t.Fatalf("Request failed: %v", err)
+	}
+
+	if resp.StatusCode() != 200 {
+		t.Errorf("Expected status code 200, got %d", resp.StatusCode())
+	}
+
+	expectedBody := `{"status": "success", "data": "123"}`
+	if string(resp.Body()) != expectedBody {
+		t.Errorf("Expected body %s, got %s", expectedBody, string(resp.Body()))
+	}
+}

+ 341 - 0
pji_client/test_pji.go

@@ -0,0 +1,341 @@
+package pji_client
+
+import (
+	"context"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"github.com/cloudwego/hertz/pkg/app/client"
+	"github.com/cloudwego/hertz/pkg/protocol"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const (
+	PEM_BEGIN = "-----BEGIN PRIVATE KEY-----\n"
+	PEM_END   = "\n-----END PRIVATE KEY-----"
+)
+
+// SysUserApiClient 是用于API交互的客户端结构体
+type SysUserApiClient struct {
+	HttpClient *client.Client  // Hertz客户端实例
+	PrivateKey *rsa.PrivateKey // RSA私钥
+}
+
+// NewSysUserApiClient 创建并返回一个SysUserApiClient实例
+func NewSysUserApiClient(privateKey *rsa.PrivateKey) (*SysUserApiClient, error) {
+	hClient, err := client.NewClient(client.WithTLSConfig(&tls.Config{
+		InsecureSkipVerify: true,
+	}))
+	if err != nil {
+		return nil, err
+	}
+	return &SysUserApiClient{
+		HttpClient: hClient,
+		PrivateKey: privateKey,
+	}, nil
+}
+
+func ParsePrivateKey(privateKeyPEM string) (*rsa.PrivateKey, error) {
+	privateKeyPEM = FormatPrivateKey(privateKeyPEM)
+	//fmt.Println("privateKeyPEM", privateKeyPEM)
+	// 2、解码私钥字节,生成加密对象
+	block, _ := pem.Decode([]byte(privateKeyPEM))
+
+	if block == nil {
+
+		return nil, errors.New("私钥信息错误!")
+	}
+
+	//fmt.Println("block", block.Bytes)
+	// 3、生成私钥对象
+	priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	// 4. 类型断言为*RSA私钥
+	privateKey := priKey.(*rsa.PrivateKey)
+	return privateKey, nil
+}
+
+func FormatPrivateKey(privateKey string) string {
+	if !strings.HasPrefix(privateKey, PEM_BEGIN) {
+		privateKey = PEM_BEGIN + privateKey
+	}
+	if !strings.HasSuffix(privateKey, PEM_END) {
+		privateKey = privateKey + PEM_END
+	}
+	return privateKey
+}
+
+// 辅助函数:对Map的键进行排序
+func sortMapByKey(m map[string]interface{}) map[string]interface{} {
+	sortedMap := make(map[string]interface{})
+	keys := make([]string, 0, len(m))
+
+	for k := range m {
+		keys = append(keys, k)
+	}
+
+	sort.Strings(keys)
+
+	for _, k := range keys {
+		sortedMap[k] = m[k]
+	}
+
+	return sortedMap
+}
+
+// 生成SHA-256哈希并进行RSA签名
+func (c *SysUserApiClient) generateSignature(val string) (string, error) {
+	fmt.Println("val", val)
+	// 签名摘要
+	hash := sha256.New()
+	hash.Write([]byte(val))
+	hashed := hash.Sum(nil)
+	fmt.Println("hashed", hashed)
+	str := hex.EncodeToString(hashed)
+	bytes := []byte(str)
+	fmt.Println("str", str)
+	fmt.Println("bytes", bytes)
+	signedData, err := rsa.SignPKCS1v15(rand.Reader, c.PrivateKey, 0, bytes)
+	str = hex.EncodeToString(signedData)
+	if err != nil {
+		return "", err
+	}
+	fmt.Println("base64", str)
+	fmt.Println("base64 signedData", base64.StdEncoding.EncodeToString([]byte(str)))
+	return base64.StdEncoding.EncodeToString([]byte(str)), nil
+}
+
+// 通用请求生成函数,设置通用头部信息
+func (c *SysUserApiClient) getHttpRequest(method string, url string, secretId string, encode string) *protocol.Request {
+	req := protocol.AcquireRequest()
+	req.Header.SetMethod(method)
+	req.SetRequestURI(url)
+	req.Header.Set("PJI-TIMESTAMP", strconv.FormatInt(time.Now().Unix(), 10))
+	req.Header.Set("PJI-API-VERSION", "v1.0")
+	req.Header.Set("PJI-ALGORITHM", "SHA3-256")
+	req.Header.Set("PJI-SECRET-ID", secretId)
+	req.Header.Set("PJI-ABSTRACT-SIGN", encode)
+	req.Header.Set("Content-Type", "application/json")
+	fmt.Println("req", req.Header.String())
+	return req
+}
+
+// JsonPostRequest 发送带有JSON请求体的POST请求
+func (c *SysUserApiClient) JsonPostRequest(url string, paramMap map[string]interface{}, secretId string) (*protocol.Response, error) {
+	paramMap = sortMapByKey(paramMap)
+
+	jsonData, err := json.Marshal(paramMap)
+	fmt.Println("jsonData", string(jsonData))
+	if err != nil {
+		return nil, err
+	}
+	str := string(jsonData)
+	if string(jsonData) == "{}" {
+		return nil, nil
+	}
+
+	signature, err := c.generateSignature(str)
+	if err != nil {
+		return nil, err
+	}
+
+	req := c.getHttpRequest("POST", url, secretId, signature)
+	req.SetBody(jsonData)
+
+	resp := protocol.AcquireResponse()
+
+	ctx := context.Background()
+	err = c.HttpClient.Do(ctx, req, resp)
+	return resp, err
+}
+
+//// PutRequest 发送PUT请求
+//func (c *SysUserApiClient) PutRequest(url string, paramMap map[string]interface{}, secretId string) (*protocol.Response, error) {
+//	paramMap = sortMapByKey(paramMap)
+//
+//	jsonData, err := json.Marshal(paramMap)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	signature, err := c.generateSignature(jsonData)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	req := c.getHttpRequest("PUT", url, secretId, signature)
+//	req.SetBody(jsonData)
+//
+//	resp := protocol.AcquireResponse()
+//	ctx := context.Background()
+//	err = c.HttpClient.Do(ctx, req, resp)
+//	return resp, err
+//}
+
+// GetRequest 发送GET请求
+func (c *SysUserApiClient) GetRequest(url string, paramMap map[string]string, secretId string) (*protocol.Response, error) {
+	//sortedParams := url.Values{}
+	//for k, v := range paramMap {
+	//	sortedParams.Add(k, v)
+	//}
+	//sortedURL := url + "?" + sortedParams.Encode()
+
+	//jsonData, err := json.Marshal(paramMap)
+	jsonData, err := json.Marshal(paramMap)
+	fmt.Println("jsonData", string(jsonData))
+	if err != nil {
+		return nil, err
+	}
+	str := string(jsonData)
+	if string(jsonData) == "{}" {
+		str = ""
+	}
+	signature, err := c.generateSignature(str)
+	if err != nil {
+		return nil, err
+	}
+
+	req := c.getHttpRequest("GET", url, secretId, signature)
+
+	resp := protocol.AcquireResponse()
+	ctx := context.Background()
+	err = c.HttpClient.Do(ctx, req, resp)
+	return resp, err
+}
+
+//// DeleteRequest 发送DELETE请求
+//func (c *SysUserApiClient) DeleteRequest(url string, paramMap map[string]string, secretId string) (*protocol.Response, error) {
+//	sortedParams := url.Values{}
+//	for k, v := range paramMap {
+//		sortedParams.Add(k, v)
+//	}
+//	sortedURL := url + "?" + sortedParams.Encode()
+//
+//	jsonData, err := json.Marshal(paramMap)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	signature, err := c.generateSignature(jsonData)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	req := c.getHttpRequest("DELETE", sortedURL, secretId, signature)
+//
+//	resp := protocol.AcquireResponse()
+//	err = c.HttpClient.Do(req, resp)
+//	return resp, err
+//}
+
+//// FormDataRequest 发送带有form-data的POST请求
+//func (c *SysUserApiClient) FormDataRequest(url string, paramMap map[string]string, secretId string) (*protocol.Response, error) {
+//	paramMap = sortMapByKeyString(paramMap)
+//
+//	jsonData, err := json.Marshal(paramMap)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	signature, err := c.generateSignature(jsonData)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	req := c.getHttpRequest("POST", url, secretId, signature)
+//	formBody := url.Values{}
+//	for k, v := range paramMap {
+//		formBody.Set(k, v)
+//	}
+//	req.Header.SetContentType("multipart/form-data")
+//	req.SetBody([]byte(formBody.Encode()))
+//
+//	resp := protocol.AcquireResponse()
+//	err = c.HttpClient.Do(req, resp)
+//	return resp, err
+//}
+
+//// UploadRequest 上传文件
+//func (c *SysUserApiClient) UploadRequest(url string, paramMap map[string]string, file []byte, secretId string) (*protocol.Response, error) {
+//	paramMap = sortMapByKeyString(paramMap)
+//
+//	jsonData, err := json.Marshal(paramMap)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	signature, err := c.generateSignature(jsonData)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	req := c.getHttpRequest("POST", url, secretId, signature)
+//	formBody := url.Values{}
+//	for k, v := range paramMap {
+//		formBody.Set(k, v)
+//	}
+//
+//	req.Header.SetContentType("multipart/form-data")
+//	req.SetBody([]byte(formBody.Encode())) // 文件数据可以单独处理
+//
+//	resp := protocol.AcquireResponse()
+//	err = c.HttpClient.Do(req, resp)
+//	return resp, err
+//}
+//
+//// DownLoadRequest 文件下载
+//func (c *SysUserApiClient) DownLoadRequest(url string, paramMap map[string]string, secretId string) (*protocol.Response, error) {
+//	sortedParams := url.Values{}
+//	for k, v := range paramMap {
+//		sortedParams.Add(k, v)
+//	}
+//	sortedURL := url + "?" + sortedParams.Encode()
+//
+//	jsonData, err := json.Marshal(paramMap)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	signature, err := c.generateSignature(jsonData)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	req := c.getHttpRequest("GET", sortedURL, secretId, signature)
+//	req.SetBody([]byte{})
+//
+//	resp := protocol.AcquireResponse()
+//	err = c.HttpClient.Do(req, resp)
+//	return resp, err
+//}
+
+// 辅助函数:对字符串Map的键进行排序
+func sortMapByKeyString(m map[string]string) map[string]string {
+	sortedMap := make(map[string]string)
+	keys := make([]string, 0, len(m))
+
+	for k := range m {
+		keys = append(keys, k)
+	}
+
+	sort.Strings(keys)
+
+	for _, k := range keys {
+		sortedMap[k] = m[k]
+	}
+
+	return sortedMap
+}

+ 7 - 0
router.go

@@ -25,6 +25,13 @@ func customizedRegister(r *server.Hertz) {
 
 	r.GET("/map/download/mapbag", map_service.DownloadMapBagFile)
 
+	r.GET("/map/upload/map", map_service.UploadMapFile)
+	r.POST("/map/upload/map", map_service.UploadMapFile)
+
+	r.POST("/map/add/record", map_service.AddMapUpdateRecord)
+
+	r.POST("/map/query/update/record", map_service.QueryMapUpdateRecord)
+
 	r.GET("/world/upload/world", world_service.UploadWorldFile)
 	r.POST("/world/upload/world", world_service.UploadWorldFile)