update service

master
李光春 2 years ago
parent a3a184da64
commit 8893bde638

@ -1,8 +0,0 @@
package service
import "errors"
var (
ErrTypeIsNil = errors.New("类型为Nil")
ErrTypeUnknown = errors.New("未处理到的数据类型")
)

@ -1,186 +0,0 @@
package ddk
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/bitly/go-simplejson"
"github.com/dtapps/go-library/service"
"github.com/nilorg/sdk/convert"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
var (
// ClientId 应用Key
ClientId string
// ClientSecret 秘密
ClientSecret string
// Router 环境请求地址
Router = "https://gw-api.pinduoduo.com/api/router"
// Timeout ...
Timeout time.Duration
)
// Parameter 参数
type Parameter map[string]interface{}
// ParameterJsonEncode 参数
type ParameterJsonEncode []string
// copyParameter 复制参数
func copyParameter(srcParams Parameter) Parameter {
newParams := make(Parameter)
for key, value := range srcParams {
newParams[key] = value
}
return newParams
}
// execute 执行API接口
func execute(param Parameter) (bytes []byte, err error) {
err = checkConfig()
if err != nil {
return
}
var req *http.Request
req, err = http.NewRequest("POST", Router, strings.NewReader(param.getRequestData()))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
httpClient := &http.Client{}
httpClient.Timeout = Timeout
var response *http.Response
response, err = httpClient.Do(req)
if err != nil {
return
}
if response.StatusCode != 200 {
err = fmt.Errorf("请求错误:%d", response.StatusCode)
return
}
defer response.Body.Close()
bytes, err = ioutil.ReadAll(response.Body)
return
}
// Execute 执行API接口
func Execute(method string, param Parameter) (res *simplejson.Json, err error) {
param["type"] = method
param.setRequestData()
var bodyBytes []byte
bodyBytes, err = execute(param)
if err != nil {
return
}
return bytesToResult(bodyBytes)
}
func bytesToResult(bytes []byte) (res *simplejson.Json, err error) {
res, err = simplejson.NewJson(bytes)
if err != nil {
return
}
if responseError, ok := res.CheckGet("error_response"); ok {
if subMsg, subOk := responseError.CheckGet("sub_msg"); subOk {
err = errors.New(subMsg.MustString())
} else {
err = errors.New(responseError.Get("msg").MustString())
}
res = nil
}
return
}
// 检查配置
func checkConfig() error {
if ClientId == "" {
return errors.New("ClientId 不能为空")
}
if ClientSecret == "" {
return errors.New("ClientSecret 不能为空")
}
if Router == "" {
return errors.New("Router 不能为空")
}
return nil
}
func (p Parameter) setRequestData() {
hh, _ := time.ParseDuration("8h")
loc := time.Now().UTC().Add(hh)
p["timestamp"] = strconv.FormatInt(loc.Unix(), 10)
p["client_id"] = ClientId
p["data_type"] = "JSON"
p["version"] = "v1"
// 设置签名
p["sign"] = getSign(p)
}
// 获取请求数据
func (p Parameter) getRequestData() string {
// 公共参数
args := url.Values{}
// 请求参数
for key, val := range p {
args.Set(key, interfaceToString(val))
}
return args.Encode()
}
// 获取签名
func getSign(params Parameter) string {
// 获取Key
var keys []string
for k := range params {
keys = append(keys, k)
}
// 排序asc
sort.Strings(keys)
// 把所有参数名和参数值串在一起
query := bytes.NewBufferString(ClientSecret)
for _, k := range keys {
query.WriteString(k)
query.WriteString(interfaceToString(params[k]))
}
query.WriteString(ClientSecret)
// 使用MD5加密
h := md5.New()
io.Copy(h, query)
// 把二进制转化为大写的十六进制
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
func interfaceToString(src interface{}) string {
if src == nil {
panic(service.ErrTypeIsNil)
}
switch src.(type) {
case string:
return src.(string)
case int, int8, int32, int64:
case uint8, uint16, uint32, uint64:
case float32, float64:
return convert.ToString(src)
}
data, err := json.Marshal(src)
if err != nil {
panic(err)
}
return string(data)
}

@ -1,28 +0,0 @@
package ddk
import (
"fmt"
"testing"
)
func init() {
ClientId = "c0372aa7ffa149cbbce852e4d397a577"
ClientSecret = "7d527f81d80bc41527dd8d680a462ff06fbfb14b"
}
func TestName(t *testing.T) {
res, err := Execute("pdd.ddk.goods.recommend.get", Parameter{
"limit": 10,
"channel_type": 3,
"offset": 0,
"pid": "1923953_141325051",
"goods_sign_list": ParameterJsonEncode{
"Y9v2lh2s6e1GWdnxwfbZF9sHlepFWs13_JmF4wnW72",
},
})
fmt.Printf("res%#v\n", res)
if err != nil {
t.Errorf("错误:%#v\n", err)
}
}

@ -0,0 +1,142 @@
package eastiot
import "net/http"
// IotApiQueryUserBalanceResult 返回参数
type IotApiQueryUserBalanceResult struct {
Code int `json:"code"`
Data struct {
Balance float64 `json:"balance"`
} `json:"data"`
Msg string `json:"msg"`
}
// IotApiQueryUserBalance 余额查询
// https://www.showdoc.com.cn/916774523755909/4857910459512420
func (app *App) IotApiQueryUserBalance() (body []byte, err error) {
// 请求
body, err = app.request("http://m2m.eastiot.net/Api/IotApi/queryUserBalance", map[string]interface{}{}, http.MethodPost)
return body, err
}
type IotApiGetAllSimTypeResult struct {
Code int `json:"code"`
Data []struct {
Type int `json:"type"` // 卡类型
Name string `json:"name"` // 类型名
MOrder int `json:"mOrder"` // 是否支持单次充值多个流量包0:不支持 1:支持
} `json:"data"`
Msg string `json:"msg"`
}
// IotApiGetAllSimType 卡类型列表查询
// https://www.showdoc.com.cn/916774523755909/4858492092033167
func (app *App) IotApiGetAllSimType() (body []byte, err error) {
// 请求
body, err = app.request("http://m2m.eastiot.net/Api/IotApi/getAllSimType", map[string]interface{}{}, http.MethodPost)
return body, err
}
type IotApiQueryUserPkgInfoResult struct {
Code int `json:"code"`
Data []struct {
Type int `json:"type"`
PkgId int64 `json:"pkgId"`
PkgName string `json:"pkgName"`
Price float64 `json:"price"`
Sprice float64 `json:"sprice"`
Traffic int `json:"traffic"`
Caltype int `json:"caltype"`
SimType int `json:"simType"`
Isdm int `json:"isdm"`
Isnm int `json:"isnm"`
Istest int `json:"istest"`
Isimm int `json:"isimm"`
Daynum int `json:"daynum"`
} `json:"data"`
Msg string `json:"msg"`
}
// IotApiQueryUserPkgInfo 账户可用流量包查询
// https://www.showdoc.com.cn/916774523755909/4850094776758927
func (app *App) IotApiQueryUserPkgInfo() (body []byte, err error) {
// 请求
body, err = app.request("http://m2m.eastiot.net/Api/IotApi/queryUserPkgInfo", map[string]interface{}{}, http.MethodPost)
return body, err
}
type IotApiRechargeSimResult struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
// IotApiRechargeSim 单卡流量充值
// https://www.showdoc.com.cn/916774523755909/4880284631482420
func (app *App) IotApiRechargeSim(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("http://m2m.eastiot.net/Api/IotApi/rechargeSim", params, http.MethodPost)
return body, err
}
type IotApiQuerySimPkgInfoResult struct {
Code int `json:"code"`
Istest int `json:"istest"`
Data []struct {
PkgId int `json:"pkgId"` // 流量包ID
PkgName string `json:"pkgName"` // 流量包名字
Price float64 `json:"price"` // 流量包成本价格,单位: 元
Sprice float64 `json:"sprice"` // 流量包零售价格,单位: 元
Traffic int `json:"traffic"` // 流量包大小,单位: MB
Type int `json:"type"` // 流量包类型1:叠加包 2:单月套餐 3:季度套餐 4:半年套餐 5:全年套餐 6:每月套餐 (3个月) 7:每月套餐(6个月) 8:每月套餐(12个月) 0:N天套餐
Isdm int `json:"isdm"` // 是否依赖主套餐,此字段只有套餐类型为叠加包时有效; 1:依赖主套餐 0:独立
Isnm int `json:"isnm"` // 是否支持次月生效,此字段只有套餐类型为独立叠加包时有效; 1:支持 0:不支持
Istest int `json:"istest"` // 是否为体验包; 1:是 0:否
Isimm int `json:"isimm"` // 订购后是否立即叠加生效; 1:是 0:否
Stime string `json:"stime"` // 套餐的生效起始日期
Etime string `json:"etime"` // 套餐的生效结束日期
Daynum int `json:"daynum"` // 当type=0时表示套餐有效天数当type=8 且 daynum>0 时,表示套餐的有效年数
} `json:"data"`
Msg string `json:"msg"`
}
// IotApiQuerySimPkgInfo 流量卡可用流量包查询
// https://www.showdoc.com.cn/916774523755909/4880284631482420
func (app *App) IotApiQuerySimPkgInfo(simId string, sd int) (body []byte, err error) {
// 参数
param := NewParams()
param.Set("simId", simId)
param.Set("sd", sd)
params := app.NewParamsWith(param)
// 请求
body, err = app.request("http://m2m.eastiot.net/Api/IotApi/querySimPkgInfo", params, http.MethodPost)
return body, err
}
type IotApiQueryOrderedPkgInfoResult struct {
Code int `json:"code"`
Istest int `json:"istest"`
Data []struct {
Name string `json:"name"` // 流量包名字
PkgId int64 `json:"pkgId"` // 流量包ID
Traffic int `json:"traffic"` // 流量大小,单位:MB
Ntraffic float64 `json:"ntraffic"` // 已用量,单位:MB
Starttime int `json:"starttime"` // 流量生效起始时间时间戳
Endtime int `json:"endtime"` // 流量生效结束时间时间戳
Addtime int `json:"addtime"` // 订购时间时间戳
} `json:"data"`
Msg string `json:"msg"`
}
// IotApiQueryOrderedPkgInfo 查询流量卡已订购流量包
// https://www.showdoc.com.cn/916774523755909/5092045889939625
func (app *App) IotApiQueryOrderedPkgInfo(simId string) (body []byte, err error) {
// 参数
param := NewParams()
param.Set("simId", simId)
params := app.NewParamsWith(param)
// 请求
body, err = app.request("http://m2m.eastiot.net/Api/IotApi/queryOrderedPkgInfo", params, http.MethodPost)
return body, err
}

@ -0,0 +1,28 @@
package eastiot
import (
"github.com/dtapps/go-library/utils/gohttp"
"net/http"
"time"
)
type App struct {
AppID string
ApiKey string
}
func (app *App) request(url string, params map[string]interface{}, method string) ([]byte, error) {
// 公共参数
params["appId"] = app.AppID
params["timeStamp"] = time.Now().Unix()
// 签名
params["sign"] = app.getSign(app.ApiKey, params)
// 请求
if method == http.MethodGet {
get, err := gohttp.Get(url, params)
return get.Body, err
} else {
postJson, err := gohttp.PostForm(url, params)
return postJson.Body, err
}
}

@ -0,0 +1,27 @@
package eastiot
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1,37 @@
package eastiot
import (
"encoding/json"
"fmt"
"github.com/dtapps/go-library/utils/gomd5"
"sort"
"strconv"
)
func (app *App) getSign(ApiKey string, p map[string]interface{}) string {
var keys []string
for k := range p {
keys = append(keys, k)
}
sort.Strings(keys)
signStr := ""
for _, key := range keys {
signStr += fmt.Sprintf("%s=%s&", key, app.getString(p[key]))
}
signStr += fmt.Sprintf("apiKey=%s", ApiKey)
return gomd5.ToUpper(signStr)
}
func (app *App) getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
default:
bytes, _ := json.Marshal(v)
return string(bytes)
}
}

@ -0,0 +1,31 @@
package ejiaofei
import (
"fmt"
"github.com/dtapps/go-library/utils/gohttp"
"github.com/dtapps/go-library/utils/gomd5"
"net/http"
)
type App struct {
UserID string
Pwd string
Key string
signStr string
}
func (app *App) request(url string, params map[string]interface{}, method string) ([]byte, error) {
// 公共参数
params["userid"] = app.UserID
params["pwd"] = app.Pwd
// 签名
params["userkey"] = gomd5.ToUpper(fmt.Sprintf("%s%s", app.signStr, app.Key))
// 请求
if method == http.MethodGet {
get, err := gohttp.Get(url, params)
return get.Body, err
} else {
postJson, err := gohttp.PostForm(url, params)
return postJson.Body, err
}
}

@ -0,0 +1,29 @@
package ejiaofei
import (
"encoding/xml"
"fmt"
"net/http"
)
type CheckCostResult struct {
XMLName xml.Name `xml:"response"`
UserID string `xml:"userid"` // 用户账号
OrderID string `xml:"orderid"` // 用户提交订单号
Face float64 `xml:"face"` // 官方价格
Price float64 `xml:"price"` // 用户成本价
Error int `xml:"error"` // 错误提示
}
// CheckCost 会员订单成本价查询接口
func (app *App) CheckCost(orderID string) (body []byte, err error) {
// 参数
param := NewParams()
param.Set("orderid", orderID)
params := app.NewParamsWith(param)
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%vorderid%v", app.UserID, app.Pwd, orderID)
// 请求
body, err = app.request("http://api.ejiaofei.net:11140/checkCost.do", params, http.MethodGet)
return body, err
}

@ -0,0 +1,40 @@
package ejiaofei
import (
"encoding/xml"
"fmt"
"net/http"
)
type ChOngZhiJkOrdersResult struct {
XMLName xml.Name `xml:"response"`
UserID string `xml:"userid"` // 会员账号
PorderID string `xml:"Porderid"` // 鼎信平台订单号
OrderID string `xml:"orderid"` // 用户订单号
Account string `xml:"account"` // 需要充值的手机号码
Face string `xml:"face"` // 充值面值
Amount string `xml:"amount"` // 购买数量
StartTime string `xml:"starttime"` // 开始时间
State string `xml:"state"` // 订单状态
EndTime string `xml:"endtime"` // 结束时间
Error string `xml:"error"` // 错误提示
}
// ChOngZhiJkOrders 话费充值接口
// orderid 用户提交的订单号 用户提交的订单号最长32位用户保证其唯一性
// face 充值面值 以元为单位包含10、20、30、50、100、200、300、500 移动联通电信
// account 手机号码 需要充值的手机号码
func (app *App) ChOngZhiJkOrders(orderID string, face int, account string) (body []byte, err error) {
// 参数
param := NewParams()
param.Set("orderid", orderID)
param.Set("face", face)
param.Set("account", account)
param.Set("amount", 1)
params := app.NewParamsWith(param)
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%vorderid%vface%vaccount%vamount1", app.UserID, app.Pwd, orderID, face, account)
// 请求
body, err = app.request("http://api.ejiaofei.net:11140/chongzhi_jkorders.do", params, http.MethodGet)
return body, err
}

