This commit is contained in:
Hsy 2025-02-20 17:32:53 +08:00
commit 144c1788f7
57 changed files with 2827 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

18
.idea/dataSources.xml generated Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="110.40.44.75" uuid="2a0dbdb2-3d96-4e1b-bb48-f766f88518a6">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://110.40.44.75:3306</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

9
.idea/hk.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/hk.iml" filepath="$PROJECT_DIR$/.idea/hk.iml" />
</modules>
</component>
</project>

6
.idea/sqldialects.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="PROJECT" dialect="MySQL" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

103
doc/api.api Normal file
View File

@ -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)
}

8
doc/sql/config_api.sql Normal file
View File

@ -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配置表';

28
doc/sql/goods_info.sql Normal file
View File

@ -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 '商品列表 ';

8
doc/sql/goods_status.sql Normal file
View File

@ -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 '商品状态';

22
doc/sql/oder_info.sql Normal file
View File

@ -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 '订单列表';

53
go.mod Normal file
View File

@ -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
)

136
go.sum Normal file
View File

@ -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=

View File

@ -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))
}

View File

@ -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
}

5
model/config_api/vars.go Normal file
View File

@ -0,0 +1,5 @@
package config_api
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@ -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))
}

View File

@ -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
}

5
model/goods_info/vars.go Normal file
View File

@ -0,0 +1,5 @@
package goods_info
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@ -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
}

View File

@ -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
}

View File

@ -0,0 +1,5 @@
package goods_status
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@ -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))
}

View File

@ -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
}

5
model/order_info/vars.go Normal file
View File

@ -0,0 +1,5 @@
package order_info
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@ -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
}

72
pkg/util/172/172.go Normal file
View File

@ -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
}

198
pkg/util/172/172_test.go Normal file
View File

@ -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("请输入正确的代理手机号")
}
}

View File

@ -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))
}

View File

@ -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
}

50
pkg/util/172/goods_v2.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

151
pkg/util/tiktok/tiktok.go Normal file
View File

@ -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
}

View File

@ -0,0 +1,7 @@
package tiktok
import "testing"
func TestTikTok(test *testing.T) {
GetTiktokVideoInfo("https://www.tiktok.com/@baotramthieu/video/6887554215598689538")
}

33
service/api/Dockerfile Normal file
View File

@ -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"]

34
service/api/api.go Normal file
View File

@ -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()
}

22
service/api/etc/api.yaml Normal file
View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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 + " * * *"
}

View File

@ -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 {}
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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"),
)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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))
}
}

View File

@ -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)),
}
}

View File

@ -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"` // 结果
}