commit 144c1788f7ee85e77a9adbc4dfa0fce959c3ffe8
Author: Hsy <32729842@qq.com>
Date: Thu Feb 20 17:32:53 2025 +0800
init
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..db33b65
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ mysql.8
+ true
+ com.mysql.cj.jdbc.Driver
+ jdbc:mysql://110.40.44.75:3306
+
+
+
+
+
+
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/hk.iml b/.idea/hk.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/hk.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..05e09cb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
new file mode 100644
index 0000000..56782ca
--- /dev/null
+++ b/.idea/sqldialects.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/api.api b/doc/api.api
new file mode 100644
index 0000000..13d5a0c
--- /dev/null
+++ b/doc/api.api
@@ -0,0 +1,103 @@
+syntax = "v1"
+
+info (
+ title: "type title here"
+ desc: "type desc here"
+ author: "DevTTL"
+ email: "admin@devttl.com"
+ version: "v0.1"
+)
+
+type Order172 {
+ OrderNo string `json:"OrderNo"` // Y 合作方订单号
+ OrderNo172 string `json:"OrderNo172"` // Y 172平台订单号,请求头sign里加密的是这个号码。
+ OrderStatus string `json:"OrderStatus"` // Y 订单状态:已发货,已完成,审核不通过,已取消,已撤单
+ ThirdPhone string `json:"ThirdPhone"` // N 办理号码
+ ExpressName string `json:"ExpressName"` // N 物流公司
+ ExpressCode string `json:"ExpressCode"` // N 物流单号
+ CardStatus string `json:"CardStatus"` // N 激活状态:已激活,未激活,可能为Null
+ ActiveTime string `json:"ActiveTime"` // N 激活时间格式yyyy-MM-dd HH:mm:ss,可能为Null
+ Remark string `json:"Remark"` // N 备注失败原因
+}
+
+type PushReq {
+ RequidId string `json:"RequidId"` // Y 推送请求唯一ID
+ Data Order172 `json:"Data"` // Y 返回订单信息
+}
+
+type Push172Resp {
+ Code int64 `json:"code",options=-1|0` // Y 响应码 -1错误 0正常
+ Msg string `json:"message"` // Y 错误信息
+}
+
+type GoodsItem {
+ Id int64 `json:"id"` // Y 商品ID
+ Name string `json:"name"` // Y 商品信息
+ MainPic string `json:"mainPic"` // Y 主图
+ DisableAge string `json:"disableAge"` // Y 年龄限制
+ UniFlow string `json:"uniFlow"` // Y 通用流量
+ DirFlow string `json:"dirFlow"` // Y 定向流量
+ TalkTime string `json:"talkTime"` // Y 通话时长
+ Remarks string `json:"remarks"` // Y 备注
+}
+
+type (
+ GoodsListReq {
+ Type string `json:"type":"type,default=0"` // Y 运营商 0:全部 1:电信 2:联通 3:移动 4:光电
+ }
+ GoodsListResp {
+ Data []GoodsItem `json:"data"`
+ }
+)
+
+type (
+ GoodsDetailsReq {
+ Id int64 `path:"id"`
+ }
+ GoodsDetailsResp {
+ Data GoodsItem `json:"data"` // Y 商品详情
+ }
+)
+
+type (
+ TiktokReq {
+ VideoUrl string `from:"videoUrl"` // 视频地址
+ }
+ TiktokResp {
+ AuthorID string `json:"authorId"` // 作者ID
+ AuthorUniqueID string `json:"authorUniqueId"` // 作者账号
+ AuthorAvatar string `json:"authorAvatar"` // 作者头像
+ AuthorNickname string `json:"authorNickname"` // 作者昵称
+ VideoID string `json:"videoId"` // 视频ID
+ VideoTitle string `json:"videoTitle"` // 作品描述
+ OriginCover string `json:"originCover"` // 静态封面
+ DynamicCover string `json:"dynamicCover"` // 动态封面
+ DestinationURL string `json:"destinationUrl"` // 无水印下载地址
+ WatermarkVideoURL string `json:"watermarkVideoUrl"` // 有水印下载地址
+ MusicURL string `json:"musicUrl"` // 背景音乐链接
+ OriginalURL string `json:"originalUrl"` // 原始下载链接
+ DownloaderURL string `json:"downloaderUrl"` // 解析后下载地址
+ CreateTime string `json:"createTime"` // 创建时间
+ Result bool `json:"result"` // 结果
+ }
+)
+
+@server (
+ group: api
+ prefix: api
+ middleware: RealIPMiddleware
+)
+service api {
+ @handler tiktokInfo
+ post /tiktok/getVideoInfo (TiktokReq) returns (TiktokResp)
+
+ @handler order172
+ post /push/order172 (PushReq) returns (Push172Resp)
+
+ @handler goodsList
+ get /goods/list (GoodsListReq) returns (GoodsListResp)
+
+ @handler goodsDetails
+ get /goods/:id (GoodsDetailsReq) returns (GoodsDetailsResp)
+}
+
diff --git a/doc/sql/config_api.sql b/doc/sql/config_api.sql
new file mode 100644
index 0000000..b96c5e9
--- /dev/null
+++ b/doc/sql/config_api.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `config_api`
+(
+ `id` bigint auto_increment NOT NULL COMMENT '主键ID',
+ `type` varchar(255) NOT NULL COMMENT '接口类型 0:172',
+ `key` varchar(20) DEFAULT NULL COMMENT 'key',
+ `secret` varchar(100) DEFAULT NULL COMMENT '密钥',
+ primary key (id)
+) COMMENT ='API配置表';
\ No newline at end of file
diff --git a/doc/sql/goods_info.sql b/doc/sql/goods_info.sql
new file mode 100644
index 0000000..6a8dd78
--- /dev/null
+++ b/doc/sql/goods_info.sql
@@ -0,0 +1,28 @@
+CREATE TABLE `goods_info`
+(
+ `id` bigint NOT NULL auto_increment COMMENT '主键ID',
+ `type` char(1) NOT NULL default '0' COMMENT '运营商 0:未标注 1:电信 2:联通 3:移动 4:光电',
+ `name` varchar(255) NOT NULL COMMENT '商品名',
+ `main_pic` varchar(1000) NOT NULL COMMENT '主图',
+ `little_picture` varchar(1000) DEFAULT '' COMMENT '详情图',
+ `netAddr` VARCHAR(255) DEFAULT '' COMMENT '商品套餐资料介绍地址',
+ `area` VARCHAR(10) DEFAULT '' COMMENT '归属地',
+
+ `uni_flow` VARCHAR(10) DEFAULT '' COMMENT '通用流量',
+ `dir_flow` VARCHAR(10) DEFAULT '' COMMENT '定向流量',
+ `talk_time` VARCHAR(10) DEFAULT '' COMMENT '通话时间',
+
+ `disable_area` VARCHAR(1000) DEFAULT '' COMMENT '禁发地区',
+ `disable_age` VARCHAR(100) DEFAULT '' COMMENT '年龄限制',
+ `disable_contract` VARCHAR(10) DEFAULT '' COMMENT '合约期',
+ `notes` text COMMENT '商品说明',
+
+ `api_id` bigint DEFAULT NULL COMMENT '三方接口',
+ `api_product_id` bigint DEFAULT NULL COMMENT '三方商品id',
+ `number_sel` char(1) NOT NULL DEFAULT '0' COMMENT '是否选号 0:不支持 1:收货地不是归属地 2:收货地是归属地',
+ `status` char(1) NOT NULL DEFAULT '0' COMMENT '状态 0:上架 1:下架',
+ `create_time` datetime NOT NULL default current_timestamp() comment '创建时间',
+ `update_time` datetime NOT NULL default current_timestamp() on update current_timestamp() comment '更新时间',
+ `remarks` VARCHAR(255) DEFAULT NULL COMMENT '备注',
+ primary key (id)
+) COMMENT '商品列表 ';
\ No newline at end of file
diff --git a/doc/sql/goods_status.sql b/doc/sql/goods_status.sql
new file mode 100644
index 0000000..aa65fef
--- /dev/null
+++ b/doc/sql/goods_status.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `goods_status`
+(
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `api_id` int(255) DEFAULT NULL COMMENT '三方接口',
+ `api_product_id` int(255) DEFAULT NULL COMMENT '三方商品id',
+ `status` int(10) DEFAULT NULL COMMENT '商品状态 0=上架 1=下架',
+ primary key (id)
+) COMMENT '商品状态';
\ No newline at end of file
diff --git a/doc/sql/oder_info.sql b/doc/sql/oder_info.sql
new file mode 100644
index 0000000..dcef490
--- /dev/null
+++ b/doc/sql/oder_info.sql
@@ -0,0 +1,22 @@
+CREATE TABLE `oder_info`
+(
+ `id` bigint NOT NULL COMMENT '订单id',
+ `oder_id` varchar(50) NOT NULL COMMENT '订单id',
+ `goods_id` varchar(50) NOT NULL COMMENT '下单产品ID',
+ `name` varchar(30) NOT NULL COMMENT '姓名',
+ `id_card` varchar(18) NOT NULL COMMENT '身份证号',
+ `phone` varchar(15) NOT NULL COMMENT '手机号码',
+ `province` varchar(20) NOT NULL COMMENT '省',
+ `city` varchar(20) NOT NULL COMMENT '城市',
+ `area` varchar(20) NOT NULL COMMENT '区/县/镇',
+ `address` varchar(100) NOT NULL COMMENT '详细地址',
+ `status` char(1) NOT NULL DEFAULT '0' COMMENT '发货处理状态:0=未处理,1=已下单 2=已发货 3已完成 4失败',
+ `api_id` varchar(255) DEFAULT NULL COMMENT '接口来源',
+ `api_oder_id` varchar(255) DEFAULT NULL COMMENT '第三方订单',
+ `third_phone` varchar(255) DEFAULT NULL COMMENT '用户办理的号码',
+ `card_status` char(1) DEFAULT '0' COMMENT '号码状态',
+ `create_time` datetime NOT NULL default current_timestamp() comment '创建时间',
+ `update_time` datetime NOT NULL default current_timestamp() on update current_timestamp() comment '更新时间',
+ `remarks` varchar(255) DEFAULT NULL COMMENT '备注',
+ primary key (id)
+) COMMENT '订单列表';
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..ef62465
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,53 @@
+module hk
+
+go 1.23.4
+
+require (
+ github.com/robfig/cron/v3 v3.0.1
+ github.com/zeromicro/go-zero v1.8.0
+)
+
+require (
+ filippo.io/edwards25519 v1.1.0 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/fatih/color v1.18.0 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-sql-driver/mysql v1.8.1 // indirect
+ github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/openzipkin/zipkin-go v0.4.3 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+ github.com/prometheus/client_golang v1.20.5 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/spaolacci/murmur3 v1.1.0 // indirect
+ go.opentelemetry.io/otel v1.24.0 // indirect
+ go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
+ go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect
+ go.opentelemetry.io/otel/metric v1.24.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.24.0 // indirect
+ go.opentelemetry.io/otel/trace v1.24.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.3.1 // indirect
+ go.uber.org/automaxprocs v1.6.0 // indirect
+ golang.org/x/net v0.34.0 // indirect
+ golang.org/x/sys v0.29.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
+ google.golang.org/grpc v1.65.0 // indirect
+ google.golang.org/protobuf v1.36.4 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..c4b71ee
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,136 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
+github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
+github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
+github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
+github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
+github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
+github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/zeromicro/go-zero v1.8.0 h1:4g/8VW+fOyM51HZYPeI3mXIZdEX+Fl6SsdYX2H5PYw4=
+github.com/zeromicro/go-zero v1.8.0/go.mod h1:xDBF+/iDzj30zPvu6HNUIbpz1J6+/g3Sx9D/DytJfss=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
+go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
+go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY=
+go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
+go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
+go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
+go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
+google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
+gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
diff --git a/model/config_api/configapimodel.go b/model/config_api/configapimodel.go
new file mode 100644
index 0000000..cc43f78
--- /dev/null
+++ b/model/config_api/configapimodel.go
@@ -0,0 +1,50 @@
+package config_api
+
+import (
+ "context"
+ "fmt"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+)
+
+var _ ConfigApiModel = (*customConfigApiModel)(nil)
+
+type (
+ // ConfigApiModel is an interface to be customized, add more methods here,
+ // and implement the added methods in customConfigApiModel.
+ ConfigApiModel interface {
+ configApiModel
+ withSession(session sqlx.Session) ConfigApiModel
+ FindList(ctx context.Context) ([]ConfigApi, error)
+ }
+
+ customConfigApiModel struct {
+ *defaultConfigApiModel
+ }
+)
+
+func (m *customConfigApiModel) FindList(ctx context.Context) ([]ConfigApi, error) {
+
+ query := fmt.Sprintf("select %s from %s", configApiRows, m.table)
+ var resp []ConfigApi
+ err := m.conn.QueryRowsCtx(ctx, &resp, query)
+ switch err {
+ case nil:
+ return resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+
+}
+
+// NewConfigApiModel returns a model for the database table.
+func NewConfigApiModel(conn sqlx.SqlConn) ConfigApiModel {
+ return &customConfigApiModel{
+ defaultConfigApiModel: newConfigApiModel(conn),
+ }
+}
+
+func (m *customConfigApiModel) withSession(session sqlx.Session) ConfigApiModel {
+ return NewConfigApiModel(sqlx.NewSqlConnFromSession(session))
+}
diff --git a/model/config_api/configapimodel_gen.go b/model/config_api/configapimodel_gen.go
new file mode 100644
index 0000000..be8b2a7
--- /dev/null
+++ b/model/config_api/configapimodel_gen.go
@@ -0,0 +1,87 @@
+// Code generated by goctl. DO NOT EDIT.
+// versions:
+// goctl version: 1.7.6
+
+package config_api
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "strings"
+
+ "github.com/zeromicro/go-zero/core/stores/builder"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+ "github.com/zeromicro/go-zero/core/stringx"
+)
+
+var (
+ configApiFieldNames = builder.RawFieldNames(&ConfigApi{})
+ configApiRows = strings.Join(configApiFieldNames, ",")
+ configApiRowsExpectAutoSet = strings.Join(stringx.Remove(configApiFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
+ configApiRowsWithPlaceHolder = strings.Join(stringx.Remove(configApiFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
+)
+
+type (
+ configApiModel interface {
+ Insert(ctx context.Context, data *ConfigApi) (sql.Result, error)
+ FindOne(ctx context.Context, id int64) (*ConfigApi, error)
+ Update(ctx context.Context, data *ConfigApi) error
+ Delete(ctx context.Context, id int64) error
+ }
+
+ defaultConfigApiModel struct {
+ conn sqlx.SqlConn
+ table string
+ }
+
+ ConfigApi struct {
+ Id int64 `db:"id"` // 主键ID
+ Type string `db:"type"` // 接口类型 0:172
+ Key sql.NullString `db:"key"` // key
+ Secret sql.NullString `db:"secret"` // 密钥
+ }
+)
+
+func newConfigApiModel(conn sqlx.SqlConn) *defaultConfigApiModel {
+ return &defaultConfigApiModel{
+ conn: conn,
+ table: "`config_api`",
+ }
+}
+
+func (m *defaultConfigApiModel) Delete(ctx context.Context, id int64) error {
+ query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
+ _, err := m.conn.ExecCtx(ctx, query, id)
+ return err
+}
+
+func (m *defaultConfigApiModel) FindOne(ctx context.Context, id int64) (*ConfigApi, error) {
+ query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", configApiRows, m.table)
+ var resp ConfigApi
+ err := m.conn.QueryRowCtx(ctx, &resp, query, id)
+ switch err {
+ case nil:
+ return &resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+}
+
+func (m *defaultConfigApiModel) Insert(ctx context.Context, data *ConfigApi) (sql.Result, error) {
+ query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, configApiRowsExpectAutoSet)
+ ret, err := m.conn.ExecCtx(ctx, query, data.Type, data.Key, data.Secret)
+ return ret, err
+}
+
+func (m *defaultConfigApiModel) Update(ctx context.Context, data *ConfigApi) error {
+ query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, configApiRowsWithPlaceHolder)
+ _, err := m.conn.ExecCtx(ctx, query, data.Type, data.Key, data.Secret, data.Id)
+ return err
+}
+
+func (m *defaultConfigApiModel) tableName() string {
+ return m.table
+}
diff --git a/model/config_api/vars.go b/model/config_api/vars.go
new file mode 100644
index 0000000..00ee11e
--- /dev/null
+++ b/model/config_api/vars.go
@@ -0,0 +1,5 @@
+package config_api
+
+import "github.com/zeromicro/go-zero/core/stores/sqlx"
+
+var ErrNotFound = sqlx.ErrNotFound
diff --git a/model/goods_info/goodsinfomodel.go b/model/goods_info/goodsinfomodel.go
new file mode 100644
index 0000000..ee98015
--- /dev/null
+++ b/model/goods_info/goodsinfomodel.go
@@ -0,0 +1,54 @@
+package goods_info
+
+import (
+ "context"
+ "fmt"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+)
+
+var _ GoodsInfoModel = (*customGoodsInfoModel)(nil)
+
+type (
+ // GoodsInfoModel is an interface to be customized, add more methods here,
+ // and implement the added methods in customGoodsInfoModel.
+ GoodsInfoModel interface {
+ goodsInfoModel
+ withSession(session sqlx.Session) GoodsInfoModel
+ GetGoodsIndex(ctx context.Context, value string) ([]GoodsInfo, error)
+ }
+
+ customGoodsInfoModel struct {
+ *defaultGoodsInfoModel
+ }
+)
+
+func (m *customGoodsInfoModel) GetGoodsIndex(ctx context.Context, value string) ([]GoodsInfo, error) {
+ var resp []GoodsInfo
+ var err error
+ if len(value) > 1 || value != "0" {
+ query := fmt.Sprintf("select %s from %s where status = 1 and type = ? order by id desc", goodsInfoRows, m.table)
+ err = m.conn.QueryRowsCtx(ctx, &resp, query, value)
+ } else {
+ query := fmt.Sprintf("select %s from %s where status = 1 order by id desc", goodsInfoRows, m.table)
+ err = m.conn.QueryRowsCtx(ctx, &resp, query)
+ }
+ switch err {
+ case nil:
+ return resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+}
+
+// NewGoodsInfoModel returns a model for the database table.
+func NewGoodsInfoModel(conn sqlx.SqlConn) GoodsInfoModel {
+ return &customGoodsInfoModel{
+ defaultGoodsInfoModel: newGoodsInfoModel(conn),
+ }
+}
+
+func (m *customGoodsInfoModel) withSession(session sqlx.Session) GoodsInfoModel {
+ return NewGoodsInfoModel(sqlx.NewSqlConnFromSession(session))
+}
diff --git a/model/goods_info/goodsinfomodel_gen.go b/model/goods_info/goodsinfomodel_gen.go
new file mode 100644
index 0000000..c2876af
--- /dev/null
+++ b/model/goods_info/goodsinfomodel_gen.go
@@ -0,0 +1,105 @@
+// Code generated by goctl. DO NOT EDIT.
+// versions:
+// goctl version: 1.7.6
+
+package goods_info
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/zeromicro/go-zero/core/stores/builder"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+ "github.com/zeromicro/go-zero/core/stringx"
+)
+
+var (
+ goodsInfoFieldNames = builder.RawFieldNames(&GoodsInfo{})
+ goodsInfoRows = strings.Join(goodsInfoFieldNames, ",")
+ goodsInfoRowsExpectAutoSet = strings.Join(stringx.Remove(goodsInfoFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
+ goodsInfoRowsWithPlaceHolder = strings.Join(stringx.Remove(goodsInfoFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
+)
+
+type (
+ goodsInfoModel interface {
+ Insert(ctx context.Context, data *GoodsInfo) (sql.Result, error)
+ FindOne(ctx context.Context, id int64) (*GoodsInfo, error)
+ Update(ctx context.Context, data *GoodsInfo) error
+ Delete(ctx context.Context, id int64) error
+ }
+
+ defaultGoodsInfoModel struct {
+ conn sqlx.SqlConn
+ table string
+ }
+
+ GoodsInfo struct {
+ Id int64 `db:"id"` // 主键ID
+ Type string `db:"type"` // 运营商 0:未标注 1:电信 2:联通 3:移动 4:光电
+ Name string `db:"name"` // 商品名
+ MainPic string `db:"main_pic"` // 主图
+ LittlePicture string `db:"little_picture"` // 详情图
+ NetAddr string `db:"netAddr"` // 商品套餐资料介绍地址
+ Area string `db:"area"` // 归属地
+ UniFlow string `db:"uni_flow"` // 通用流量
+ DirFlow string `db:"dir_flow"` // 定向流量
+ TalkTime string `db:"talk_time"` // 通话时间
+ DisableArea string `db:"disable_area"` // 禁发地区
+ DisableAge string `db:"disable_age"` // 年龄限制
+ DisableContract string `db:"disable_contract"` // 合约期
+ Notes sql.NullString `db:"notes"` // 商品说明
+ ApiId sql.NullInt64 `db:"api_id"` // 三方接口
+ ApiProductId sql.NullInt64 `db:"api_product_id"` // 三方商品id
+ NumberSel string `db:"number_sel"` // 是否选号 0:不支持 1:收货地不是归属地 2:收货地是归属地
+ Status string `db:"status"` // 状态 0:上架 1:下架
+ CreateTime time.Time `db:"create_time"` // 创建时间
+ UpdateTime time.Time `db:"update_time"` // 更新时间
+ Remarks sql.NullString `db:"remarks"` // 备注
+ }
+)
+
+func newGoodsInfoModel(conn sqlx.SqlConn) *defaultGoodsInfoModel {
+ return &defaultGoodsInfoModel{
+ conn: conn,
+ table: "`goods_info`",
+ }
+}
+
+func (m *defaultGoodsInfoModel) Delete(ctx context.Context, id int64) error {
+ query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
+ _, err := m.conn.ExecCtx(ctx, query, id)
+ return err
+}
+
+func (m *defaultGoodsInfoModel) FindOne(ctx context.Context, id int64) (*GoodsInfo, error) {
+ query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", goodsInfoRows, m.table)
+ var resp GoodsInfo
+ err := m.conn.QueryRowCtx(ctx, &resp, query, id)
+ switch err {
+ case nil:
+ return &resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+}
+
+func (m *defaultGoodsInfoModel) Insert(ctx context.Context, data *GoodsInfo) (sql.Result, error) {
+ query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, goodsInfoRowsExpectAutoSet)
+ ret, err := m.conn.ExecCtx(ctx, query, data.Type, data.Name, data.MainPic, data.LittlePicture, data.NetAddr, data.Area, data.UniFlow, data.DirFlow, data.TalkTime, data.DisableArea, data.DisableAge, data.DisableContract, data.Notes, data.ApiId, data.ApiProductId, data.NumberSel, data.Status, data.Remarks)
+ return ret, err
+}
+
+func (m *defaultGoodsInfoModel) Update(ctx context.Context, data *GoodsInfo) error {
+ query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, goodsInfoRowsWithPlaceHolder)
+ _, err := m.conn.ExecCtx(ctx, query, data.Type, data.Name, data.MainPic, data.LittlePicture, data.NetAddr, data.Area, data.UniFlow, data.DirFlow, data.TalkTime, data.DisableArea, data.DisableAge, data.DisableContract, data.Notes, data.ApiId, data.ApiProductId, data.NumberSel, data.Status, data.Remarks, data.Id)
+ return err
+}
+
+func (m *defaultGoodsInfoModel) tableName() string {
+ return m.table
+}
diff --git a/model/goods_info/vars.go b/model/goods_info/vars.go
new file mode 100644
index 0000000..f7b0b75
--- /dev/null
+++ b/model/goods_info/vars.go
@@ -0,0 +1,5 @@
+package goods_info
+
+import "github.com/zeromicro/go-zero/core/stores/sqlx"
+
+var ErrNotFound = sqlx.ErrNotFound
diff --git a/model/goods_status/goodsstatusmodel.go b/model/goods_status/goodsstatusmodel.go
new file mode 100644
index 0000000..5233937
--- /dev/null
+++ b/model/goods_status/goodsstatusmodel.go
@@ -0,0 +1,92 @@
+package goods_status
+
+import (
+ "context"
+ "fmt"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+ "strings"
+)
+
+var _ GoodsStatusModel = (*customGoodsStatusModel)(nil)
+
+type (
+ // GoodsStatusModel is an interface to be customized, add more methods here,
+ // and implement the added methods in customGoodsStatusModel.
+ GoodsStatusModel interface {
+ goodsStatusModel
+ withSession(session sqlx.Session) GoodsStatusModel
+ DeleteByApiId(ctx context.Context, id int64) error
+ FindUpList(ctx context.Context, apiId int64) ([]int64, error)
+ UpdateDownByIds(ctx context.Context, ids []int64) error
+ FindNotIdOne(ctx context.Context, apiId int64) (int64, error)
+ }
+
+ customGoodsStatusModel struct {
+ *defaultGoodsStatusModel
+ }
+)
+
+func (m *customGoodsStatusModel) FindNotIdOne(ctx context.Context, apiId int64) (int64, error) {
+ query := fmt.Sprintf("select gs.`api_product_id` from %s gs left join `goods_info` gi on gs.`api_id` = gi.`api_id` where gs.`api_id` = ? and gs.`api_product_id` not in (select gs.api_product_id from `goods_status` gs join `goods_info` gi on gs.`api_id` = gi.`api_id` and gi.api_product_id = gs.api_product_id where gs.`api_id` = ?) limit 1", m.table)
+ var resp int64
+ err := m.conn.QueryRowCtx(ctx, &resp, query, apiId, apiId)
+ switch err {
+ case nil:
+ return resp, nil
+ case sqlx.ErrNotFound:
+ return 0, ErrNotFound
+ default:
+ return 0, err
+ }
+}
+
+func (m *customGoodsStatusModel) UpdateDownByIds(ctx context.Context, ids []int64) error {
+ // 动态构造 IN 子句中的占位符
+ placeholders := make([]string, len(ids))
+ for i := range ids {
+ placeholders[i] = "?"
+ }
+ query := fmt.Sprintf("update %s set `status` = 0 where `id` in (%s)", m.table, strings.Join(placeholders, ","))
+ _, err := m.conn.ExecCtx(ctx, query, convertToInterface(ids)...)
+ return err
+}
+
+func (m *customGoodsStatusModel) FindUpList(ctx context.Context, apiId int64) ([]int64, error) {
+ query := fmt.Sprintf("select g.`id` from %s g join `config_api` c on g.`api_id` = c.id where g.status = 0 and c.id = ?", m.table)
+ var resp []int64
+ err := m.conn.QueryRowsCtx(ctx, &resp, query, apiId)
+ switch err {
+ case nil:
+ return resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+}
+
+func (m *customGoodsStatusModel) DeleteByApiId(ctx context.Context, id int64) error {
+ query := fmt.Sprintf("delete from %s where `api_id` = ?", m.table)
+ _, err := m.conn.ExecCtx(ctx, query, id)
+ return err
+}
+
+// NewGoodsStatusModel returns a model for the database table.
+func NewGoodsStatusModel(conn sqlx.SqlConn) GoodsStatusModel {
+ return &customGoodsStatusModel{
+ defaultGoodsStatusModel: newGoodsStatusModel(conn),
+ }
+}
+
+func (m *customGoodsStatusModel) withSession(session sqlx.Session) GoodsStatusModel {
+ return NewGoodsStatusModel(sqlx.NewSqlConnFromSession(session))
+}
+
+// convertToInterface 将 int64 切片转换为接口切片
+func convertToInterface(ids []int64) []interface{} {
+ result := make([]interface{}, len(ids))
+ for i, id := range ids {
+ result[i] = id
+ }
+ return result
+}
diff --git a/model/goods_status/goodsstatusmodel_gen.go b/model/goods_status/goodsstatusmodel_gen.go
new file mode 100644
index 0000000..2c29817
--- /dev/null
+++ b/model/goods_status/goodsstatusmodel_gen.go
@@ -0,0 +1,87 @@
+// Code generated by goctl. DO NOT EDIT.
+// versions:
+// goctl version: 1.7.6
+
+package goods_status
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "strings"
+
+ "github.com/zeromicro/go-zero/core/stores/builder"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+ "github.com/zeromicro/go-zero/core/stringx"
+)
+
+var (
+ goodsStatusFieldNames = builder.RawFieldNames(&GoodsStatus{})
+ goodsStatusRows = strings.Join(goodsStatusFieldNames, ",")
+ goodsStatusRowsExpectAutoSet = strings.Join(stringx.Remove(goodsStatusFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
+ goodsStatusRowsWithPlaceHolder = strings.Join(stringx.Remove(goodsStatusFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
+)
+
+type (
+ goodsStatusModel interface {
+ Insert(ctx context.Context, data *GoodsStatus) (sql.Result, error)
+ FindOne(ctx context.Context, id int64) (*GoodsStatus, error)
+ Update(ctx context.Context, data *GoodsStatus) error
+ Delete(ctx context.Context, id int64) error
+ }
+
+ defaultGoodsStatusModel struct {
+ conn sqlx.SqlConn
+ table string
+ }
+
+ GoodsStatus struct {
+ Id int64 `db:"id"` // id
+ ApiId sql.NullInt64 `db:"api_id"` // 三方接口
+ ApiProductId sql.NullInt64 `db:"api_product_id"` // 三方商品id
+ Status sql.NullInt64 `db:"status"` // 商品状态 0=上架 1=下架
+ }
+)
+
+func newGoodsStatusModel(conn sqlx.SqlConn) *defaultGoodsStatusModel {
+ return &defaultGoodsStatusModel{
+ conn: conn,
+ table: "`goods_status`",
+ }
+}
+
+func (m *defaultGoodsStatusModel) Delete(ctx context.Context, id int64) error {
+ query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
+ _, err := m.conn.ExecCtx(ctx, query, id)
+ return err
+}
+
+func (m *defaultGoodsStatusModel) FindOne(ctx context.Context, id int64) (*GoodsStatus, error) {
+ query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", goodsStatusRows, m.table)
+ var resp GoodsStatus
+ err := m.conn.QueryRowCtx(ctx, &resp, query, id)
+ switch err {
+ case nil:
+ return &resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+}
+
+func (m *defaultGoodsStatusModel) Insert(ctx context.Context, data *GoodsStatus) (sql.Result, error) {
+ query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, goodsStatusRowsExpectAutoSet)
+ ret, err := m.conn.ExecCtx(ctx, query, data.ApiId, data.ApiProductId, data.Status)
+ return ret, err
+}
+
+func (m *defaultGoodsStatusModel) Update(ctx context.Context, data *GoodsStatus) error {
+ query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, goodsStatusRowsWithPlaceHolder)
+ _, err := m.conn.ExecCtx(ctx, query, data.ApiId, data.ApiProductId, data.Status, data.Id)
+ return err
+}
+
+func (m *defaultGoodsStatusModel) tableName() string {
+ return m.table
+}
diff --git a/model/goods_status/vars.go b/model/goods_status/vars.go
new file mode 100644
index 0000000..0a806da
--- /dev/null
+++ b/model/goods_status/vars.go
@@ -0,0 +1,5 @@
+package goods_status
+
+import "github.com/zeromicro/go-zero/core/stores/sqlx"
+
+var ErrNotFound = sqlx.ErrNotFound
diff --git a/model/order_info/oderinfomodel.go b/model/order_info/oderinfomodel.go
new file mode 100644
index 0000000..97edd22
--- /dev/null
+++ b/model/order_info/oderinfomodel.go
@@ -0,0 +1,29 @@
+package order_info
+
+import "github.com/zeromicro/go-zero/core/stores/sqlx"
+
+var _ OderInfoModel = (*customOderInfoModel)(nil)
+
+type (
+ // OderInfoModel is an interface to be customized, add more methods here,
+ // and implement the added methods in customOderInfoModel.
+ OderInfoModel interface {
+ oderInfoModel
+ withSession(session sqlx.Session) OderInfoModel
+ }
+
+ customOderInfoModel struct {
+ *defaultOderInfoModel
+ }
+)
+
+// NewOderInfoModel returns a model for the database table.
+func NewOderInfoModel(conn sqlx.SqlConn) OderInfoModel {
+ return &customOderInfoModel{
+ defaultOderInfoModel: newOderInfoModel(conn),
+ }
+}
+
+func (m *customOderInfoModel) withSession(session sqlx.Session) OderInfoModel {
+ return NewOderInfoModel(sqlx.NewSqlConnFromSession(session))
+}
diff --git a/model/order_info/oderinfomodel_gen.go b/model/order_info/oderinfomodel_gen.go
new file mode 100644
index 0000000..61560e9
--- /dev/null
+++ b/model/order_info/oderinfomodel_gen.go
@@ -0,0 +1,102 @@
+// Code generated by goctl. DO NOT EDIT.
+// versions:
+// goctl version: 1.7.6
+
+package order_info
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/zeromicro/go-zero/core/stores/builder"
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+ "github.com/zeromicro/go-zero/core/stringx"
+)
+
+var (
+ oderInfoFieldNames = builder.RawFieldNames(&OderInfo{})
+ oderInfoRows = strings.Join(oderInfoFieldNames, ",")
+ oderInfoRowsExpectAutoSet = strings.Join(stringx.Remove(oderInfoFieldNames, "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
+ oderInfoRowsWithPlaceHolder = strings.Join(stringx.Remove(oderInfoFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
+)
+
+type (
+ oderInfoModel interface {
+ Insert(ctx context.Context, data *OderInfo) (sql.Result, error)
+ FindOne(ctx context.Context, id int64) (*OderInfo, error)
+ Update(ctx context.Context, data *OderInfo) error
+ Delete(ctx context.Context, id int64) error
+ }
+
+ defaultOderInfoModel struct {
+ conn sqlx.SqlConn
+ table string
+ }
+
+ OderInfo struct {
+ Id int64 `db:"id"` // 订单id
+ OderId string `db:"oder_id"` // 订单id
+ GoodsId string `db:"goods_id"` // 下单产品ID
+ Name string `db:"name"` // 姓名
+ IdCard string `db:"id_card"` // 身份证号
+ Phone string `db:"phone"` // 手机号码
+ Province string `db:"province"` // 省
+ City string `db:"city"` // 城市
+ Area string `db:"area"` // 区/县/镇
+ Address string `db:"address"` // 详细地址
+ Status string `db:"status"` // 发货处理状态:0=未处理,1=已下单 2=已发货 3已完成 4失败
+ ApiId sql.NullString `db:"api_id"` // 接口来源
+ ApiOderId sql.NullString `db:"api_oder_id"` // 第三方订单
+ ThirdPhone sql.NullString `db:"third_phone"` // 用户办理的号码
+ CardStatus string `db:"card_status"` // 号码状态
+ CreateTime time.Time `db:"create_time"` // 创建时间
+ UpdateTime time.Time `db:"update_time"` // 更新时间
+ Remarks sql.NullString `db:"remarks"` // 备注
+ }
+)
+
+func newOderInfoModel(conn sqlx.SqlConn) *defaultOderInfoModel {
+ return &defaultOderInfoModel{
+ conn: conn,
+ table: "`oder_info`",
+ }
+}
+
+func (m *defaultOderInfoModel) Delete(ctx context.Context, id int64) error {
+ query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
+ _, err := m.conn.ExecCtx(ctx, query, id)
+ return err
+}
+
+func (m *defaultOderInfoModel) FindOne(ctx context.Context, id int64) (*OderInfo, error) {
+ query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", oderInfoRows, m.table)
+ var resp OderInfo
+ err := m.conn.QueryRowCtx(ctx, &resp, query, id)
+ switch err {
+ case nil:
+ return &resp, nil
+ case sqlx.ErrNotFound:
+ return nil, ErrNotFound
+ default:
+ return nil, err
+ }
+}
+
+func (m *defaultOderInfoModel) Insert(ctx context.Context, data *OderInfo) (sql.Result, error) {
+ query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, oderInfoRowsExpectAutoSet)
+ ret, err := m.conn.ExecCtx(ctx, query, data.Id, data.OderId, data.GoodsId, data.Name, data.IdCard, data.Phone, data.Province, data.City, data.Area, data.Address, data.Status, data.ApiId, data.ApiOderId, data.ThirdPhone, data.CardStatus, data.Remarks)
+ return ret, err
+}
+
+func (m *defaultOderInfoModel) Update(ctx context.Context, data *OderInfo) error {
+ query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, oderInfoRowsWithPlaceHolder)
+ _, err := m.conn.ExecCtx(ctx, query, data.OderId, data.GoodsId, data.Name, data.IdCard, data.Phone, data.Province, data.City, data.Area, data.Address, data.Status, data.ApiId, data.ApiOderId, data.ThirdPhone, data.CardStatus, data.Remarks, data.Id)
+ return err
+}
+
+func (m *defaultOderInfoModel) tableName() string {
+ return m.table
+}
diff --git a/model/order_info/vars.go b/model/order_info/vars.go
new file mode 100644
index 0000000..d386e26
--- /dev/null
+++ b/model/order_info/vars.go
@@ -0,0 +1,5 @@
+package order_info
+
+import "github.com/zeromicro/go-zero/core/stores/sqlx"
+
+var ErrNotFound = sqlx.ErrNotFound
diff --git a/pkg/middleware/getRealIP.go b/pkg/middleware/getRealIP.go
new file mode 100644
index 0000000..467642b
--- /dev/null
+++ b/pkg/middleware/getRealIP.go
@@ -0,0 +1,82 @@
+package middleware
+
+import (
+ "errors"
+ "net"
+ "net/http"
+ "strings"
+)
+
+// GetRealIP 提取客户端真实 IP 地址
+func GetRealIP(r *http.Request) string {
+ headers := []string{"x-forwarded-for", "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "X-Real-IP"}
+
+ // 遍历头信息,找到第一个有效 IP
+ for _, header := range headers {
+ ip := extractIP(r.Header.Get(header))
+ if ip != "" {
+ return ip
+ }
+ }
+
+ // 获取 RemoteAddr,如果经过代理则是代理 IP
+ ip, _, err := net.SplitHostPort(r.RemoteAddr)
+ if err == nil && ip != "" {
+ return ip
+ }
+
+ // 检查是否是本地地址
+ if strings.HasPrefix(ip, "127.0.0.1") || strings.HasPrefix(ip, "[::1]") {
+ if externalIP, err := getExternalIP(); err == nil {
+ return externalIP.String()
+ }
+ }
+ return ""
+}
+
+// 提取 IP 地址并返回第一个非空部分
+func extractIP(ips string) string {
+ if ips == "" || strings.EqualFold(ips, "unknown") {
+ return ""
+ }
+ // 返回第一个有效 IP
+ return strings.TrimSpace(strings.Split(ips, ",")[0])
+}
+
+// 获取非 127.0.0.1 的局域网 IP
+func getExternalIP() (net.IP, error) {
+ ifaces, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ for _, iface := range ifaces {
+ if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
+ continue
+ }
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, err
+ }
+ for _, addr := range addrs {
+ ip := getIPFromAddr(addr)
+ if ip != nil {
+ return ip, nil
+ }
+ }
+ }
+ return nil, errors.New("not connected to the network")
+}
+
+func getIPFromAddr(addr net.Addr) net.IP {
+ var ip net.IP
+ switch v := addr.(type) {
+ case *net.IPNet:
+ ip = v.IP
+ case *net.IPAddr:
+ ip = v.IP
+ }
+ if ip != nil && !ip.IsLoopback() {
+ return ip.To4()
+ }
+ return nil
+}
diff --git a/pkg/util/172/172.go b/pkg/util/172/172.go
new file mode 100644
index 0000000..92a5203
--- /dev/null
+++ b/pkg/util/172/172.go
@@ -0,0 +1,72 @@
+package _72
+
+import (
+ "encoding/json"
+ "fmt"
+ "hk/pkg/util/httpUtil"
+ "time"
+)
+
+const (
+ productsUrl = "https://haokaopenapi.lot-ml.com/api/order/GetProducts" // 商品列表查询Url
+ productsV2Url = "https://haokaopenapi.lot-ml.com/api/order/GetProductsV2" // 商品信息查询Url
+ pickNumberUrl = "https://haokaopenapi.lot-ml.com/api/order/PickNumber" // 商品选号Url
+ blackUserUrl = "https://haokaopenapi.lot-ml.com/api/black/BlackCheckCus" // 用户黑名单Url
+ blackAgentUrl = "https://haokaopenapi.lot-ml.com/api/black/BlackCheckAgent" // 代理黑名单Url
+ upFileUrl = "https://haokaopenapi.lot-ml.com/api/order/UpPicFile" // 证件照上传Url
+ addOrderUrl = "https://haokaopenapi.lot-ml.com/api/order/ApiToOrder" // 下单Url
+ orderInfoUrl = "https://haokaopenapi.lot-ml.com/api/order/GetOrderInfo" // 订单查询Url
+)
+
+type BaseParams struct {
+ Timestamp string `json:"Timestamp"` // Y 时间戳
+ UserID string `json:"user_id"` // Y 用户ID
+ UserSign string `json:"user_sign"` // Y 密钥
+}
+
+// GoodsReq 商品请求参数
+type GoodsReq struct {
+ ProductID string `json:"ProductID"`
+ BaseParams
+ // Timestamp string `json:"Timestamp"` // Y 时间戳
+ // UserID string `json:"user_id"` // Y 用户ID
+ // UserSign string `json:"user_sign"` // Y 密钥
+}
+
+// ProductResp 定义产品信息的结构体
+type ProductResp struct {
+ ProductID int64 `json:"productID"`
+ ProductName string `json:"productName"`
+ Flag string `json:"flag"` // 上架中
+}
+
+// GetProduct 获取上架中商品列表
+func GetProduct(params GoodsReq) (ApiResponse[[]ProductResp], error) {
+ // 设置时间戳
+ timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 当前时间戳,长度为10位
+ params.Timestamp = timestamp
+ // 生成 MD5 签名
+ userSign := generateMD5SignV2(params, params.UserSign)
+
+ formParams := map[string]string{
+ "ProductID": params.ProductID,
+ "Timestamp": params.Timestamp,
+ "user_sign": userSign,
+ "user_id": params.UserID,
+ }
+
+ body, err := httpUtil.NewRequest().SendFormData(productsUrl, nil, formParams)
+ if err != nil {
+ return ApiResponse[[]ProductResp]{}, err
+ }
+
+ // 解析 JSON 响应
+ var apiResponse ApiResponse[[]ProductResp]
+ err = json.Unmarshal([]byte(body), &apiResponse)
+ if err != nil {
+ fmt.Println("解析响应体时发生错误:", err)
+ return ApiResponse[[]ProductResp]{}, err
+ }
+
+ return apiResponse, nil
+}
diff --git a/pkg/util/172/172_test.go b/pkg/util/172/172_test.go
new file mode 100644
index 0000000..5f2c1de
--- /dev/null
+++ b/pkg/util/172/172_test.go
@@ -0,0 +1,198 @@
+package _72
+
+import (
+ "fmt"
+ "testing"
+ "time"
+)
+
+func TestGetProduct(t *testing.T) {
+ key := "devttl"
+ secret := "2eed544990ff898cf4fe47ef90b1ce3a"
+ productID := ""
+ timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 当前时间戳,长度为10位
+
+ // 创建请求参数
+ params := GoodsReq{
+ ProductID: productID,
+ BaseParams: BaseParams{
+ Timestamp: timestamp,
+ UserID: key,
+ UserSign: secret,
+ },
+ }
+
+ // 发送 POST 请求
+ apiResponse, err := GetProduct(params)
+ if err != nil {
+ return
+ }
+
+ // 如果成功,处理 data 中的数据
+ if apiResponse.Code == 0 {
+ for index, item := range apiResponse.Data {
+ fmt.Printf("------------------%d\n", index)
+ fmt.Printf("产品ID: %v\n", item.ProductID)
+ fmt.Printf("产品名称: %v\n", item.ProductName)
+ fmt.Printf("产品状态: %v\n", item.Flag)
+ }
+ }
+}
+
+func TestGetProductV2(t *testing.T) {
+ key := "devttl"
+ secret := "2eed544990ff898cf4fe47ef90b1ce3a"
+ productID := "1128"
+ timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 当前时间戳,长度为10位
+
+ // 创建请求参数
+ params := GoodsReq{
+ ProductID: productID,
+ BaseParams: BaseParams{
+ Timestamp: timestamp,
+ UserID: key,
+ },
+ }
+
+ // 生成 MD5 签名
+ userSign := generateMD5SignV2(params, secret)
+
+ params.UserSign = userSign
+
+ fmt.Print(params)
+
+ // 发送 POST 请求
+ apiResponse, err := getProductV2(params)
+ if err != nil {
+ return
+ }
+
+ // 如果成功,处理 data 中的数据
+ if apiResponse.Code == 0 {
+ for index, item := range apiResponse.Data {
+ fmt.Printf("------------------%d\n", index)
+ fmt.Printf("产品ID: %v\n", item.ProductID)
+ fmt.Printf("产品名称: %v\n", item.ProductName)
+ fmt.Printf("产品主图: %v\n", item.MainPic)
+ fmt.Printf("发货地区: %v\n", item.Area)
+ fmt.Printf("禁发地区: %v\n", item.DisableArea)
+ fmt.Printf("详情图片: %v\n", item.LittlePicture)
+ fmt.Printf("详情链接: %v\n", item.NetAddr)
+ fmt.Printf("产品状态: %v\n", item.Flag)
+ fmt.Printf("是否选号: %v\n", item.NumberSel)
+ }
+ }
+}
+
+func TestGetPickNumber(t *testing.T) {
+ key := "devttl"
+ secret := "2eed544990ff898cf4fe47ef90b1ce3a"
+ productID := "1128"
+ timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 当前时间戳,长度为10位
+
+ // 创建请求参数
+ params := PickNumberReq{
+ ProductID: productID,
+ SearchCategory: "3",
+ BaseParams: BaseParams{
+ UserID: key,
+ Timestamp: timestamp,
+ },
+ }
+
+ // 生成 MD5 签名
+ userSign := generateMD5SignV2(params, secret)
+
+ params.UserSign = userSign
+
+ fmt.Println(params)
+
+ // 发送 POST 请求
+ apiResponse, err := GetPickNumber(params)
+ if err != nil {
+ return
+ }
+
+ // 如果成功,处理 data 中的数据
+ if apiResponse.Code == 0 {
+ for index, item := range apiResponse.Data {
+ fmt.Printf("------------------%d\n", index)
+ fmt.Printf("号码: %v\n", item.Number)
+ fmt.Printf("号码类型: %v\n", item.Type)
+ fmt.Printf("号码ID: %v\n", item.NumberId)
+ fmt.Printf("号码池ID: %v\n", item.NumberPoolId)
+ }
+ }
+}
+
+func TestCheckUserBlack(t *testing.T) {
+ key := "devttl"
+ secret := "2eed544990ff898cf4fe47ef90b1ce3a"
+ number := "15538654901"
+ numberType := "1"
+ timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 当前时间戳,长度为10位
+
+ // 创建请求参数
+ params := BlackReq{
+ Number: number,
+ Type: numberType,
+ Timestamp: timestamp,
+ UserID: key,
+ UserSign: secret,
+ }
+
+ // 发送 POST 请求
+ apiResponse, err := CheckBlackUser(params)
+ if err != nil {
+ return
+ }
+
+ // 如果成功,处理 data 中的数据
+ if apiResponse.Code == 0 {
+ fmt.Println("此用户是黑名单")
+ }
+ if apiResponse.Code == 1 {
+ fmt.Println("此用户不是黑名单")
+ }
+ if apiResponse.Code == -1 {
+ fmt.Println("请输入正确的手机号")
+ }
+}
+
+func TestCheckAgentBlack(t *testing.T) {
+ key := "devttl"
+ secret := "2eed544990ff898cf4fe47ef90b1ce3a"
+ number := "15538654901"
+ numberType := "1"
+
+ // 创建请求参数
+ params := BlackReq{
+ Number: number,
+ Type: numberType,
+ UserID: key,
+ }
+
+ // 生成 MD5 签名
+ userSign := generateMD5SignV2(params, secret)
+
+ params.UserSign = userSign
+
+ fmt.Println(params)
+
+ // 发送 POST 请求
+ apiResponse, err := CheckBlackAgent(params)
+ if err != nil {
+ return
+ }
+
+ // 如果成功,处理 data 中的数据
+ if apiResponse.Code == 0 {
+ fmt.Println("此用户是黑名单代理")
+ }
+ if apiResponse.Code == 1 {
+ fmt.Println("此用户不是黑名单代理")
+ }
+ if apiResponse.Code == -1 {
+ fmt.Println("请输入正确的代理手机号")
+ }
+}
diff --git a/pkg/util/172/api_result.go b/pkg/util/172/api_result.go
new file mode 100644
index 0000000..5bfdb02
--- /dev/null
+++ b/pkg/util/172/api_result.go
@@ -0,0 +1,70 @@
+package _72
+
+import (
+ "crypto/md5"
+ "encoding/hex"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// ApiResponse 定义响应体的结构体
+type ApiResponse[T any] struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Errs *string `json:"errs"`
+ Data T `json:"data"`
+}
+
+// 优化后的 generateMD5Sign 方法
+func generateMD5SignV2(params interface{}, secret string) string {
+ // 获取结构体中的字段信息
+ var strBuilder strings.Builder
+
+ // 获取参数类型
+ v := reflect.ValueOf(params)
+
+ // 遍历结构体中的字段
+ for i := 0; i < v.NumField(); i++ {
+ // 获取字段名和值
+ field := v.Type().Field(i)
+ jsonTag := field.Tag.Get("json") // 获取 json 标签
+ value := v.Field(i)
+ // 如果字段是嵌套结构体,跳过
+ if value.Kind() == reflect.Struct {
+ continue
+ }
+ // 获取字段值
+ fieldValue := value.String()
+
+ // 排除 user_id 和空字符串字段
+ if field.Name != "UserID" && field.Name != "UserSign" {
+ // 拼接字段名和值
+ strBuilder.WriteString(fmt.Sprintf("%s=%s&", jsonTag, fieldValue))
+ }
+ }
+
+ // 使用反射获取字段并拼接
+ timestamp := v.FieldByName("Timestamp")
+ if timestamp.IsValid() {
+ timestampTag, _ := v.Type().FieldByName("Timestamp")
+ strBuilder.WriteString(fmt.Sprintf("%s=%s&", timestampTag.Tag.Get("json"), timestamp.String()))
+ }
+ userID := v.FieldByName("UserID")
+ if userID.IsValid() {
+ userIDTag, _ := v.Type().FieldByName("UserID")
+ strBuilder.WriteString(fmt.Sprintf("%s=%s", userIDTag.Tag.Get("json"), userID.String()))
+ }
+
+ // 拼接 secret 到最后
+ strBuilder.WriteString(secret)
+
+ // 获取拼接后的字符串
+ concatenatedStr := strBuilder.String()
+
+ fmt.Println(concatenatedStr)
+ // 计算 MD5 哈希
+ hash := md5.New()
+ hash.Write([]byte(concatenatedStr))
+ return hex.EncodeToString(hash.Sum(nil))
+}
diff --git a/pkg/util/172/black_user.go b/pkg/util/172/black_user.go
new file mode 100644
index 0000000..c9733dc
--- /dev/null
+++ b/pkg/util/172/black_user.go
@@ -0,0 +1,69 @@
+package _72
+
+import (
+ "encoding/json"
+ "fmt"
+ "hk/pkg/util/httpUtil"
+)
+
+// BlackReq 黑名单请求
+type BlackReq struct {
+ Number string `json:"number"` // Y 手机号或身份证号
+ Type string `json:"type"` // Y 查询类别 1:手机号 2:身份证号
+ Timestamp string `json:"Timestamp"` // Y 时间戳
+ UserID string `json:"username"` // Y 用户ID
+ UserSign string `json:"sign"` // Y 密钥
+}
+
+// CheckBlackUser 判断用户是否为黑名单用户
+func CheckBlackUser(params BlackReq) (ApiResponse[any], error) {
+
+ formParams := map[string]string{
+ "number": params.Number,
+ "type": params.Type,
+ "Timestamp": params.Timestamp,
+ "username": params.UserID,
+ "sign": params.UserSign,
+ }
+
+ body, err := httpUtil.NewRequest().SendFormData(blackUserUrl, nil, formParams)
+ if err != nil {
+ return ApiResponse[any]{}, err
+ }
+
+ // 解析 JSON 响应
+ var apiResponse ApiResponse[any]
+ err = json.Unmarshal([]byte(body), &apiResponse)
+ if err != nil {
+ fmt.Println("解析响应体时发生错误:", err)
+ return ApiResponse[any]{}, err
+ }
+
+ return apiResponse, nil
+}
+
+// CheckBlackAgent 判断用户是否为黑名单代理
+func CheckBlackAgent(params BlackReq) (ApiResponse[any], error) {
+
+ formParams := map[string]string{
+ "number": params.Number,
+ "type": params.Type,
+ "username": params.UserID,
+ "sign": params.UserSign,
+ }
+
+ body, err := httpUtil.NewRequest().SendFormData(blackAgentUrl, nil, formParams)
+ if err != nil {
+ return ApiResponse[any]{}, err
+ }
+
+ // 解析 JSON 响应
+ var apiResponse ApiResponse[any]
+ err = json.Unmarshal([]byte(body), &apiResponse)
+ if err != nil {
+ fmt.Println("解析响应体时发生错误:", err)
+ return ApiResponse[any]{}, err
+ }
+
+ return apiResponse, nil
+}
diff --git a/pkg/util/172/goods_v2.go b/pkg/util/172/goods_v2.go
new file mode 100644
index 0000000..7602ede
--- /dev/null
+++ b/pkg/util/172/goods_v2.go
@@ -0,0 +1,50 @@
+package _72
+
+import (
+ "encoding/json"
+ "fmt"
+ "hk/pkg/util/httpUtil"
+ "time"
+)
+
+const ()
+
+// ProductV2Resp 定义商品套餐的结构
+type ProductV2Resp struct {
+ ProductID int64 `json:"productID"`
+ ProductName string `json:"productName"`
+ MainPic string `json:"mainPic"`
+ Area string `json:"area"`
+ DisableArea string `json:"disableArea"`
+ LittlePicture string `json:"littlepicture"`
+ NetAddr string `json:"netAddr"`
+ Flag bool `json:"flag"`
+ NumberSel int `json:"numberSel"`
+}
+
+// GetProductV2 获取单个商品信息
+func GetProductV2(params GoodsReq) (ApiResponse[[]ProductV2Resp], error) {
+ // 设置时间戳
+ timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 当前时间戳,长度为10位
+ params.Timestamp = timestamp
+ // 生成 MD5 签名
+ userSign := generateMD5SignV2(params, params.UserSign)
+ formParams := map[string]string{
+ "ProductID": params.ProductID,
+ "user_id": params.UserID,
+ "Timestamp": params.Timestamp,
+ "user_sign": userSign,
+ }
+
+ body, err := httpUtil.NewRequest().SendFormData(productsV2Url, nil, formParams)
+
+ // 解析 JSON 响应
+ var apiResponse ApiResponse[[]ProductV2Resp]
+ err = json.Unmarshal([]byte(body), &apiResponse)
+ if err != nil {
+ return ApiResponse[[]ProductV2Resp]{}, fmt.Errorf("解析响应体时发生错误: %v", err)
+ }
+
+ // 返回解析后的响应
+ return apiResponse, nil
+}
diff --git a/pkg/util/172/pick_number.go b/pkg/util/172/pick_number.go
new file mode 100644
index 0000000..2ff0b5e
--- /dev/null
+++ b/pkg/util/172/pick_number.go
@@ -0,0 +1,53 @@
+package _72
+
+import (
+ "encoding/json"
+ "fmt"
+ "hk/pkg/util/httpUtil"
+)
+
+const ()
+
+type PickNumberReq struct {
+ City string `json:"city"` // 市
+ ProductID string `json:"prodID"` // Y 商品ID
+ Province string `json:"province"` // 省
+ SearchCategory string `json:"searchCategory"` // 查询分类 默认3
+ SearchValue string `json:"searchValue"` // 查询关键字2-4位
+ BaseParams
+}
+
+type PickNumberResp struct {
+ Type string `json:"type"` // 号码类型 普通
+ Number string `json:"number"` // 号码
+ NumberId string `json:"numberId"` // 号码ID
+ NumberPoolId string `json:"numberPoolId"` // 号码池ID
+
+}
+
+// GetPickNumber 商品选号
+func GetPickNumber(params PickNumberReq) (ApiResponse[[]PickNumberResp], error) {
+
+ formParams := map[string]string{
+ "city": params.City,
+ "prodID": params.ProductID,
+ "province": params.Province,
+ "searchCategory": "3",
+ "searchValue": params.SearchValue,
+ "Timestamp": params.Timestamp,
+ "user_id": params.UserID,
+ "user_sign": params.UserSign,
+ }
+
+ body, err := httpUtil.NewRequest().SendFormData(pickNumberUrl, nil, formParams)
+
+ // 解析 JSON 响应
+ var apiResponse ApiResponse[[]PickNumberResp]
+ err = json.Unmarshal([]byte(body), &apiResponse)
+ if err != nil {
+ return ApiResponse[[]PickNumberResp]{}, fmt.Errorf("解析响应体时发生错误: %v", err)
+ }
+
+ // 返回解析后的响应
+ return apiResponse, nil
+}
diff --git a/pkg/util/httpUtil/post_request.go b/pkg/util/httpUtil/post_request.go
new file mode 100644
index 0000000..c3d9d01
--- /dev/null
+++ b/pkg/util/httpUtil/post_request.go
@@ -0,0 +1,140 @@
+package httpUtil
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+)
+
+// Request 封装的 POST 请求工具类
+type Request struct {
+ client *http.Client
+}
+
+// NewRequest 创建一个新的 PostRequest 实例
+func NewRequest() *Request {
+ return &Request{
+ client: &http.Client{
+ Timeout: 10 * time.Second, // 设置请求超时时间
+ },
+ }
+}
+
+// SendJSON 发送一个 JSON 格式的 POST 请求
+func (p *Request) SendJSON(urlPath string, headers map[string]string, body interface{}) (string, error) {
+ // 将请求体转为 JSON
+ requestBody, err := json.Marshal(body)
+ if err != nil {
+ return "", fmt.Errorf("无法编码 JSON 请求体: %v", err)
+ }
+
+ // 创建 HTTP 请求
+ req, err := http.NewRequest("POST", urlPath, bytes.NewBuffer(requestBody))
+ if err != nil {
+ return "", fmt.Errorf("无法创建请求: %v", err)
+ }
+
+ // 设置请求头
+ req.Header.Set("Content-Type", "application/json")
+ for key, value := range headers {
+ req.Header.Set(key, value)
+ }
+
+ // 发送请求
+ resp, err := p.client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("发送请求失败: %v", err)
+ }
+ defer resp.Body.Close()
+
+ // 读取响应内容
+ respBody, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("读取响应体失败: %v", err)
+ }
+
+ // 返回响应内容
+ return string(respBody), nil
+}
+
+// SendFormData 发送一个 form-data 格式的 POST 请求
+func (p *Request) SendFormData(urlPath string, headers map[string]string, params map[string]string) (string, error) {
+ // 将参数拼接为表单数据
+ formData := url.Values{}
+ for key, value := range params {
+ formData.Set(key, value)
+ }
+
+ // 创建 HTTP 请求
+ req, err := http.NewRequest("POST", urlPath, strings.NewReader(formData.Encode()))
+ if err != nil {
+ return "", fmt.Errorf("无法创建请求: %v", err)
+ }
+
+ // 设置请求头
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ for key, value := range headers {
+ req.Header.Set(key, value)
+ }
+
+ // 发送请求
+ resp, err := p.client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("发送请求失败: %v", err)
+ }
+ defer resp.Body.Close()
+
+ // 读取响应内容
+ respBody, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("读取响应体失败: %v", err)
+ }
+
+ // 返回响应内容
+ return string(respBody), nil
+}
+
+// SendGET 发送一个 GET 请求
+func (p *Request) SendGET(urlPath string, headers map[string]string, params map[string]string) (string, error) {
+ // 如果有查询参数,拼接到 URL 中
+ if len(params) > 0 {
+ urlValues := url.Values{}
+ for key, value := range params {
+ urlValues.Set(key, value)
+ }
+ urlPath = fmt.Sprintf("%s?%s", urlPath, urlValues.Encode())
+ }
+
+ // 创建 HTTP GET 请求
+ req, err := http.NewRequest("GET", urlPath, nil)
+ if err != nil {
+ return "", fmt.Errorf("无法创建请求: %v", err)
+ }
+
+ // 设置请求头
+ for key, value := range headers {
+ req.Header.Set(key, value)
+ }
+
+ // 发送请求
+ resp, err := p.client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("发送请求失败: %v", err)
+ }
+ defer resp.Body.Close()
+
+ // 读取响应内容
+ respBody, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("读取响应体失败: %v", err)
+ }
+
+ // 返回响应内容
+ return string(respBody), nil
+}
diff --git a/pkg/util/httpUtil/post_request_test.go b/pkg/util/httpUtil/post_request_test.go
new file mode 100644
index 0000000..8655968
--- /dev/null
+++ b/pkg/util/httpUtil/post_request_test.go
@@ -0,0 +1,43 @@
+package httpUtil
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestRequest(t *testing.T) {
+ // 创建 PostRequest 实例
+ postRequest := NewRequest()
+
+ // 示例:发送 JSON 请求
+ url := "https://example.com/api"
+ headers := map[string]string{
+ "Authorization": "Bearer your_token",
+ }
+ body := map[string]interface{}{
+ "key1": "value1",
+ "key2": "value2",
+ }
+
+ // 发送 JSON 请求
+ resp, err := postRequest.SendJSON(url, headers, body)
+ if err != nil {
+ fmt.Println("发送请求失败:", err)
+ return
+ }
+
+ fmt.Println("响应内容:", resp)
+
+ // 示例:发送 form-data 请求
+ formParams := map[string]string{
+ "user_id": "your_user_id",
+ "product_id": "12345",
+ }
+ resp2, err := postRequest.SendFormData(url, headers, formParams)
+ if err != nil {
+ fmt.Println("发送 form-data 请求失败:", err)
+ return
+ }
+
+ fmt.Println("响应内容:", resp2)
+}
diff --git a/pkg/util/strUtil/strUtil.go b/pkg/util/strUtil/strUtil.go
new file mode 100644
index 0000000..92434fd
--- /dev/null
+++ b/pkg/util/strUtil/strUtil.go
@@ -0,0 +1,58 @@
+package strUtil
+
+import (
+ "database/sql"
+ "regexp"
+ "strings"
+)
+
+// JoinStrings 字符串拼接
+func JoinStrings(separator string, elems ...string) string {
+ return strings.Join(elems, separator)
+}
+
+// ValidString sql.NullString 转 string
+func ValidString(sqlString sql.NullString) string {
+ if sqlString.Valid {
+ return sqlString.String
+ }
+ return ""
+}
+
+// StringToNullString string 转 sql.NullString
+func StringToNullString(str string) sql.NullString {
+ return sql.NullString{
+ String: str,
+ Valid: str != "",
+ }
+}
+
+// ValidInt64 sql.NullInt64 转 int64
+func ValidInt64(sqlInt sql.NullInt64) int64 {
+ if sqlInt.Valid {
+ return sqlInt.Int64
+ }
+ return 0
+}
+
+// Int64ToNullInt64 StringToNullString int64 转 sql.NullInt64
+func Int64ToNullInt64(value int64) sql.NullInt64 {
+ return sql.NullInt64{
+ Int64: value,
+ Valid: value >= 0,
+ }
+}
+
+// ValidBool sql.NullBool 转 bool
+func ValidBool(sqlBool sql.NullBool) bool {
+ if sqlBool.Valid {
+ return sqlBool.Bool
+ }
+ return false
+}
+
+// MatchRegexp 正则匹配
+func MatchRegexp(pattern string, value string) bool {
+ r := regexp.MustCompile(pattern)
+ return r.MatchString(value)
+}
diff --git a/pkg/util/tiktok/tiktok.go b/pkg/util/tiktok/tiktok.go
new file mode 100644
index 0000000..38dc601
--- /dev/null
+++ b/pkg/util/tiktok/tiktok.go
@@ -0,0 +1,151 @@
+package tiktok
+
+import (
+ "encoding/json"
+ "fmt"
+ "hk/pkg/util/httpUtil"
+ "strings"
+)
+
+type tiktokResp struct {
+ Code int64 `json:"code"`
+ Data tiktokData `json:"data"`
+}
+
+type tiktokData struct {
+ ID string `json:"id"`
+ AwesomeID string `json:"aweme_id"`
+ Region string `json:"region"`
+ Title string `json:"title"`
+ Cover string `json:"cover"`
+ AiDynamicCover string `json:"ai_dynamic_cover"` // 动态封面
+ OriginCover string `json:"origin_cover"` // 静态封面
+ Duration int `json:"duration"`
+ Play string `json:"play"` // 无水印视频
+ Wmplay string `json:"wmplay"` // 有水印视频
+ Size int `json:"size"`
+ WmSize int `json:"wm_size"`
+ Music string `json:"music"`
+ MusicInfo musicInfo `json:"music_info"`
+ PlayCount int `json:"play_count"`
+ DiggCount int `json:"digg_count"`
+ CommentCount int `json:"comment_count"`
+ ShareCount int `json:"share_count"`
+ DownloadCount int `json:"download_count"`
+ CollectCount int `json:"collect_count"`
+ CreateTime int `json:"create_time"`
+ AnchorsExtras string `json:"anchors_extras"`
+ IsAd bool `json:"is_ad"`
+ CommercialVideoInfo string `json:"commercial_video_info"`
+ ItemCommentSettings int `json:"item_comment_settings"`
+ Author authorDTO `json:"author"`
+}
+
+type musicInfo struct {
+ ID string `json:"id"`
+ Title string `json:"title"`
+ Play string `json:"play"` // 背景音乐
+ Cover string `json:"cover"`
+ Author string `json:"author"`
+ Original bool `json:"original"`
+ Duration int `json:"duration"`
+ Album string `json:"album"`
+}
+
+type authorDTO struct {
+ ID string `json:"id"`
+ UniqueID string `json:"unique_id"`
+ Nickname string `json:"nickname"`
+ Avatar string `json:"avatar"`
+}
+
+type VideoInfoResponse struct {
+ AuthorID string `json:"authorId"` // 作者ID
+ AuthorUniqueID string `json:"authorUniqueId"` // 作者账号
+ AuthorAvatar string `json:"authorAvatar"` // 作者头像
+ AuthorNickname string `json:"authorNickname"` // 作者昵称
+
+ VideoID string `json:"videoId"` // 视频ID
+ VideoTitle string `json:"videoTitle"` // 作品描述
+ OriginCover string `json:"originCover"` // 静态封面
+ DynamicCover string `json:"dynamicCover"` // 动态封面
+ DestinationURL string `json:"destinationUrl"` // 无水印下载地址
+ WatermarkVideoURL string `json:"watermarkVideoUrl"` // 有水印下载地址
+
+ MusicURL string `json:"musicUrl"` // 背景音乐链接
+
+ OriginalURL string `json:"originalUrl"` // 原始下载链接
+ DownloaderURL string `json:"downloaderUrl"` // 解析后下载地址
+ CreateTime string `json:"createTime"` // 创建时间
+ Result bool `json:"result"` // 结果
+}
+
+func GetTiktokVideoInfo(videoUrl string) (*VideoInfoResponse, error) {
+ if len(videoUrl) <= 0 {
+ return nil, nil
+ }
+
+ // 解析视频地址
+ // 定义需要匹配的前缀
+ prefixes := []string{
+ "https://www.tiktok.com/t/",
+ "https://m.tiktok.com/v/",
+ "https://vm.tiktok.com/",
+ "https://vt.tiktok.com/",
+ "https://dltik.com/",
+ }
+
+ // 检查是否有匹配的前缀
+ for _, prefix := range prefixes {
+ if strings.HasPrefix(videoUrl, prefix) {
+ return nil, nil
+ }
+ }
+
+ // 获取视频信息
+ var url = "https://tiktok-download-without-watermark.p.rapidapi.com/analysis?url=" + videoUrl
+ headers := map[string]string{
+ "x-rapidapi-host": "tiktok-download-without-watermark.p.rapidapi.com",
+ "x-rapidapi-key": "4a5bbe21bfmshbd98e7404b74063p19ba22jsne87a37e3b675",
+ }
+
+ body, err := httpUtil.NewRequest().SendGET(url, headers, nil)
+ if err != nil || len(body) <= 0 {
+ return nil, err
+ }
+
+ var tiktokResp tiktokResp
+ err = json.Unmarshal([]byte(body), &tiktokResp)
+ if err != nil {
+ fmt.Println("解析响应体时发生错误:", err)
+ return nil, err
+ }
+ // 比对 statusCode 是否等于0
+ if tiktokResp.Code != 0 {
+ return nil, nil
+ }
+ var videoInfo = VideoInfoResponse{}
+
+ // 作者信息
+ videoInfo.AuthorID = tiktokResp.Data.Author.ID
+ videoInfo.AuthorAvatar = tiktokResp.Data.Author.Avatar
+ videoInfo.AuthorUniqueID = tiktokResp.Data.Author.UniqueID
+ videoInfo.AuthorNickname = tiktokResp.Data.Author.Nickname
+
+ videoInfo.VideoID = tiktokResp.Data.ID
+ videoInfo.VideoTitle = tiktokResp.Data.Title
+ videoInfo.OriginCover = tiktokResp.Data.OriginCover
+ videoInfo.DynamicCover = tiktokResp.Data.AiDynamicCover
+ videoInfo.DestinationURL = tiktokResp.Data.Play
+ videoInfo.WatermarkVideoURL = tiktokResp.Data.Wmplay
+
+ videoInfo.MusicURL = tiktokResp.Data.MusicInfo.Play
+
+ videoInfo.OriginalURL = videoUrl
+ videoInfo.DownloaderURL = videoUrl
+
+ //videoInfo.CreateTime = tiktokResp.Data.CreateTime
+
+ videoInfo.Result = true
+ return &videoInfo, nil
+}
diff --git a/pkg/util/tiktok/tiktok_test.go b/pkg/util/tiktok/tiktok_test.go
new file mode 100644
index 0000000..f7dbad2
--- /dev/null
+++ b/pkg/util/tiktok/tiktok_test.go
@@ -0,0 +1,7 @@
+package tiktok
+
+import "testing"
+
+func TestTikTok(test *testing.T) {
+ GetTiktokVideoInfo("https://www.tiktok.com/@baotramthieu/video/6887554215598689538")
+}
diff --git a/service/api/Dockerfile b/service/api/Dockerfile
new file mode 100644
index 0000000..ca45876
--- /dev/null
+++ b/service/api/Dockerfile
@@ -0,0 +1,33 @@
+FROM golang:alpine as builder
+# 设置工作目录
+WORKDIR /hk
+# 将当前目录内容拷到工作目录 (相对路径)
+COPY ../../../ .
+
+# 配置 golang 环境
+RUN go env -w GO111MODULE=on \
+ && go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct \
+ && go mod tidy \
+ && go build -o main ./service/api/api.go
+
+# 使用更小的基础镜像
+FROM alpine:latest
+
+# 设置工作目录
+WORKDIR /hk
+ENV WORK_PATH /hk
+
+WORKDIR ${WORK_PATH}
+
+# 从构建阶段复制二进制文件
+COPY --from=builder ${WORK_PATH}/main .
+COPY --from=0 ${WORK_PATH}/service/api/etc/api.yaml ./config/
+
+# 暴露端口
+EXPOSE 8888
+
+# 如果不使用上面的方式需要打开下面这行注释
+# ENTRYPOINT ./main -c config.docker.toml
+
+###############################################
+CMD ["./main","-f","./config/api.yaml"]
\ No newline at end of file
diff --git a/service/api/api.go b/service/api/api.go
new file mode 100644
index 0000000..46d5e32
--- /dev/null
+++ b/service/api/api.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "hk/service/api/internal/cmd"
+ "hk/service/api/internal/config"
+ "hk/service/api/internal/handler"
+ "hk/service/api/internal/svc"
+
+ "github.com/zeromicro/go-zero/core/conf"
+ "github.com/zeromicro/go-zero/rest"
+)
+
+var configFile = flag.String("f", "service/api/etc/api.yaml", "the config file")
+
+func main() {
+ flag.Parse()
+
+ var c config.Config
+ conf.MustLoad(*configFile, &c)
+
+ server := rest.MustNewServer(c.RestConf)
+
+ defer server.Stop()
+
+ ctx := svc.NewServiceContext(c)
+ handler.RegisterHandlers(server, ctx)
+
+ cmd.Execute(ctx)
+
+ fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
+ server.Start()
+}
diff --git a/service/api/etc/api.yaml b/service/api/etc/api.yaml
new file mode 100644
index 0000000..eedc39c
--- /dev/null
+++ b/service/api/etc/api.yaml
@@ -0,0 +1,22 @@
+Name: HK
+Host: 0.0.0.0
+Port: 8888
+
+# 控制go-zero提供的中间件是否启用
+# Middlewares:
+# Breaker: false
+# Shedding: false
+# Metrics: false
+Log:
+ Stat: false
+
+Mysql:
+ DataSource: root:G6fB2okoPstKvA6R@tcp(110.40.44.75:3306)/hk?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
+
+Auth:
+ AccessSecret: uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl
+ AccessExpire: 86400
+
+Redis:
+ Host: 192.168.1.13:6379
+ Type: node
\ No newline at end of file
diff --git a/service/api/internal/cmd/config_api_list.go b/service/api/internal/cmd/config_api_list.go
new file mode 100644
index 0000000..612a24c
--- /dev/null
+++ b/service/api/internal/cmd/config_api_list.go
@@ -0,0 +1,145 @@
+package cmd
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "hk/model/config_api"
+ "hk/model/goods_info"
+ "hk/model/goods_status"
+ _73 "hk/pkg/util/172"
+ "hk/pkg/util/strUtil"
+ "strconv"
+ "time"
+)
+
+func configApiList() {
+ configApiInfo, err := svcCtx.ConfigApiModel.FindList(context.Background())
+ if err != nil {
+ fmt.Println(err)
+ }
+ if configApiInfo == nil {
+ return
+ }
+ for _, item := range configApiInfo {
+ switch item.Type {
+ case "0":
+ getGoodsStatus(item)
+ updateGoodsStatus(item)
+ }
+ }
+}
+
+func configApiListv1() {
+ configApiInfo, err := svcCtx.ConfigApiModel.FindList(context.Background())
+ if err != nil {
+ fmt.Println(err)
+ }
+ if configApiInfo == nil {
+ return
+ }
+ for _, item := range configApiInfo {
+ switch item.Type {
+ case "0":
+ addGoodsInfo(item)
+ }
+ }
+}
+
+func addGoodsInfo(configApi config_api.ConfigApi) {
+ ids, err := svcCtx.GoodsStatusModel.FindNotIdOne(context.Background(), configApi.Id)
+ if err != nil || ids <= 0 {
+ return
+ }
+
+ req := _73.GoodsReq{
+ ProductID: strconv.FormatInt(ids, 10),
+ BaseParams: _73.BaseParams{
+ UserID: strUtil.ValidString(configApi.Key),
+ UserSign: strUtil.ValidString(configApi.Secret),
+ },
+ }
+
+ result, err := _73.GetProductV2(req)
+ if err != nil {
+ return
+ }
+
+ if result.Code != 0 || len(result.Data) <= 0 {
+ return
+ }
+ data := result.Data[0]
+ status := "0"
+ if data.Flag {
+ status = "1"
+ }
+ goodsStatus := goods_info.GoodsInfo{
+ Name: data.ProductName,
+ Type: "0",
+ MainPic: data.MainPic,
+ LittlePicture: data.LittlePicture,
+ NetAddr: data.NetAddr,
+ Area: data.Area,
+ DisableArea: data.DisableArea,
+ DisableAge: "",
+ DisableContract: "",
+ Notes: sql.NullString{},
+ ApiId: strUtil.Int64ToNullInt64(configApi.Id),
+ ApiProductId: strUtil.Int64ToNullInt64(data.ProductID),
+ NumberSel: strconv.Itoa(data.NumberSel),
+ Status: status,
+ CreateTime: time.Now(),
+ UpdateTime: time.Now(),
+ Remarks: sql.NullString{},
+ }
+ svcCtx.GoodsInfoModel.Insert(context.Background(), &goodsStatus)
+}
+
+func updateGoodsStatus(item config_api.ConfigApi) {
+ ids, err := svcCtx.GoodsStatusModel.FindUpList(context.Background(), item.Id)
+ if err != nil {
+ return
+ }
+ if len(ids) <= 0 {
+ return
+ }
+ svcCtx.GoodsStatusModel.UpdateDownByIds(context.Background(), ids)
+}
+
+func getGoodsStatus(configApi config_api.ConfigApi) {
+ req := _73.GoodsReq{
+ ProductID: "",
+ BaseParams: _73.BaseParams{
+ UserID: strUtil.ValidString(configApi.Key),
+ UserSign: strUtil.ValidString(configApi.Secret),
+ },
+ }
+
+ result, err := _73.GetProduct(req)
+ if err != nil {
+ return
+ }
+
+ if result.Code == 0 {
+ var goodsStatusList []goods_status.GoodsStatus
+ if len(result.Data) > 0 {
+ err = svcCtx.GoodsStatusModel.DeleteByApiId(context.Background(), configApi.Id)
+ if err != nil {
+ return
+ }
+ }
+ for _, item := range result.Data {
+ var status int64 = 0
+ if item.Flag == "上架中" {
+ status = 1
+ }
+ goodsStatus := goods_status.GoodsStatus{
+ ApiId: strUtil.Int64ToNullInt64(configApi.Id),
+ ApiProductId: strUtil.Int64ToNullInt64(item.ProductID),
+ Status: strUtil.Int64ToNullInt64(status),
+ }
+ svcCtx.GoodsStatusModel.Insert(context.Background(), &goodsStatus)
+ goodsStatusList = append(goodsStatusList, goodsStatus)
+ }
+ }
+}
diff --git a/service/api/internal/cmd/cronx/time.go b/service/api/internal/cmd/cronx/time.go
new file mode 100644
index 0000000..4c6fa3f
--- /dev/null
+++ b/service/api/internal/cmd/cronx/time.go
@@ -0,0 +1,46 @@
+package cronx
+
+// 每5秒
+func Every5s() string {
+ return "*/5 * * * * *"
+}
+
+// 每10秒
+func Every10s() string {
+ return "*/10 * * * * *"
+}
+
+// 每分钟
+func EveryMinute() string {
+ return "0 */1 * * * *"
+}
+
+// 每五分钟
+func EveryFiveMinute() string {
+ return "0 */5 * * * *"
+}
+
+// 每十分钟
+func EveryTenMinute() string {
+ return "0 */10 * * * *"
+}
+
+// 每半小时
+func EveryHalfHour() string {
+ return "0 0,30 * * * *"
+}
+
+// EveryHour 每小时
+func EveryHour() string {
+ return "0 0 * * * *"
+}
+
+// 每几分钟执行 1,2,3,26
+func Hourly(m string) string {
+ return "0 " + m + " * * * *"
+}
+
+// 每天几点执行
+func Daily(h string) string {
+ return "0 0 " + h + " * * *"
+}
diff --git a/service/api/internal/cmd/root.go b/service/api/internal/cmd/root.go
new file mode 100644
index 0000000..8ef06e8
--- /dev/null
+++ b/service/api/internal/cmd/root.go
@@ -0,0 +1,20 @@
+package cmd
+
+import (
+ "fmt"
+ "github.com/robfig/cron/v3"
+ "hk/service/api/internal/svc"
+)
+
+var svcCtx *svc.ServiceContext
+
+func Execute(ctx *svc.ServiceContext) {
+ svcCtx = ctx
+ c := cron.New(cron.WithSeconds())
+
+ ScheduleRun(c)
+ fmt.Println("定时任务启动...")
+ go c.Start()
+ defer c.Stop()
+ //select {}
+}
diff --git a/service/api/internal/cmd/schedule.go b/service/api/internal/cmd/schedule.go
new file mode 100644
index 0000000..39d10f1
--- /dev/null
+++ b/service/api/internal/cmd/schedule.go
@@ -0,0 +1,11 @@
+package cmd
+
+import (
+ "github.com/robfig/cron/v3"
+ "hk/service/api/internal/cmd/cronx"
+)
+
+func ScheduleRun(c *cron.Cron) {
+ c.AddFunc(cronx.EveryHour(), configApiList)
+ c.AddFunc(cronx.EveryTenMinute(), configApiListv1)
+}
diff --git a/service/api/internal/config/config.go b/service/api/internal/config/config.go
new file mode 100644
index 0000000..728434e
--- /dev/null
+++ b/service/api/internal/config/config.go
@@ -0,0 +1,21 @@
+package config
+
+import "github.com/zeromicro/go-zero/rest"
+
+type Config struct {
+ rest.RestConf
+
+ Auth struct {
+ AccessSecret string
+ AccessExpire int64
+ }
+
+ Mysql struct {
+ DataSource string
+ }
+
+ Redis struct {
+ Host string
+ Type string
+ }
+}
diff --git a/service/api/internal/handler/api/goodsdetailshandler.go b/service/api/internal/handler/api/goodsdetailshandler.go
new file mode 100644
index 0000000..6754e5c
--- /dev/null
+++ b/service/api/internal/handler/api/goodsdetailshandler.go
@@ -0,0 +1,28 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/zeromicro/go-zero/rest/httpx"
+ "hk/service/api/internal/logic/api"
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+)
+
+func GoodsDetailsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req types.GoodsDetailsReq
+ if err := httpx.Parse(r, &req); err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ return
+ }
+
+ l := api.NewGoodsDetailsLogic(r.Context(), svcCtx)
+ resp, err := l.GoodsDetails(&req)
+ if err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ } else {
+ httpx.OkJsonCtx(r.Context(), w, resp)
+ }
+ }
+}
diff --git a/service/api/internal/handler/api/goodslisthandler.go b/service/api/internal/handler/api/goodslisthandler.go
new file mode 100644
index 0000000..09938d0
--- /dev/null
+++ b/service/api/internal/handler/api/goodslisthandler.go
@@ -0,0 +1,28 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/zeromicro/go-zero/rest/httpx"
+ "hk/service/api/internal/logic/api"
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+)
+
+func GoodsListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req types.GoodsListReq
+ if err := httpx.Parse(r, &req); err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ return
+ }
+
+ l := api.NewGoodsListLogic(r.Context(), svcCtx)
+ resp, err := l.GoodsList(&req)
+ if err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ } else {
+ httpx.OkJsonCtx(r.Context(), w, resp)
+ }
+ }
+}
diff --git a/service/api/internal/handler/api/order172handler.go b/service/api/internal/handler/api/order172handler.go
new file mode 100644
index 0000000..ae0476d
--- /dev/null
+++ b/service/api/internal/handler/api/order172handler.go
@@ -0,0 +1,28 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/zeromicro/go-zero/rest/httpx"
+ "hk/service/api/internal/logic/api"
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+)
+
+func Order172Handler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req types.PushReq
+ if err := httpx.Parse(r, &req); err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ return
+ }
+
+ l := api.NewOrder172Logic(r.Context(), svcCtx)
+ resp, err := l.Order172(&req)
+ if err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ } else {
+ httpx.OkJsonCtx(r.Context(), w, resp)
+ }
+ }
+}
diff --git a/service/api/internal/handler/api/tiktokinfohandler.go b/service/api/internal/handler/api/tiktokinfohandler.go
new file mode 100644
index 0000000..e5492c9
--- /dev/null
+++ b/service/api/internal/handler/api/tiktokinfohandler.go
@@ -0,0 +1,28 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/zeromicro/go-zero/rest/httpx"
+ "hk/service/api/internal/logic/api"
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+)
+
+func TiktokInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req types.TiktokReq
+ if err := httpx.Parse(r, &req); err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ return
+ }
+
+ l := api.NewTiktokInfoLogic(r.Context(), svcCtx)
+ resp, err := l.TiktokInfo(&req)
+ if err != nil {
+ httpx.ErrorCtx(r.Context(), w, err)
+ } else {
+ httpx.OkJsonCtx(r.Context(), w, resp)
+ }
+ }
+}
diff --git a/service/api/internal/handler/routes.go b/service/api/internal/handler/routes.go
new file mode 100644
index 0000000..f7dd4cb
--- /dev/null
+++ b/service/api/internal/handler/routes.go
@@ -0,0 +1,44 @@
+// Code generated by goctl. DO NOT EDIT.
+// goctl 1.7.6
+
+package handler
+
+import (
+ "net/http"
+
+ api "hk/service/api/internal/handler/api"
+ "hk/service/api/internal/svc"
+
+ "github.com/zeromicro/go-zero/rest"
+)
+
+func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
+ server.AddRoutes(
+ rest.WithMiddlewares(
+ []rest.Middleware{serverCtx.RealIPMiddleware},
+ []rest.Route{
+ {
+ Method: http.MethodGet,
+ Path: "/goods/:id",
+ Handler: api.GoodsDetailsHandler(serverCtx),
+ },
+ {
+ Method: http.MethodGet,
+ Path: "/goods/list",
+ Handler: api.GoodsListHandler(serverCtx),
+ },
+ {
+ Method: http.MethodPost,
+ Path: "/push/order172",
+ Handler: api.Order172Handler(serverCtx),
+ },
+ {
+ Method: http.MethodPost,
+ Path: "/tiktok/getVideoInfo",
+ Handler: api.TiktokInfoHandler(serverCtx),
+ },
+ }...,
+ ),
+ rest.WithPrefix("/api"),
+ )
+}
diff --git a/service/api/internal/logic/api/goodsdetailslogic.go b/service/api/internal/logic/api/goodsdetailslogic.go
new file mode 100644
index 0000000..898bdb5
--- /dev/null
+++ b/service/api/internal/logic/api/goodsdetailslogic.go
@@ -0,0 +1,48 @@
+package api
+
+import (
+ "context"
+ "hk/pkg/util/strUtil"
+
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+
+ "github.com/zeromicro/go-zero/core/logx"
+)
+
+type GoodsDetailsLogic struct {
+ logx.Logger
+ ctx context.Context
+ svcCtx *svc.ServiceContext
+}
+
+func NewGoodsDetailsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GoodsDetailsLogic {
+ return &GoodsDetailsLogic{
+ Logger: logx.WithContext(ctx),
+ ctx: ctx,
+ svcCtx: svcCtx,
+ }
+}
+
+func (l *GoodsDetailsLogic) GoodsDetails(req *types.GoodsDetailsReq) (resp *types.GoodsDetailsResp, err error) {
+ if req.Id <= 0 {
+ return nil, nil
+ }
+ goods, err := l.svcCtx.GoodsInfoModel.FindOne(l.ctx, req.Id)
+ if err != nil || goods == nil || goods.Status == "0" {
+ return nil, err
+ }
+ resp = &types.GoodsDetailsResp{
+ Data: types.GoodsItem{
+ Id: goods.Id,
+ Name: goods.Name,
+ MainPic: goods.MainPic,
+ DisableAge: goods.DisableAge,
+ UniFlow: goods.UniFlow,
+ DirFlow: goods.DirFlow,
+ TalkTime: goods.TalkTime,
+ Remarks: strUtil.ValidString(goods.Remarks),
+ },
+ }
+ return resp, nil
+}
diff --git a/service/api/internal/logic/api/goodslistlogic.go b/service/api/internal/logic/api/goodslistlogic.go
new file mode 100644
index 0000000..145ca69
--- /dev/null
+++ b/service/api/internal/logic/api/goodslistlogic.go
@@ -0,0 +1,50 @@
+package api
+
+import (
+ "context"
+ "hk/pkg/util/strUtil"
+
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+
+ "github.com/zeromicro/go-zero/core/logx"
+)
+
+type GoodsListLogic struct {
+ logx.Logger
+ ctx context.Context
+ svcCtx *svc.ServiceContext
+}
+
+func NewGoodsListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GoodsListLogic {
+ return &GoodsListLogic{
+ Logger: logx.WithContext(ctx),
+ ctx: ctx,
+ svcCtx: svcCtx,
+ }
+}
+
+func (l *GoodsListLogic) GoodsList(req *types.GoodsListReq) (resp *types.GoodsListResp, err error) {
+ goods, err := l.svcCtx.GoodsInfoModel.GetGoodsIndex(l.ctx, req.Type)
+ if err != nil || len(goods) == 0 {
+ return nil, err
+ }
+ var goodsList []types.GoodsItem
+ for _, item := range goods {
+ good := types.GoodsItem{
+ Id: item.Id,
+ Name: item.Name,
+ MainPic: item.MainPic,
+ DisableAge: item.DisableAge,
+ UniFlow: item.UniFlow,
+ DirFlow: item.DirFlow,
+ TalkTime: item.TalkTime,
+ Remarks: strUtil.ValidString(item.Remarks),
+ }
+ goodsList = append(goodsList, good)
+ }
+ resp = &types.GoodsListResp{
+ Data: goodsList,
+ }
+ return resp, nil
+}
diff --git a/service/api/internal/logic/api/order172logic.go b/service/api/internal/logic/api/order172logic.go
new file mode 100644
index 0000000..11404e0
--- /dev/null
+++ b/service/api/internal/logic/api/order172logic.go
@@ -0,0 +1,30 @@
+package api
+
+import (
+ "context"
+
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+
+ "github.com/zeromicro/go-zero/core/logx"
+)
+
+type Order172Logic struct {
+ logx.Logger
+ ctx context.Context
+ svcCtx *svc.ServiceContext
+}
+
+func NewOrder172Logic(ctx context.Context, svcCtx *svc.ServiceContext) *Order172Logic {
+ return &Order172Logic{
+ Logger: logx.WithContext(ctx),
+ ctx: ctx,
+ svcCtx: svcCtx,
+ }
+}
+
+func (l *Order172Logic) Order172(req *types.PushReq) (resp *types.Push172Resp, err error) {
+ // todo: add your logic here and delete this line
+
+ return
+}
diff --git a/service/api/internal/logic/api/tiktokinfologic.go b/service/api/internal/logic/api/tiktokinfologic.go
new file mode 100644
index 0000000..f41b181
--- /dev/null
+++ b/service/api/internal/logic/api/tiktokinfologic.go
@@ -0,0 +1,53 @@
+package api
+
+import (
+ "context"
+ "hk/pkg/util/tiktok"
+
+ "hk/service/api/internal/svc"
+ "hk/service/api/internal/types"
+
+ "github.com/zeromicro/go-zero/core/logx"
+)
+
+type TiktokInfoLogic struct {
+ logx.Logger
+ ctx context.Context
+ svcCtx *svc.ServiceContext
+}
+
+func NewTiktokInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TiktokInfoLogic {
+ return &TiktokInfoLogic{
+ Logger: logx.WithContext(ctx),
+ ctx: ctx,
+ svcCtx: svcCtx,
+ }
+}
+
+func (l *TiktokInfoLogic) TiktokInfo(req *types.TiktokReq) (resp *types.TiktokResp, err error) {
+ if len(req.VideoUrl) <= 0 {
+ return nil, nil
+ }
+ tiktokInfo, err := tiktok.GetTiktokVideoInfo(req.VideoUrl)
+ if err != nil || tiktokInfo == nil {
+ return nil, nil
+ }
+ resp = &types.TiktokResp{
+ AuthorID: tiktokInfo.AuthorID,
+ AuthorAvatar: tiktokInfo.AuthorAvatar,
+ AuthorUniqueID: tiktokInfo.AuthorUniqueID,
+ AuthorNickname: tiktokInfo.AuthorNickname,
+ VideoID: tiktokInfo.VideoID,
+ VideoTitle: tiktokInfo.VideoTitle,
+ OriginCover: tiktokInfo.OriginCover,
+ DynamicCover: tiktokInfo.DynamicCover,
+ DestinationURL: tiktokInfo.DestinationURL,
+ WatermarkVideoURL: tiktokInfo.WatermarkVideoURL,
+ MusicURL: tiktokInfo.MusicURL,
+ OriginalURL: tiktokInfo.OriginalURL,
+ DownloaderURL: tiktokInfo.DownloaderURL,
+ CreateTime: tiktokInfo.CreateTime,
+ Result: true,
+ }
+ return resp, nil
+}
diff --git a/service/api/internal/middleware/realipmiddleware.go b/service/api/internal/middleware/realipmiddleware.go
new file mode 100644
index 0000000..fb32431
--- /dev/null
+++ b/service/api/internal/middleware/realipmiddleware.go
@@ -0,0 +1,22 @@
+package middleware
+
+import (
+ "context"
+ "hk/pkg/middleware"
+ "net/http"
+)
+
+type RealIPMiddleware struct {
+}
+
+func NewRealIPMiddleware() *RealIPMiddleware {
+ return &RealIPMiddleware{}
+}
+
+func (m *RealIPMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ ipaddress := middleware.GetRealIP(r)
+ ctx := context.WithValue(r.Context(), "ip", ipaddress)
+ next(w, r.WithContext(ctx))
+ }
+}
diff --git a/service/api/internal/svc/servicecontext.go b/service/api/internal/svc/servicecontext.go
new file mode 100644
index 0000000..248683b
--- /dev/null
+++ b/service/api/internal/svc/servicecontext.go
@@ -0,0 +1,29 @@
+package svc
+
+import (
+ "github.com/zeromicro/go-zero/core/stores/sqlx"
+ "github.com/zeromicro/go-zero/rest"
+ "hk/model/config_api"
+ "hk/model/goods_info"
+ "hk/model/goods_status"
+ "hk/service/api/internal/config"
+ "hk/service/api/internal/middleware"
+)
+
+type ServiceContext struct {
+ Config config.Config
+ RealIPMiddleware rest.Middleware
+ ConfigApiModel config_api.ConfigApiModel
+ GoodsStatusModel goods_status.GoodsStatusModel
+ GoodsInfoModel goods_info.GoodsInfoModel
+}
+
+func NewServiceContext(c config.Config) *ServiceContext {
+ return &ServiceContext{
+ Config: c,
+ RealIPMiddleware: middleware.NewRealIPMiddleware().Handle,
+ ConfigApiModel: config_api.NewConfigApiModel(sqlx.NewMysql(c.Mysql.DataSource)),
+ GoodsStatusModel: goods_status.NewGoodsStatusModel(sqlx.NewMysql(c.Mysql.DataSource)),
+ GoodsInfoModel: goods_info.NewGoodsInfoModel(sqlx.NewMysql(c.Mysql.DataSource)),
+ }
+}
diff --git a/service/api/internal/types/types.go b/service/api/internal/types/types.go
new file mode 100644
index 0000000..9a753f3
--- /dev/null
+++ b/service/api/internal/types/types.go
@@ -0,0 +1,75 @@
+// Code generated by goctl. DO NOT EDIT.
+// goctl 1.7.6
+
+package types
+
+type GoodsDetailsReq struct {
+ Id int64 `path:"id"`
+}
+
+type GoodsDetailsResp struct {
+ Data GoodsItem `json:"data"` // Y 商品详情
+}
+
+type GoodsItem struct {
+ Id int64 `json:"id"` // Y 商品ID
+ Name string `json:"name"` // Y 商品信息
+ MainPic string `json:"mainPic"` // Y 主图
+ DisableAge string `json:"disableAge"` // Y 年龄限制
+ UniFlow string `json:"uniFlow"` // Y 通用流量
+ DirFlow string `json:"dirFlow"` // Y 定向流量
+ TalkTime string `json:"talkTime"` // Y 通话时长
+ Remarks string `json:"remarks"` // Y 备注
+}
+
+type GoodsListReq struct {
+ Type string `json:"type":"type,default=0"` // Y 运营商 0:全部 1:电信 2:联通 3:移动 4:光电
+}
+
+type GoodsListResp struct {
+ Data []GoodsItem `json:"data"`
+}
+
+type Order172 struct {
+ OrderNo string `json:"OrderNo"` // Y 合作方订单号
+ OrderNo172 string `json:"OrderNo172"` // Y 172平台订单号,请求头sign里加密的是这个号码。
+ OrderStatus string `json:"OrderStatus"` // Y 订单状态:已发货,已完成,审核不通过,已取消,已撤单
+ ThirdPhone string `json:"ThirdPhone"` // N 办理号码
+ ExpressName string `json:"ExpressName"` // N 物流公司
+ ExpressCode string `json:"ExpressCode"` // N 物流单号
+ CardStatus string `json:"CardStatus"` // N 激活状态:已激活,未激活,可能为Null
+ ActiveTime string `json:"ActiveTime"` // N 激活时间格式yyyy-MM-dd HH:mm:ss,可能为Null
+ Remark string `json:"Remark"` // N 备注失败原因
+}
+
+type Push172Resp struct {
+ Code int64 `json:"code",options=-1|0` // Y 响应码 -1错误 0正常
+ Msg string `json:"message"` // Y 错误信息
+}
+
+type PushReq struct {
+ RequidId string `json:"RequidId"` // Y 推送请求唯一ID
+ Data Order172 `json:"Data"` // Y 返回订单信息
+}
+
+type TiktokReq struct {
+ VideoUrl string `json:"videoUrl"` // 视频地址
+}
+
+type TiktokResp struct {
+ AuthorID string `json:"authorId"` // 作者ID
+ AuthorUniqueID string `json:"authorUniqueId"` // 作者账号
+ AuthorAvatar string `json:"authorAvatar"` // 作者头像
+ AuthorNickname string `json:"authorNickname"` // 作者昵称
+ VideoID string `json:"videoId"` // 视频ID
+ VideoTitle string `json:"videoTitle"` // 作品描述
+ OriginCover string `json:"originCover"` // 静态封面
+ DynamicCover string `json:"dynamicCover"` // 动态封面
+ DestinationURL string `json:"destinationUrl"` // 无水印下载地址
+ WatermarkVideoURL string `json:"watermarkVideoUrl"` // 有水印下载地址
+ MusicURL string `json:"musicUrl"` // 背景音乐链接
+ OriginalURL string `json:"originalUrl"` // 原始下载链接
+ DownloaderURL string `json:"downloaderUrl"` // 解析后下载地址
+ CreateTime string `json:"createTime"` // 创建时间
+ Result bool `json:"result"` // 结果
+}