@ -0,0 +1,47 @@
package ejiaofei
import (
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
)
type GprsChOngZhiAdvanceParams struct {
OrderID string `json:"orderid"` // 用户提交的订单号 用户提交的订单号最长32位用户保证其唯一性
Account string `json:"account"` // 充值手机号 需要充值的手机号
Gprs int `json:"gprs"` // 充值流量值 单位MB具体流量值请咨询商务
Area int `json:"area"` // 充值流量范围 0 全国流量1 省内流量
EffectTime int `json:"effecttime"` // 生效日期 0 即时生效1次日生效2 次月生效
Validity int `json:"validity"` // 流量有效期 传入月数0为当月有效
Times string `json:"times"` // 时间戳 格式yyyyMMddhhmmss
}
type GprsChOngZhiAdvanceResult struct {
XMLName xml.Name `xml:"response"`
UserID string `xml:"userid"` // 会员账号
OrderID string `xml:"orderid"` // 会员提交订单号
PorderID string `xml:"Porderid"` // 平台订单号
Account string `xml:"account"` // 充值手机号
State int `xml:"state"` // 订单状态
StartTime string `xml:"starttime"` // 开始时间
EndTime string `xml:"endtime"` // 结束时间
Error string `xml:"error"` // 错误提示
UserPrice float64 `xml:"userprice"` // 会员购买价格
Gprs string `xml:"gprs"` // 充值流量值单位MB
Area string `xml:"area"` // 流量范围0 全国流量1省内流量
EffectTime string `xml:"effecttime"` // 生效日期0即时1次日2次月
Validity string `xml:"validity"` // 流量有效期显示月数0为当月
}
// GprsChOngZhiAdvance 流量充值接口
func (app *App) GprsChOngZhiAdvance(param GprsChOngZhiAdvanceParams) (body []byte, err error) {
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%vorderid%vaccount%vgprs%varea%veffecttime%vvalidity%vtimes%v", app.UserID, app.Pwd, param.OrderID, param.Account, param.Gprs, param.Area, param.EffectTime, param.Validity, param.Times)
// 请求
b, _ := json.Marshal(&param)
var params map[string]interface{}
_ = json.Unmarshal(b, &params)
body, err = app.request("http://api.ejiaofei.net:11140/gprsChongzhiAdvance.do", params, http.MethodGet)
return body, err
}

@ -0,0 +1,23 @@
package ejiaofei
import (
"encoding/xml"
"fmt"
"net/http"
)
type MoneyJkUserResult struct {
XMLName xml.Name `xml:"response"`
LastMoney float64 `xml:"lastMoney"` // 用户余额
Tag int `xml:"tag"` // 用户状态0正常 1暂停
Error int `xml:"error"` // 错误提示
}
// MoneyJkUser 用户余额查询
func (app *App) MoneyJkUser() (body []byte, err error) {
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%v", app.UserID, app.Pwd)
// 请求
body, err = app.request("http://api.ejiaofei.net:11140/money_jkuser.do", map[string]interface{}{}, http.MethodGet)
return body, err
}

@ -0,0 +1,27 @@
package ejiaofei
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1,35 @@
package ejiaofei
import (
"encoding/xml"
"fmt"
"net/http"
)
type QueryJkOrdersResult struct {
XMLName xml.Name `xml:"response"`
UserID string `xml:"userid"` // 会员账号
POrderID string `xml:"Porderid"` // 鼎信平台订单号
OrderID string `xml:"orderid"` // 用户订单号
Account string `xml:"account"` // 需要充值的手机号码
Face string `xml:"face"` // 充值面值
Amount string `xml:"amount"` // 购买数量
StartTime string `xml:"starttime"` // 开始时间
State string `xml:"state"` // 订单状态
EndTime string `xml:"endtime"` // 结束时间
Error string `xml:"error"` // 错误提示
}
// QueryJkOrders 通用查询接口
// orderid 用户提交的订单号 用户提交的订单号最长32位用户保证其唯一性
func (app *App) QueryJkOrders(orderID string) (body []byte, err error) {
// 参数
param := NewParams()
param.Set("orderid", orderID)
params := app.NewParamsWith(param)
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%vorderid%v", app.UserID, app.Pwd, orderID)
// 请求
body, err = app.request("http://api.ejiaofei.net:11140/query_jkorders.do", params, http.MethodGet)
return body, err
}

@ -0,0 +1,21 @@
package ejiaofei
import (
"encoding/xml"
"fmt"
"net/http"
)
type QueryTxProductResult struct {
XMLName xml.Name `xml:"response"`
Error string `xml:"error"` // 错误提示
}
// QueryTxProduct 可充值腾讯产品查询
func (app *App) QueryTxProduct() (body []byte, err error) {
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%v", app.UserID, app.Pwd)
// 请求
body, err = app.request("http://api.ejiaofei.net:11140/queryTXproduct.do", map[string]interface{}{}, http.MethodGet)
return body, err
}

@ -0,0 +1,43 @@
package ejiaofei
import (
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
)
type TxChOngZhiParams struct {
OrderID string `json:"orderid"` // 用户提交的订单号 用户提交的订单号最长32位用户保证其唯一性
Account string `json:"account"` // QQ号 需要充值的QQ号
ProductID int `json:"productid"` // 产品id
Amount int `json:"amount"` // 购买数量
Ip string `json:"ip"` // 充值QQ号ip
Times string `json:"times"` // 时间戳 格式yyyyMMddhhmmss
}
type TxChOngZhiResult struct {
XMLName xml.Name `xml:"response"`
UserID string `xml:"userid"` // 用户编号
PorderID string `xml:"Porderid"` // 鼎信平台订单号
OrderID string `xml:"orderid"` // 用户订单号
Account string `xml:"account"` // 需要充值的QQ号
ProductID int `xml:"productid"` // 充值产品id
Amount int `xml:"amount"` // 购买数量
State int `xml:"state"` // 订单状态
StartTime string `xml:"starttime"` // 开始时间
EndTime string `xml:"endtime"` // 结束时间
Error string `xml:"error"` // 错误提示
}
// TxChOngZhi 流量充值接口
func (app *App) TxChOngZhi(param TxChOngZhiParams) (body []byte, err error) {
// 签名
app.signStr = fmt.Sprintf("userid%vpwd%vorderid%vaccount%vproductid%vamount%vip%vtimes%v", app.UserID, app.Pwd, param.OrderID, param.Account, param.ProductID, param.Amount, param.Ip, param.Times)
// 请求
b, _ := json.Marshal(&param)
var params map[string]interface{}
_ = json.Unmarshal(b, &params)
body, err = app.request("http://api.ejiaofei.net:11140/txchongzhi.do", params, http.MethodGet)
return body, err
}

@ -0,0 +1,53 @@
package jd
import (
"encoding/json"
"github.com/dtapps/go-library/utils/gohttp"
)
type App struct {
AppKey string // 应用Key
SecretKey string // 密钥
}
type ErrResp struct {
Code string `json:"code"`
ErrorMessage string `json:"errorMessage"`
ErrorSolution string `json:"errorSolution"`
}
func (app *App) request(params map[string]interface{}) (resp []byte, err error) {
// 签名
app.Sign(params)
// 发送请求
httpGet, err := gohttp.PostForm("https://api.jd.com/routerjson", params)
// 检查错误
var errResp ErrResp
_ = json.Unmarshal(httpGet.Body, &errResp)
return httpGet.Body, err
}
// GoodsPriceToInt64 商品券后价
func (app *App) GoodsPriceToInt64(LowestCouponPrice float64) int64 {
return int64(LowestCouponPrice * 100)
}
// GoodsOriginalPriceToInt64 商品原价
func (app *App) GoodsOriginalPriceToInt64(Price float64) int64 {
return int64(Price * 100)
}
// CouponProportionToInt64 佣金比率
func (app *App) CouponProportionToInt64(CommissionShare float64) int64 {
return int64(CommissionShare * 10)
}
// CouponAmountToInt64 优惠券金额
func (app *App) CouponAmountToInt64(Commission float64) int64 {
return int64(Commission * 100)
}
// CommissionIntegralToInt64 佣金积分
func (app *App) CommissionIntegralToInt64(GoodsPrice, CouponProportion int64) int64 {
return (GoodsPrice * CouponProportion) / 1000
}

@ -0,0 +1,15 @@
package jd
import (
"crypto/md5"
"encoding/hex"
"strings"
)
// 签名
func createSign(signStr string) string {
h := md5.New()
h.Write([]byte(signStr))
cipherStr := h.Sum(nil)
return strings.ToUpper(hex.EncodeToString(cipherStr))
}

@ -0,0 +1,89 @@
package jd
import (
"encoding/json"
"net/url"
"sort"
"strconv"
"time"
)
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func NewParamsWithType(_method string, params ...Params) Params {
p := make(Params)
p["method"] = _method
hh, _ := time.ParseDuration("8h")
loc := time.Now().UTC().Add(hh)
p["timestamp"] = loc.Format("2006-01-02 15:04:05")
p["format"] = "json"
p["v"] = "1.0"
p["sign_method"] = "md5"
for _, v := range params {
p.SetParams(v)
}
return p
}
func (app *App) Sign(p Params) {
p["app_key"] = app.AppKey
// 排序所有的 key
var keys []string
for key := range p {
keys = append(keys, key)
}
sort.Strings(keys)
signStr := app.SecretKey
for _, key := range keys {
signStr += key + getString(p[key])
}
signStr += app.SecretKey
p["sign"] = createSign(signStr)
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}
func (p Params) SetCustomParameters(uid string, sid string) {
p["custom_parameters"] = map[string]interface{}{
"uid": uid,
"sid": sid,
}
}
func (p Params) GetQuery() string {
u := url.Values{}
for k, v := range p {
u.Set(k, getString(v))
}
return u.Encode()
}
func getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
case []byte:
return string(v)
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
default:
bytes, _ := json.Marshal(v)
return string(bytes)
}
}

