Merge branch 'master' of e.coding.net:rosydev/baseapi
This commit is contained in:
@@ -3,11 +3,10 @@ package ebaiapi
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
"git.rosy.net.cn/baseapi"
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -20,6 +19,11 @@ const (
|
|||||||
CmdShopMsgPush = "shop.msg.push"
|
CmdShopMsgPush = "shop.msg.push"
|
||||||
CmdShopBindMsg = "shop.bind.msg"
|
CmdShopBindMsg = "shop.bind.msg"
|
||||||
CmdShopUnbindMsg = "shop.unbind.msg"
|
CmdShopUnbindMsg = "shop.unbind.msg"
|
||||||
|
|
||||||
|
//IM消息回调通知
|
||||||
|
CmdImMessageSendEvent = "im.message.send.event" //用户/骑手消息通知
|
||||||
|
CmdImMessageReadEvent = "im.message.read.event" //用户/骑手已读通知
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CallbackResponse struct {
|
type CallbackResponse struct {
|
||||||
@@ -85,6 +89,55 @@ type CBUserCancelInfo struct {
|
|||||||
CancelType int `json:"cancel_type"`
|
CancelType int `json:"cancel_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//temp IM 用户/骑手消息通知
|
||||||
|
type TempSent struct {
|
||||||
|
SubBizType string `json:"subBizType"` //业务子类型,枚举值:SEND_MESSAGE-发送消息
|
||||||
|
BizType string `json:"bizType"` //业务类型,枚举值:IM-消息
|
||||||
|
PayLoad struct {
|
||||||
|
SenderID string `json:"senderId"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录)
|
||||||
|
ReceiverIDs []string `json:"receiverIds"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录)
|
||||||
|
CreateTime int64 `json:"createTime"` //时间戳
|
||||||
|
GroupID string `json:"groupId"` //会话id
|
||||||
|
MsgID string `json:"msgId"` //消息ID
|
||||||
|
ContentType int `json:"contentType"` //消息类型,枚举值:1-普通文本
|
||||||
|
} `json:"payload"`
|
||||||
|
PlatformShopID string `json:"platformShopId"` //平台门店ID
|
||||||
|
}
|
||||||
|
|
||||||
|
//IM 用户/骑手消息通知
|
||||||
|
type ImMessageSend struct {
|
||||||
|
SubBizType string `json:"subBizType"` //业务子类型,枚举值:SEND_MESSAGE-发送消息
|
||||||
|
BizType string `json:"bizType"` //业务类型,枚举值:IM-消息
|
||||||
|
PayLoad PayLoad `json:"payLoad"`
|
||||||
|
PlatformShopID string `json:"platformShopId"` //平台门店ID
|
||||||
|
}
|
||||||
|
type PayLoad struct {
|
||||||
|
SenderID string `json:"senderId"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录)
|
||||||
|
ReceiverIDs []string `json:"receiverIds"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录)
|
||||||
|
CreateTime int64 `json:"createTime"` //时间戳
|
||||||
|
GroupID string `json:"groupId"` //会话id
|
||||||
|
MsgID string `json:"msgId"` //消息ID
|
||||||
|
ContentType int `json:"contentType"` //消息类型,枚举值:1-普通文本
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//ContentType =1-普通文本,8-@消息
|
||||||
|
type Content struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//IM 用户/骑手已读通知
|
||||||
|
type ImMessageRead struct {
|
||||||
|
PlatformShopID string `json:"platformShopId"` //平台门店ID
|
||||||
|
BizType string `json:"bizType"` //业务类型,枚举值:IM-消息
|
||||||
|
SubBizType string `json:"subBizType"` //业务子类型,枚举值:READ_MESSAGE-读取消息
|
||||||
|
PayLoad struct {
|
||||||
|
MsgIDs string `json:"msgIds"` //消息ID 列表
|
||||||
|
CID string `json:"cid"` //会话id
|
||||||
|
UID string `json:"uid"` //已读操作人
|
||||||
|
} `json:"payLoad"`
|
||||||
|
}
|
||||||
|
|
||||||
func (a *API) Err2CallbackResponse(cmd string, err error, data interface{}) *CallbackResponse {
|
func (a *API) Err2CallbackResponse(cmd string, err error, data interface{}) *CallbackResponse {
|
||||||
response := &CallbackResponse{
|
response := &CallbackResponse{
|
||||||
Cmd: "resp." + cmd,
|
Cmd: "resp." + cmd,
|
||||||
@@ -168,6 +221,10 @@ func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackR
|
|||||||
case CmdOrderUserCancel:
|
case CmdOrderUserCancel:
|
||||||
var userCancelData CBUserCancelInfo
|
var userCancelData CBUserCancelInfo
|
||||||
tmpObj = &userCancelData
|
tmpObj = &userCancelData
|
||||||
|
case CmdImMessageSendEvent:
|
||||||
|
tmpObj = &ImMessageSend{}
|
||||||
|
case CmdImMessageReadEvent:
|
||||||
|
tmpObj = &ImMessageRead{}
|
||||||
}
|
}
|
||||||
if tmpObj != nil {
|
if tmpObj != nil {
|
||||||
if utils.Map2StructByJson(msg.Body, tmpObj, true) == nil {
|
if utils.Map2StructByJson(msg.Body, tmpObj, true) == nil {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package ebaiapi
|
package ebaiapi
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestGetStoreImStatus(t *testing.T) {
|
func TestGetStoreImStatus(t *testing.T) {
|
||||||
data, err := api.GetStoreIMStatus("1139781155")
|
data, err := api.GetStoreIMStatus("1139781155")
|
||||||
@@ -9,3 +13,36 @@ func TestGetStoreImStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(data)
|
t.Log(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//获取门店线上IM状态
|
||||||
|
func TestAPI_GetImOnlineStatus(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseMultilayerJson(t *testing.T) {
|
||||||
|
//var data1 = `{"subBizType": "SEND_MESSAGE","bizType": "IM","payload": {"senderId":"20235760123","receiverIds":["105872382789","30506545123","20235760456"],"createTime":1642647893901,"groupId":"$2$10514249123$PNM","msgId": "1654907240123.PNM","contentType": "1","content":"{"text":"测试消息"}"},"platformShopId": "32267818868"}`
|
||||||
|
var data8 = `{
|
||||||
|
"subBizType": "SEND_MESSAGE",
|
||||||
|
"bizType": "IM",
|
||||||
|
"payload": {
|
||||||
|
"senderId": "102000022769889",
|
||||||
|
"receiverIds": ["102000022769889", "30507511668"],
|
||||||
|
"createTime": 1680579669946,
|
||||||
|
"groupId": "$2$10996707119$PNM",
|
||||||
|
"msgId": "1734454964456.PNM",
|
||||||
|
"contentType": 8,
|
||||||
|
"content": "{\"elements\":[{\"elementContent\":\"{\\\"atAll\\\":false,\\\"defaultNick\\\":\\\"\\\",\\\"uid\\\":{\\\"appUid\\\":\\\"30507511668\\\",\\\"domain\\\":\\\"eleme\\\"}}\",\"elementType\":3},{\"elementContent\":\"{\\\"extensions\\\":{},\\\"text\\\":\\\"@商家 我选的就是退一个杯子呀\\\"}\",\"elementType\":1}]}"
|
||||||
|
},
|
||||||
|
"platformShopId": "507511668"
|
||||||
|
}`
|
||||||
|
//retVal1 := ParseMultilayerJson(data1)
|
||||||
|
//fmt.Println(utils.Format4Output(retVal1, false))
|
||||||
|
//retVal8 := ParseMultilayerJson(data8)
|
||||||
|
//fmt.Println(utils.Format4Output(retVal8, false))
|
||||||
|
temp := ImMessageSent{}
|
||||||
|
err := json.Unmarshal([]byte(data8), &temp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Println(temp)
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,10 +9,60 @@ const (
|
|||||||
IMStoreStatusOnLine = "ONLINE" // 门店im在线状态
|
IMStoreStatusOnLine = "ONLINE" // 门店im在线状态
|
||||||
IMStoreStatusBusy = "BUSY" // 忙碌状态
|
IMStoreStatusBusy = "BUSY" // 忙碌状态
|
||||||
IMType = "IM" // 业务类型,消息默认IM
|
IMType = "IM" // 业务类型,消息默认IM
|
||||||
SubIMType = "SEND_MESSAGE" // 子业务类型,发送消息。默认值:SEND_MESSAGE
|
SubTypeDef = "SEND_MESSAGE" // 子业务类型,发送消息。默认值:SEND_MESSAGE
|
||||||
ReadIMType = "READ_MESSAGE"
|
ReadIMType = "READ_MESSAGE"
|
||||||
|
|
||||||
|
//消息类型
|
||||||
|
ContentTypeNormal = 1 //普通文本信息
|
||||||
|
ContentTypeAt = 8 //@ 消息
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BusinessSendMsgReq im发送消息
|
||||||
|
type BusinessSendMsgReq struct {
|
||||||
|
PlatformShopId string `json:"platformShopId"` // 平台门店id
|
||||||
|
BizType string `json:"bizType"` // 业务类型,IM消息。默认值:IM
|
||||||
|
SubBizType string `json:"subBizType"` // 子业务类型,发送消息。默认值:SEND_MESSAGE
|
||||||
|
Payload BusinessMsgPayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BusinessMsgPayload struct {
|
||||||
|
GroupId string `json:"groupId"` // 会话ID
|
||||||
|
MsgId string `json:"msgId"` // 消息ID
|
||||||
|
ReceiverIds []string `json:"receiverIds"` // 接收人列表
|
||||||
|
Content string `json:"content"` // 发送内容,格式:JSON {"text":"msg"}
|
||||||
|
ContentType string `json:"contentType"` // 内容类型,目前只支持文本消息。枚举值: 1-普通文本
|
||||||
|
}
|
||||||
|
|
||||||
|
// BusinessSendMsg 门店老板发送消息 主要用这个
|
||||||
|
func (a *API) BusinessSendMsg(param *BusinessSendMsgReq) error {
|
||||||
|
result, err := a.AccessAPI("im.message.send", utils.Struct2MapByJson(param))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if result.ErrNo != 0 {
|
||||||
|
return errors.New(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingStoreMsgRead 设置消息已读
|
||||||
|
func (a *API) SettingStoreMsgRead(platformShopId string, msgId string) error {
|
||||||
|
result, err := a.AccessAPI("im.message.read", map[string]interface{}{
|
||||||
|
"platformShopId": platformShopId,
|
||||||
|
"bizType": IMType,
|
||||||
|
"subBizType": ReadIMType,
|
||||||
|
"payload": map[string]string{"msgId": msgId},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if result.ErrNo != 0 {
|
||||||
|
return errors.New(result.Error)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetStoreIMStatus 获取门店的im状态(这个应该不怎么用)
|
// GetStoreIMStatus 获取门店的im状态(这个应该不怎么用)
|
||||||
func (a *API) GetStoreIMStatus(platformShopId string) (int, error) {
|
func (a *API) GetStoreIMStatus(platformShopId string) (int, error) {
|
||||||
result, err := a.AccessAPI("im.getIMStatus", map[string]interface{}{"platformShopId": platformShopId})
|
result, err := a.AccessAPI("im.getIMStatus", map[string]interface{}{"platformShopId": platformShopId})
|
||||||
@@ -51,50 +101,3 @@ func (a *API) SetImOnlineStatus(platformShopId string, status string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BusinessSendMsg 门店老板发送消息
|
|
||||||
func (a *API) BusinessSendMsg(param *BusinessSendMsgReq) error {
|
|
||||||
result, err := a.AccessAPI("im.message", utils.Struct2MapByJson(param))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if result.ErrNo != 0 {
|
|
||||||
return errors.New(result.Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BusinessSendMsgReq im发送消息
|
|
||||||
type BusinessSendMsgReq struct {
|
|
||||||
PlatformShopId string `json:"platformShopId"` // 平台门店id
|
|
||||||
BizType string `json:"bizType"` // 业务类型,IM消息。默认值:IM
|
|
||||||
SubBizType string `json:"subBizType"` // 子业务类型,发送消息。默认值:SEND_MESSAGE
|
|
||||||
Payload BusinessMsgPayload `json:"payload"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BusinessMsgPayload struct {
|
|
||||||
GroupId string `json:"groupId"` // 会话ID
|
|
||||||
MsgId string `json:"msgId"` // 消息ID
|
|
||||||
ReceiverIds []string `json:"receiverIds"` // 接收人列表
|
|
||||||
Content string `json:"content"` // 发送内容,格式:JSON {"text":"msg"}
|
|
||||||
ContentType string `json:"contentType"` // 内容类型,目前只支持文本消息。枚举值: 1-普通文本
|
|
||||||
}
|
|
||||||
|
|
||||||
// SettingStoreMsgRead 设置消息已读
|
|
||||||
func (a *API) SettingStoreMsgRead(platformShopId string, msgId string) error {
|
|
||||||
result, err := a.AccessAPI("im.message.read", map[string]interface{}{
|
|
||||||
"platformShopId": platformShopId,
|
|
||||||
"bizType": IMType,
|
|
||||||
"subBizType": ReadIMType,
|
|
||||||
"payload": map[string]string{"msgId": msgId},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if result.ErrNo != 0 {
|
|
||||||
return errors.New(result.Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,50 @@
|
|||||||
package mtwmapi
|
package mtwmapi
|
||||||
|
|
||||||
|
const (
|
||||||
|
MsgSourceStore = 1 //商家
|
||||||
|
MsgSourceUser = 2 //用户
|
||||||
|
MsgTypeText = 1 //文字
|
||||||
|
MsgTypePic = 2 //图片
|
||||||
|
MsgTypeVoice = 3 //语音
|
||||||
|
MsgTypeGoodsCard = 4 //商品卡片
|
||||||
|
MsgTypeOrderCard = 5 //订单卡片
|
||||||
|
)
|
||||||
|
|
||||||
|
//单聊信息体
|
||||||
|
type SingleChat struct {
|
||||||
|
AppID int `json:"app_id"` //应用标识
|
||||||
|
AppPoiCode string `json:"app_poi_code"` //门店标识
|
||||||
|
Cts int `json:"cts"` //消息发送时间,10位时间戳
|
||||||
|
MsgContent string `json:"msg_content"` //消息内容
|
||||||
|
MsgID int `json:"msg_id"` //消息id,确保消息唯一性,发送消息时,为三方的消息id,接收消息时,为美团的消息id
|
||||||
|
MsgSource int `json:"msg_source"` //消息发送方 商家:1,用户:2
|
||||||
|
MsgType int `json:"msg_type"` //消息类型: 文字-1; 图片-2;语音-3,注意b2c不支持语音; 商品卡片-4(发送商品卡片类型则不关注msg_content); 订单卡片-5(订单卡片类型商家只能接收消息,不支持给用户发送消息,只支持单聊)
|
||||||
|
OpenUserID int `json:"open_user_id"` //用户id
|
||||||
|
OrderID int `json:"order_id"` // 订单id
|
||||||
|
AppSpuCodes string `json:"app_spu_codes"` //开放平台侧商品标识(无须加密)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取长链接token返回参数
|
||||||
|
type GetConnTokenResp struct {
|
||||||
|
ConnectionToken string `json:"connectionToken"` //建立长连接的token
|
||||||
|
UserCount int `json:"userCount"` //30分钟内,消息发送失败的用户数
|
||||||
|
AppKey string `json:"appKey"` //建立长连接的appkey
|
||||||
|
}
|
||||||
|
|
||||||
//获取长连接的token
|
//获取长连接的token
|
||||||
//https://developer.waimai.meituan.com/home/docDetail/461
|
//https://developer.waimai.meituan.com/home/docDetail/461
|
||||||
func (a *API) GetConnectionToken() (err error) {
|
func (a *API) GetConnectionToken() (retVal interface{}, err error) {
|
||||||
_, err = a.AccessAPI("wm/IM/getConnectionToken", false, nil)
|
retVal, err = a.AccessAPI("wm/IM/getConnectionToken", false, nil)
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//设置消息已读
|
||||||
|
//https://open-shangou.meituan.com/home/docDetail/465
|
||||||
|
func (a *API) MsgRead(appPoiCode string, msgID, openUserID int) error {
|
||||||
|
_, err := a.AccessAPI("/wm/IM/msgRead", false, map[string]interface{}{
|
||||||
|
"app_poi_code": appPoiCode,
|
||||||
|
"msg_id": msgID,
|
||||||
|
"open_user_id": openUserID,
|
||||||
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
171
platformapi/mtwmapi/im_server.go
Normal file
171
platformapi/mtwmapi/im_server.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package mtwmapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ip配置信息
|
||||||
|
type global struct {
|
||||||
|
LocalHost string //本机内网IP
|
||||||
|
RemoteHost string //远程端IP
|
||||||
|
RemotePort string //远程端口
|
||||||
|
ServerList map[string]string
|
||||||
|
ServerListLock sync.RWMutex
|
||||||
|
}
|
||||||
|
type commonConf struct {
|
||||||
|
HttpPort string
|
||||||
|
RPCPort string
|
||||||
|
Cluster bool
|
||||||
|
CryptoKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
GlobalSetting = &global{}
|
||||||
|
CommonSetting = &commonConf{
|
||||||
|
HttpPort: "6000",
|
||||||
|
RPCPort: "7000",
|
||||||
|
Cluster: false,
|
||||||
|
CryptoKey: "Adba723b7fe06819",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
以下为clientID相关逻辑
|
||||||
|
*/
|
||||||
|
|
||||||
|
//对称加密IP和端口,当做clientId
|
||||||
|
func GenClientId() string {
|
||||||
|
raw := []byte(GlobalSetting.LocalHost + ":" + CommonSetting.RPCPort)
|
||||||
|
//raw := []byte(hostStr)
|
||||||
|
str, err := Encrypt(raw, []byte(CommonSetting.CryptoKey))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encrypt(rawData, key []byte) (string, error) {
|
||||||
|
data, err := aesCBCEncrypt(rawData, key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//AES加密
|
||||||
|
func aesCBCEncrypt(rawData, key []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//填充原文
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
|
||||||
|
rawData = pKCS7Padding(rawData, blockSize)
|
||||||
|
//初始向量IV必须是唯一,但不需要保密
|
||||||
|
cipherText := make([]byte, blockSize+len(rawData))
|
||||||
|
//block大小 16
|
||||||
|
iv := cipherText[:blockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//block大小和初始向量大小一定要一致
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
mode.CryptBlocks(cipherText[blockSize:], rawData)
|
||||||
|
|
||||||
|
return cipherText, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptDESECB(d, key []byte) string {
|
||||||
|
data, err := base64.StdEncoding.DecodeString(string(d))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
bs := block.BlockSize()
|
||||||
|
if len(data)%bs != 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
out := make([]byte, len(data))
|
||||||
|
dst := out
|
||||||
|
for len(data) > 0 {
|
||||||
|
block.Decrypt(dst, data[:bs])
|
||||||
|
data = data[bs:]
|
||||||
|
dst = dst[bs:]
|
||||||
|
}
|
||||||
|
out = PKCS5UnPadding(out)
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
func PKCS5UnPadding(origData []byte) []byte {
|
||||||
|
length := len(origData)
|
||||||
|
unpadding := int(origData[length-1])
|
||||||
|
return origData[:(length - unpadding)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decrypt(rawData string, key []byte) (string, error) {
|
||||||
|
data, err := base64.StdEncoding.DecodeString(rawData)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
dnData, err := aesCBCDncrypt(data, key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(dnData), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//AES解密
|
||||||
|
func aesCBCDncrypt(encryptData, key []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
|
||||||
|
if len(encryptData) < blockSize {
|
||||||
|
return []byte{}, errors.New("ciphertext too short")
|
||||||
|
}
|
||||||
|
iv := encryptData[:blockSize]
|
||||||
|
encryptData = encryptData[blockSize:]
|
||||||
|
|
||||||
|
if len(encryptData)%blockSize != 0 {
|
||||||
|
return []byte{}, errors.New("ciphertext is not a multiple of the block size")
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
|
||||||
|
mode.CryptBlocks(encryptData, encryptData)
|
||||||
|
//解填充
|
||||||
|
encryptData, err = pKCS7UnPadding(encryptData)
|
||||||
|
return encryptData, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func pKCS7Padding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padText...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pKCS7UnPadding(origData []byte) ([]byte, error) {
|
||||||
|
length := len(origData)
|
||||||
|
unPadding := int(origData[length-1])
|
||||||
|
if length-unPadding < 0 || length-unPadding > len(origData) {
|
||||||
|
return nil, errors.New("unPadding error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return origData[:(length - unPadding)], nil
|
||||||
|
}
|
||||||
@@ -1,15 +1,269 @@
|
|||||||
package mtwmapi
|
package mtwmapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"github.com/gazeboxu/mapstructure"
|
||||||
|
"github.com/go-redis/redis"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MTIMPushUrl = "wss://wpush.meituan.com/websocket"
|
||||||
|
TestAppID = "589_WMOPEN"
|
||||||
|
TestToken = "wo589i4VsZHFH2fh4uVsr6Dtc3k6vG8Xu0vxpreBQFy6QAvg"
|
||||||
|
|
||||||
|
TestMTIMPushUrl = "wss://wpush.meituan.com/websocket/589_WMOPEN/wo589i4VsZHFH2fh4uVsr6Dtc3k6vG8Xu0vxpreBQFy6QAvg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientManager struct {
|
||||||
|
ClientIdMap map[string]*Client // 全部的连接
|
||||||
|
ClientIdMapLock sync.RWMutex // 读写锁
|
||||||
|
|
||||||
|
Connect chan *Client // 连接处理
|
||||||
|
DisConnect chan *Client // 断开连接处理
|
||||||
|
|
||||||
|
GroupLock sync.RWMutex
|
||||||
|
Groups map[string][]string
|
||||||
|
|
||||||
|
//SystemClientsLock sync.RWMutex
|
||||||
|
//SystemClients map[string][]string
|
||||||
|
Clients map[string]*Client // 保存连接
|
||||||
|
Accounts map[string][]string // 账号和连接关系,map的key是账号id即:AccountId,这里主要考虑到一个账号多个连接
|
||||||
|
mu *sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var Manager = NewClientManager()
|
||||||
|
|
||||||
|
func NewClientManager() (clientManager *ClientManager) {
|
||||||
|
clientManager = &ClientManager{
|
||||||
|
Accounts: make(map[string][]string),
|
||||||
|
ClientIdMap: make(map[string]*Client, 100),
|
||||||
|
Connect: make(chan *Client, 10000),
|
||||||
|
DisConnect: make(chan *Client, 10000),
|
||||||
|
mu: new(sync.Mutex),
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var RegisterChan = make(chan *Client, 100)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
ID string // 连接ID
|
||||||
|
AccountId string // 账号id, 一个账号可能有多个连接
|
||||||
|
Socket *websocket.Conn // 连接
|
||||||
|
HeartbeatTime int64 // 前一次心跳时间
|
||||||
|
}
|
||||||
|
|
||||||
|
var rdb = redis.NewClient(&redis.Options{
|
||||||
|
//Addr: "www.jxc4.com:6379",
|
||||||
|
//Password: "",
|
||||||
|
Addr: "127.0.0.1:6379",
|
||||||
|
Password: "123456",
|
||||||
|
DB: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
//测试心跳
|
||||||
|
func TestHeartCheck(t *testing.T) {
|
||||||
|
//go func() {
|
||||||
|
// ticker := time.NewTicker(5 * time.Second)
|
||||||
|
// defer ticker.Stop()
|
||||||
|
// for {
|
||||||
|
// <-ticker.C
|
||||||
|
//发送心跳
|
||||||
|
conn, resp, err := websocket.DefaultDialer.Dial(TestMTIMPushUrl, nil)
|
||||||
|
fmt.Println(resp, err)
|
||||||
|
err1 := conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
|
||||||
|
for {
|
||||||
|
_, msg, err := conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("%s receive: %s\n", conn.RemoteAddr(), string(msg))
|
||||||
|
}
|
||||||
|
fmt.Println(err1)
|
||||||
|
//}
|
||||||
|
//}()
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetConnectionToken(t *testing.T) {
|
func TestGetConnectionToken(t *testing.T) {
|
||||||
err := api.GetConnectionToken()
|
resp, err := api.GetConnectionToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// t.Log(utils.Format4Output(result, false))
|
retVal := GetConnTokenResp{}
|
||||||
|
err = mapstructure.Decode(resp, &retVal)
|
||||||
|
fmt.Println(err)
|
||||||
|
fmt.Println(utils.Format4Output(retVal, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
//解密测试
|
||||||
|
func TestAesCBCDecrypt(t *testing.T) {
|
||||||
|
secret := "a81eb3df418d83d6a1a4b7c572156d2f"
|
||||||
|
key := secret[:16]
|
||||||
|
str := "qodhoVd4IGtgPKrvYwq6QrzBecJZkeSUPYR88iGRUsCRFmCFxDHpUhqsbBztNXQx"
|
||||||
|
//str := "Vv+Y/K8vfS42W+P7xq26aIb6uoaG/nL0ZoMMXpitc5QQ3XJm3Roh10NuSoojYrG/3JZwbzgtYA+kBvodoY2eJV00f9MBY+kLkxToP+aSofsYva9tHbipvjVtexebc+eP7aQMtzbwU4BNNnuRG6e7TkXP+BLdtiGsyvHolGfky+p2fZgWes9R6JIxkuRCXW/yBhUo8F+wWCZ2YQl/szp5lHJ3cmneD6cwem36E0FBcvxZNB9an4pRkBrqi1p43V8QBLO719oXkQ+dqTqJMi1/xDSBrCDYN8QORnARP8+j1oDuqE34Kklcse4WL9rwTJ2sOmOu/O2h6Gx3ZaFaMaWRXBDYv8JpzTZjCbRrLSENlEHTof29BmvXTJ0QZ7qi6iAD"
|
||||||
|
data, err := Decrypt(str, []byte(key))
|
||||||
|
//data, err := DecryptAES(key, str)
|
||||||
|
fmt.Println(data)
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var wsList []*websocket.Conn
|
||||||
|
|
||||||
|
func sendmsg() {
|
||||||
|
for _, conn := range wsList {
|
||||||
|
if err := conn.WriteMessage(websocket.TextMessage, []byte("~#HHHBBB#~")); err != nil {
|
||||||
|
fmt.Printf("%s", err) //"use of closed network connection"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestPut(t *testing.T) {
|
||||||
|
fmt.Println(wsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWebSocketClient(t *testing.T) {
|
||||||
|
//发送webSocket请求
|
||||||
|
conn, resp, err := websocket.DefaultDialer.Dial(TestMTIMPushUrl, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("连接失败:%v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("响应:%s", fmt.Sprint(resp))
|
||||||
|
//wsList = append(wsList, conn)
|
||||||
|
//关闭
|
||||||
|
conn.SetCloseHandler(func(code int, text string) error {
|
||||||
|
fmt.Printf("WebSocket connection closed with code %d and text: %s\n", code, text)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
defer func(conn *websocket.Conn) {
|
||||||
|
err := conn.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}(conn)
|
||||||
|
|
||||||
|
//赋入全局变量
|
||||||
|
//Default(conn)
|
||||||
|
//生成clientID
|
||||||
|
clientID := GenClientId()
|
||||||
|
|
||||||
|
//创建实例连接
|
||||||
|
client := &Client{
|
||||||
|
ID: clientID,
|
||||||
|
//AccountId:conn. ,
|
||||||
|
Socket: conn,
|
||||||
|
HeartbeatTime: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
//rdb.Set("testPush", client, 0)
|
||||||
|
|
||||||
|
//注册到连接管理
|
||||||
|
RegisterChan <- client
|
||||||
|
//todo 暂时不确定放哪
|
||||||
|
//go Start()
|
||||||
|
|
||||||
|
done := make(chan SingleChat)
|
||||||
|
//err = conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
|
||||||
|
err = conn.WriteMessage(websocket.TextMessage, []byte("~#HHHBBB#~"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
_, msg, err := conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
//log.Fatal(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("%s receive: %s\n", conn.RemoteAddr(), string(msg))
|
||||||
|
}
|
||||||
|
<-done
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPUSH(t *testing.T) {
|
||||||
|
key := "589:7954977:10"
|
||||||
|
//rdb.RPush(key, "1111111111")
|
||||||
|
//rdb.RPush(key, "{\"vendorID\":10,\"userID\":11158569333,\"NewMessageNum\":3,\"latestMsg\":\"hhhhhhhhhhh\",\"latestTime\":1681983980}")
|
||||||
|
//rdb.RPush(key, "{\"vendorID\":10,\"userID\":11158569333,\"NewMessageNum\":3,\"latestMsg\":\"oooooooooo\",\"latestTime\":1681983980}")
|
||||||
|
//rdb.RPush(key, "2222222222222")
|
||||||
|
rdb.RPush(key, "{\"vendorID\":10,\"userID\":11158569333,\"NewMessageNum\":4,\"latestMsg\":\"成功插入新数据,看下cnt\",\"latestTime\":1681983980}")
|
||||||
|
rdb.RPush(key, "{\"vendorID\":10,\"userID\":11158569333,\"NewMessageNum\":5,\"latestMsg\":\"成功插入新数据,看下cnt\",\"latestTime\":1681983980}")
|
||||||
|
}
|
||||||
|
|
||||||
|
//用户消息列表
|
||||||
|
type UserMessageList struct {
|
||||||
|
VendorID int `json:"vendorID"` //平台品牌 10-美团 11-饿了么
|
||||||
|
UserID int `json:"userID"` //用户ID
|
||||||
|
NewMessageNum int `json:"NewMessageNum"` //新消息数量
|
||||||
|
LatestMsg string `json:"latestMsg"` //最新一条消息
|
||||||
|
LatestTime int `json:"latestTime"` //最新一条消息发送时间
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewRedis(t *testing.T) {
|
||||||
|
var flag = 11158569333
|
||||||
|
var key = "589:7954977:10"
|
||||||
|
s2 := rdb.LRange(key, 0, -1).Val()
|
||||||
|
fmt.Printf("before len %d\n", len(s2))
|
||||||
|
fmt.Printf("before ans %s\n", s2)
|
||||||
|
cnt := 0
|
||||||
|
n := rdb.Exists(key).Val()
|
||||||
|
if n > 0 {
|
||||||
|
for i := 0; i < len(s2); i++ {
|
||||||
|
v := UserMessageList{}
|
||||||
|
_ = json.Unmarshal([]byte(s2[i]), &v)
|
||||||
|
if v.UserID == flag {
|
||||||
|
rdb.LSet(key, int64(i), "del")
|
||||||
|
rdb.LRem(key, 0, "del")
|
||||||
|
s2 = append(s2[:i], s2[i+1:]...)
|
||||||
|
i--
|
||||||
|
if v.NewMessageNum == 0 { //目前为首条
|
||||||
|
cnt++ //赋值1
|
||||||
|
} else {
|
||||||
|
cnt = v.NewMessageNum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("after cnt %d\n", cnt)
|
||||||
|
fmt.Printf("after len %d\n", len(s2))
|
||||||
|
fmt.Printf("after ans %s\n", s2)
|
||||||
|
//存入flag数据
|
||||||
|
ans := UserMessageList{
|
||||||
|
VendorID: 10,
|
||||||
|
UserID: 11158569333,
|
||||||
|
NewMessageNum: cnt,
|
||||||
|
LatestMsg: "成功插入新数据,看下cnt",
|
||||||
|
LatestTime: 1681983980,
|
||||||
|
}
|
||||||
|
param, _ := json.Marshal(ans)
|
||||||
|
rdb.RPush(key, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据账号获取连接
|
||||||
|
func TestGetClient(t *testing.T) {
|
||||||
|
accountId := "QW+r2FtsRKGGLJnlgyDNlChzcKcSZ8Kfgh0qw//ONuQCDKzky4x+nlbnx3k1JX13"
|
||||||
|
clients := make([]*Client, 0)
|
||||||
|
|
||||||
|
Manager.mu.Lock()
|
||||||
|
defer Manager.mu.Unlock()
|
||||||
|
|
||||||
|
if len(Manager.Accounts[accountId]) > 0 {
|
||||||
|
for _, clientId := range Manager.Accounts[accountId] {
|
||||||
|
if c, ok := Manager.Clients[clientId]; ok {
|
||||||
|
clients = append(clients, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(utils.Format4Output(clients, false))
|
||||||
|
}
|
||||||
|
func TestMal(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetWayBillFee(t *testing.T) {
|
func TestGetWayBillFee(t *testing.T) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
// "authority_id": ""
|
// "authority_id": ""
|
||||||
//}`
|
//}`
|
||||||
|
|
||||||
var token = `{"access_token":"cfb17c78-6aad-47db-80a3-a9ed9f7b3482","expires_in":1682516556,"scope":"SCOPE","shop_id":68023619,"shop_name":"京西到家","refresh_token":"d921257a-1c39-491d-a691-bbf9850ed926","authority_id":""}`
|
var token = `{"access_token":"c2c6e258-847d-4e8f-a695-b20488a5a667","expires_in":1682270239,"scope":"SCOPE","shop_id":57939570,"shop_name":"京西菜市速食","refresh_token":"ebf0e9f1-b200-47c2-a2bb-bafefbdaed47","authority_id":""}`
|
||||||
|
|
||||||
//var token = `{"access_token":"e3173e9f-266f-4d87-88e7-e7cd837bc9d9","expires_in":1672882632,"scope":"SCOPE","shop_id":68023619,"shop_name":"京西到家","refresh_token":"5070aae2-493f-46bd-b5d6-6ea0cd64729f","authority_id":""}`
|
//var token = `{"access_token":"e3173e9f-266f-4d87-88e7-e7cd837bc9d9","expires_in":1672882632,"scope":"SCOPE","shop_id":68023619,"shop_name":"京西到家","refresh_token":"5070aae2-493f-46bd-b5d6-6ea0cd64729f","authority_id":""}`
|
||||||
|
|
||||||
@@ -52,8 +52,3 @@ func TestName(t *testing.T) {
|
|||||||
sign := fmt.Sprintf("%X", md5.Sum([]byte(signParam)))
|
sign := fmt.Sprintf("%X", md5.Sum([]byte(signParam)))
|
||||||
fmt.Println(sign)
|
fmt.Println(sign)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAa(t *testing.T) {
|
|
||||||
aa := 1842 + 1318 + 1268 + 3441 + 4372 + 4333 + 3669 + 1158 + 2154 + 2639 + 4748 + 3526
|
|
||||||
fmt.Println(aa)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ func TestUpdateStore(t *testing.T) {
|
|||||||
|
|
||||||
//获取门店绑定仓库
|
//获取门店绑定仓库
|
||||||
func TestGetWarehouseByStore(t *testing.T) {
|
func TestGetWarehouseByStore(t *testing.T) {
|
||||||
storeIDs := []int64{89519481, 89476907, 89127678, 89107647, 88868369, 88580829, 86794412, 86793595, 86763746, 85770993, 83727828, 81386642, 81385390, 78318835, 78118788, 76879546, 76877797, 76877419, 76876821, 76875172, 75323740, 71199379, 71199371, 71199369, 71199367, 71199362, 71199352, 70870393, 69395217, 65585133, 65402632, 65401463, 64270373, 64270365, 64270337, 64270333, 64270318, 64270279, 64270267, 64270240, 64270227, 64270222, 64270214, 64270206, 64270183, 64270137, 64270136, 64270122, 64270095, 64270063, 64270050, 64270027, 64269990, 64269953, 64251889, 64251887, 64251878, 64251875, 64251857, 64251634, 64251633, 64251632, 64251631, 64251630, 64251629, 64251624, 64251623, 64251622, 64251620, 64251617, 64251616, 64251614, 64251611, 64251610, 64251608, 64251604, 64251603, 64251600, 64251599, 64251224, 64251223, 64251221, 64251219, 64251214, 64251213, 64251208, 64251207, 64251204, 64251198, 64250754, 64250751, 64250746, 64250744, 64250742, 64250741, 64250739, 64250735, 64250734, 64250731, 64250730, 64250729, 64250728, 64250727, 64250722, 64250720, 64250709, 64250707, 64250704, 64212758, 64212030, 64208821, 64208482, 64208305, 64208009, 64089616, 64042829, 63841925, 63840103, 63836369, 63521502, 63521394, 63511878, 63468038, 63467659, 63467462, 63465423, 63463026, 63462817, 63224599, 63183340, 63181030, 63179331, 63178998, 62490423}
|
storeIDs := []int64{64363086}
|
||||||
need := []int64{}
|
need := []int64{}
|
||||||
errList := errlist.New()
|
errList := errlist.New()
|
||||||
for _, v := range storeIDs {
|
for _, v := range storeIDs {
|
||||||
|
|||||||
@@ -14,35 +14,38 @@ func TestLen(t *testing.T) {
|
|||||||
|
|
||||||
//打印
|
//打印
|
||||||
func TestAPI_Print(t *testing.T) {
|
func TestAPI_Print(t *testing.T) {
|
||||||
content := `<C><font# bolder=1 height=2 width=2>美团外卖</font#></C>
|
name1 := "[优]猪肉馅约250g/份"
|
||||||
<font# bolder=1 height=1 width=1>--------------------------------</font#>
|
name2 := "鲜鸡蛋约250g/份"
|
||||||
<LEFT>下单时间:2023-03-27 13:22:05</LEFT>
|
name3 := "[精选优品][精选优品][精选优品][精选优品][精选优品]豌豆米-手工剥豆约100g/份"
|
||||||
<LEFT>期望送达:2023-03-27 14:22:05</LEFT>
|
name4 := "娃娃菜200g/个"
|
||||||
<LEFT>客户姓名:梅朵(女士)</LEFT>
|
len1 := len(name1)
|
||||||
<LEFT>客户电话:163473526172</LEFT>
|
len2 := len(name2)
|
||||||
<LEFT><font# bolder=0 height=2 width=1>订单编号: E22092832084572779</font#></LEFT><BR>
|
len3 := len(name3)
|
||||||
<C><font# bolder=1 height=2 width=2>美团外卖#20</font#></C>
|
len4 := len(name4)
|
||||||
<C><BAR>E22092832084572779</BAR></C>
|
len5 := len("--------------------------------")
|
||||||
<C><font# bolder=1 height=1 width=1>--------------------------------</font#></C>
|
fmt.Println(len1, len2, len3, len4, len5)
|
||||||
<LEFT><font# bolder=0 height=2 width=1>客户地址:四川省成都市武侯区双流县金华镇芳草街道小区5栋1单元104号</font#></LEFT>
|
content := `
|
||||||
<C><font# bolder=0 height=1 width=1>--------------------------------</font#></C>
|
|
||||||
<LEFT><font# bolder=0 height=2 width=1>客户备注:缺货时电话与我沟通 收货人隐私号17882904902——5355,手机号 181****6752</font#></LEFT>
|
|
||||||
<font# bolder=1 height=1 width=1>--------------------------------</font#>
|
|
||||||
<LEFT>商品列表</LEFT><BR>`
|
<LEFT>商品列表</LEFT><BR>`
|
||||||
content += "商品名" + StrRepeat(" ", 3) + "数量" + StrRepeat(" ", 4) + "单价" + StrRepeat(" ", 6) + "小计" + "<BR>"
|
content += "商品名" + StrRepeat(" ", 13) + "数量" + "<BR>"
|
||||||
content += `--------------------------------`
|
content += `--------------------------------`
|
||||||
content += FormatPrintOrderItem("[优]猪肉馅约250g/份", 1, 999)
|
content += FormatPrintOrderItemV2(name1, 1, 1)
|
||||||
content += FormatPrintOrderItem("鲜鸡蛋约250g/份", 1, 17.8)
|
content += FormatPrintOrderItemV2(name2, 1, 2)
|
||||||
content += FormatPrintOrderItem("豌豆米-手工剥豆约100g/份", 1, 40)
|
content += FormatPrintOrderItemV2(name3, 1, 3)
|
||||||
content += FormatPrintOrderItem("娃娃菜200g/个", 5, 2)
|
content += FormatPrintOrderItemV2(name4, 5, 4)
|
||||||
content += `<LEFT>共4种9件商品
|
content += `<BR><LEFT><font# bolder=0 height=2 width=1>共4种9件商品</font#></LEFT><BR>`
|
||||||
实付金额: 327.83元</LEFT><BR>
|
content += `<font# bolder=0 height=2 width=1>--------------#20完-------------</font#>`
|
||||||
<font# bolder=0 height=1 width=1>--------------#20完-------------</font#>`
|
|
||||||
msg, err := api.Print(TestSn, content, VoiceNewShort)
|
msg, err := api.Print(TestSn, content, VoiceNewShort)
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCal(t *testing.T) {
|
||||||
|
str := "豌豆米-手工剥豆约100g/份"
|
||||||
|
//ans := "--------------------------------"
|
||||||
|
cnt := CalWidth(str)
|
||||||
|
fmt.Println(cnt)
|
||||||
|
}
|
||||||
|
|
||||||
//打印取消/退货模板
|
//打印取消/退货模板
|
||||||
func TestAPI_Print2(t *testing.T) {
|
func TestAPI_Print2(t *testing.T) {
|
||||||
content := `<C><font# bolder=1 height=2 width=2>京西菜市</font#></C><BR>`
|
content := `<C><font# bolder=1 height=2 width=2>京西菜市</font#></C><BR>`
|
||||||
@@ -81,7 +84,7 @@ func TestAPI_DelPrinter(t *testing.T) {
|
|||||||
|
|
||||||
//设置打印浓度
|
//设置打印浓度
|
||||||
func TestAPI_SetDensity(t *testing.T) {
|
func TestAPI_SetDensity(t *testing.T) {
|
||||||
err := api.SetDensity(TestSn, DensityStronger)
|
err := api.SetDensity(TestSn, DensityStrong)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +96,7 @@ func TestAPI_SetVolume(t *testing.T) {
|
|||||||
|
|
||||||
//查询打印机状态
|
//查询打印机状态
|
||||||
func TestGetDevicesStatus(t *testing.T) {
|
func TestGetDevicesStatus(t *testing.T) {
|
||||||
onlineStatus, workStatus, err := api.GetDeviceStatus(TestSn)
|
onlineStatus, workStatus, err := api.GetDeviceStatus("570010021789")
|
||||||
fmt.Println(onlineStatus)
|
fmt.Println(onlineStatus)
|
||||||
fmt.Println(workStatus)
|
fmt.Println(workStatus)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -104,3 +107,9 @@ func TestAPI_CleanWaitingQueue(t *testing.T) {
|
|||||||
err := api.CleanWaitingQueue(TestSn)
|
err := api.CleanWaitingQueue(TestSn)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInt(t *testing.T) {
|
||||||
|
|
||||||
|
temp := 1000
|
||||||
|
fmt.Println(int(temp / 1000))
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
r "math/rand"
|
r "math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
@@ -155,3 +157,74 @@ func FormatPrintOrderItem(foodName string, quantity int, price float64) string {
|
|||||||
result += "<BR>"
|
result += "<BR>"
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ROW_MAX_CHAR_LEN = 34
|
||||||
|
LAST_ROW_MAX_NAME_CHAR_LEN = 16
|
||||||
|
MAX_NAME_CHAR_LEN = 16
|
||||||
|
MaxLineLength = 30
|
||||||
|
LineLength = 32
|
||||||
|
NewLineLength = 28
|
||||||
|
)
|
||||||
|
|
||||||
|
//不带单价版本
|
||||||
|
func FormatPrintOrderItemV2(foodName string, quantity, cnt int) string {
|
||||||
|
var (
|
||||||
|
result = ""
|
||||||
|
restLen int
|
||||||
|
)
|
||||||
|
quantityStr := strconv.Itoa(quantity)
|
||||||
|
foodNameLen := CalWidth(foodName) + 3
|
||||||
|
if foodNameLen >= MaxLineLength {
|
||||||
|
if n := foodNameLen / LineLength; n > 0 {
|
||||||
|
restLen = foodNameLen % LineLength
|
||||||
|
} else {
|
||||||
|
restLen = foodNameLen - LineLength
|
||||||
|
}
|
||||||
|
result += `<font# bolder=0 height=2 width=1>` + utils.Int2Str(cnt) + `.` + foodName
|
||||||
|
result += StrRepeat(" ", MaxLineLength-restLen) + `x` + quantityStr + `</font#>`
|
||||||
|
} else {
|
||||||
|
result += `<font# bolder=0 height=2 width=1>` + utils.Int2Str(cnt) + `.` + foodName + StrRepeat(" ", MaxLineLength-foodNameLen) + `x` + quantityStr + `</font#>`
|
||||||
|
}
|
||||||
|
result += "<BR>"
|
||||||
|
fmt.Println(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatPrintOrderItemBigV2(foodName string, quantity, cnt int) string {
|
||||||
|
var (
|
||||||
|
result = ""
|
||||||
|
restLen int
|
||||||
|
)
|
||||||
|
quantityStr := strconv.Itoa(quantity)
|
||||||
|
foodNameLen := CalWidth(foodName) + 3
|
||||||
|
if foodNameLen >= MaxLineLength {
|
||||||
|
if n := foodNameLen / LineLength; n > 0 {
|
||||||
|
restLen = foodNameLen % LineLength
|
||||||
|
} else {
|
||||||
|
restLen = foodNameLen - LineLength
|
||||||
|
}
|
||||||
|
result += `<font# bolder=1 height=2 width=1>` + utils.Int2Str(cnt) + `.` + foodName
|
||||||
|
result += StrRepeat(" ", MaxLineLength-restLen) + `x` + quantityStr + `</font#>`
|
||||||
|
} else {
|
||||||
|
result += `<font# bolder=1 height=2 width=1>` + utils.Int2Str(cnt) + `.` + foodName + StrRepeat(" ", MaxLineLength-foodNameLen) + `x` + quantityStr + `</font#>`
|
||||||
|
}
|
||||||
|
result += "<BR>"
|
||||||
|
fmt.Println(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
//正则计算宽度
|
||||||
|
func CalWidth(str string) int {
|
||||||
|
hzc := 0
|
||||||
|
for _, v := range str {
|
||||||
|
if unicode.Is(unicode.Han, v) {
|
||||||
|
hzc++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateStr := regexp.MustCompile("[\u4e00-\u9fa5]{1,}").ReplaceAllString(str, "")
|
||||||
|
l := len(updateStr)
|
||||||
|
fmt.Println(hzc)
|
||||||
|
ans := 2*hzc + l
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|||||||
@@ -176,14 +176,15 @@ func TestPrintCancelOrRefund(t *testing.T) {
|
|||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
////清空待打印队列
|
////清空待打印队列
|
||||||
//func TestEmptyPrinterQueue(t *testing.T) {
|
func TestEmptyPrinterQueue(t *testing.T) {
|
||||||
//request := &EmpPrinterQueueRequest{
|
//request := &EmpPrinterQueueRequest{
|
||||||
// RestRequest: api.GenerateRestRequest(),
|
// RestRequest: api.GenerateRestRequest(),
|
||||||
// Sn: TestPrinterSN,
|
// Sn: TestPrinterSN,
|
||||||
//}
|
//}
|
||||||
// err := api.EmptyPrinterQueue(request)
|
err := api.EmptyPrinterQueue(TestPrinterSN)
|
||||||
// fmt.Println(err)
|
fmt.Println(err)
|
||||||
//}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
////查询订单状态
|
////查询订单状态
|
||||||
//func TestQueryOrderState(t *testing.T) {
|
//func TestQueryOrderState(t *testing.T) {
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import (
|
|||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,3 +171,48 @@ func FormatPrintOrderItem(foodName string, quantity int, price float64) string {
|
|||||||
result += "<BR>"
|
result += "<BR>"
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//正则计算宽度
|
||||||
|
func CalWidth(str string) int {
|
||||||
|
hzc := 0
|
||||||
|
for _, v := range str {
|
||||||
|
if unicode.Is(unicode.Han, v) {
|
||||||
|
hzc++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateStr := regexp.MustCompile("[\u4e00-\u9fa5]{1,}").ReplaceAllString(str, "")
|
||||||
|
l := len(updateStr)
|
||||||
|
fmt.Println(hzc)
|
||||||
|
ans := 2*hzc + l
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
MaxLineLength = 30
|
||||||
|
LineLength = 32
|
||||||
|
NewLineLength = 28
|
||||||
|
)
|
||||||
|
|
||||||
|
func FormatPrintOrderItemV2(foodName string, quantity, index int) string {
|
||||||
|
var (
|
||||||
|
restLen int
|
||||||
|
quantityStr = strconv.Itoa(quantity)
|
||||||
|
//quantityLen = CalcAsciiLenForPrint(quantityStr)
|
||||||
|
foodNameLen = CalWidth(foodName) + 3
|
||||||
|
result = ""
|
||||||
|
)
|
||||||
|
if foodNameLen >= MaxLineLength {
|
||||||
|
if n := foodNameLen / LineLength; n > 0 {
|
||||||
|
restLen = foodNameLen % LineLength
|
||||||
|
} else {
|
||||||
|
restLen = foodNameLen - LineLength
|
||||||
|
}
|
||||||
|
result += "<HB>" + utils.Int2Str(index) + `.` + foodName + "</HB>"
|
||||||
|
result += "<HB>" + StrRepeat(" ", MaxLineLength-restLen) + `x` + quantityStr + "</HB>"
|
||||||
|
} else {
|
||||||
|
result += "<HB>" + utils.Int2Str(index) + `.` + foodName + StrRepeat(" ", MaxLineLength-foodNameLen) + `x` + quantityStr + "</HB>"
|
||||||
|
}
|
||||||
|
//result += orderNameEmpty + "x" + quantityStr + StrRepeat(" ", MAX_QUANTITY_CHAR_LEN-quantityLen)
|
||||||
|
result += "<BR>"
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user