@ -0,0 +1,115 @@
package jd
type UnionOpenGoodsJIngFenQueryResult struct {
JdUnionOpenGoodsJingfenQueryResponce struct {
Code string `json:"code"`
QueryResult string `json:"queryResult"`
} `json:"jd_union_open_goods_jingfen_query_responce"`
}
type UnionOpenGoodsJIngFenQueryQueryResult struct {
Code int `json:"code"`
Data []struct {
BrandCode string `json:"brandCode"`
BrandName string `json:"brandName"`
CategoryInfo struct {
Cid1 int64 `json:"cid1"`
Cid1Name string `json:"cid1Name"`
Cid2 int `json:"cid2"`
Cid2Name string `json:"cid2Name"`
Cid3 int `json:"cid3"`
Cid3Name string `json:"cid3Name"`
} `json:"categoryInfo"`
Comments int `json:"comments"`
CommissionInfo struct {
Commission float64 `json:"commission"`
CommissionShare float64 `json:"commissionShare"`
CouponCommission float64 `json:"couponCommission"`
EndTime int64 `json:"endTime"`
IsLock int `json:"isLock"`
PlusCommissionShare float64 `json:"plusCommissionShare"`
StartTime int64 `json:"startTime"`
} `json:"commissionInfo"`
CouponInfo struct {
CouponList []struct {
BindType int `json:"bindType"`
Discount float64 `json:"discount"`
GetEndTime int64 `json:"getEndTime"`
GetStartTime int64 `json:"getStartTime"`
HotValue int `json:"hotValue,omitempty"`
IsBest int `json:"isBest"`
Link string `json:"link"`
PlatformType int `json:"platformType"`
Quota float64 `json:"quota"`
UseEndTime int64 `json:"useEndTime"`
UseStartTime int64 `json:"useStartTime"`
} `json:"couponList"`
} `json:"couponInfo"`
DeliveryType int `json:"deliveryType"`
ForbidTypes []int `json:"forbidTypes"`
GoodCommentsShare float64 `json:"goodCommentsShare"`
ImageInfo struct {
ImageList []struct {
Url string `json:"url"`
} `json:"imageList"`
WhiteImage string `json:"whiteImage,omitempty"`
} `json:"imageInfo"`
InOrderCount30Days int64 `json:"inOrderCount30Days"`
InOrderCount30DaysSku int `json:"inOrderCount30DaysSku"`
IsHot int `json:"isHot"`
JxFlags []int `json:"jxFlags,omitempty"`
MaterialUrl string `json:"materialUrl"`
Owner string `json:"owner"`
PinGouInfo struct {
PingouEndTime int64 `json:"pingouEndTime,omitempty"`
PingouPrice float64 `json:"pingouPrice,omitempty"`
PingouStartTime int64 `json:"pingouStartTime,omitempty"`
PingouTmCount int `json:"pingouTmCount,omitempty"`
PingouUrl string `json:"pingouUrl,omitempty"`
} `json:"pinGouInfo"`
PriceInfo struct {
HistoryPriceDay int `json:"historyPriceDay"`
LowestCouponPrice float64 `json:"lowestCouponPrice"`
LowestPrice float64 `json:"lowestPrice"`
LowestPriceType int `json:"lowestPriceType"`
Price float64 `json:"price"`
} `json:"priceInfo"`
ResourceInfo struct {
EliteId int `json:"eliteId"`
EliteName string `json:"eliteName"`
} `json:"resourceInfo"`
ShopInfo struct {
ShopId int64 `json:"shopId"`
ShopLabel string `json:"shopLabel"`
ShopLevel float64 `json:"shopLevel"`
ShopName string `json:"shopName"`
AfsFactorScoreRankGrade string `json:"afsFactorScoreRankGrade,omitempty"`
AfterServiceScore string `json:"afterServiceScore,omitempty"`
CommentFactorScoreRankGrade string `json:"commentFactorScoreRankGrade,omitempty"`
LogisticsFactorScoreRankGrade string `json:"logisticsFactorScoreRankGrade,omitempty"`
LogisticsLvyueScore string `json:"logisticsLvyueScore,omitempty"`
ScoreRankRate string `json:"scoreRankRate,omitempty"`
UserEvaluateScore string `json:"userEvaluateScore,omitempty"`
} `json:"shopInfo"`
SkuId int64 `json:"skuId"`
SkuLabelInfo struct {
FxgServiceList []interface{} `json:"fxgServiceList"`
Is7ToReturn int `json:"is7ToReturn"`
} `json:"skuLabelInfo"`
SkuName string `json:"skuName"`
Spuid int64 `json:"spuid"`
} `json:"data"`
Message string `json:"message"`
TotalCount int `json:"totalCount"`
}
// UnionOpenGoodsJIngFenQuery
// 京东联盟精选优质商品每日更新可通过频道ID查询各个频道下的精选商品。用获取的优惠券链接调用转链接口时需传入搜索接口link字段返回的原始优惠券链接切勿对链接进行任何encode、decode操作否则将导致转链二合一推广链接时校验失败
// https://union.jd.com/openplatform/api/v2?apiName=jd.union.open.goods.jingfen.query
func (app *App) UnionOpenGoodsJIngFenQuery(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("jd.union.open.goods.jingfen.query", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,50 @@
package jd
type UnionOpenGoodsPromotionGoodsInfoQueryResult struct {
JdUnionOpenGoodsPromotiongoodsinfoQueryResponce struct {
Code string `json:"code"`
QueryResult string `json:"queryResult"`
} `json:"jd_union_open_goods_promotiongoodsinfo_query_responce"`
}
type UnionOpenGoodsPromotionGoodsInfoQueryQueryResult struct {
Code int `json:"code"`
Data []struct {
UnitPrice float64 `json:"unitPrice"`
MaterialUrl string `json:"materialUrl"`
EndDate int64 `json:"endDate"`
IsFreeFreightRisk int `json:"isFreeFreightRisk"`
IsFreeShipping int `json:"isFreeShipping"`
CommisionRatioWl float64 `json:"commisionRatioWl"`
CommisionRatioPc float64 `json:"commisionRatioPc"`
ImgUrl string `json:"imgUrl"`
Vid int `json:"vid"`
CidName string `json:"cidName"`
WlUnitPrice float64 `json:"wlUnitPrice"`
Cid2Name string `json:"cid2Name"`
IsSeckill int `json:"isSeckill"`
Cid2 int `json:"cid2"`
Cid3Name string `json:"cid3Name"`
Unt int `json:"unt"`
Cid3 int `json:"cid3"`
ShopId int `json:"shopId"`
IsJdSale int `json:"isJdSale"`
GoodsName string `json:"goodsName"`
SkuId int64 `json:"skuId"`
StartDate int64 `json:"startDate"`
Cid int64 `json:"cid"`
} `json:"data"`
Message string `json:"message"`
RequestId string `json:"requestId"`
}
// UnionOpenGoodsPromotionGoodsInfoQuery
// 通过SKUID查询推广商品的名称、主图、类目、价格、物流、是否自营、30天引单数量等详细信息支持批量获取。通常用于在媒体侧展示商品详情。
// https://union.jd.com/openplatform/api/v2?apiName=jd.union.open.goods.promotiongoodsinfo.query
func (app *App) UnionOpenGoodsPromotionGoodsInfoQuery(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("jd.union.open.goods.promotiongoodsinfo.query", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,29 @@
package jd
type UnionOpenPromotionCommonGetResult struct {
JdUnionOpenPromotionCommonGetResponce struct {
Code string `json:"code"`
GetResult string `json:"getResult"`
} `json:"jd_union_open_promotion_common_get_responce"`
}
type UnionOpenPromotionCommonGetGetResult struct {
Code int `json:"code"`
Data struct {
ClickURL string `json:"clickURL"`
JCommand string `json:"jCommand"`
} `json:"data"`
Message string `json:"message"`
RequestId string `json:"requestId"`
}
// UnionOpenPromotionCommonGet
// 网站/APP来获取的推广链接功能同宙斯接口的自定义链接转换、 APP领取代码接口通过商品链接、活动链接获取普通推广链接支持传入subunionid参数可用于区分媒体自身的用户ID该参数可在订单查询接口返回需向cps-qxsq@jd.com申请权限。
// https://union.jd.com/openplatform/api/v2?apiName=jd.union.open.promotion.common.get
func (app *App) UnionOpenPromotionCommonGet(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("jd.union.open.promotion.common.get", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -1,183 +0,0 @@
package jdk
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/bitly/go-simplejson"
"github.com/dtapps/go-library/service"
"github.com/nilorg/sdk/convert"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
var (
// AppKey 应用Key
AppKey string
// SecretKey 秘密
SecretKey string
// Router 环境请求地址
Router = "https://api.jd.com/routerjson"
// Timeout ...
Timeout time.Duration
)
// Parameter 参数
type Parameter map[string]interface{}
// copyParameter 复制参数
func copyParameter(srcParams Parameter) Parameter {
newParams := make(Parameter)
for key, value := range srcParams {
newParams[key] = value
}
return newParams
}
// execute 执行API接口
func execute(param Parameter) (bytes []byte, err error) {
err = checkConfig()
if err != nil {
return
}
var req *http.Request
req, err = http.NewRequest("POST", Router, strings.NewReader(param.getRequestData()))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
httpClient := &http.Client{}
httpClient.Timeout = Timeout
var response *http.Response
response, err = httpClient.Do(req)
if err != nil {
return
}
if response.StatusCode != 200 {
err = fmt.Errorf("请求错误:%d", response.StatusCode)
return
}
defer response.Body.Close()
bytes, err = ioutil.ReadAll(response.Body)
return
}
// Execute 执行API接口
func Execute(method string, param Parameter) (res *simplejson.Json, err error) {
param["method"] = method
param.setRequestData()
var bodyBytes []byte
bodyBytes, err = execute(param)
if err != nil {
return
}
return bytesToResult(bodyBytes)
}
func bytesToResult(bytes []byte) (res *simplejson.Json, err error) {
res, err = simplejson.NewJson(bytes)
if err != nil {
return
}
if responseError, ok := res.CheckGet("error_response"); ok {
if subMsg, subOk := responseError.CheckGet("sub_msg"); subOk {
err = errors.New(subMsg.MustString())
} else {
err = errors.New(responseError.Get("msg").MustString())
}
res = nil
}
return
}
// 检查配置
func checkConfig() error {
if AppKey == "" {
return errors.New("AppKey 不能为空")
}
if SecretKey == "" {
return errors.New("SecretKey 不能为空")
}
if Router == "" {
return errors.New("Router 不能为空")
}
return nil
}
func (p Parameter) setRequestData() {
hh, _ := time.ParseDuration("8h")
loc := time.Now().UTC().Add(hh)
p["app_key"] = AppKey
p["timestamp"] = loc.Format("2006-01-02 15:04:05")
p["format"] = "json"
p["v"] = "1.0"
p["sign_method"] = "md5"
// 设置签名
p["sign"] = getSign(p)
}
// 获取请求数据
func (p Parameter) getRequestData() string {
// 公共参数
args := url.Values{}
// 请求参数
for key, val := range p {
args.Set(key, interfaceToString(val))
}
return args.Encode()
}
// 获取签名
func getSign(params Parameter) string {
// 获取Key
keys := []string{}
for k := range params {
keys = append(keys, k)
}
// 排序asc
sort.Strings(keys)
// 把所有参数名和参数值串在一起
query := bytes.NewBufferString(SecretKey)
for _, k := range keys {
query.WriteString(k)
query.WriteString(interfaceToString(params[k]))
}
query.WriteString(SecretKey)
// 使用MD5加密
h := md5.New()
io.Copy(h, query)
// 把二进制转化为大写的十六进制
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
func interfaceToString(src interface{}) string {
if src == nil {
panic(service.ErrTypeIsNil)
}
switch src.(type) {
case string:
return src.(string)
case int, int8, int32, int64:
case uint8, uint16, uint32, uint64:
case float32, float64:
return convert.ToString(src)
}
data, err := json.Marshal(src)
if err != nil {
panic(err)
}
return string(data)
}

@ -0,0 +1,28 @@
package meituan
import (
"encoding/json"
"github.com/dtapps/go-library/utils/gohttp"
"net/http"
)
// App 美团联盟
type App struct {
Secret string // 秘钥
AppKey string // 渠道标记
}
func (app *App) request(url string, params map[string]interface{}, method string) (resp []byte, err error) {
// GET方式
if method == http.MethodGet {
get, err := gohttp.Get(url, params)
return get.Body, err
} else {
// 请求参数
paramsStr, err := json.Marshal(params)
postJson, err := gohttp.PostJson(url, paramsStr)
return postJson.Body, err
}
}

@ -0,0 +1,40 @@
package meituan
import (
"encoding/json"
)
// GenerateLinkResult 返回参数
type GenerateLinkResult struct {
Status int `json:"status"` // 状态值0为成功非0为异常
Des string `json:"des,omitempty"` // 异常描述信息
Data string `json:"data,omitempty"` // 最终的推广链接
}
// GenerateLink 自助取链接口 https://union.meituan.com/v2/apiDetail?id=25
func (app *App) GenerateLink(actId int64, sid string, linkType, shortLink int) (result GenerateLinkResult, err error) {
// 参数
param := NewParams()
param.Set("appkey", app.AppKey)
param.Set("actId", actId)
param.Set("sid", sid)
param.Set("linkType", linkType)
param.Set("shortLink", shortLink)
// 转换
params := app.NewParamsWith(param)
params["sign"] = app.getSign(app.Secret, params)
// 请求
body, err := app.request("https://openapi.meituan.com/api/generateLink", params, "GET")
if err != nil {
return
}
// 解析
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,38 @@
package meituan
import (
"encoding/json"
)
// MiniCodeResult 返回参数
type MiniCodeResult struct {
Status int `json:"status"` // 状态值0为成功非0为异常
Des string `json:"des,omitempty"` // 异常描述信息
Data string `json:"data,omitempty"` // 小程序二维码图片地址
}
// MiniCode 小程序二维码生成 https://union.meituan.com/v2/apiDetail?id=26
func (app *App) MiniCode(actId int64, sid string) (result MiniCodeResult, err error) {
// 参数
param := NewParams()
param.Set("appkey", app.AppKey)
param.Set("sid", sid)
param.Set("actId", actId)
// 转换
params := app.NewParamsWith(param)
params["sign"] = app.getSign(app.Secret, params)
// 请求
body, err := app.request("https://openapi.meituan.com/api/miniCode", params, "GET")
if err != nil {
return
}
// 解析
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,120 @@
package meituan
import (
"encoding/json"
)
type OpenapiPoiCategoryResult struct {
Code int `json:"code"`
Data []struct {
Name string `json:"name"`
Subcate []struct {
Name string `json:"name"` // 品类名称
ID int `json:"id"` // 品类id
} `json:"subcate"`
ID int `json:"id"`
} `json:"data"`
}
// OpenapiPoiCategory 基础数据 - 品类接口 https://openapi.meituan.com/#api-0.%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE-GetHttpsOpenapiMeituanComPoiDistrictCityid1
func (app *App) OpenapiPoiCategory(cityID int) (result OpenapiPoiCategoryResult, err error) {
param := NewParams()
param.Set("cityid", cityID)
// 参数
params := app.NewParamsWith(param)
// 请求
body, err := app.request("https://openapi.meituan.com/poi/category", params, "GET")
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}
type OpenapiPoiAreaResult struct {
Code int `json:"code"`
Data []struct {
Area []struct {
Name string `json:"name"` // 商圈名称
ID int `json:"id"` // 商圈id
} `json:"area"`
Name string `json:"name"` // 行政区名称
ID int `json:"id"` // 行政区id
} `json:"data"`
}
// OpenapiPoiArea 基础数据 - 商圈接口 https://openapi.meituan.com/#api-0.%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE-GetHttpsOpenapiMeituanComPoiAreaCityid1
func (app *App) OpenapiPoiArea(cityID int) (result OpenapiPoiAreaResult, err error) {
param := NewParams()
param.Set("cityid", cityID)
// 参数
params := app.NewParamsWith(param)
// 请求
body, err := app.request("https://openapi.meituan.com/poi/area", params, "GET")
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}
type OpenapiPoiDistrictResult struct {
Code int `json:"code"` // 状态码 0表示请求正常
Data []struct {
Name string `json:"name"` // 行政区名称
ID int `json:"id"` // 行政区id
} `json:"data"` // 返回行政区列表
}
// OpenapiPoiDistrict 基础数据 - 城市的行政区接口 https://openapi.meituan.com/#api-0.%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE-GetHttpsOpenapiMeituanComPoiDistrictCityid1
func (app *App) OpenapiPoiDistrict(cityID int) (result OpenapiPoiDistrictResult, err error) {
param := NewParams()
param.Set("cityid", cityID)
// 参数
params := app.NewParamsWith(param)
// 请求
body, err := app.request("https://openapi.meituan.com/poi/district", params, "GET")
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}
type OpenapiPoiCityResult struct {
Code int `json:"code"` // 状态码 0表示请求正常
Data []struct {
Pinyin string `json:"pinyin"` // 城市拼音
Name string `json:"name"` // 城市名称
ID int `json:"id"` // 城市id
} `json:"data"` // 返回城市列表
}
// OpenapiPoiCity 基础数据 - 开放城市接口 https://openapi.meituan.com/#api-0.%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE-GetHttpsOpenapiMeituanComPoiCity
func (app *App) OpenapiPoiCity() (result OpenapiPoiCityResult, err error) {
// 请求
body, err := app.request("https://openapi.meituan.com/poi/city", map[string]interface{}{}, "GET")
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,72 @@
package meituan
import (
"encoding/json"
"github.com/dtapps/go-library/utils/gotime"
)
// OrderList 请求参数
type OrderList struct {
Type string `json:"type"` // 查询订单类型 0 团购订单 2 酒店订单 4 外卖订单 5 话费&团好货订单 6 闪购订单 8 优选订单
StartTime string `json:"startTime"` // 查询起始时间10位时间戳以下单时间为准
EndTime string `json:"endTime"` // 查询截止时间10位时间戳以下单时间为准
Page string `json:"page"` // 分页参数起始值从1开始
Limit string `json:"limit"` // 每页显示数据条数最大值为100
QueryTimeType string `json:"queryTimeType,omitempty"` // 查询时间类型,枚举值 1 按订单支付时间查询 2 按订单发生修改时间查询
}
// OrderListResult 返回参数
type OrderListResult struct {
DataList []struct {
Orderid string `json:"orderid"` // 订单id
Paytime string `json:"paytime"` // 订单支付时间10位时间戳
Payprice string `json:"payprice"` // 订单用户实际支付金额
Profit string `json:"profit"` // 订单预估返佣金额
CpaProfit string `json:"cpaProfit"` // 订单预估cpa总收益优选、话费券
Sid string `json:"sid"` // 订单对应的推广位sid
Appkey string `json:"appkey,omitempty"` // 订单对应的appkey外卖、话费、闪购、优选订单会返回该字段
Smstitle string `json:"smstitle"` // 订单标题
Refundprice string `json:"refundprice,omitempty"` // 订单实际退款金额,外卖、话费、闪购、优选、酒店订单若发生退款会返回该字段
Refundtime string `json:"refundtime,omitempty"` // 订单退款时间10位时间戳外卖、话费、闪购、优选、酒店订单若发生退款会返回该字段
Refundprofit string `json:"refundprofit,omitempty"` // 订单需要扣除的返佣金额,外卖、话费、闪购、优选、酒店订单若发生退款会返回该字段
CpaRefundProfit string `json:"cpaRefundProfit"` // 订单需要扣除的cpa返佣金额优选、话费券
Status string `json:"status,omitempty"` // 订单状态,外卖、话费、闪购、优选、酒店订单会返回该字段 1 已付款 8 已完成 9 已退款或风控
TradeTypeList []interface{} `json:"tradeTypeList,omitempty"` // 订单的奖励类型 话费订单类型返回该字段 3 首购奖励 5 留存奖励 优选订单类型返回该字段 2 cps 3 首购奖励
TradeTypeBusinessTypeMapStr string `json:"tradeTypeBusinessTypeMapStr"` // 奖励类型对应平台类型的映射 格式:{3:[3,5]} value的枚举值1 外卖 2 分销酒店 3 平台 4 券类型酒店 5 团好货 6 优选
RiskOrder string `json:"riskOrder,omitempty"` // 0表示正常退款1表示风控退款订单状态为退款时有效
} `json:"dataList"` // 订单列表
Total int `json:"total"` // 查询条件命中的总数据条数,用于计算分页参数
}
// OrderList 订单列表查询(新) https://union.meituan.com/v2/apiDetail?id=1
func (app *App) OrderList(param OrderList) (result OrderListResult, err error) {
// 处理默认数据
if param.Page == "" {
param.Page = "1"
}
if param.Limit == "" {
param.Limit = "100"
}
// 接口参数
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
// 请求时刻10位时间戳(秒级)有效期60s
params["ts"] = gotime.Current().Timestamp()
params["key"] = app.AppKey
params["sign"] = app.getSign(app.Secret, params)
body, err := app.request("https://runion.meituan.com/api/orderList", params, "GET")
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,27 @@
package meituan
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1,45 @@
package meituan
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"io"
"sort"
"strconv"
)
func (app *App) getSign(Secret string, params map[string]interface{}) string {
// 参数按照参数名的字典升序排列
var keys []string
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
signStr := bytes.NewBufferString(Secret)
for _, k := range keys {
signStr.WriteString(k)
signStr.WriteString(app.getString(params[k]))
}
signStr.WriteString(Secret)
// md5加密
has := md5.New()
io.Copy(has, signStr)
return hex.EncodeToString(has.Sum(nil))
}
func (app *App) getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
default:
marshal, _ := json.Marshal(v)
return string(marshal)
}
}

@ -0,0 +1,50 @@
package pintoto
import (
"encoding/json"
)
type ApiOrderCreateSoonOrder struct {
ShowId string `json:"showId"` // 排期的showId,由影院接口得来
Seat string `json:"seat"` // 用户所选的座位1排1座,1排2座 以英文的逗号 “ , “隔开。 如果座位是情侣座,请传入 1排1座(情侣座),1排2座(情侣座)
ReservedPhone string `json:"reservedPhone,omitempty"` // 下单时预留的手机号,方便问题沟通
ThirdOrderId string `json:"thirdOrderId"` // 接入方的订单号, 接入方须保证此订单号唯一性
NotifyUrl string `json:"notifyUrl"` // 回调地址各个场景发生时将通过此地址通知接入方详情请看【回调api】
AcceptChangeSeat int `json:"acceptChangeSeat"` // 是否允许调座1-允许0-不允许
SeatId string `json:"seatId,omitempty"` // 座位接口的seatId字段 如果有多个,则以竖线分割
SeatNo string `json:"seatNo,omitempty"` // 座位接口的seatNo字段如果有多个则以竖线分割
NetPrice int `json:"netPrice"` // 所下单所有座位的市场总价单位:分,不可随意乱传,必须是真实价格,如座位有分区定价,也许一一计算后得到总价,否则自动出票失败。由于场次价格延迟问题,有可能造成场次价格和最终价格不一致,此时会出票失败。
TestType int `json:"testType"` // 仅当为调用测试环境时候,此字段有用, 可模拟秒出票结果。 200 模拟出票成功结果 201 模拟正在出票中结果 500模拟出票失败结果
}
type ApiOrderCreateSoonOrderResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
ThirdOrderId string `json:"third_order_id"` // 接入方的订单号
Ticket string `json:"ticket"`
TicketStatus int `json:"ticketStatus"`
OrderId string `json:"order_id"`
} `json:"data"`
Success bool `json:"success"`
}
// ApiOrderCreateSoonOrder 秒出单下单 https://www.showdoc.com.cn/1154868044931571/6437295495912025
func (app *App) ApiOrderCreateSoonOrder(param ApiOrderCreateSoonOrder) (result ApiOrderCreateSoonOrderResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/api/order/create-soon-order", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,40 @@
package pintoto
import "encoding/json"
type ApiOrderCreate struct {
ShowId string `json:"showId"` // 排期的showId,由影院接口得来
Seat string `json:"seat"` // 用户所选的座位1排1座,1排2座 以英文的逗号 “ , “隔开。 如果座位是情侣座,请传入 1排1座(情侣座),1排2座(情侣座)
ReservedPhone string `json:"reservedPhone,omitempty"` // 下单时预留的手机号,方便问题沟通
ThirdOrderId string `json:"thirdOrderId"` // 接入方的订单号, 接入方须保证此订单号唯一性
NotifyUrl string `json:"notifyUrl"` // 回调地址各个场景发生时将通过此地址通知接入方详情请看【回调api】
AcceptChangeSeat int `json:"acceptChangeSeat"` // 是否允许调座1-允许0-不允许
SeatId string `json:"seatId,omitempty"` // 座位接口的seatId字段 如果有多个,则以竖线分割
SeatNo string `json:"seatNo,omitempty"` // 座位接口的seatNo字段如果有多个则以竖线分割
}
type ApiOrderCreateResult struct {
Code int `json:"code"`
Message string `json:"message"`
Success bool `json:"success"`
}
// ApiOrderCreate 下单api https://www.showdoc.com.cn/1154868044931571/5891022916496848
func (app *App) ApiOrderCreate(param ApiOrderCreate) (result ApiOrderCreateResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/api/order/create", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,57 @@
package pintoto
import (
"encoding/json"
)
type ApiOrderQuery struct {
ThirdOrderId string `json:"thirdOrderId"` // 接入方的订单号
}
type ApiOrderQueryResult struct {
Success bool `json:"success"`
Message string `json:"message"`
Data struct {
AppKey string `json:"appKey"` // 下单appKey
ThirdOrderId string `json:"thirdOrderId"` // 接入方的订单号
OrderStatus int `json:"orderStatus"` // 订单状态2-受理中3-待出票4-已出票待结算5-已结算10-订单关闭
OrderStatusStr string `json:"orderStatusStr"` // 订单状态说明
InitPrice int `json:"initPrice"` // 订单市场价:分
OrderPrice int `json:"orderPrice"` // 订单成本价:分,接入方可拿次字段作为下单成本价
Seat string `json:"seat"` // 座位:英文逗号隔开
OrderNum int `json:"orderNum"` // 座位数
ReservedPhone string `json:"reservedPhone"` // 下单预留手机号码
CreateTime string `json:"createTime"` // 下单时间
ReadyTicketTime string `json:"readyTicketTime"` // 待出票时间
TicketTime string `json:"ticketTime"` // 出票时间
NotifyUrl string `json:"notifyUrl"` // 回调通知地址
CloseTime interface{} `json:"closeTime"` // 关闭时间
CloseCause interface{} `json:"closeCause"` // 关闭原因
TicketCode []struct {
Code string `json:"code"`
Type int `json:"type"`
Url string `json:"url"`
} `json:"ticketCode"` // 取票码type为1时为字符串type为2时为取票码原始截图。 理论上一个取票码包含各字符串和原始截图, 原始截图可能不和字符串同步返回,有滞后性。
} `json:"data"`
Code int `json:"code"`
}
// ApiOrderQuery 订单查询 https://www.showdoc.com.cn/1154868044931571/5965244588489845
func (app *App) ApiOrderQuery(param ApiOrderQuery) (result ApiOrderQueryResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/api/order/query", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,29 @@
package pintoto
import (
"encoding/json"
)
type ApiUserInfoResult struct {
Success bool `json:"success"`
Message string `json:"message"`
Data struct {
Nickname string `json:"nickname"` // 用户昵称
Mobile int64 `json:"mobile"` // 注册号码
Balance float64 `json:"balance"` // 账户余额
FreezeAmount float64 `json:"freeze_amount"` // 冻结金额
} `json:"data"`
Code int `json:"code"`
}
// ApiUserInfo 账号信息查询 https://www.showdoc.com.cn/1154868044931571/6269224958928211
func (app *App) ApiUserInfo() (result ApiUserInfoResult, err error) {
body, err := app.request("https://movieapi2.pintoto.cn/api/user/info", map[string]interface{}{})
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,79 @@
package pintoto
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math"
"net/http"
"strconv"
"strings"
"time"
)
// App 电影票服务
type App struct {
AppKey string
AppSecret string
}
type ErrResp struct {
Success bool `json:"success"`
Message string `json:"message"`
Data interface{} `json:"data"`
Code int `json:"code"`
}
func (app *App) request(url string, params map[string]interface{}) ([]byte, error) {
// 公共参数
params["time"] = time.Now().Unix()
params["appKey"] = app.AppKey
// 签名
params["sign"] = app.getSign(app.AppSecret, params)
var req *http.Request
req, err := http.NewRequest("POST", url, strings.NewReader(app.getRequestData(params)))
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
httpClient := &http.Client{}
var response *http.Response
response, err = httpClient.Do(req)
if err != nil {
return nil, nil
}
// 请求错误
if response.StatusCode != 200 {
return nil, errors.New(fmt.Sprintf("请求错误:%d", response.StatusCode))
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
// 检查错误
apiErr := ErrResp{}
if err := json.Unmarshal(body, &apiErr); err != nil {
return nil, err
}
// 接口状态错误
if apiErr.Code != 200 {
return nil, errors.New(apiErr.Message)
}
return body, nil
}
func (app *App) GradeToFloat64(i interface{}) float64 {
switch v := i.(type) {
case string:
float, _ := strconv.ParseFloat(v, 64)
return float
case float64:
return v
case int64:
return float64(v) / math.Pow10(0)
default:
return 0
}
}

@ -0,0 +1,49 @@
package pintoto
import (
"encoding/json"
)
type GetCinemaList struct {
CityId int `json:"cityId"` // 城市id
}
type GetCinemaListResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
List []struct {
CinemaId int `json:"cinemaId"` // 影院id
CityId int `json:"cityId"` // 城市id
CinemaName string `json:"cinemaName"` // 影院名称
Address string `json:"address"` // 影院地址
Latitude float64 `json:"latitude"` // 纬度
Longitude float64 `json:"longitude"` // 经度
Phone string `json:"phone"` // 影院电话
RegionName string `json:"regionName"` // 地区名称
IsAcceptSoonOrder int `json:"isAcceptSoonOrder"` // 是否支持秒出票0为不支持1为支持
NetPrice int `json:"netPrice"` // 当前影院最低价的排期
} `json:"list"`
} `json:"data"`
Success bool `json:"success"`
}
// GetCinemaList 影院列表 https://www.showdoc.com.cn/1154868044931571/5866426126744792
func (app *App) GetCinemaList(param GetCinemaList) (result GetCinemaListResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-cinema-list", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,41 @@
package pintoto
import (
"encoding/json"
)
type GetCityArea struct {
CityId int `json:"cityId"` // 城市id
}
type GetCityAreaResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
List []struct {
AreaId int `json:"areaId"` // 区域id
AreaName string `json:"areaName"` // 区域名
} `json:"list"`
} `json:"data"`
Success bool `json:"success"`
}
// GetCityArea 城市下区域 https://www.showdoc.com.cn/1154868044931571/6243539682553126
func (app *App) GetCityArea(param GetCityArea) (result GetCityAreaResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-city-area", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,30 @@
package pintoto
import (
"encoding/json"
)
type GetCityListResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
List []struct {
PinYin string `json:"pinYin"` // 城市首字母
RegionName string `json:"regionName"` // 城市名
CityId int `json:"cityId"` // 城市id
} `json:"list"`
} `json:"data"`
Success bool `json:"success"`
}
// GetCityList 城市列表 https://www.showdoc.com.cn/1154868044931571/5865562425538244
func (app *App) GetCityList() (result GetCityListResult, err error) {
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-city-list", map[string]interface{}{})
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,54 @@
package pintoto
import (
"encoding/json"
)
type GetHotList struct {
CityId int `json:"cityId,omitempty"` // 传入cityId时会显示当前城市下的相关电影。 如果不传,则默认显示北京的电影
}
type GetHotListResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
HasMore int `json:"hasMore"`
List []struct {
Director string `json:"director"` // 导演
PublishDate string `json:"publishDate"` // 影片上映日期
VersionTypes string `json:"versionTypes"` // 上映类型
Language string `json:"language"` // 语言
ShowStatus int `json:"showStatus"` // 放映状态1 正在热映。2 即将上映
Pic string `json:"pic"` // 海报URL地址
FilmTypes string `json:"filmTypes"` // 影片类型
LikeNum int `json:"likeNum"` // 想看人数
Duration int `json:"duration"` // 时长,分钟
Cast string `json:"cast"` // 主演
FilmId int `json:"filmId"` // 影片id
Grade string `json:"grade"` // 评分
Intro string `json:"intro"` // 简介
Name string `json:"name"` // 影片名
} `json:"list"`
} `json:"data"`
Success bool `json:"success"`
}
// GetHotList 正在热映 https://www.showdoc.com.cn/1154868044931571/5866125707634369
func (app *App) GetHotList(param GetHotList) (result GetHotListResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-hot-list", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,58 @@
package pintoto
import (
"encoding/json"
)
type GetScheduleList struct {
CinemaId int `json:"cinemaId"` // 影院id
}
type GetScheduleListResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
List []struct {
PlanType string `json:"planType"` // 影厅类型 2D 3D
ShowTime string `json:"showTime"` // 放映时间
NetPrice int `json:"netPrice"` // 参考价,单位:分
Language string `json:"language"` // 语言
ShowDate string `json:"showDate"` //
Duration int `json:"duration"` // 时长,分钟
ShowId string `json:"showId"` // 场次标识
StopSellTime string `json:"stopSellTime"` // 停售时间
CinemaId int `json:"cinemaId"` // 影院id
CinemaName string `json:"cinemaName"` //
FilmId int `json:"filmId"` // 影片id
ScheduleArea string `json:"scheduleArea"` // 该排期的分区座位价格信息,当此字段有值的时候,代表座位里面支持分区价格。 如果调用的是秒出票下单, 那价格必须计算正确,才能正确出票成功,即必须处理好座位分区价格
FilmName string `json:"filmName"` // 影片名字
HallName string `json:"hallName"` // 影厅名
ShowVersionType string `json:"showVersionType"` // 场次类型
} `json:"list"`
DiscountRule struct {
UpDiscountRate float64 `json:"upDiscountRate"` // 影院最高成本折扣当价格大于等于39元时候可取此字段
DownDiscountRate float64 `json:"downDiscountRate"` // 影院最高成本折扣当价格小于39元时候可取此字段
} `json:"discountRule"`
} `json:"data"`
Success bool `json:"success"`
}
// GetScheduleList 场次排期 https://www.showdoc.com.cn/1154868044931571/5866708808899217
func (app *App) GetScheduleList(param GetScheduleList) (result GetScheduleListResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-schedule-list", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,51 @@
package pintoto
import (
"encoding/json"
)
type GetSeat struct {
ShowId string `json:"showId"` // 场次标识
}
type GetSeatResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
SeatData struct {
Restrictions int `json:"restrictions"`
Seats []GetSeatSeats `json:"seats"`
} `json:"seatData"`
} `json:"data"`
Success bool `json:"success"`
}
type GetSeatSeats struct {
Area string `json:"area"` // 本座位所在的区域,根据场次排期接口的 scheduleArea 字段, 可得到当前座位的分区价格
ColumnNo string `json:"columnNo"` // 列
Lovestatus int `json:"lovestatus"` // 0为非情侣座1为情侣座左2为情侣座右
RowNo string `json:"rowNo"` // 行
SeatId string `json:"seatId"` // 座位标识符,锁座位和秒出票的时候需要用到
SeatNo string `json:"seatNo"` // 座位名
Status string `json:"status"` // N可售LK不可售
}
// GetSeat 座位 https://www.showdoc.com.cn/1154868044931571/5866824368760475
func (app *App) GetSeat(param GetSeat) (result GetSeatResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-seat", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,39 @@
package pintoto
import (
"encoding/json"
)
type GetShowDate struct {
FilmId int `json:"filmId"` // 影片id由热映/即将上映接口获得
CityId int `json:"cityId"` // 城市id由城市列表接口获得
}
type GetShowDateResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
DateList []string `json:"dateList"`
} `json:"data"`
Success bool `json:"success"`
}
// GetShowDate 包含某电影的日期 https://www.showdoc.com.cn/1154868044931571/6091788579441818
func (app *App) GetShowDate(param GetShowDate) (result GetShowDateResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-show-date", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,56 @@
package pintoto
import (
"encoding/json"
)
type GetShowList struct {
Page int `json:"page,omitempty"` // 页码默认1
Limit int `json:"limit,omitempty"` // 条数,默认 10
FilmId int `json:"filmId"` // 影片id由热映/即将上映接口获得
CityId int `json:"cityId"` // 城市id由城市列表接口获得
Area string `json:"area,omitempty"` // 区域名,由区域列表接口获得
Date string `json:"date,omitempty"` // 日期2020-01-01不传默认当天
Latitude float64 `json:"latitude,omitempty"` // 纬度,不传则无距离排序
Longitude float64 `json:"longitude,omitempty"` // 经度,不传则无距离排序
}
type GetShowListResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
HasMore int `json:"hasMore"`
List []struct {
Address string `json:"address"`
ShowId string `json:"showId"`
Distance string `json:"distance"`
CinemaId int `json:"cinemaId"`
CinemaName string `json:"cinemaName"`
Latitude float64 `json:"latitude"`
ShowTime string `json:"showTime"`
HallName string `json:"hallName"`
Longitude float64 `json:"longitude"`
} `json:"list"`
} `json:"data"`
Success bool `json:"success"`
}
// GetShowList 包含某电影的影院 https://www.showdoc.com.cn/1154868044931571/6067372188376779
func (app *App) GetShowList(param GetShowList) (result GetShowListResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-show-list", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,54 @@
package pintoto
import (
"encoding/json"
)
type GetSoonList struct {
CityId int `json:"cityId,omitempty"` // 传入cityId时会显示当前城市下的相关电影。 如果不传,则默认显示北京的电影
}
type GetSoonListResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
HasMore int `json:"hasMore"`
List []struct {
Director string `json:"director"` // 导演
PublishDate string `json:"publishDate"` // 影片上映日期
VersionTypes string `json:"versionTypes"` // 上映类型
Language string `json:"language"` // 语言
ShowStatus int `json:"showStatus"` // 放映状态1 正在热映。2 即将上映
Pic string `json:"pic"` // 海报URL地址
FilmTypes string `json:"filmTypes"` // 影片类型
LikeNum int `json:"likeNum"` // 想看人数
Duration int `json:"duration"` // 时长,分钟
Cast string `json:"cast"` // 主演
FilmId int `json:"filmId"` // 影片id
Grade interface{} `json:"grade"` // 评分
Intro string `json:"intro"` // 简介
Name string `json:"name"` // 影片名
} `json:"list"`
} `json:"data"`
Success bool `json:"success"`
}
// GetSoonList 即将上映 https://www.showdoc.com.cn/1154868044931571/5866125707634369
func (app *App) GetSoonList(param GetSoonList) (result GetSoonListResult, err error) {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-soon-list", params)
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,24 @@
package pintoto
import (
"encoding/json"
)
type GetVersionResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data string `json:"data"`
Success bool `json:"success"`
}
// GetVersion 获取同步版本号 https://www.showdoc.com.cn/1154868044931571/6566701084841699
func (app *App) GetVersion() (result GetVersionResult, err error) {
body, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-version", map[string]interface{}{})
if err != nil {
return
}
if err = json.Unmarshal(body, &result); err != nil {
return
}
return
}

@ -0,0 +1,52 @@
package pintoto
import (
"crypto/md5"
"encoding/json"
"fmt"
"net/url"
"sort"
"strconv"
)
func (app *App) getSign(appSecret string, p map[string]interface{}) string {
var keys []string
for k := range p {
keys = append(keys, k)
}
sort.Strings(keys)
signStr := ""
for _, key := range keys {
signStr += fmt.Sprintf("%s=%s&", key, app.getString(p[key]))
}
signStr += fmt.Sprintf("appSecret=%s", appSecret)
// md5加密
data := []byte(signStr)
has := md5.Sum(data)
return fmt.Sprintf("%x", has)
}
func (app *App) getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
default:
bytes, _ := json.Marshal(v)
return string(bytes)
}
}
// 获取请求数据
func (app *App) getRequestData(params map[string]interface{}) string {
// 公共参数
args := url.Values{}
// 请求参数
for key, val := range params {
args.Set(key, app.getString(val))
}
return args.Encode()
}

@ -1,3 +0,0 @@
package config
const Api = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send"

@ -1,39 +0,0 @@
package message
type Message struct {
MsgType MsgType_ `json:"msgtype"`
Text Text_ `json:"text"`
Markdown Markdown_ `json:"markdown"`
News News_ `json:"link"`
File File_ `json:"file"`
}
// Text_ text类型
type Text_ struct {
Content string `json:"content"` // 文本内容最长不超过2048个字节必须是utf8编码
MentionedList []string `json:"mentioned_list"` // userid的列表提醒群中的指定成员(@某个成员)@all表示提醒所有人如果开发者获取不到userid可以使用mentioned_mobile_list
MentionedMobileList []string `json:"mentioned_mobile_list"` // 手机号列表,提醒手机号对应的群成员(@某个成员)@all表示提醒所有人
}
// Markdown_ markdown类型
type Markdown_ struct {
Content string `json:"content"` // markdown内容最长不超过4096个字节必须是utf8编码
}
// News_ news类型
type News_ struct {
Articles []articles `json:"articles"` // 图文消息一个图文消息支持1到8条图文
}
// articles
type articles struct {
Title string `json:"title"` // 标题不超过128个字节超过会自动截断
Description string `json:"description"` // 描述不超过512个字节超过会自动截断
Url string `json:"url"` // 点击后跳转的链接。
Picurl string `json:"picurl"` // 图文消息的图片链接支持JPG、PNG格式较好的效果为大图 1068*455小图150*150。
}
// File_ file类型
type File_ struct {
MediaId string `json:"media_id"` // 文件id通过下文的文件上传接口获取
}

@ -1,10 +0,0 @@
package message
type MsgType_ string
const (
TextStr MsgType_ = "text"
NewsStr MsgType_ = "news"
MarkdownStr MsgType_ = "markdown"
fileStr MsgType_ = "file"
)

@ -1,45 +0,0 @@
package qywechat
import (
"encoding/json"
"fmt"
"github.com/dtapps/go-library/service/qywechat/config"
"github.com/dtapps/go-library/service/qywechat/message"
"github.com/dtapps/go-library/utils/gojson"
"io/ioutil"
"net/http"
"strings"
)
type QyBot struct {
Key string
}
type Response struct {
Errcode int64 `json:"errcode"`
Errmsg string `json:"errmsg"`
Type string `json:"type"`
MediaId string `json:"media_id"`
CreatedAt string `json:"created_at"`
}
func (bot *QyBot) Send(msg message.Message) (Response, error) {
var response Response
qyUrl := fmt.Sprintf("%s?key=%s", config.Api, bot.Key)
toString, err := gojson.MarshalToString(msg)
if err != nil {
return response, err
}
resp, e := http.Post(qyUrl, "application/json", strings.NewReader(toString))
if e != nil {
return response, e
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
e = json.Unmarshal(body, &response)
if e != nil {
return response, e
}
return response, nil
}

@ -1,25 +0,0 @@
package qywechat
import (
"fmt"
"github.com/dtapps/go-library/service/qywechat/message"
"testing"
)
func TestName(t *testing.T) {
bot := QyBot{
Key: "",
}
msg := message.Message{
MsgType: message.TextStr,
Text: message.Text_{
Content: "测试",
},
}
send, err := bot.Send(msg)
fmt.Printf("send%v\n", send)
if err != nil {
t.Errorf("err%v\n", err)
return
}
}

@ -0,0 +1,74 @@
package taobao
import (
"encoding/json"
"fmt"
"github.com/dtapps/go-library/utils/gohttp"
"github.com/dtapps/go-library/utils/gostring"
"regexp"
"strconv"
)
// App 公共请求参数
type App struct {
AppKey string // 应用Key
AppSecret string // 密钥
}
type ErrResp struct {
ErrorResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
RequestId string `json:"request_id"`
} `json:"error_response"`
}
func (app *App) request(params map[string]interface{}) (resp []byte, err error) {
// 签名
app.Sign(params)
// 发送请求
httpGet, err := gohttp.Get("https://eco.taobao.com/router/rest", params)
// 检查错误
var errResp ErrResp
_ = json.Unmarshal(httpGet.Body, &errResp)
return httpGet.Body, err
}
func (app *App) ZkFinalPriceParseInt64(ZkFinalPrice string) int64 {
parseInt, err := strconv.ParseInt(ZkFinalPrice, 10, 64)
if err != nil {
re := regexp.MustCompile("[0-9]+")
SalesTipMap := re.FindAllString(ZkFinalPrice, -1)
if len(SalesTipMap) == 2 {
return gostring.ToInt64(fmt.Sprintf("%s%s", SalesTipMap[0], SalesTipMap[1])) * 10
} else {
return gostring.ToInt64(SalesTipMap[0]) * 100
}
} else {
return parseInt * 100
}
}
func (app *App) CommissionRateParseInt64(CommissionRate string) int64 {
parseInt, err := strconv.ParseInt(CommissionRate, 10, 64)
if err != nil {
re := regexp.MustCompile("[0-9]+")
SalesTipMap := re.FindAllString(CommissionRate, -1)
if len(SalesTipMap) == 2 {
return gostring.ToInt64(fmt.Sprintf("%s%s", SalesTipMap[0], SalesTipMap[1]))
} else {
return gostring.ToInt64(SalesTipMap[0])
}
} else {
return parseInt
}
}
func (app *App) CouponAmountToInt64(CouponAmount int64) int64 {
return CouponAmount * 100
}
func (app *App) CommissionIntegralToInt64(GoodsPrice, CouponProportion int64) int64 {
return (GoodsPrice * CouponProportion) / 100
}

@ -0,0 +1,15 @@
package taobao
import (
"crypto/md5"
"encoding/hex"
"strings"
)
// 签名
func createSign(signStr string) string {
h := md5.New()
h.Write([]byte(signStr))
cipherStr := h.Sum(nil)
return strings.ToUpper(hex.EncodeToString(cipherStr))
}

@ -0,0 +1,83 @@
package taobao
import (
"encoding/json"
"net/url"
"sort"
"strconv"
"time"
)
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func NewParamsWithType(_method string, params ...Params) Params {
p := make(Params)
p["method"] = _method
hh, _ := time.ParseDuration("8h")
loc := time.Now().UTC().Add(hh)
p["timestamp"] = strconv.FormatInt(loc.Unix(), 10)
p["format"] = "json"
p["v"] = "2.0"
p["sign_method"] = "md5"
p["partner_id"] = "Nilorg"
for _, v := range params {
p.SetParams(v)
}
return p
}
func (app *App) Sign(p Params) {
p["app_key"] = app.AppKey
// 排序所有的 key
var keys []string
for key := range p {
keys = append(keys, key)
}
sort.Strings(keys)
signStr := app.AppSecret
for _, key := range keys {
signStr += key + getString(p[key])
}
signStr += app.AppSecret
p["sign"] = createSign(signStr)
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}
func (p Params) GetQuery() string {
u := url.Values{}
for k, v := range p {
u.Set(k, getString(v))
}
return u.Encode()
}
func getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
case []byte:
return string(v)
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
default:
bytes, _ := json.Marshal(v)
return string(bytes)
}
}

@ -0,0 +1,26 @@
package taobao
type TbkActivityInfoGetResult struct {
TbkActivityInfoGetResponse struct {
Data struct {
WxQrcodeUrl string `json:"wx_qrcode_url"`
ClickUrl string `json:"click_url"`
ShortClickUrl string `json:"short_click_url"`
TerminalType string `json:"terminal_type"`
MaterialOssUrl string `json:"material_oss_url"`
PageName string `json:"page_name"`
PageStartTime string `json:"page_start_time"`
PageEndTime string `json:"page_end_time"`
WxMiniprogramPath string `json:"wx_miniprogram_path"`
} `json:"data"`
} `json:"tbk_activity_info_get_response"`
}
// TbkActivityInfoGet 淘宝客-推广者-官方活动转链 https://open.taobao.com/api.htm?spm=a219a.7386797.0.0.5a83669a7rURsF&source=search&docId=48340&docType=2
func (app *App) TbkActivityInfoGet(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("taobao.tbk.activity.info.get", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,69 @@
package taobao
type TbkDgMaterialOptionalResult struct {
TbkDgMaterialOptionalResponse struct {
ResultList struct {
MapData []struct {
CategoryId int `json:"category_id"`
CategoryName string `json:"category_name"`
CommissionRate string `json:"commission_rate"`
CommissionType string `json:"commission_type"`
CouponId string `json:"coupon_id"`
CouponInfo string `json:"coupon_info"`
CouponRemainCount int `json:"coupon_remain_count"`
CouponCount int `json:"coupon__count"`
CpaRewardType string `json:"cpa_reward_type"`
IncludeDxjh string `json:"include_dxjh"`
IncludeMkt string `json:"include_mkt"`
InfoDxjh string `json:"info_dxjh"`
ItemDescription string `json:"item_description"`
ItemId int64 `json:"item_id"`
ItemUrl string `json:"item_url"`
LevelOneCategoryId int64 `json:"level_one_category_id"`
LevelOneCategoryName string `json:"level_one_category_name"`
Nick string `json:"nick"`
NumIid int64 `json:"num_iid"`
PictUrl string `json:"pict_url"`
Presale int `json:"presale"`
PresaleDiscountFeeText string `json:"presale_discount_fee_text"`
PresaleEndTime int64 `json:"presale_end_time"`
PresaleStartTime int64 `json:"presale_start_time"`
PresaleTailEndTime int64 `json:"presale_tail_end_time"`
PresaleTailStartTime int64 `json:"presale_tail_start_time"`
Provcity string `json:"provcity"`
RealPostFe int `json:"real_post_fe"`
ReservePrice string `json:"reserve_price"`
SellerId int64 `json:"seller_id"`
ShopDsr int `json:"shop_dsr"`
ShopTitle string `json:"shop_title"`
ShortTitle string `json:"short_title"`
SmallImages struct {
String []string `json:"string"`
} `json:"small_images"`
SuperiorBrand string `json:"superior_brand"`
Title string `json:"title"`
TkTotalCommi string `json:"tk_total_commi"`
TkTotalSales string `json:"tk_total_sales"`
Url string `json:"url"`
UserType int `json:"user_type"`
Volume int64 `json:"volume"`
WhiteImage string `json:"white_image"`
XId string `json:"x_id"`
ZkFinalPrice string `json:"zk_final_price"`
CouponShareUrl string `json:"coupon_share_url"`
CouponAmount string `json:"coupon_amount"`
} `json:"map_data"`
} `json:"result_list"`
TotalResults int `json:"total_results"`
RequestId string `json:"request_id"`
} `json:"tbk_dg_material_optional_response"`
}
// TbkDgMaterialOptional 淘宝客-推广者-物料搜索 https://open.taobao.com/api.htm?docId=35896&docType=2&source=search
func (app *App) TbkDgMaterialOptional(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("taobao.tbk.dg.material.optional", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,53 @@
package taobao
type TbkDgOptimusMaterialResult struct {
TbkDgOptimusMaterialResponse struct {
IsDefault string `json:"is_default"`
ResultList struct {
MapData []struct {
CategoryId int `json:"category_id"`
ClickUrl string `json:"click_url"`
CommissionRate string `json:"commission_rate"`
CouponAmount int64 `json:"coupon_amount"`
CouponClickUrl string `json:"coupon_click_url"`
CouponEndTime string `json:"coupon_end_time"`
CouponRemainCount int `json:"coupon_remain_count"`
CouponShareUrl string `json:"coupon_share_url"`
CouponStartFee string `json:"coupon_start_fee"`
CouponStartTime string `json:"coupon_start_time"`
CouponTotalCount int `json:"coupon_total_count"`
CpaRewardType string `json:"cpa_reward_type"`
ItemDescription string `json:"item_description"`
ItemId int64 `json:"item_id"`
JhsPriceUspList string `json:"jhs_price_usp_list"`
LevelOneCategoryId int64 `json:"level_one_category_id"`
LevelOneCategoryName string `json:"level_one_category_name"`
Nick string `json:"nick"`
PictUrl string `json:"pict_url"`
ReservePrice string `json:"reserve_price"`
SellerId int64 `json:"seller_id"`
ShopTitle string `json:"shop_title"`
ShortTitle string `json:"short_title"`
SmallImages struct {
String []string `json:"string"`
} `json:"small_images"`
SubTitle string `json:"sub_title"`
Title string `json:"title"`
UserType int `json:"user_type"`
Volume int64 `json:"volume"`
WhiteImage string `json:"white_image"`
ZkFinalPrice string `json:"zk_final_price"`
} `json:"map_data"`
} `json:"result_list"`
RequestId string `json:"request_id"`
} `json:"tbk_dg_optimus_material_response"`
}
// TbkDgOptimusMaterial 淘宝客-推广者-物料精选 https://open.taobao.com/api.htm?spm=a219a.7386797.0.0.5d67669aIeQeVI&source=search&docId=33947&docType=2
func (app *App) TbkDgOptimusMaterial(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("taobao.tbk.dg.optimus.material", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,50 @@
package taobao
type TbkItemInfoGetResult struct {
TbkItemInfoGetResponse struct {
Results struct {
NTbkItem []struct {
CatLeafName string `json:"cat_leaf_name"`
CatName string `json:"cat_name"`
FreeShipment bool `json:"free_shipment"`
HotFlag string `json:"hot_flag"`
ItemUrl string `json:"item_url"`
JuOnlineEnd string `json:"ju_online_end"`
JuOnlineStartTime string `json:"ju_online_start_time"`
JuPreShowEndTime string `json:"ju_pre_show_end_time"`
JuPreShowStartTime string `json:"ju_pre_show_start_time"`
MaterialLibType string `json:"material_lib_type"`
Nick string `json:"nick"`
NumIid int64 `json:"num_iid"`
PictUrl string `json:"pict_url"`
PresaleDeposit string `json:"presale_deposit"`
PresaleEndTime int `json:"presale_end_time"`
PresaleStartTime int `json:"presale_start_time"`
PresaleTailEndTime int `json:"presale_tail_end_time"`
PresaleTailStartTime int `json:"presale_tail_start_time"`
Provcity string `json:"provcity"`
ReservePrice string `json:"reserve_price"`
SellerId int64 `json:"seller_id"`
SmallImages struct {
String []string `json:"string"`
} `json:"small_images"`
SuperiorBrand string `json:"superior_brand"`
Title string `json:"title"`
TmallPllPlayActivityStartTime int `json:"tmall_pll_play_activity_start_time"`
UserType int `json:"user_type"`
Volume int64 `json:"volume"`
ZkFinalPrice string `json:"zk_final_price"`
} `json:"n_tbk_item"`
} `json:"results"`
RequestId string `json:"request_id"`
} `json:"tbk_item_info_get_response"`
}
// TbkItemInfoGet 淘宝客-公用-淘宝客商品详情查询(简版) https://open.taobao.com/api.htm?docId=24518&docType=2&source=search
func (app *App) TbkItemInfoGet(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("taobao.tbk.item.info.get", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,23 @@
package taobao
type TbkSpreadGetResult struct {
TbkSpreadGetResponse struct {
Results struct {
TbkSpread []struct {
Content string `json:"content"`
ErrMsg string `json:"err_msg"`
} `json:"tbk_spread"`
} `json:"results"`
TotalResults int `json:"total_results"`
RequestId string `json:"request_id"`
} `json:"tbk_spread_get_response"`
}
// TbkSpreadGet 淘宝客-公用-长链转短链 https://open.taobao.com/api.htm?docId=27832&docType=2&source=search
func (app *App) TbkSpreadGet(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("taobao.tbk.spread.get", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -0,0 +1,20 @@
package taobao
type TbkTPwdCreateResult struct {
TbkTpwdCreateResponse struct {
Data struct {
Model string `json:"model"`
PasswordSimple string `json:"password_simple"`
} `json:"data"`
RequestId string `json:"request_id"`
} `json:"tbk_tpwd_create_response"`
}
// TbkTPwdCreate 淘宝客-公用-淘口令生成 https://open.taobao.com/api.htm?docId=31127&docType=2&source=search
func (app *App) TbkTPwdCreate(notMustParams ...Params) (body []byte, err error) {
// 参数
params := NewParamsWithType("taobao.tbk.tpwd.create", notMustParams...)
// 请求
body, err = app.request(params)
return
}

@ -1,190 +0,0 @@
package tbk
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/bitly/go-simplejson"
"github.com/dtapps/go-library/service"
"github.com/nilorg/sdk/convert"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
var (
// AppKey 应用Key
AppKey string
// AppSecret 秘密
AppSecret string
// Router 环境请求地址
Router = "https://eco.taobao.com/router/rest"
// Session 用户登录授权成功后TOP颁发给应用的授权信息。当此API的标签上注明“需要授权”则此参数必传“不需要授权”则此参数不需要传“可选授权”则此参数为可选
Session string
// Timeout ...
Timeout time.Duration
)
// Parameter 参数
type Parameter map[string]interface{}
// copyParameter 复制参数
func copyParameter(srcParams Parameter) Parameter {
newParams := make(Parameter)
for key, value := range srcParams {
newParams[key] = value
}
return newParams
}
// execute 执行API接口
func execute(param Parameter) (bytes []byte, err error) {
err = checkConfig()
if err != nil {
return
}
var req *http.Request
req, err = http.NewRequest("POST", Router, strings.NewReader(param.getRequestData()))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
httpClient := &http.Client{}
httpClient.Timeout = Timeout
var response *http.Response
response, err = httpClient.Do(req)
if err != nil {
return
}
if response.StatusCode != 200 {
err = fmt.Errorf("请求错误:%d", response.StatusCode)
return
}
defer response.Body.Close()
bytes, err = ioutil.ReadAll(response.Body)
return
}
// Execute 执行API接口
func Execute(method string, param Parameter) (res *simplejson.Json, err error) {
param["method"] = method
param.setRequestData()
var bodyBytes []byte
bodyBytes, err = execute(param)
if err != nil {
return
}
return bytesToResult(bodyBytes)
}
func bytesToResult(bytes []byte) (res *simplejson.Json, err error) {
res, err = simplejson.NewJson(bytes)
if err != nil {
return
}
if responseError, ok := res.CheckGet("error_response"); ok {
if subMsg, subOk := responseError.CheckGet("sub_msg"); subOk {
err = errors.New(subMsg.MustString())
} else {
err = errors.New(responseError.Get("msg").MustString())
}
res = nil
}
return
}
// 检查配置
func checkConfig() error {
if AppKey == "" {
return errors.New("AppKey 不能为空")
}
if AppSecret == "" {
return errors.New("AppSecret 不能为空")
}
if Router == "" {
return errors.New("Router 不能为空")
}
return nil
}
func (p Parameter) setRequestData() {
hh, _ := time.ParseDuration("8h")
loc := time.Now().UTC().Add(hh)
p["timestamp"] = strconv.FormatInt(loc.Unix(), 10)
p["format"] = "json"
p["app_key"] = AppKey
p["v"] = "2.0"
p["sign_method"] = "md5"
p["partner_id"] = "Nilorg"
if Session != "" {
p["session"] = Session
}
// 设置签名
p["sign"] = getSign(p)
}
// 获取请求数据
func (p Parameter) getRequestData() string {
// 公共参数
args := url.Values{}
// 请求参数
for key, val := range p {
args.Set(key, interfaceToString(val))
}
return args.Encode()
}
// 获取签名
func getSign(params Parameter) string {
// 获取Key
keys := []string{}
for k := range params {
keys = append(keys, k)
}
// 排序asc
sort.Strings(keys)
// 把所有参数名和参数值串在一起
query := bytes.NewBufferString(AppSecret)
for _, k := range keys {
query.WriteString(k)
query.WriteString(interfaceToString(params[k]))
}
query.WriteString(AppSecret)
// 使用MD5加密
h := md5.New()
io.Copy(h, query)
// 把二进制转化为大写的十六进制
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
func interfaceToString(src interface{}) string {
if src == nil {
panic(service.ErrTypeIsNil)
}
switch src.(type) {
case string:
return src.(string)
case int, int8, int32, int64:
case uint8, uint16, uint32, uint64:
case float32, float64:
return convert.ToString(src)
}
data, err := json.Marshal(src)
if err != nil {
panic(err)
}
return string(data)
}

@ -0,0 +1,21 @@
package tianyancha
import (
"encoding/json"
"github.com/dtapps/go-library/utils/gohttp"
"net/http"
)
type App struct{}
func (app *App) request(url string, params map[string]interface{}, method string) (resp []byte, err error) {
// 请求
if method == http.MethodGet {
get, err := gohttp.Get(url, params)
return get.Body, err
} else {
paramsStr, err := json.Marshal(params)
postJson, err := gohttp.PostJson(url, paramsStr)
return postJson.Body, err
}
}

@ -0,0 +1,21 @@
package tianyancha
import (
"net/http"
)
type EquityHumanIndexNodeResult struct {
IsLogin int `json:"isLogin"`
Message string `json:"message"`
Special string `json:"special"`
State string `json:"state"`
VipMessage string `json:"vipMessage"`
}
func (app *App) EquityHumanIndexNode(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://capi.tianyancha.com/cloud-equity-provider/v4/equity/humanIndexnode.json", params, http.MethodGet)
return body, err
}

@ -0,0 +1,27 @@
package tianyancha
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1,50 @@
package tianyancha
import (
"fmt"
"net/http"
)
type SearchHumanSuggestResult struct {
Data struct {
Id int `json:"id"`
HumanName interface{} `json:"humanName"`
DistinctNum int `json:"distinctNum"`
ViewNum int `json:"viewNum"`
ResultCount int `json:"resultCount"`
ResultList []struct {
Name string `json:"name"`
Hid int64 `json:"hid"`
HeadUrl interface{} `json:"headUrl"`
Introduction interface{} `json:"introduction"`
Event interface{} `json:"event"`
BossCertificate int `json:"bossCertificate"`
CompanyNum int `json:"companyNum"`
Office []interface{} `json:"office"`
Companys interface{} `json:"companys"`
PartnerNum int `json:"partnerNum"`
CoopCount int `json:"coopCount"`
Partners interface{} `json:"partners"`
Cid int64 `json:"cid"`
TypeJoin interface{} `json:"typeJoin"`
Alias interface{} `json:"alias"`
ServiceType int `json:"serviceType"`
ServiceCount int `json:"serviceCount"`
OfficeV1 []interface{} `json:"officeV1"`
Pid interface{} `json:"pid"`
Role interface{} `json:"role"`
} `json:"resultList"`
TotalPage int `json:"totalPage"`
CurrentPage int `json:"currentPage"`
RealName interface{} `json:"realName"`
AdviceQuery interface{} `json:"adviceQuery"`
} `json:"data"`
VipMessage string `json:"vipMessage"`
Special string `json:"special"`
State string `json:"state"`
}
func (app *App) SearchHumanSuggest(key string) (body []byte, err error) {
body, err = app.request(fmt.Sprintf("https://www.tianyancha.com/search/humanSuggest.json?key=%s", key), map[string]interface{}{}, http.MethodGet)
return body, err
}

@ -0,0 +1,18 @@
package wechatqy
import (
"encoding/json"
"github.com/dtapps/go-library/utils/gohttp"
)
type App struct {
Key string
}
func (app *App) request(url string, params map[string]interface{}) (body []byte, err error) {
// 请求参数
paramsStr, err := json.Marshal(params)
// 请求
postJson, err := gohttp.PostJson(url, paramsStr)
return postJson.Body, err
}

@ -0,0 +1,27 @@
package wechatqy
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1,40 @@
package wechatqy
import (
"encoding/json"
"fmt"
)
// WebhookSendText 文本类型
type WebhookSendText struct {
Msgtype string `json:"msgtype"` // 消息类型此时固定为text
Text struct {
Content string `json:"content"` // 文本内容最长不超过2048个字节必须是utf8编码
MentionedList []string `json:"mentioned_list"` // userid的列表提醒群中的指定成员(@某个成员)@all表示提醒所有人如果开发者获取不到userid可以使用mentioned_mobile_list
MentionedMobileList []string `json:"mentioned_mobile_list"` // 手机号列表,提醒手机号对应的群成员(@某个成员)@all表示提醒所有人
} `json:"text"`
}
type WebhookSendResult struct {
Errcode int64 `json:"errcode"`
Errmsg string `json:"errmsg"`
Type string `json:"type"`
MediaId string `json:"media_id"`
CreatedAt string `json:"created_at"`
}
// WebhookSend https://work.weixin.qq.com/api/doc/90000/90136/91770
func (app *App) WebhookSend(notMustParams ...Params) (result WebhookSendResult, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
request, err := app.request(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=%s&type=%s", app.Key, "text"), params)
if err != nil {
return WebhookSendResult{}, err
}
err = json.Unmarshal(request, &result)
if err != nil {
return WebhookSendResult{}, err
}
return result, err
}

@ -0,0 +1,25 @@
package wechatunion
import (
"encoding/json"
"github.com/dtapps/go-library/utils/gohttp"
"net/http"
)
type App struct {
AppId string // 小程序唯一凭证,即 AppID
AppSecret string // 小程序唯一凭证密钥,即 AppSecret
AccessToken string // 接口调用凭证
}
func (app *App) request(url string, params map[string]interface{}, method string) (resp []byte, err error) {
if method == http.MethodGet {
get, err := gohttp.Get(url, params)
return get.Body, err
} else {
// 请求参数
paramsStr, err := json.Marshal(params)
postJson, err := gohttp.PostJson(url, paramsStr)
return postJson.Body, err
}
}

@ -0,0 +1,136 @@
package wechatunion
import (
"encoding/json"
"errors"
"fmt"
"net/http"
)
type OrderInfoResult struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
OrderList []struct {
OrderId string `json:"orderId"` // 订单ID
PayTime int `json:"payTime"` // 支付时间戳单位为s
ConfirmReceiptTime int `json:"confirmReceiptTime"` // 确认收货时间戳单位为s没有时为0
ShopName string `json:"shopName"` // 店铺名称
ShopAppid string `json:"shopAppid"` // 店铺 Appid
ProductList []struct {
ProductId string `json:"productId"` // 商品SPU ID
SkuId string `json:"skuId"` // sku ID
Title string `json:"title"` // 商品名称
ThumbImg string `json:"thumbImg"` // 商品缩略图 url
Price string `json:"price"` // 商品成交总价,前带单位 ¥
ProductCnt int `json:"productCnt"` // 成交数量
Ratio int `json:"ratio"` // 分佣比例,单位为万分之一
CommissionStatus string `json:"commissionStatus"` // 分佣状态
CommissionStatusUpdateTime string `json:"commissionStatusUpdateTime"` // 分佣状态更新时间戳单位为s
ProfitShardingSucTime string `json:"profitShardingSucTime"` // 结算时间当分佣状态为已结算才有值单位为s
Commission string `json:"commission"` // 分佣金额,前带单位 ¥
EstimatedCommission int `json:"estimatedCommission"` // 预估分佣金额,单位为分
CategoryStr string `json:"categoryStr"` // 类目名称,多个用英文逗号分隔
PromotionInfo struct {
PromotionSourcePid string `json:"promotionSourcePid"` // 推广位 id
PromotionSourceName string `json:"promotionSourceName"` // 推广位名称
} `json:"promotionInfo"` // 推广信息
CustomizeInfo string `json:"customizeInfo"` // 自定义信息
} `json:"productList"` // 商品列表
} `json:"orderList"` // 订单列表
}
// OrderInfo 根据订单ID查询订单详情 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/order/order-info.html
func (app *App) OrderInfo(orderIdList []string) (result OrderInfoResult, err error) {
if len(app.AccessToken) <= 0 {
return result, errors.New("调用凭证异常")
}
if len(orderIdList) <= 0 || len(orderIdList) > 200 {
return result, errors.New("未传入 orderIdList 或 orderIdList 超过上限 200")
}
body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/order/info?access_token=%s", app.AccessToken), map[string]interface{}{
"orderIdList": orderIdList,
}, http.MethodPost)
if err != nil {
return result, err
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, err
}
return result, err
}
type OrderSearch struct {
Page int `json:"page,omitempty"` // 页码,起始为 1
PageSize int `json:"pageSize,omitempty"` // 分页大小,最大 200
StartTimestamp string `json:"startTimestamp,omitempty"` // 起始时间戳,单位为秒
EndTimestamp string `json:"endTimestamp,omitempty"` // 结束时间戳,单位为秒
CommissionStatus string `json:"commissionStatus,omitempty"` // 分佣状态
SortByCommissionUpdateTime string `json:"sortByCommissionUpdateTime,omitempty"` // 是否按照分佣状态更新时间排序和筛选订单10
StartCommissionUpdateTime string `json:"startCommissionUpdateTime,omitempty"` // 分佣状态更新时间起始时间戳,单位为秒
EndCommissionUpdateTime string `json:"endCommissionUpdateTime,omitempty"` // 分佣状态更新时间结束时间戳,单位为秒
}
type OrderSearchResult struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
OrderList []struct {
OrderId string `json:"orderId"` // 订单ID
PayTime int `json:"payTime"` // 支付时间戳单位为s
ConfirmReceiptTime int `json:"confirmReceiptTime"` // 确认收货时间戳单位为s没有时为0
ShopName string `json:"shopName"` // 店铺名称
ShopAppid string `json:"shopAppid"` // 店铺 Appid
ProductList []struct {
ProductId string `json:"productId"` // 商品SPU ID
SkuId string `json:"skuId"` // sku ID
Title string `json:"title"` // 商品名称
ThumbImg string `json:"thumbImg"` // 商品缩略图 url
Price string `json:"price"` // 商品成交总价,前带单位 ¥
ProductCnt int `json:"productCnt"` // 成交数量
Ratio int `json:"ratio"` // 分佣比例,单位为万分之一
CommissionStatus string `json:"commissionStatus"` // 分佣状态
CommissionStatusUpdateTime string `json:"commissionStatusUpdateTime"` // 分佣状态更新时间戳单位为s
ProfitShardingSucTime string `json:"profitShardingSucTime"` // 结算时间当分佣状态为已结算才有值单位为s
Commission string `json:"commission"` // 分佣金额,前带单位 ¥
EstimatedCommission int `json:"estimatedCommission"` // 预估分佣金额,单位为分
CategoryStr string `json:"categoryStr"` // 类目名称,多个用英文逗号分隔
PromotionInfo struct {
PromotionSourcePid string `json:"promotionSourcePid"` // 推广位 id
PromotionSourceName string `json:"promotionSourceName"` // 推广位名称
} `json:"promotionInfo"` // 推广信息
CustomizeInfo string `json:"customizeInfo"` // 自定义信息
} `json:"productList"` // 商品列表
} `json:"orderList"` // 订单列表
PageSize int `json:"pageSize"` // 分页大小
TotalNum int `json:"totalNum"` // 订单总数
}
// OrderSearch 根据订单支付时间、订单分佣状态拉取订单详情 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/order/order-info.html
func (app *App) OrderSearch(notMustParams ...Params) (result OrderSearchResult, err error) {
if len(app.AccessToken) <= 0 {
return result, errors.New("调用凭证异常")
}
// 参数
//params := app.NewParamsWith(notMustParams...)
//if len(orderIdList) <= 0 || len(orderIdList) > 200 {
// return result, errors.New("未传入 orderIdList 或 orderIdList 超过上限 200")
//}
//body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/order/info?access_token=%s", app.AccessToken), map[string]interface{}{
// "orderIdList": orderIdList,
//}, http.MethodPost)
//if err != nil {
// return result, err
//}
//err = json.Unmarshal(body, &result)
//if err != nil {
// return result, err
//}
//return result, err
return
}

@ -0,0 +1,27 @@
package wechatunion
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1 @@
package wechatunion

@ -0,0 +1,25 @@
package wechatunion
import (
"fmt"
"net/http"
)
type PromoterProductCategoryResult struct {
Errcode int `json:"errcode"` // 错误码
Errmsg string `json:"errmsg"` // 错误信息
ProductCats []struct {
CatId string `json:"catId"` // 类目ID
Name string `json:"name"` // 类目名称
} `json:"productCats"` // 类目数据
}
// PromoterProductCategory
// 获取联盟商品类目列表及类目ID
// 通过该接口获取联盟商品的一级类目列表以及类目ID可用于筛选联盟商品
// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html
func (app *App) PromoterProductCategory() (body []byte, err error) {
// 请求
body, err = app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/product/category?access_token=%s", app.AccessToken), map[string]interface{}{}, http.MethodGet)
return body, err
}

@ -0,0 +1,50 @@
package wechatunion
import (
"fmt"
"net/http"
)
type PromoterProductGenerateResult struct {
Errcode int `json:"errcode"` // 错误码
Errmsg string `json:"errmsg"` // 错误信息
List []struct {
ProductId string `json:"productId"` // 商品SPU ID
Pid string `json:"pid"` // 推广位PID
ProductInfo struct {
ProductId string `json:"productId"` // 商品SPU ID
Title string `json:"title"` // 商品标题
SubTitle string `json:"subTitle"` // 商品子标题
HeadImg []string `json:"headImg"` // 商品主图
MinPrice int `json:"minPrice"` // 商品最低价格,单位分
Discount int `json:"discount"` // 商品优惠金额,单位分
DiscountPrice int `json:"discountPrice"` // 商品券后最低价格,单位分
ShopName string `json:"shopName"` // 商店名称
PluginResult int `json:"pluginResult"` // 是否引用小商店组件未引用组件的商品不可推广01
TotalStockNum int `json:"totalStockNum"` // 商品库存
} `json:"productInfo"` // 商品相关信息
ShareInfo struct {
AppId string `json:"appId"` // 推广商品的小程序AppID
Path string `json:"path"` // 推广商品的小程序Path
CouponPath string `json:"couponPath"` // 推广商品的带券小程序Path
WxaCode string `json:"wxaCode"` // 已废弃。推广商品详情页的不带券葵花码图片
CouponWxaCode string `json:"couponWxaCode"` // 已废弃。推广商品详情页的带券葵花码图片
PromotionUrl string `json:"promotionUrl"` // 推广商品短链
CouponPromotionUrl string `json:"couponPromotionUrl"` // 推广商品带券短链
PromotionWording string `json:"promotionWording"` // 推广商品文案
CouponPromotionWording string `json:"couponPromotionWording"` // 推广商品带券文案
} `json:"shareInfo"` // 推广相关信息
} `json:"list"`
}
// PromoterProductGenerate
// 获取商品推广素材
// 通过该接口获取商品的推广素材包括店铺appID、商品详情页Path、推广文案及推广短链、商品图片等
// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html
func (app *App) PromoterProductGenerate(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/product/generate?access_token=%s", app.AccessToken), params, http.MethodPost)
return body, err
}

@ -0,0 +1,136 @@
package wechatunion
import (
"fmt"
"net/http"
)
type PromoterProductListResult struct {
Errcode int `json:"errcode"` // 错误码
Errmsg string `json:"errmsg"` // 错误信息
Msg string `json:"msg"` // 错误信息
Total int `json:"total"` // 商品总数
ProductList []struct {
ProductId string `json:"productId"` // 商品SPU ID
Product struct {
ProductId string `json:"productId"` // 商品SPU ID
Info struct {
Title string `json:"title"` // 商品标题
SubTitle string `json:"subTitle"` // 商品子标题
HeadImg []string `json:"headImg"` // 商品主图
Category []struct {
CatId string `json:"catId"` // 类目ID
Name string `json:"name"` // 类目名称
} `json:"category"` // 商品类目
Brand string `json:"brand,omitempty"` // 品牌名称
BrandId string `json:"brandId"` // 品牌ID
Model string `json:"model,omitempty"` // 型号
Detail struct {
DetailImg []string `json:"detailImg"` // 商品详情图片
} `json:"detail"` // 商品详细数据
Param []interface{} `json:"param"` // 商品参数
MinPrice int `json:"minPrice"` // 商品最低价格,单位分
TotalStockNum int `json:"totalStockNum"` // 总库存
TotalOrderNum int `json:"totalOrderNum"` // 累计订单量
DiscountPrice int `json:"discountPrice"` // 商品券后价
} `json:"info"` // 商品具体信息
Skus []struct {
SkuId string `json:"skuId"` // 商品SKU ID
ProductSkuInfo struct {
ThumbImg string `json:"thumbImg"` // 商品SKU 小图
SalePrice int `json:"salePrice"` // 商品SKU 销售价格,单位分
MarketPrice int `json:"marketPrice"` // 商品SKU 市场价格,单位分
StockInfo struct {
StockNum int `json:"stockNum"` // 商品SKU 库存
} `json:"stockInfo"`
} `json:"productSkuInfo"`
} `json:"skus"` // 商品SKU
} `json:"product"` // 商品数据
LeagueExInfo struct {
HasCommission int `json:"hasCommission"` // 是否有佣金1/0
CommissionRatio int `json:"commissionRatio"` // 佣金比例,万分之一
CommissionValue int `json:"commissionValue"` // 佣金金额,单位分
} `json:"leagueExInfo"` // 联盟佣金相关数据
ShopInfo struct {
Name string `json:"name"` // 小商店名称
AppId string `json:"appId"` // 小商店AppID
Username string `json:"username"` // 小商店原始id
HeadImgUrl string `json:"headImgUrl"` // 小商店店铺头像
ShippingMethods struct {
Express int `json:"express"` // 是否支持快递10
SameCity int `json:"sameCity"` // 是否支持同城配送10
Pickup int `json:"pickup"` // 是否支持上门自提10
} `json:"shippingMethods"` // 配送方式
AddressList []struct {
AddressInfo struct {
ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址
CityName string `json:"cityName"` // 国标收货地址第二级地址
CountyName string `json:"countyName"` // 国标收货地址第三级地址
} `json:"addressInfo"` // 地址信息
AddressType struct {
Express int `json:"express"` // 是否支持快递10
SameCity int `json:"sameCity"` // 是否支持同城配送10
Pickup int `json:"pickup"` // 是否支持上门自提10
} `json:"addressType"` // 地址类型
} `json:"addressList"` // 发货地,只有当配送方式包含「同城配送、上门自提」才出该项
SameCityTemplate struct {
DeliverScopeType int `json:"deliverScopeType"` // 配送范围的定义方式0按照距离定义配送范围1按照区域定义配送范围
Scope string `json:"scope"` // 配送范围
Region struct {
ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址
CityName string `json:"cityName"` // 国标收货地址第二级地址
CountyName string `json:"countyName"` // 国标收货地址第三级地址
} `json:"region"` // 全城配送时的配送范围
} `json:"sameCityTemplate"` // 配送范围,只有当配送方式包含「同城配送」才出该项
FreightTemplate struct {
NotSendArea struct {
AddressInfoList []struct {
ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址
CityName string `json:"cityName"` // 国标收货地址第二级地址
CountyName string `json:"countyName"` // 国标收货地址第三级地址
} `json:"addressInfoList"` // 不发货地区地址列表
} `json:"notSendArea,omitempty"` // 不发货地区
} `json:"freightTemplate"` // 运费模板,只有当配送方式包含「快递」才出此项
} `json:"shopInfo"` // 商品所属小商店数据
CouponInfo struct {
HasCoupon int `json:"hasCoupon"` // 是否有联盟券1为含券商品0为全部商品
CouponId string `json:"couponId"` // 券id
CouponDetail struct {
RestNum int `json:"restNum"` // 券库存
Type int `json:"type"` // 券类型
DiscountInfo struct {
DiscountCondition struct {
ProductIds []string `json:"productIds"` // 指定商品 id
ProductCnt string `json:"productCnt"` // 商品数
ProductPrice string `json:"productPrice"` // 商品金额
} `json:"discountCondition"` // 指定商品 id
DiscountNum int `json:"discountNum,omitempty"` // 折扣数,如 5.1 折 为 5.1 * 1000
DiscountFee int64 `json:"discountFee,omitempty"` // 直减金额,单位为分
} `json:"discountInfo"` // 券面额
ValidInfo struct {
ValidType int `json:"validType"` // 有效期类型1 为商品指定时间区间2 为生效天数
ValidDayNum int `json:"validDayNum"` // 生效天数
StartTime string `json:"startTime"` // 有效开始时间
EndTime string `json:"endTime"` // 有效结束时间
} `json:"validInfo"` // 有效期
ReceiveInfo struct {
StartTime string `json:"startTime"` // 有效结束时间
EndTime string `json:"endTime"` // 领取结束时间戳
LimitNumOnePerson int `json:"limitNumOnePerson"` // 每人限领张数
} `json:"receiveInfo"` // 领券时间
} `json:"couponDetail"` // 券详情
} `json:"couponInfo"` // 联盟优惠券数据
} `json:"productList"` // 商品列表数据
}
// PromoterProductList
// 查询全量商品
// 支持开发者根据多种筛选条件获取可供推广的商品列表及详情筛选条件包括商品关键词名称、店铺、spuID、商品累计销量、商品价格、商品佣金、佣金比例、是否含有联盟券、配送方式、发货地区等
// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html
func (app *App) PromoterProductList(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/product/list?access_token=%s", app.AccessToken), params, http.MethodGet)
return body, err
}

@ -0,0 +1,136 @@
package wechatunion
import (
"fmt"
"net/http"
)
type PromoterProductSelectResult struct {
Errcode int `json:"errcode"` // 错误码
Errmsg string `json:"errmsg"` // 错误信息
Total int `json:"total"` // 商品总数
ProductList []struct {
ProductId string `json:"productId"` // 商品SPU ID
Product struct {
ProductId string `json:"productId"` // 商品SPU ID
Info struct {
Title string `json:"title"` // 商品标题
SubTitle string `json:"subTitle"` // 商品子标题
HeadImg []string `json:"headImg"` // 商品主图
Category []struct {
CatId string `json:"catId"` // 类目ID
Name string `json:"name"` // 类目ID
} `json:"category"` // 商品类目
Brand string `json:"brand"` // 品牌名称
BrandId string `json:"brandId"` // 品牌ID
Model string `json:"model"` // 型号
Detail struct {
DetailImg []string `json:"detailImg"` // 商品详情图片
} `json:"detail"` // 商品详细数据
Param []interface{} `json:"param"` // 商品参数
MinPrice int64 `json:"minPrice"` // 商品最低价格,单位分
TotalStockNum int64 `json:"totalStockNum"` // 总库存
TotalSoldNum int `json:"totalSoldNum"` // 累计销量
TotalOrderNum int `json:"totalOrderNum"` // 累计订单量
DiscountPrice int64 `json:"discountPrice"` // 商品券后价
} `json:"info"` // 商品具体信息
Skus []struct {
SkuId string `json:"skuId"` // 商品SKU ID
ProductSkuInfo struct {
ThumbImg string `json:"thumbImg"` // 商品SKU 小图
SalePrice int `json:"salePrice"` // 商品SKU 销售价格,单位分
MarketPrice int `json:"marketPrice,omitempty"` // 商品SKU 市场价格,单位分
StockInfo struct {
StockNum int `json:"stockNum"` // 商品SKU 库存
} `json:"stockInfo"`
} `json:"productSkuInfo"`
} `json:"skus"` // 商品SKU
} `json:"product"` // 商品数据
LeagueExInfo struct {
HasCommission int `json:"hasCommission"` // 是否有佣金1/0
CommissionRatio int64 `json:"commissionRatio"` // 佣金比例,万分之一
CommissionValue int64 `json:"commissionValue"` // 佣金金额,单位分
} `json:"leagueExInfo"` // 联盟佣金相关数据
ShopInfo struct {
Name string `json:"name"` // 小商店名称
AppId string `json:"appId"` // 小商店AppID
Username string `json:"username"` // 小商店原始id
HeadImgUrl string `json:"headImgUrl"` // 小商店店铺头像
AddressList []struct {
AddressInfo struct {
ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址
CityName string `json:"cityName"` // 国标收货地址第二级地址
CountyName string `json:"countyName"` // 国标收货地址第三级地址
} `json:"addressInfo"` // 地址信息
AddressType struct {
Express int `json:"express"` // 是否支持快递10
SameCity int `json:"sameCity"` // 是否支持同城配送10
Pickup int `json:"pickup"` // 是否支持上门自提10
} `json:"addressType"` // 地址类型
} `json:"addressList"` // 发货地,只有当配送方式包含「同城配送、上门自提」才出该项
ShippingMethods struct {
Express int `json:"express"` // 是否支持快递10
SameCity int `json:"sameCity"` // 是否支持同城配送10
Pickup int `json:"pickup"` // 是否支持上门自提10
} `json:"shippingMethods"` // 配送方式
SameCityTemplate struct {
DeliverScopeType int `json:"deliverScopeType"` // 配送范围的定义方式0按照距离定义配送范围1按照区域定义配送范围
Scope string `json:"scope"` // 配送范围
Region struct {
ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址
CityName string `json:"cityName"` // 国标收货地址第二级地址
CountyName string `json:"countyName"` // 国标收货地址第三级地址
} `json:"region"` // 全城配送时的配送范围
} `json:"sameCityTemplate"` // 配送范围,只有当配送方式包含「同城配送」才出该项
FreightTemplate struct {
NotSendArea struct {
AddressInfoList []struct {
ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址
CityName string `json:"cityName"` // 国标收货地址第二级地址
CountyName string `json:"countyName"` // 国标收货地址第三级地址
} `json:"addressInfoList"` // 不发货地区地址列表
} `json:"notSendArea,omitempty"` // 不发货地区
} `json:"freightTemplate"` // 运费模板,只有当配送方式包含「快递」才出此项
} `json:"shopInfo"` // 商品所属小商店数据
CouponInfo struct {
HasCoupon int `json:"hasCoupon"` // 是否有联盟券1为含券商品0为全部商品
CouponId string `json:"couponId"` // 券id
CouponDetail struct {
RestNum int `json:"restNum"` // 券库存
Type int `json:"type"` // 券类型
DiscountInfo struct {
DiscountCondition struct {
ProductIds []string `json:"productIds"` // 指定商品 id
ProductCnt string `json:"productCnt"` // 商品数
ProductPrice string `json:"productPrice"` // 商品金额
} `json:"discountCondition"` // 指定商品 id
DiscountNum int `json:"discountNum,omitempty"` // 折扣数,如 5.1 折 为 5.1 * 1000
DiscountFee int64 `json:"discountFee,omitempty"` // 直减金额,单位为分
} `json:"discountInfo"` // 券面额
ValidInfo struct {
ValidType int `json:"validType"` // 有效期类型1 为商品指定时间区间2 为生效天数
ValidDayNum int `json:"validDayNum"` // 生效天数
StartTime string `json:"startTime"` // 有效开始时间
EndTime string `json:"endTime"` // 有效结束时间
} `json:"validInfo"` // 有效期
ReceiveInfo struct {
StartTime string `json:"startTime"` // 有效结束时间
EndTime string `json:"endTime"` // 领取结束时间戳
LimitNumOnePerson int `json:"limitNumOnePerson"` // 每人限领张数
} `json:"receiveInfo"` // 领券时间
} `json:"couponDetail"` // 券详情
} `json:"couponInfo"` // 联盟优惠券数据
} `json:"productList"` // 商品列表数据
}
// PromoterProductSelect
// 查询联盟精选商品
// 支持开发者根据多种筛选条件获取联盟精选的商品列表及详情,筛选条件包括商品价格、商品佣金、商品累计销量、佣金比例、是否含有联盟券、配送方式、发货地区
// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html#3.%E6%9F%A5%E8%AF%A2%E8%81%94%E7%9B%9F%E7%B2%BE%E9%80%89%E5%95%86%E5%93%81
func (app *App) PromoterProductSelect(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/product/select?access_token=%s", app.AccessToken), params, http.MethodGet)
return body, err
}

@ -0,0 +1,164 @@
package wechatunion
import (
"encoding/json"
"errors"
"fmt"
"net/http"
)
type PromotionAddResult struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
Pid string `json:"pid"` // 推广位IDPID
}
// PromotionAdd 添加推广位 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html
func (app *App) PromotionAdd(promotionSourceName string) (result PromotionAddResult, err error) {
if len(app.AccessToken) <= 0 {
return result, errors.New("调用凭证异常")
}
if len(promotionSourceName) > 20 {
return result, errors.New(fmt.Sprintf("推广位名称最长20个字名称不可重复%d", len(promotionSourceName)))
}
// request
body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/promotion/add?access_token%s", app.AccessToken), map[string]interface{}{
"promotionSourceName": promotionSourceName,
}, http.MethodPost)
if err != nil {
return result, err
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, err
}
if result.Errcode == 14005 {
return result, errors.New(fmt.Sprintf("推广位数量达到上限:%s", err))
}
if result.Errcode == 14007 {
return result, errors.New(fmt.Sprintf("推广位名称重复:%s", err))
}
return result, err
}
type PromotionDel struct {
PromotionSourcePid string `json:"promotionSourcePid"` // 推广位PID
PromotionSourceName string `json:"promotionSourceName"` // 推广位名称
}
type PromotionDelResult struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
// PromotionDel 删除某个推广位 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html
func (app *App) PromotionDel(param PromotionDel) (result PromotionDelResult, err error) {
if len(app.AccessToken) <= 0 {
return result, errors.New("调用凭证异常")
}
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
// request
body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/promotion/del?access_token%s", app.AccessToken), params, http.MethodPost)
if err != nil {
return result, err
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, err
}
return result, err
}
type PromotionUpd struct {
PreviousPromotionInfo struct {
PromotionSourcePid string `json:"promotionSourcePid"` // 要修改的推广位PID
PromotionSourceName string `json:"promotionSourceName"` // 修改前名称
} `json:"previousPromotionInfo"`
PromotionInfo struct {
PromotionSourceName string `json:"promotionSourceName"` // 修改后名称
} `json:"promotionInfo"`
}
type PromotionUpdResult struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
// PromotionUpd 修改指定的推广位名称 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html
func (app *App) PromotionUpd(param PromotionUpd) (result PromotionUpdResult, err error) {
if len(app.AccessToken) <= 0 {
return result, errors.New("调用凭证异常")
}
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
for k, v := range m {
params[k] = v
}
// request
body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/promotion/upd?access_token%s", app.AccessToken), params, http.MethodPost)
if err != nil {
return result, err
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, err
}
return result, err
}
type PromotionListResult struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
PromotionSourceList []struct {
PromotionSourceName string `json:"promotionSourceName"` // 推广位名称
PromotionSourcePid string `json:"promotionSourcePid"` // 推广位IDPID
Status string `json:"status"` // 状态
PidId string `json:"pidId"`
} `json:"promotionSourceList"` // 推广位数据
Total int `json:"total"` // 推广位总数
PromotionMaxCnt int `json:"promotionMaxCnt"` // 允许创建的推广位最大数量
}
// PromotionList 获取推广位列表 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html
func (app *App) PromotionList(start int, limit int) (result PromotionListResult, err error) {
if len(app.AccessToken) <= 0 {
return result, errors.New("调用凭证异常")
}
// request
body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/promotion/list?access_token%s", app.AccessToken), map[string]interface{}{
"start": start, // 偏移
"limit": limit, // 每页条数
}, http.MethodGet)
if err != nil {
return result, err
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, err
}
return result, err
}

@ -0,0 +1 @@
package wechatunion

@ -0,0 +1,7 @@
package wechatunion
const (
commissionStatus_SettlementPending = "SETTLEMENT_PENDING" // 待结算
commissionStatus_SettlementSuccess = "SETTLEMENT_SUCCESS" // 已结算
commissionStatus_SettlementCanceled = "SETTLEMENT_CANCELED" // 取消结算
)

@ -0,0 +1,22 @@
package wikeyun
import (
"fmt"
"github.com/dtapps/go-library/utils/gohttp"
)
type App struct {
StoreID int
AppKey int
AppSecret string
ClientIP string
}
func (app *App) request(url string, params map[string]interface{}) (resp []byte, err error) {
// 签名
sign := app.sign(params)
// 请求
requestUrl := fmt.Sprintf("%s?app_key=%d&timestamp=%s&client=%s&format=%s&v=%s&sign=%s", url, app.AppKey, sign.Timestamp, sign.Client, sign.Format, sign.V, sign.Sign)
postForm, err := gohttp.PostForm(requestUrl, params)
return postForm.Body, err
}

@ -0,0 +1,55 @@
package wikeyun
// OilCardAdd 添加充值卡
func (app *App) OilCardAdd(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Oil/addCard", params)
return body, err
}
// OilCardEdit 编辑充值卡
func (app *App) OilCardEdit(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Oil/editCard", params)
return body, err
}
// OilCardDel 油卡删除
func (app *App) OilCardDel(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Oil/delCard", params)
return body, err
}
// OilCardInfo 油卡详情
func (app *App) OilCardInfo(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Oil/cardInfo", params)
return body, err
}
// OilOrderPush 充值下单
func (app *App) OilOrderPush(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Oil/pushOrder", params)
return body, err
}
// OilOrderQuery 订单查询
func (app *App) OilOrderQuery(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Oil/query", params)
return body, err
}

@ -0,0 +1,27 @@
package wikeyun
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -0,0 +1,94 @@
package wikeyun
type PowerAddCardResult struct {
Code string `json:"code"`
Msg string `json:"msg"`
Time string `json:"time"`
Data struct {
CardNum string `json:"card_num"`
StoreId string `json:"store_id"`
CreateTime int `json:"create_time"`
Type int `json:"type"` // 缴费单位
CmsUid int `json:"cms_uid"`
Province string `json:"province"` // 缴费省份
City string `json:"city"` // 缴费城市
Id string `json:"id"` // 缴费卡编号
} `json:"data"`
}
// PowerAddCard 添加充值卡
func (app *App) PowerAddCard(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Power/addCard", params)
return body, err
}
// PowerEditCard 编辑充值卡
func (app *App) PowerEditCard(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Power/editCard", params)
return body, err
}
// PowerDelCard 充值卡删除
func (app *App) PowerDelCard(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Power/delCard", params)
return body, err
}
// PowerCardInfo 充值卡详情
func (app *App) PowerCardInfo(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Power/cardInfo", params)
return body, err
}
type PowerPushOrderResult struct {
Code string `json:"code"`
Msg string `json:"msg"`
Time string `json:"time"`
Data struct {
OrderNumber string `json:"order_number"`
} `json:"data"`
}
// PowerPushOrder 充值下单
func (app *App) PowerPushOrder(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Power/pushOrder", params)
return body, err
}
type PowerQueryResult struct {
Code string `json:"code"`
Msg string `json:"msg"`
Time string `json:"time"`
Data struct {
OrderNumber string `json:"order_number"` // 订单号
OrderNo string `json:"order_no"` // 订单号
CardId string `json:"card_id"` // 卡编号
Amount int `json:"amount"` // 充值金额
CostPrice string `json:"cost_price"` // 成本价
Fanli string `json:"fanli"` // 平台返利
Status int `json:"status"` // 交易结果0 待支付 1 已付充值中 2充值成功 3充值失败需要退款 4退款成功 6 待充值 7 已匹配)
} `json:"data"`
}
func (app *App) PowerQuery(notMustParams ...Params) (body []byte, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err = app.request("https://router.wikeyun.cn/rest/Power/query", params)
return body, err
}

@ -0,0 +1 @@
package wikeyun

@ -0,0 +1,43 @@
package wikeyun
import (
"encoding/json"
"errors"
)
// RechargePpushOrderRequest 请求参数
type RechargePpushOrderRequest struct {
StoreId string `json:"store_id"` // 铺ID
Mobile string `json:"mobile"` // 充值号码
OrderNo string `json:"order_no"` // 充值订单号
Money int `json:"money"` // 充值金额100200
RechargeTyp int `json:"recharge_typ"` // 是 1快充 0慢充
NotifyUrl string `json:"notify_url"` // 异步回调地址POST
Change int `json:"change,omitempty"` // 失败更换渠道充值 0 否 1是
Source int `json:"source,omitempty"` // 是否强制渠道 传source字段则可以强制某渠道强制快充走94折则source传6
}
// RechargePpushOrderResponse 返回参数
type RechargePpushOrderResponse struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data struct {
OrderNumber string `json:"order_number"`
} `json:"data"`
}
// RechargePushOrder 充值请求业务参数
func (app *App) RechargePushOrder(notMustParams ...Params) (result RechargePpushOrderResponse, err error) {
// 参数
params := app.NewParamsWith(notMustParams...)
// 请求
body, err := app.request("https://router.wikeyun.cn/rest/Recharge/pushOrder", params)
if err != nil {
return result, errors.New(err.Error())
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, errors.New(err.Error())
}
return result, nil
}

@ -0,0 +1,35 @@
package wikeyun
import (
"encoding/json"
"errors"
)
// RechargeQueryResponse 返回参数
type RechargeQueryResponse struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data struct {
OrderNumber string `json:"order_number"`
Status int `json:"status"`
Mobile string `json:"mobile"`
Amount int `json:"amount"`
OrderNo string `json:"order_no"`
} `json:"data"`
}
// RechargeQuery 查询接口
func (app *App) RechargeQuery(orderNumber string) (result RechargeQueryResponse, err error) {
// 请求
body, err := app.request("https://router.wikeyun.cn/rest/Recharge/query", map[string]interface{}{
"order_number": orderNumber, // 官方订单号
})
if err != nil {
return result, errors.New(err.Error())
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, errors.New(err.Error())
}
return result, nil
}

@ -0,0 +1,75 @@
package wikeyun
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"sort"
"strconv"
"strings"
"time"
)
type respSign struct {
AppKey int
Timestamp string
Client string
V string
Format string
Sign string
}
func (app *App) sign(params map[string]interface{}) respSign {
// 默认参数
v := "1.0"
format := "json"
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
params["v"] = v // 客户端接口版本目前是1.0
params["format"] = format // 默认json
params["app_key"] = app.AppKey // 应用唯一表示
params["client"] = app.ClientIP // 客户端请求ip
params["timestamp"] = timestamp // unix时间戳秒单位
// 排序所有的 key
var keys []string
for key := range params {
keys = append(keys, key)
}
sort.Strings(keys)
signStr := app.AppSecret
for _, key := range keys {
signStr += key + getString(params[key])
}
signStr += app.AppSecret
return respSign{
AppKey: app.AppKey,
Timestamp: timestamp,
Client: app.ClientIP,
V: v,
Format: format,
Sign: app.createSign(signStr),
}
}
// 签名
func (app *App) createSign(signStr string) string {
h := md5.New()
h.Write([]byte(signStr))
cipherStr := h.Sum(nil)
return strings.ToUpper(hex.EncodeToString(cipherStr))
}
func getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
case []byte:
return string(v)
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
default:
bytes, _ := json.Marshal(v)
return string(bytes)
}
}

@ -0,0 +1,30 @@
package wikeyun
import (
"encoding/json"
"errors"
)
// UserQueryResponse 返回参数
type UserQueryResponse struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data struct {
Money string `json:"money"`
ID int `json:"id"`
} `json:"data"`
}
// UserQuery 查询余额接口
func (app *App) UserQuery() (result UserQueryResponse, err error) {
// 请求
body, err := app.request("https://router.wikeyun.cn/rest/User/query", map[string]interface{}{})
if err != nil {
return result, errors.New(err.Error())
}
err = json.Unmarshal(body, &result)
if err != nil {
return result, errors.New(err.Error())
}
return result, nil
}

@ -214,7 +214,7 @@ func readLength(reader *bytes.Reader) (int, error) {
return 0, err
}
if raw, err = readUntil(reader, ':'); err != nil {
return 0, fmt.Errorf("UnMarshal: Error while reading lenght of value: %v", err)
return 0, fmt.Errorf("UnMarshal: Error while reading length of value: %v", err)
} else {
if val, err = strconv.Atoi(raw); err != nil {
return 0, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err)

Loading…
Cancel
Save