Commit f5365530 authored by wangp's avatar wangp

拉卡拉统一支付新项目

parent 68357129
.idea/
.DS_Store
logs/*
tmp
main
# 声明镜像来源为golang:alpine
FROM golang:alpine
# 设置环境变量GO111MODULE为on
ENV GO111MODULE=on
# 设置环境变量GOPROXY为https://goproxy.io,direct
ENV GOPROXY=https://goproxy.cn,direct
# 声明工作目录
WORKDIR /go/src/system_pay
# 拷贝当前工程代码到工作目录
COPY . .
# go env为查看go的环境变量, go build -o server . 为打包项目,二进制
RUN go env && go mod tidy && go build -o server .
# ======= 以下为多阶段构建 =======
# 声明镜像来源为alpine:latest
FROM alpine:latest
ENV TZ=Asia/Shanghai
RUN echo "http://mirrors.aliyun.com/alpine/v3.4/main/" > /etc/apk/repositories \
&& apk --no-cache add tzdata zeromq \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo '$TZ' > /etc/timezone
# 声明工作目录
WORKDIR /go/src/system_pay
# 拷贝打包好的server二进制文件到当前工作目录
COPY --from=0 /go/src/system_pay/server ./
# 拷贝配置文件到当前工作目录
COPY --from=0 /go/src/system_pay/conf/dev ./conf
# 拷贝国际化文件夹到当前工作目录
COPY --from=0 /go/src/system_pay/i18n ./i18n
# 拷贝国际化文件夹到当前工作目录
COPY --from=0 /go/src/system_pay/docs ./docs
# 运行打包好的二进制
ENTRYPOINT ./server
\ No newline at end of file
# 声明镜像来源为golang:alpine
FROM golang:alpine
# 设置环境变量GO111MODULE为on
ENV GO111MODULE=on
# 设置环境变量GOPROXY为https://goproxy.io,direct
ENV GOPROXY=https://goproxy.cn,direct
# 声明工作目录
WORKDIR /go/src/system_pay
# 拷贝当前工程代码到工作目录
COPY . .
# go env为查看go的环境变量, go build -o server . 为打包项目,二进制
RUN go env && go mod tidy && go build -o server .
# ======= 以下为多阶段构建 =======
# 声明镜像来源为alpine:latest
FROM alpine:latest
ENV TZ=Asia/Shanghai
RUN echo "http://mirrors.aliyun.com/alpine/v3.4/main/" > /etc/apk/repositories \
&& apk --no-cache add tzdata zeromq \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo '$TZ' > /etc/timezone
# 声明工作目录
WORKDIR /go/src/system_pay
# 拷贝打包好的server二进制文件到当前工作目录
COPY --from=0 /go/src/system_pay/server ./
# 拷贝配置文件到当前工作目录
COPY --from=0 /go/src/system_pay/conf/prod ./conf
COPY --from=0 /go/src/system_pay/conf/consts.go ./conf
# 拷贝国际化文件夹到当前工作目录
COPY --from=0 /go/src/system_pay/i18n ./i18n
# 拷贝国际化文件夹到当前工作目录
COPY --from=0 /go/src/system_pay/docs ./docs
# 运行打包好的二进制
ENTRYPOINT ./server
\ No newline at end of file
# system_pay
谛语-谛宝医生数据分析平台
## 项目结构
```bigquery
├── conf 配置文件
├── controller controller层
│   ├── api
│   │   └── v1
│   └── base controller共用方法
├── docs swagger
├── i18n 多语言文件
├── logs 日志
├── middleware 中间件
│   └── jwt
├── models 结构体
├── mysql
├── pkg 第三方包
│   ├── logging
│   └── sms
├── redis redis
├── repository 数据层
├── router
│   ├── pack 路由封装
│   ├── router.go 路由入口
│   └── v1 v1版本接口
├── run-dev.sh 启动脚本
├── service 业务
├── setting 配置
├── tests 测试
└── utils 工具
├── main.go 项目入口
├── go.mod gomod
├── go.sum
```
## 关于国际化-i18n
国际化文件
` base.ResponseErrorWithMsg(c, base.ServerError)`
ServerError为200,在i18n对应文件写
200 = "对应文字"
`t.SetLanguage(语言类型)`
语言类型即使toml文件的文件名
## 关于swagger
` swag init ` 更新swagger
## 关于热更新
` air ` 启动air热更新
<br/>
` air -d ` 启动air热更新并且显示具体日志
<br/>
安装air
<br/>
`
curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
`
<br/>
`
curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s
`
<br/>
`
air -v
`
package conf
import "time"
//token过期时间
const TokenExpireDuration = time.Hour * 24 * 7
//Redis过期时间
const RedisExpireDuration = time.Minute*10 //默认(短信验证码)
const RedisExpireDurationExpress = time.Minute*120 //查看物流
//Redis前缀
const RedisPrefix = "system_pay_"
const (
AesKey = "dbcaespassword01"
SmsAes = "dbcaespassword01"
)
//采购订单状态
//const (
// PURCHASE_ORDER_SUBMITTED = 10 // 待发货
// PURCHASE_ORDER_PENDING = 11 // 待付款(已发货)
// PURCHASE_ORDER_ACCEPTED = 20 // 已付款
// PURCHASE_ORDER_CHARGED = 21 // 已挂账
// PURCHASE_ORDER_FINISHED = 40 // 已结算(平台)
// PURCHASE_ORDER_EXAMINE = 60 // 已核查(卖家)
// PURCHASE_ORDER_CANCELED = 0 // 已取消
//)
//
//const (
// purchase_order_submitted = "待发货"
// purchase_order_pending = "待付款"
// purchase_order_accepted = "已付款"
// purchase_order_charged = "已挂账"
// purchase_order_finished = "已结算"
// purchase_order_examined = "已核查"
// purchase_order_canceled = "已取消"
//)
//const (
// // BILL_COMPLETE_STATUS 账单完成状态
// BILL_COMPLETE_STATUS = "1, 4, 6, 7"
// // 部分退款
// BILL_COMPLETE_STATUS_REBATES = "1, 4, 6, 7,2"
//)
//const (
// // 时间格式化
// TIME_FMT_DAY = "2006-01-02"
// TIME_FMT_DAY_SQL = "'%Y-%m-%d'"
//)
// PhonePrefix 号码前缀
//var PhonePrefix = map[int]string{
// 1: "86",
// 2: "60",
//}
// PayType 支付方式
//var PayType = map[int]string{
// 1: "现金",
// 2: "银行卡",
// 3: "支付宝",
// 4: "微信支付",
// //5: "预收款",
// //6: "预付款",
// 7: "押金",
// 8: "会员卡余额",
// 9: "会员卡赠额",
// 10: "团购",
//}
// PayTypeZhCN 支付方式
//var PayTypeZhCN = map[int]int{
// 1: 0,
// 2: 2,
// 3: 1,
//}
// SecondaryCardLineChartList 次卡折线图
//var SecondaryCardLineChartList = map[int]int{
// //1: 1306,
// 2: 1307,
// 3: 1308,
// 4: 1309,
//}
//var CountryPrefix = map[string]string{
// "86": "中国",
// "60": "马来西亚",
//}
// PrefixLocalList 开通列表
//var PrefixLocalList = map[string]string{
// "86": "zh-CN",
// "60": "en-US",
//}
// ZH_CN 中国开通列表
//var ZH_CN = []string{
// "免费试用%v%v",
// "支付宝支付",
// "微信支付",
//}
// EN_US 美国
//var EN_US = []string{
// "Free trial for %v %v",
// "Alipay Pay",
// "WeChat Pay",
//}
// PayTypeListAddKey 前端开通列表ID差
//var PayTypeListAddKey = map[string]int{
// "zh-CN": 1,
// "en-US": 4,
//}
// PayTypeList 开通列表
//var PayTypeList = map[string]interface{}{
// "zh-CN": ZH_CN,
// "en-US": EN_US,
//}
// pay
//const (
// QueryIsOpenDY = "/gateway/dy/is_open_py" // 查询医院是否开通谛语智慧
// DYTrial = "/gateway/dy/trial" // 谛语智慧试用
// PurchasePacs = "/gateway/dy/buy" // 谛语智慧购买
// OpeningData = "/gateway/dy/data" // 谛语智慧购买页信息
// //QueryDYBuy = "/gateway/dy/buy" // 查询 订单
// //QueryDYMeal = "/gateway/py/py_meal" // pacs 套餐列表
// //QueryDcmList = "/gateway/py/dcm_list" // pacs 套餐列表
//)
//const (
// AesKey = "dbcaespassword01"
// SmsAes = "dbcaespassword01"
//)
# 服务
server:
runMode: 'debug'
httpport: 19880
readtimeout: 60
writetimeout: 60
# 通用设置
app:
name: 'system_pay'
version: '1.0.0.0'
timeformat: 20060102
# 数据库
database:
type: 'mysql'
#crmdb: "root:abc123456@tcp(39.96.85.45:3307)/dbc_crm_manage?charset=utf8"
shopdb: "root:abc123456@tcp(39.96.85.45:3307)/dbc_shop?charset=utf8"
#accountdb: 'dbc_saas:dbc_saas888888@tcp(rm-2zepcf8kag0aol0q48o.mysql.rds.aliyuncs.com:3306)/hos_database?charset=utf8'
#userdb: 'root_dbc:dbc_root888888@tcp(rm-2ze8jnj44l6ta299pro.mysql.rds.aliyuncs.com:3306)/mysql?charset=utf8'
#seconddb: 'root_dbc:dbc_root888888@tcp(rm-2ze095l91j14r251wno.mysql.rds.aliyuncs.com:3306)/mysql?charset=utf8'
#paydb: 'dbc_saas:dbc_saas888888@tcp(rm-2zepcf8kag0aol0q48o.mysql.rds.aliyuncs.com:3306)/diyu_analysis?charset=utf8'
max_open_conns: 200
max_idle_conns: 50
# host: "127.0.0.1"
# user: "root"
# password: "rootroot"
# port: 3306
# dbname: "test_food"
# redis
redis:
host: '39.96.85.45'
port: 6382
password: 'saas123456'
db: 0
pool_size: 200
# mongo
#mongo:
# dburl: 'mongodb://saas888:saas888@39.97.234.228:27018'
# max_open_conns: 300
# 日志
log:
logsavepath: logs/
logsavename: log
logfileext: log
level: 'debug'
max_size: 200
max_age: 30
max_backups: 7
sms:
smskey: 'dbc2021888000000'
sendsmsurl: 'https://tsms.pet-dbc.cn/v1/send'
smscontent: '【谛宝医生】登录验证码为:%s'
# 支付
#payurl:
# checkorder: 'https://tpay.pet-dbc.cn/v1/pay/unified_order'
# orderstate: 'https://tpay.pet-dbc.cn/v1/pay/order_state/'
# gateway
#gateway:
# url: 'http://saas.pet-dbc.cn'
# port: '8003'
# gateway
#gatewaydev:
# url: '127.0.0.1'
# port: '80'
#图片上传目录
uploadimage:
upload_dir: 'credit_shop'
max_file_size: 50000000
image_types: '(jpg|jpeg|png|pdf|gif|zip|rar)'
accept_file_types: 'IMAGE_TYPES'
#OSS配置
oss:
oss_url: 'https://dbc-static.oss-cn-beijing.aliyuncs.com/'
accesskeyid: 'LTAIDfwPBC9AnsRt'
accesskeysecret: 'Z6FtUptrAk0Sl6H8vrVBGZLbBzXEpO'
endpoint: 'oss-cn-beijing.aliyuncs.com'
bucket: 'dbc-static'
#阿里云 - 全国快递物流查询
alicloud:
appcode: '6d1da9eb15b540688a505c1814e0c25f'
#time_duration: 7200
#e签宝
esign:
project_id: "5111575783"
project_secret: "5255e7159b6262b92b03c4e307a23ed2"
organ_auth_url: "https://openapi2.tsign.cn:8444/realname/rest/external/organ/orgAuth"
info_auth_url: "https://openapi2.tsign.cn:8444/realname/rest/external/organ/infoAuth-special"
# jwt 与 des解密
jwtsecret: 'Rtg8BPKNEf5mo4mgvKONGPZZQSaJWNLijxJ52qRgq0iBb7'
deskey: 'yaoll123'
#system_pay777
# 服务
server:
runMode: 'release'
httpport: 19880
readtimeout: 60
writetimeout: 60
# 通用设置
app:
name: 'system_pay'
version: '1.0.0.0'
timeformat: 20060102
# 数据库
database:
type: 'mysql'
#crmdb: "root_shop:DBC_shopqwe@tcp(rm-2zenl1z0v6209a4jrbo.mysql.rds.aliyuncs.com:3306)/dbc_crm_manage?charset=utf8"
shopdb: "root_shop:DBC_shopqwe@tcp(rm-2zenl1z0v6209a4jrbo.mysql.rds.aliyuncs.com:3306)/dbc_shop?charset=utf8"
# accountdb: 'dbc_saas:dbc_saas888888@tcp(rm-2zepcf8kag0aol0q48o.mysql.rds.aliyuncs.com:3306)/hos_database?charset=utf8'
# userdb: 'root_dbc:dbc_root888888@tcp(rm-2ze8jnj44l6ta299pro.mysql.rds.aliyuncs.com:3306)/mysql?charset=utf8'
# seconddb: 'root_dbc:dbc_root888888@tcp(rm-2ze095l91j14r251wno.mysql.rds.aliyuncs.com:3306)/mysql?charset=utf8'
# paydb: 'dbc_saas:dbc_saas888888@tcp(rm-2zepcf8kag0aol0q48o.mysql.rds.aliyuncs.com:3306)/diyu_analysis?charset=utf8'
max_open_conns: 200
max_idle_conns: 50
# host: "127.0.0.1"
# user: "root"
# password: "rootroot"
# port: 3306
# dbname: "test_food"
# redis
redis:
host: '39.97.179.15'
port: 6382
password: 'saas123456'
db: 0
pool_size: 200
# mongo
#mongo:
# dburl: 'mongodb://saas888:saas888@39.97.179.15:27017'
# max_open_conns: 300
# 日志
log:
logsavepath: logs/
logsavename: log
logfileext: log
level: 'debug'
max_size: 200
max_age: 30
max_backups: 7
# 国际化短信服务
sms:
smskey: 'dbc2021888000000'
sendsmsurl: 'https://sms.pet-dbc.cn/v1/send'
smscontent: '【谛宝多多】登录验证码为:%s'
# 支付
#payurl:
# checkorder: 'https://pay.pet-dbc.cn/v1/pay/unified_order'
# orderstate: 'https://pay.pet-dbc.cn/v1/pay/order_state/'
# gateway
#gateway:
# url: 'http://saas.pet-dbc.cn'
# port: '8003'
# gateway
#gatewaydev:
# url: '127.0.0.1'
# port: '80'
#图片上传目录
uploadimage:
upload_dir: 'credit_shop'
max_file_size: 50000000
image_types: '(jpg|jpeg|png|pdf|gif|zip|rar)'
accept_file_types: 'IMAGE_TYPES'
#OSS配置
oss:
oss_url: 'https://dbc-static.oss-cn-beijing.aliyuncs.com/'
accesskeyid: 'LTAIDfwPBC9AnsRt'
accesskeysecret: 'Z6FtUptrAk0Sl6H8vrVBGZLbBzXEpO'
endpoint: 'oss-cn-beijing.aliyuncs.com'
bucket: 'dbc-static'
#阿里云 - 全国快递物流查询
alicloud:
appcode: '6d1da9eb15b540688a505c1814e0c25f'
time_duration: 7200
#e签宝
esign:
project_id: "7438819206"
project_secret: "64c6e023ee98c82a1a7180107c320d08"
organ_auth_url: "http://smlrealname.tsign.cn:8080/realname/rest/external/organ/orgAuth"
info_auth_url: "http://smlrealname.tsign.cn:8080/realname/rest/external/organ/infoAuth-special"
# jwt 与 des解密
jwtsecret: 'Rtg8BPKNEf5mo4mgvKONGPZZQSaJWNLijxJ52qRgq0iBb7'
deskey: 'yaoll123'
package pay
import (
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"system_pay/controller/base"
"system_pay/models"
"system_pay/repository/pay"
)
// 卡拉卡统一支付
type PayController struct {
}
// UnifiedOrder 拉卡拉统一支付
// @Summary 拉卡拉统一支付
// @Description 拉卡拉统一支付
// @Tags 拉卡拉统一支付
// @Accept application/json
// @Produce application/json
// @Param body body models.PlaceAnOrderParamInput true "参数"
// @Param language header string ture "语言类型 zh-CN简体中文 en-US英文 ja 日文 默认中文"
// @Success 200
// @router /api/v1/index/unified_order [post]
func (l *PayController) UnifiedOrder(c *gin.Context) {
ph := new(models.PlaceAnOrderParamInput)
err := c.ShouldBind(ph)
if err != nil {
zap.L().Error(err.Error())
base.ResponseErrorWithMsg(c, base.ServerError)
return
}
// 绑定
rtn, err := pay.UnifiedOrder(ph)
if err != nil {
zap.L().Error(err.Error())
//base.ResponseErrorWithMsg(c, base.ServerError)
base.ResponseErrorMsg(c, err.Error())
return
}
base.ResponseSuccess(c, rtn)
}
package base
import (
"github.com/gin-gonic/gin"
)
// 获取登录时保存的常量
func GetMyClaimsItem(c *gin.Context, name string) (string) {
return c.MustGet(name).(string)
}
//// GetHospitalCode 获取hospital code
//func GetHospitalCode(c *gin.Context) string {
//
// hospitalCode := c.MustGet("hospital_code").(string)
//
// if hospitalCode == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital code 失败", zap.Error(err))
// return ""
// }
//
// hospitalCode = utils.ToDesDecrypt(parseToken.HospitalCode)
// }
//
// return hospitalCode
//}
//
//
//
//
//// GetChainID get chainID
//func GetChainID(c *gin.Context) string {
//
// ChainID := c.MustGet("chain_id").(string)
//
// if ChainID == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("chain_id 失败", zap.Error(err))
// return ""
// }
//
// ChainID = utils.ToDesDecrypt(parseToken.ChainID)
// }
//
// return ChainID
//}
//
//// GetUserPhone 获取user phone
//func GetUserPhone(c *gin.Context) string {
//
// userPhone := c.MustGet("user_phone").(string)
//
// if userPhone == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital code 失败", zap.Error(err))
// return ""
// }
//
// userPhone = utils.ToDesDecrypt(parseToken.UserPhone)
// }
//
// return userPhone
//
//}
//
//// GetChainCode 获取chain code
//func GetChainCode(c *gin.Context) string {
//
// chainCode := c.MustGet("chain_code").(string)
//
// if chainCode == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital code 失败", zap.Error(err))
// return ""
// }
//
// chainCode = utils.ToDesDecrypt(parseToken.ChainCode)
// }
//
// return chainCode
//
//}
//
//// GetHospitalID 获取hospital id
//func GetHospitalID(c *gin.Context) string {
//
// hospitalID := c.MustGet("hospital_id").(string)
//
// if hospitalID == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital id 失败", zap.Error(err))
// return ""
// }
//
// hospitalID = utils.ToDesDecrypt(parseToken.HospitalID)
// }
//
// return hospitalID
//
//}
//
//// GetHospitalIDAndChainCode 获取hospital id
//func GetHospitalIDAndChainCode(c *gin.Context) (hospitalIDS, chainCodeS string) {
//
// hospitalID := c.MustGet("hospital_id").(string)
//
// if hospitalID == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital id 失败", zap.Error(err))
// return "", ""
// }
//
// hospitalID = utils.ToDesDecrypt(parseToken.HospitalID)
// }
//
// chainCode := c.MustGet("chain_code").(string)
//
// if chainCode == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital code 失败", zap.Error(err))
// return "", ""
// }
//
// chainCode = utils.ToDesDecrypt(parseToken.ChainCode)
// }
//
// return hospitalID, chainCode
//
//}
//
//
//// GetHospitalIDAndChainID 获取hospital id and chain id
//func GetHospitalIDAndChainID(c *gin.Context) (hospitalIDS, chainIDS string) {
//
// hospitalID := c.MustGet("hospital_id").(string)
//
// if hospitalID == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital id 失败", zap.Error(err))
// return "", ""
// }
//
// hospitalID = utils.ToDesDecrypt(parseToken.HospitalID)
// }
//
// ChainID := c.MustGet("chain_id").(string)
//
// if ChainID == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("chain_id 失败", zap.Error(err))
// return "", "" }
//
// ChainID = utils.ToDesDecrypt(parseToken.ChainID)
// }
//
//
// return hospitalID, ChainID
//
//}
//
//
//
//// GetHospitalName 获取hospital name
//func GetHospitalName(c *gin.Context) (name string) {
//
// hospitalName := c.MustGet("hospital_name").(string)
//
// if hospitalName == "" {
//
// token := c.Request.Header.Get("Authorization")
//
// parseToken, err := utils.ParseToken(token)
// if err != nil {
// zap.L().Error("获取hospital name 失败", zap.Error(err))
// return ""
// }
//
// hospitalName = utils.ToDesDecrypt(parseToken.HospitalName)
// }
//
//
//
// return hospitalName
//
//}
//
//func ParamInt(c *gin.Context, key string) (int, error) {
//
// showType := c.Param(key)
//
// showTypeInt, err := strconv.Atoi(showType)
//
// return showTypeInt, err
//}
//
//
//func QueryInt(c *gin.Context, key string) int {
//
// showType := c.Query(key)
//
// showTypeInt, _ := strconv.Atoi(showType)
//
// return showTypeInt
//}
package base
/*
返回码
*/
const (
// Success 请求成功
Success = 1000
// ServerError 服务器错误
ServerError = 1100
// Warning 警告
Warning = 1200
// FailedToObtainVerificationCode 验证码获取失败
//FailedToObtainVerificationCode = 1001
// PleaseCheckIfThePhoneNumberIsEnteredCorrectly 请检查电话号码是否输入正确
//PleaseCheckIfThePhoneNumberIsEnteredCorrectly = 1002
// VerificationCodeError 验证码错误
//VerificationCodeError = 1003
// AuthorizationEmpty token为空
AuthorizationEmpty = 1004
// ThisAccountDoesNotHavePermission 此账号没有权限
//ThisAccountDoesNotHavePermission = 1005
// ParameterValidationFailed 参数效验失败
//ParameterValidationFailed = 1006
// 此国家暂不支持
//NotCurrentlySupportedInThisCountry = 1007
)
package base
import (
"github.com/gin-gonic/gin"
"github.com/gogf/gf/i18n/gi18n"
"strconv"
)
/*
国际化处理
*/
var (
t *gi18n.Manager
)
// InternationalizedMsg 国际化msg
func InternationalizedMsg(ctx *gin.Context, code int) string {
t = gi18n.New()
languageType := ctx.Request.Header.Get("language")
// 设置默认语言类型
if languageType == "" {
languageType = "zh-CN"
}
// 设置语言类型
t.SetLanguage(languageType)
// 传入错误码
stringCode := strconv.Itoa(code)
// 拿到对应国家的错误信息
translateMsg := t.Translate(ctx, stringCode)
return translateMsg
}
// InternationalizedMsgByLanguageType 国际化msg
func InternationalizedMsgByLanguageType(languageType string, code int) string {
t = gi18n.New()
// 设置默认语言类型
if languageType == "" {
languageType = "zh-CN"
}
// 设置语言类型
t.SetLanguage(languageType)
// 传入错误码
stringCode := strconv.Itoa(code)
// 拿到对应国家的错误信息
translateMsg := t.Translate(nil, stringCode)
return translateMsg
}
func GetLanguageType(c *gin.Context) string {
languageType := c.Request.Header.Get("language")
if languageType == "" {
languageType = "zh-CN"
}
return languageType
}
// BuriedPointMsg 国际化msg
func BuriedPointMsg(code int) string {
t = gi18n.New()
//languageType := ctx.Request.Header.Get("language")
// 设置默认语言类型
//if languageType == "" {
languageType := "bp"
//}
// 设置语言类型
t.SetLanguage(languageType)
// 传入错误码
stringCode := strconv.Itoa(code)
// 拿到对应国家的错误信息
translateMsg := t.Translate(nil, stringCode)
return translateMsg
}
package base
import (
"github.com/gin-gonic/gin"
"net/http"
)
/*
{
"code": 10000, // 程序中的错误码
"msg": xx, // 提示信息
"data": {}, // 数据
}
*/
// ResponseData 统一返回数据
type ResponseData struct {
Code int `json:"code"`
Msg interface{} `json:"msg"`
Data interface{} `json:"data,omitempty"`
}
// ResponseErrorWithMsg 返回错误
func ResponseErrorWithMsg(c *gin.Context, code int) {
c.JSON(http.StatusOK, &ResponseData{
Code: code,
Msg: InternationalizedMsg(c, code),
Data: nil,
})
}
// ResponseSuccess 返回正确
func ResponseSuccess(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, &ResponseData{
Code: Success,
Msg: InternationalizedMsg(c, Success),
Data: data,
})
}
// ResponseErrorMsg 直接返回msg
func ResponseErrorMsg(c *gin.Context, msg string) {
c.JSON(http.StatusOK, &ResponseData{
Code: Warning,
Msg: msg,
Data: nil,
})
}
\ No newline at end of file
#!/bin/bash
git pull
export runmode=dev
docker-compose up --build -d
docker image prune -f
\ No newline at end of file
version: '3.5'
services:
system_pay_dev:
restart: always
build:
context: .
args:
ENVARG: dev
dockerfile: Dockerfile
image: system_pay:dev
ports:
- 19880:19880
environment:
runmode: dev
networks:
- system_pay_network
networks:
system_pay_network:
driver: bridge
// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag
package docs
import (
"bytes"
"encoding/json"
"strings"
"text/template"
"github.com/swaggo/swag"
)
var doc = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{.Description}}",
"title": "{{.Title}}",
"contact": {},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/api/v1/index/unified_order": {
"post": {
"description": "拉卡拉统一支付",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"拉卡拉统一支付"
],
"summary": "拉卡拉统一支付",
"parameters": [
{
"description": "参数",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.PlaceAnOrderParamInput"
}
},
{
"type": "string",
"description": "语言类型 zh-CN简体中文 en-US英文 ja 日文 默认中文",
"name": "language",
"in": "header"
}
],
"responses": {
"200": {
"description": ""
}
}
}
}
},
"definitions": {
"models.PlaceAnOrderParamInput": {
"type": "object",
"properties": {
"app_id": {
"type": "string"
},
"attach_info": {
"type": "string"
},
"customer": {
"type": "string"
},
"dynamic_id": {
"type": "string"
},
"goods_des": {
"type": "string"
},
"goods_detail": {
"type": "string"
},
"goods_price": {
"type": "number"
},
"is_serve": {
"type": "integer"
},
"notice_url": {
"type": "string"
},
"open_id": {
"type": "string"
},
"operator": {
"type": "string"
},
"pay_type": {
"type": "integer"
},
"platform_info": {
"type": "string"
},
"platform_type": {
"type": "integer"
},
"quit_url": {
"type": "string"
},
"return_url": {
"type": "string"
},
"source_code": {
"type": "integer"
},
"store_sn": {
"type": "string"
},
"sub_mchid": {
"type": "string"
},
"wap_name": {
"type": "string"
},
"wap_url": {
"type": "string"
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
}
}`
type swaggerInfo struct {
Version string
Host string
BasePath string
Schemes []string
Title string
Description string
}
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = swaggerInfo{
Version: "1.0",
Host: "",
BasePath: "",
Schemes: []string{},
Title: "谛宝多多平台",
Description: "采购订单项目",
}
type s struct{}
func (s *s) ReadDoc() string {
sInfo := SwaggerInfo
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}).Parse(doc)
if err != nil {
return doc
}
var tpl bytes.Buffer
if err := t.Execute(&tpl, sInfo); err != nil {
return doc
}
return tpl.String()
}
func init() {
swag.Register(swag.Name, &s{})
}
{
"swagger": "2.0",
"info": {
"description": "采购订单项目",
"title": "谛宝多多平台",
"contact": {},
"version": "1.0"
},
"paths": {
"/api/v1/index/unified_order": {
"post": {
"description": "拉卡拉统一支付",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"拉卡拉统一支付"
],
"summary": "拉卡拉统一支付",
"parameters": [
{
"description": "参数",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.PlaceAnOrderParamInput"
}
},
{
"type": "string",
"description": "语言类型 zh-CN简体中文 en-US英文 ja 日文 默认中文",
"name": "language",
"in": "header"
}
],
"responses": {
"200": {
"description": ""
}
}
}
}
},
"definitions": {
"models.PlaceAnOrderParamInput": {
"type": "object",
"properties": {
"app_id": {
"type": "string"
},
"attach_info": {
"type": "string"
},
"customer": {
"type": "string"
},
"dynamic_id": {
"type": "string"
},
"goods_des": {
"type": "string"
},
"goods_detail": {
"type": "string"
},
"goods_price": {
"type": "number"
},
"is_serve": {
"type": "integer"
},
"notice_url": {
"type": "string"
},
"open_id": {
"type": "string"
},
"operator": {
"type": "string"
},
"pay_type": {
"type": "integer"
},
"platform_info": {
"type": "string"
},
"platform_type": {
"type": "integer"
},
"quit_url": {
"type": "string"
},
"return_url": {
"type": "string"
},
"source_code": {
"type": "integer"
},
"store_sn": {
"type": "string"
},
"sub_mchid": {
"type": "string"
},
"wap_name": {
"type": "string"
},
"wap_url": {
"type": "string"
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
}
}
\ No newline at end of file
definitions:
models.PlaceAnOrderParamInput:
properties:
app_id:
type: string
attach_info:
type: string
customer:
type: string
dynamic_id:
type: string
goods_des:
type: string
goods_detail:
type: string
goods_price:
type: number
is_serve:
type: integer
notice_url:
type: string
open_id:
type: string
operator:
type: string
pay_type:
type: integer
platform_info:
type: string
platform_type:
type: integer
quit_url:
type: string
return_url:
type: string
source_code:
type: integer
store_sn:
type: string
sub_mchid:
type: string
wap_name:
type: string
wap_url:
type: string
type: object
info:
contact: {}
description: 采购订单项目
title: 谛宝多多平台
version: "1.0"
paths:
/api/v1/index/unified_order:
post:
consumes:
- application/json
description: 拉卡拉统一支付
parameters:
- description: 参数
in: body
name: body
required: true
schema:
$ref: '#/definitions/models.PlaceAnOrderParamInput'
- description: 语言类型 zh-CN简体中文 en-US英文 ja 日文 默认中文
in: header
name: language
type: string
produces:
- application/json
responses:
"200":
description: ""
summary: 拉卡拉统一支付
tags:
- 拉卡拉统一支付
securityDefinitions:
ApiKeyAuth:
in: header
name: Authorization
type: apiKey
swagger: "2.0"
module system_pay
go 1.16
require (
github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible
github.com/astaxie/beego v1.12.3
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fsnotify/fsnotify v1.5.1
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
github.com/gin-gonic/gin v1.7.4
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/gogf/gf v1.16.6
github.com/google/uuid v1.3.0
github.com/jmoiron/sqlx v1.3.4
github.com/json-iterator/go v1.1.11
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.16.0 // indirect
github.com/pkg/errors v0.9.1
github.com/satori/go.uuid v1.2.0
github.com/spf13/viper v1.8.1
github.com/swaggo/gin-swagger v1.3.1
github.com/swaggo/swag v1.7.1
go.mongodb.org/mongo-driver v1.7.2
go.uber.org/zap v1.19.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
)
This diff is collapsed.
# 数据分析
# 9000 = ""
# 9001 = "数据概览"
# 9002 = "顾客分析"
# 9003 = "会员卡分析"
# 9004 = "次卡分析"
# 9005 = "病历量分析"
# 9006 = "医疗消费分析"
# 9007 = "商品分析"
# 9008 = "员工分析"
#
# 9100 = ""
# 9101 = "新增用户"
# 9102 = "到店消费"
# 9103 = "新客消费"
# 9104 = "老客消费"
# 9105 = "新增办卡数"
# 9106 = "会员卡充值额度"
# 9107 = "赠额充值额度"
# 9108 = "会员卡消费次数"
# 9109 = "会员卡消费金额"
# 9110 = "就诊量"
# 9111 = "新客户初诊"
# 9112 = "老客户初诊"
# 9113 = "新客户复诊"
# 9114 = "老客户复诊"
# 9115 = "销量下跌"
# 9116 = "滞销商品"
# 英语
1000 = "success"
1100 = "server error"
# 1001 = "failed to obtain verification code"
# 1002 = "Please check if the phone number is entered correctly"
# 1003 = "Verification code error"
1004 = "authorizatione is error"
# 1005 = "this account does not have permission"
# 1006 = "parameter validation failed"
# 1007 = "this country does not currently support"
# 项目中key
# 1300 = "Business sales performance"
# 1301 = "Sub-card performance"
# 1302 = "Service performance"
# 1303 = "Year"
# 1304 = "Month"
# 1305 = "Day"
# 1306 = "Recharge amount"
# 1307 = "Number of recharges"
# 1308 = "Number of purchases"
# 1309 = "Add a new card"
\ No newline at end of file
# 日语
1000 = "success"
1100 = "サーバエラー"
1004 = "authorizationeが正しくない"
# 1007 = "この国はしばらくサポートしていません"
# 简体中文
1000 = "success"
1100 = "服务器错误"
# 1001 = "验证码获取失败"
# 1002 = "请检查电话号码是否输入正确"
# 1003 = "验证码错误"
1004 = "Authorization不正确" #Authorization为空
# 1005 ="此帐号没有权限"
# 1006 ="参数效验失败"
# 1007 = "此国家暂时不支持"
# 警告信息
# 1200 = "您已经是VIP用户,无需试用"
# 1201 = "试用已经到期, 请付费后使用"
# 1202 = "正在试用中"
# 1203 = "服务已经到期, 请付费后使用"
# 项目中key
# 1300 = "经营销售业绩"
# 1301 = "次卡业绩"
# 1302 = "服务业绩"
# 1303 = "年"
# 1304 = "个月"
# 1305 = "日"
# 1306 = "充值金额"
# 1307 = "充值次数"
# 1308 = "消费次数"
# 1309 = "新增次卡"
#
# 1500 = "用户名长度错误,应保持在3到25位之间"
# 1501 = "密码长度错误,应保持在6-20位之间"
# 1502 = "手机号码格式错误"
\ No newline at end of file
package main
import (
"bytes"
"fmt"
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
"os"
"os/exec"
_ "system_pay/docs"
logger "system_pay/pkg/logging"
"system_pay/redis"
routers "system_pay/router"
"system_pay/setting"
)
// @title 谛宝多多平台
// @version 1.0
// @description 采购订单项目
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
func main() {
if os.Getenv("runmode") == "release" {
gin.SetMode(gin.ReleaseMode)
} else {
gin.SetMode(gin.DebugMode)
}
// 设置
if err := setting.Init(); err != nil {
panic("load config failed, new_error:"+ err.Error())
//fmt.Printf("load config failed, new_error:%v\n", new_error)
//return
}
if gin.Mode() == gin.TestMode || gin.Mode() == gin.DebugMode {
//自动更新swagger
runCommand()
}
// 日志
if err := logger.Init(setting.Conf.LogSetting); err != nil {
panic("init logger failed, new_error:"+ err.Error())
//fmt.Printf("init logger failed, new_error:%v\n", new_error)
//return
}
// redis
if err := redis.Init(setting.Conf.Redis); err != nil {
panic("init redis failed, new_error:"+ err.Error())
//fmt.Printf("init redis failed, new_error:%v\n", new_error)
//return
}
// 关闭项目时候关闭redis连接
defer redis.Close()
// mongo
//MongoDB, err := mongo.ConnectToMongoDB()
//if err != nil {
// panic("err" + err.Error())
//}
//defer mongo.Close(MongoDB)
// 注册路由
r := routers.InitRouter()
// 优雅启停
err := endless.ListenAndServe(setting.GetPort(), r)
if err != nil {
panic("route initialization failed, new_error:"+ err.Error())
//fmt.Println("route_initialization_failed" + new_error.Error())
//return
}
}
// runCommand 重启时候更新swagger
func runCommand() {
cmd := exec.Command("swag", "init")
fmt.Println("Cmd", cmd.Args)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
fmt.Println(err)
}
fmt.Println(out.String())
}
package jwt
import (
"fmt"
"github.com/gin-gonic/gin"
"system_pay/controller/base"
"system_pay/utils"
)
//var DataAnalysisCh chan models.DataAnalysisModel
func init() {
//DataAnalysisCh = make(chan models.DataAnalysisModel, 1000)
//go DataAnalysisChannel()
}
// JWTAuthMiddleWare 基于JWT的认证中间件
func JWTAuthMiddleWare() func(c *gin.Context) {
return func(c *gin.Context) {
//客户端携带Token放在请求头
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
base.ResponseErrorWithMsg(c, base.AuthorizationEmpty)
c.Abort()
return
}
mc, err := utils.ParseToken(authHeader)
if err != nil {
base.ResponseErrorWithMsg(c, base.AuthorizationEmpty)
c.Abort()
return
}
// des解密
phoneMob := utils.ToDesDecrypt(mc.PhoneMob)
userId := utils.ToDesDecrypt(mc.UserId)
userName := utils.ToDesDecrypt(mc.UserName)
//hospitalCode := utils.ToDesDecrypt(mc.HospitalCode)
//chainCode := utils.ToDesDecrypt(mc.ChainCode)
//hospitalID := utils.ToDesDecrypt(mc.HospitalID)
//hospitalName := utils.ToDesDecrypt(mc.HospitalName)
//ChainID := utils.ToDesDecrypt(mc.ChainID)
// 将当前请求的username信息保存到请求的上下文c上
c.Set("phone_mob", phoneMob)
fmt.Println(phoneMob)
c.Set("user_id", userId)
fmt.Println(userId)
c.Set("user_name", userName)
fmt.Println(userName)
//c.Set("hospital_code", hospitalCode)
//c.Set("chain_code", chainCode)
//c.Set("hospital_id", hospitalID)
//c.Set("hospital_name", hospitalName)
//c.Set("chain_id", ChainID)
// 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
// 埋点生产者
//BuriedProducer(c, hospitalCode, hospitalName, hospitalID)
c.Next()
}
}
// 埋点消费者
//func DataAnalysisChannel() {
//
// for {
// select {
// case c := <-DataAnalysisCh:
// buried_point.BuriedPointDistribution(c)
// default:
// //fmt.Println("当前没有处理的数据")
// time.Sleep(500 * time.Millisecond )
// }
// }
//}
//
//func BuriedProducer(c *gin.Context, hospitalCode, hospitalName, hospitalID string) {
//
// // 记录埋点
// var d models.DataAnalysisModel
// d.HospitalCode = hospitalCode
// d.HospitalName = hospitalName
// d.HospitalID = hospitalID
// d.RequestBody = c.Request.Body
// d.RequestTime = time.Now().Format("2006-01-02 15:04:05")
// d.RequestUrl = c.Request.RequestURI
// d.RequestPath = c.Request.URL.Path
// d.RequestShowType = base.QueryInt(c, "showType")
//
// //为防止对接口入侵达到最小 达到接口隔离效果 舍弃此方法 副本传递到下一方法
// //data, _ := c.GetRawData()
// //d.RequestData = data
// ////解决gin框架框架的数据不能重复用的问题(拿出来后放回去) 关键点
// //c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
//
// // 埋点生产者
// DataAnalysisCh <- d
//}
package models
import (
"errors"
"github.com/astaxie/beego/validation"
"reflect"
)
type PlaceAnOrderParamInput struct {
PlatformType uint8 `json:"platform_type" description:"平台类型 1: saas 2: shop 3: shop mobile 4: 收银台"`
PlatformInfo string `json:"platform_info" description:"平台信息"`
GoodsDes string `json:"goods_des" description:"商品描述"`
GoodsDetail string `json:"goods_detail" description:"商品详情"`
AttachInfo string `json:"attach_info" description:"附加信息"`
GoodsPrice float64 `json:"goods_price" description:"商品金额,个位为分"`
NoticeURL string `json:"notice_url" description:"客户端回调的url"`
PayType int `json:"pay_type" description:"1: 微信,2: 支付宝, 3: 拉卡拉 4: 收钱吧"`
SourceCode uint8 `json:"source_code" description:"1: 微信 Native 2:微信小程序 3:微信内支付 4:h5 跳微信 5:支付宝(web)-扫码或登录支付宝账户 6:alipay(mobile) 7:alipay(app) 9: B2C 10:bk支付宝web 11:bk 支付宝手机"`
OpenID string `json:"open_id" description:"此参数 支付类型是 JS API 的时候 必传"`
WapURL string `json:"wap_url" description:"WAP网站URL地址, 支付方式为微信MWEB时 必传"`
WapName string `json:"wap_name" description:"WAP网站名称, 支付方式为微信MWEB时 必传"`
QuitURL string `json:"quit_url" description:"返回按钮 可用于用户付款中途退出并返回到该参数指定的商户网站地址, 支付方式为 支付宝手机网站时 必传(尽量传)"`
ReturnURL string `json:"return_url" description:"用户在完成支付后,会根据商户在请求支付API中传入的前台回跳地址return_url自动跳转return_url地址页面(必传)"`
AppID string `json:"app_id,omitempty" description:"wxAppId source code 2 小程序支付时必传、同时小程序支付必须关联了商户号支付"`
Operator string `json:"operator" description:"操作员"`
Customer string `json:"customer" description:"顾客信息"`
DynamicID string `json:"dynamic_id" description:"顾客手机条码的内容"`
StoreSn string `json:"store_sn" description:"商户门店编号"`
IsServe uint `json:"is_serve" description:"0直连模式 1服务商模式"`
OrderId string `json:"-" description:"订单号"`
SubMchid string `json:"sub_mchid" description:"通过进件接口申请的支付商户号、这是由微信生成并下发的"`
Nonce string `json:"-"`
ServeNoticeUrl string `json:"-" description:"传递给支付渠道的、而不是业务方的"`
}
func (this *PlaceAnOrderParamInput) ValidPlaceAnOrderParamInput() (err error) {
valid := validation.Validation{}
if b, _ := valid.Valid(this); !b {
//表示获取验证的结构体
st := reflect.TypeOf(PlaceAnOrderParamInput{})
for _, err := range valid.Errors {
//获取验证的字段名和提示信息的别名
filed, _ := st.FieldByName(err.Field)
var alias= filed.Tag.Get("alias")
//返回验证的错误信息
return errors.New(alias + err.Message)
}
}
return nil
}
type LakalaParamInput struct {
Version string `json:"version" description:"版本"`
ReqTime string `json:"req_time" description:"请求时间"`
ReqData LakalaParamData `json:"req_data"`
}
type LakalaParamData struct {
OutOrderNo string `json:"out_order_no" description:"商户订单号"`
MerchantNo string `json:"merchant_no" description:"银联商户号"`
TotalAmount float64 `json:"total_amount" description:"订单金额,单位:分"`
OrderEfficientTime string `json:"order_efficient_time" description:"订单有效期 格式yyyyMMddHHmmss,最大支持下单时间+2天"`
NotifyUrl string `json:"notify_url" description:"订单支付成功后商户接收订单通知的地址 http://xxx.xxx.com"`
CallbackUrl string `json:"callback_url" description:"客户端下单完成支付后返回的商户网页跳转地址"`
OrderInfo string `json:"order_info" description:"订单标题,在使用收银台扫码支付时必输入,交易时送往账户端"`
GoodsMark string `json:"goods_mark" description:"商品信息标识 (1:含商品信息,不填默认不含商品信息)"`
}
\ No newline at end of file
This diff is collapsed.
package mysql
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"system_pay/setting"
)
var (
shopDB *sqlx.DB
//db *sqlx.DB
// 0 ~ h
//userDB *sqlx.DB
// i ~ z
//secondDB *sqlx.DB
// PayDB 支付
//payDB *sqlx.DB
err error
)
// NewShopConn is 连接谛宝多多库
func NewShopConn() (*sqlx.DB, error) {
if shopDB == nil {
shopDB, err = sqlx.Connect("mysql", setting.Conf.DatabaseSetting.ShopDB)
return shopDB, err
}
//shopDB.SetMaxOpenConns(setting.Conf.DatabaseSetting.MaxOpenConns)
return shopDB, err
}
// ShopDBClose 关闭MySQL连接
func ShopDBClose() {
_ = shopDB.Close()
}
// NewAccountConn is 连接医院用户库
//func NewAccountConn() (*sqlx.DB, error) {
// if db == nil {
// db, err = sqlx.Connect("mysql", setting.Conf.DatabaseSetting.AccountDB)
// return db, err
// }
// //db.SetMaxOpenConns(setting.Conf.DatabaseSetting.MaxOpenConns)
// return db, err
//}
// NewUserConn 连接用户存放数据的库
//func NewUserConn(chainCode string) (*sqlx.DB, error) {
//
// chainCode = strings.ToLower(chainCode)
// if len(chainCode[:1]) != 1 {
// return nil, err
// }
// word := chainCode[:1]
// if word > "h" {
// if secondDB == nil {
// secondDB, err = sqlx.Connect("mysql", setting.Conf.DatabaseSetting.SecondDB)
// return secondDB, err
// }
// //secondDB.SetMaxOpenConns(setting.Conf.DatabaseSetting.MaxOpenConns)
// return secondDB, err
// }
//
// if userDB == nil {
// userDB, err = sqlx.Connect("mysql", setting.Conf.DatabaseSetting.UserDB)
// return userDB, err
// }
// //userDB.SetMaxOpenConns(setting.Conf.DatabaseSetting.MaxOpenConns)
// return userDB, err
//}
// NewPayConn 支付
//func NewPayConn() (*sqlx.DB, error) {
// if payDB == nil {
// payDB, err = sqlx.Connect("mysql", setting.Conf.DatabaseSetting.PayDB)
// return payDB, err
// }
// //payDB.SetMaxOpenConns(setting.Conf.DatabaseSetting.MaxOpenConns)
// return payDB, err
//}
// Close 关闭MySQL连接
//func Close() {
// _ = db.Close()
//}
// PayDBClose 关闭MySQL连接
//func PayDBClose() {
// _ = payDB.Close()
//}
\ No newline at end of file
package logging
import (
"fmt"
"system_pay/setting"
"time"
)
// getLogFilePath 获取日志文件保存路径
func getLogFilePath() string {
return fmt.Sprintf("%s" , setting.Conf.LogSetting.LogSavePath)
}
// getLogFileName 获取日志文件的保存名称
func getLogFileName() string {
return fmt.Sprintf("%s%s.%s",
setting.Conf.LogSetting.LogSaveName,
time.Now().Format(setting.Conf.AppSetting.TimeFormat),
setting.Conf.LogSetting.LogFileExt,
)
}
package logging
import (
"github.com/gin-gonic/gin"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"system_pay/setting"
)
var (
// DBCNormalLogger log
DBCNormalLogger *zap.Logger
)
// Init 初始化log
func Init(cfg *setting.Log) (err error) {
fileName := getLogFileName()
filePath := getLogFilePath()
writeSyncer := getLogWriter(filePath+fileName, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)
encoder := getEncoder()
var l = new(zapcore.Level)
err = l.UnmarshalText([]byte(cfg.Level))
if err != nil {
return
}
var core zapcore.Core
if gin.Mode() == gin.DebugMode {
// 进入开发模式,日志输出到终端
consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
core = zapcore.NewTee(
zapcore.NewCore(encoder, writeSyncer, l),
zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), zapcore.DebugLevel),
)
} else {
core = zapcore.NewCore(encoder, writeSyncer, l)
}
DBCNormalLogger = zap.New(core, zap.AddCaller())
zap.ReplaceGlobals(DBCNormalLogger)
zap.L().Info("init logger success")
return
}
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.TimeKey = "time"
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
return zapcore.NewJSONEncoder(encoderConfig)
}
func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: filename,
MaxSize: maxSize,
MaxBackups: maxBackup,
MaxAge: maxAge,
}
return zapcore.AddSync(lumberJackLogger)
}
//// GinLogger 接收gin框架默认的日志
//func GinLogger() gin.HandlerFunc {
// return func(c *gin.Context) {
// start := time.Now()
// path := c.Request.URL.Path
// query := c.Request.URL.RawQuery
// c.Next()
//
// cost := time.Since(start)
// DBCNormalLogger.Info(path,
// zap.Int("status", c.Writer.Status()),
// zap.String("method", c.Request.Method),
// zap.String("path", path),
// zap.String("query", query),
// zap.String("ip", c.ClientIP()),
// zap.String("user-agent", c.Request.UserAgent()),
// zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
// zap.Duration("cost", cost),
// )
// }
//}
//
//// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志
//func GinRecovery(stack bool) gin.HandlerFunc {
// return func(c *gin.Context) {
// defer func() {
// if err := recover(); err != nil {
// // Check for a broken connection, as it is not really a
// // condition that warrants a panic stack trace.
// var brokenPipe bool
// if ne, ok := err.(*net.OpError); ok {
// if se, ok := ne.Err.(*os.SyscallError); ok {
// if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
// brokenPipe = true
// }
// }
// }
//
// httpRequest, _ := httputil.DumpRequest(c.Request, false)
// if brokenPipe {
// DBCNormalLogger.Error(c.Request.URL.Path,
// zap.Any("error", err),
// zap.String("request", string(httpRequest)),
// )
// // If the connection is dead, we can't write a status to it.
// c.Error(err.(error)) // nolint: errcheck
// c.Abort()
// return
// }
//
// if stack {
// DBCNormalLogger.Error("[Recovery from panic]",
// zap.Any("error", err),
// zap.String("request", string(httpRequest)),
// zap.String("stack", string(debug.Stack())),
// )
// } else {
// DBCNormalLogger.Error("[Recovery from panic]",
// zap.Any("error", err),
// zap.String("request", string(httpRequest)),
// )
// }
// c.AbortWithStatus(http.StatusInternalServerError)
// }
// }()
// c.Next()
// }
//}
package sms
//func TestSendSmsChina(t *testing.T) {
//
// var tModel Send
//
// tModel.AreaCode = "86"
// tModel.Phone = "17538147716"
// tModel.Content = "【谛宝医生】验证码:433212,三分钟内有效"
// tModel.Source = 2
// tModel.SourceName = "谛语智慧"
//
// b, _ := json.Marshal(tModel)
//
// sign, _ := AesEncrypt(b, []byte("dbc2021888000000"))
//
// t.Log("sign: ", sign)
//
// client := &http.Client{}
// req, err := http.NewRequest("POST", "https://tsms.pet-dbc.cn/v1/send", bytes.NewReader(b))
// if err != nil {
// panic(err)
// }
//
// req.Header.Set("Content-Type", "application/json")
// req.Header.Set("sign", sign)
//
// resp, err := client.Do(req)
// if err != nil {
// panic(err)
// }
//
// defer resp.Body.Close()
// body, err := ioutil.ReadAll(resp.Body)
// if err != nil {
// panic(err)
// }
//
// fmt.Println("body: ", string(body))
//}
//
//func TestSendSmsOtherRegion(t *testing.T) {
//
// var tModel Send
//
// tModel.AreaCode = "60"
// // 手机号在刚哥那里
// tModel.Phone = "1139427345"
// tModel.Content = "【DBC】Verification code: 229900, Valid within three minutes"
//
// b, _ := json.Marshal(tModel)
//
// sign, _ := AesEncrypt(b, []byte("dbc2021888000000"))
//
// t.Log("sign: ", sign)
//
// client := &http.Client{}
// req, err := http.NewRequest("POST", "https://tsms.pet-dbc.cn/v1/send", bytes.NewReader(b))
// if err != nil {
// panic(err)
// }
//
// req.Header.Set("Content-Type", "application/json")
// req.Header.Set("sign", sign)
//
// resp, err := client.Do(req)
// if err != nil {
// panic(err)
// }
//
// defer resp.Body.Close()
// body, err := ioutil.ReadAll(resp.Body)
// if err != nil {
// panic(err)
// }
//
// fmt.Println("body: ", string(body))
//}
package sms
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"strings"
)
//Aes 对称加密
func AesEncrypt(origData, key []byte) (string, error) {
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
result := base64.StdEncoding.EncodeToString(crypted)
return result, nil
}
//Aes 对称解密
func AesDecrypt(crypted, key []byte) (string, error) {
ciphertext := strings.Replace(string(crypted), " ", "", -1)
cryptedOri, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(cryptedOri))
blockMode.CryptBlocks(origData, cryptedOri)
origData = PKCS7UnPadding(origData)
return string(origData), nil
}
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
package sms
type Send struct {
Phone string `json:"phone" description:"手机号"`
Content string `json:"content" description:"发送的内容、注意需要携带短信签名 【】"`
AreaCode string `json:"area_code" description:"区号"`
Source int `json:"source" description:"来源 1:谛宝多多 2:谛宝医生 3:收银台 4:谛宠有品 5:CRM 6:谛赋"`
SourceName string `json:"source_name" description:"业务子系统名称 业务系统自定义"`
}
\ No newline at end of file
version: '3.5'
services:
system_pay:
restart: always
build:
context: .
args:
ENVARG: prod
dockerfile: PROD.Dockerfile
image: system_pay:prod
ports:
- 19880:19880
environment:
runmode: prod
networks:
- system_pay_network
networks:
system_pay_network:
driver: bridge
#!/bin/bash
git pull
export runmode=prod
docker-compose -f prod-docker-compose.yaml up --build -d
docker image prune -f
\ No newline at end of file
package redis
import (
"fmt"
"github.com/go-redis/redis"
"system_pay/setting"
)
var (
Redisclient *redis.Client
Nil = redis.Nil
)
// Init 初始化连接
func Init(cfg *setting.RedisConfig) (err error) {
Redisclient = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
Password: cfg.Password, // no password set
DB: cfg.DB, // use default DB
PoolSize: cfg.PoolSize,
MinIdleConns: cfg.MinIdleConns,
})
_, err = Redisclient.Ping().Result()
if err != nil {
return err
}
return err
}
func Close() {
_ = Redisclient.Close()
}
package repository
import (
"strings"
)
////QueryChainCodeAndLocalIDByPhone 查询用户信息
//func QueryChainCodeAndLocalIDByPhone(phone string) (string, int, error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return "", 0, err
// }
// // 查询医院是否存在
// var chainCode string
// var employeeLocalID int
// err = db.QueryRow(`select default_chain_code, employee_local_id from hos_database.employee_wx
// where employee_phone = ?`, phone).Scan(&chainCode, &employeeLocalID)
// switch {
// case err == sql.ErrNoRows:
// return "", 0, errors.New("没有这个用户")
// case err != nil:
// return "", 0, err
// }
//
// return chainCode, employeeLocalID, nil
//}
//
//// 根据医院code 获取云端id
//func GetHospitalIdByCode(hospitalCode string) (string, error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return "", err
// }
//
// var hospitalId string
//
// err = db.QueryRow("select id from hospital_main where hospital_code = ?", hospitalCode).Scan(&hospitalId)
// if err != nil {
// return "", err
// }
//
// return hospitalId, nil
//}
//
//// QueryChainCodeByPhone 查询用户使用的是哪个医院的数据
//func QueryChainCodeByPhone(phone string) (chain string, err error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return "", err
// }
//
// // 查询医院是否存在
// var chainCode string
// err = db.QueryRow(`select default_chain_code from employee_wx
// where employee_phone = ?`, phone).Scan(&chainCode)
// if err != nil {
// return "", err
// }
//
// if chainCode == "" {
// return "", errors.New("查不到这个用户")
// }
//
// return chainCode, nil
//}
//
//// QueryChainCode 查询chain_code
//func QueryChainCode(phone string) (string, error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return "", err
// }
//
// var code string
//
// err = db.QueryRow(`select c.chain_code from hospital_main as h
// LEFT JOIN chain_main as c on h.chain_id = c.id
// where c.delflag = 0 AND h.delflag = 0 AND h.create_phone = ?`, phone).Scan(&code)
//
// if err != nil {
// return "", err
// }
//
// return code, nil
//}
//
//// QueryChainID 查询chain_ID
//func QueryChainID(phone string) (int, error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return 0, err
// }
//
// var id int
//
// err = db.QueryRow(`select c.id from hospital_main as h
// LEFT JOIN chain_main as c on h.chain_id = c.id
// where c.delflag = 0 AND h.delflag = 0 AND h.create_phone = ?`, phone).Scan(&id)
//
// if err != nil {
// return 0, err
// }
//
// return id, nil
//}
//
//// QueryHospitalCode 查询医院码
//func QueryHospitalCode(phone string) (string, error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return "", err
// }
//
// var code string
//
// err = db.QueryRow(`select hospital_code from hospital_main where delflag = 0 and create_phone = ?`, phone).Scan(&code)
//
// if err != nil {
// return "", err
// }
//
// return code, nil
//}
//
//// CheckHospitalPhone 检查手机号码是否有效
//func CheckHospitalPhone(phone string) (bool, error) {
//
// db, err := mysql.NewAccountConn()
// if err != nil {
// return false, err
// }
//
// var (
// code int
// authorizeState int
// storageMethod int
// chainID int64
// )
// // 查询是否注册过
// err = db.QueryRow(`select count(*) from hospital_main where create_phone = ?`, phone).Scan(&code)
// if err != nil {
// return false, err
// }
//
// //chain_id
// err = db.QueryRow(`select chain_id from hospital_main where create_phone = ?`, phone).Scan(&chainID)
// if err != nil {
// return false, err
// }
//
// // 查询是否授权
// err = db.QueryRow(`SELECT IFNULL(b.authorize_state ,0) FROM hospital_main AS a left join hospital_operate AS b
// ON a.id = b.hospital_main_id WHERE a.create_phone = ? `, phone).Scan(&authorizeState)
// if err != nil {
// return false, err
// }
//
// // 查询是否授权
// err = db.QueryRow(`SELECT store_type FROM chain_config where chain_main_id = ? `, chainID).Scan(&storageMethod)
// if err != nil {
// return false, err
// }
//
// if authorizeState == 1 && code > 0 && storageMethod == 0 {
// return true, nil
// }
//
// return false, err
//}
// PackingDatabaseName 包装数据库名称
func PackingDatabaseName(tableName, code string) string {
return "dbc_" + strings.ToLower(code) + "." + tableName
}
// QueryHospitalID 查询医院码
//func QueryHospitalID(chainCode, hospitalCode string) (int, string, error) {
//
// db, err := mysql.NewUserConn(chainCode)
// if err != nil {
// return 0, "", err
// }
//
// tableName := PackingDatabaseName("sys_hospital", chainCode)
//
// querySQL := fmt.Sprintf(`select id,_name from %s
// where delflag = 0 and hospital_code = ?`, tableName)
//
// var (
// id int
// name string
// )
//
// err = db.QueryRow(querySQL, hospitalCode).Scan(&id, &name)
// if err != nil {
// zap.L().Error("err", zap.Error(err))
// return 0, "", err
// }
// return id, name, err
//}
//GetTheCostOfGoods 获取商品成本
//func GetTheCostOfGoods(chainCode, hospitalID string, db *sqlx.DB) ([]models.CommodityCost, error) {
//
// commodityCosts := make([]models.CommodityCost, 0)
//
// getTheCostOfGoodsSQL := fmt.Sprintf(`select con_commodity_id,costmoney from g_stock
// where delflag = 0 and sys_hospital_id = %d`, hospitalID)
//
// rows, err := db.Query(getTheCostOfGoodsSQL)
// if err != nil {
// zap.L().Error("err", zap.Error(err))
// return nil, err
// }
//
// for rows.Next() {
// var t models.CommodityCost
// err = rows.Scan(&t.CommodityID, t.CommodityCostPrice)
// if err != nil {
// zap.L().Error("err", zap.Error(err))
// return nil, err
// }
// commodityCosts = append(commodityCosts, t)
// }
//
// return commodityCosts, err
//
//}
This diff is collapsed.
package pack
const (
PayUrl = "/api/v1/pay/"
)
// 卡拉卡统一支付
func PayUrlPacking(s string) string {
return PayUrl + s
}
\ No newline at end of file
package routers
import (
"github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
v1_router "system_pay/router/v1"
)
// InitRouter 注册路由
func InitRouter() *gin.Engine {
if gin.Mode() == gin.ReleaseMode {
gin.SetMode(gin.ReleaseMode) // gin设置成发布模式
}
r := gin.Default()
// 测试与开发状态启用swagger
if gin.Mode() == gin.TestMode || gin.Mode() == gin.DebugMode {
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
// 发布后禁用swagger
if gin.Mode() == gin.ReleaseMode {
r.GET("/swagger/*any", ginSwagger.DisablingWrapHandler(swaggerFiles.Handler, "NAME_OF_ENV_VARIABLE"))
}
// 拉卡拉统一支付
v1_router.PayRouter(r)
// 登录
//v1_router.LoginRouter(r)
// 注册
//v1_router.RegisterRouter(r)
// 上传
//v1_router.UploadRouter(r)
// v1版本接口
//v1 := r.Group("/api/v1")
//v1.Use(jwt.JWTAuthMiddleWare())
//{
// // 全国快递物流
// v1_router.ExpressRouter(v1)
//
// // 谛宝多多账号
// v1_router.MemberRouter(v1)
//
// // 采购订单
// v1_router.PurchaseOrderRouter(v1)
//
// // 数据概览
// //v1_router.DataOverview(v1)
// //
// //// 顾客分析
// //v1_router.CustomerAnalysisRouter(v1)
// //
// //// 会员卡分析
// //v1_router.MembershipCardAnalysis(v1)
// //
// //// 次卡分析
// //v1_router.SecondaryCardAnalysis(v1)
// //
// //// 医疗消费
// //v1_router.MedicalConsumptionAnalysis(v1)
// //
// //// 病历量分析
// //v1_router.MedicalRecordsAnalysis(v1)
// //
// //// 商品分析
// //v1_router.CommodityAnalysis(v1)
// //
// //// 员工分析
// //v1_router.EmployeeAnalysis(v1)
// //
// //// 支付相关
// //v1_router.PayMoney(v1)
// //
// //// 埋点
// //v1_router.BuriedPoint(v1)
//}
return r
}
package v1
import (
"github.com/gin-gonic/gin"
"system_pay/controller/api/v1/pay"
"system_pay/router/pack"
)
// 统一支付
func PayRouter (r *gin.Engine) {
PayController := pay.PayController{}
// 卡拉卡统一支付
r.POST(pack.PayUrlPacking("unified_order"), PayController.UnifiedOrder)
}
# 设置运行时环境
export runmode=dev
# 热加载
air
# 设置运行时环境
export runmode=prod
# 热加载
air
\ No newline at end of file
package setting
import (
"fmt"
"strconv"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
var Conf = new(Config)
type Config struct {
ServerSetting *Server `mapstructure:"server"`
AppSetting *App `mapstructure:"app"`
DatabaseSetting *Database `mapstructure:"database"`
Redis *RedisConfig `mapstructure:"redis"`
LogSetting *Log `mapstructure:"log"`
Sms *SmsInternationalConfig `mapstructure:"sms"`
UploadImage *UploadImage `mapstructure:"uploadimage"`
Oss *Oss `mapstructure:"oss"`
AliCloud *AliCloud `mapstructure:"alicloud"`
Esign *Esign `mapstructure:"esign"`
JwtSecret string `mapstructure:"jwtsecret"`
DesKey string `mapstructure:"deskey"`
//SmsInternational *SmsInternationalConfig `mapstructure:"newsms"`
//GateWay *GateWayDetail `mapstructure:"gateway"`
//GateWayDev *GateWayDevDetail `mapstructure:"gatewaydev"`
//Mongo *MongoConfig `mapstructure:"mongo"`
//PayUrl *PayUrlDetail `mapstructure:"payurl"`
}
type App struct {
Name string `mapstructure:"name"`
Version string `mapstructure:"version"`
TimeFormat string `mapstructure:"timeformat""`
}
type Log struct {
LogSavePath string `mapstructure:"logsavepath"`
LogSaveName string `mapstructure:"logsavename"`
LogFileExt string `mapstructure:"logfileext"`
Level string `mapstructure:"level"`
MaxSize int `mapstructure:"max_size"`
MaxAge int `mapstructure:"max_age"`
MaxBackups int `mapstructure:"max_backups"`
}
// Server 服务
type Server struct {
RunMode string `mapstructure:"runmode"`
HttpPort int `mapstructure:"httpport"`
ReadTimeout time.Duration `mapstructure:"readtimeout"`
WriteTimeout time.Duration `mapstructure:"writetimeout"`
}
// Database DB
type Database struct {
Type string `mapstructure:"type""`
ShopDB string `mapstructure:"shopdb"`
UserDB string `mapstructure:"userdb"`
SecondDB string `mapstructure:"seconddb"`
AccountDB string `mapstructure:"accountdb"`
PayDB string `mapstructure:"paydb"`
//MaxOpenConns int `mapstructure:"max_open_conns"`
//MaxIdleConns int `mapstructure:"max_idle_conns"`
//Host string `mapstructure:"host"`
//User string `mapstructure:"user""`
//Password string `mapstructure:"password""`
//Port int `mapstructure:"port"`
//DB string `mapstructure:"dbname"`
}
// RedisConfig redis
type RedisConfig struct {
Host string `mapstructure:"host"`
Password string `mapstructure:"password"`
Port int `mapstructure:"port"`
DB int `mapstructure:"db"`
PoolSize int `mapstructure:"pool_size"`
MinIdleConns int `mapstructure:"min_idle_conns"`
}
// MongoConfig mongo设置
//type MongoConfig struct {
// DBUrl string `mapstructure:"dburl"`
// MaxOpenConns uint64 `mapstructure:"max_open_conns"`
//}
// SmsInternationalConfig 国际化短信
type SmsInternationalConfig struct {
SmsKey string `mapstructure:"smskey"`
SendSmsUrl string `mapstructure:"sendsmsurl"`
SmsContent string `mapstructure:"smscontent"`
}
//
//// GateWayDetail 网关
//type GateWayDetail struct {
// URL string `mapstructure:"url"`
// Port string `mapstructure:"port"`
//}
//
//// GateWayDevDetail 网关
//type GateWayDevDetail struct {
// URL string `mapstructure:"url"`
// Port string `mapstructure:"port"`
//}
//
//// PayUrlDetail 网关
//type PayUrlDetail struct {
// CheckOrder string `mapstructure:"checkorder"`
// OrderState string `mapstructure:"orderstate"`
//}
type UploadImage struct {
UploadDir string `mapstructure:"upload_dir"`
MaxFileSize int `mapstructure:"max_file_size"`
ImageTypes string `mapstructure:"image_types""`
AcceptFileTypes string `mapstructure:"accept_file_types""`
}
type Oss struct {
OssUrl string `mapstructure:"oss_url"`
AccessKeyID string `mapstructure:"accesskeyid"`
AccessKeySecret string `mapstructure:"accesskeysecret""`
EndPoint string `mapstructure:"endpoint""`
Bucket string `mapstructure:"bucket""`
}
type AliCloud struct {
AppCode string `mapstructure:"appcode"`
TimeDuration int `mapstructure:"time_duration"`
}
//e签宝
type Esign struct {
ProjectId string `mapstructure:"project_id"`
ProjectSecret string `mapstructure:"project_secret"`
OrganAuthUrl string `mapstructure:"organ_auth_url"`
InfoAuthUrl string `mapstructure:"info_auth_url"`
}
// Init 支持热修改的viper设置
func Init() error {
viper.SetConfigFile("conf/dev/config.yaml") // 指定配置文件路径
err := viper.ReadInConfig() // 读取配置信息
if err != nil { // 读取配置信息失败
fmt.Printf("viper.ReadInConfig failed, new_error:%v\n", err)
return err
}
// 将读取的配置信息保存至全局变量Conf
if err = viper.Unmarshal(Conf); err != nil {
fmt.Printf("viper.Unmarshal failed, new_error:%v\n", err)
}
// 监控配置文件变化
viper.WatchConfig()
// 注意!!!配置文件发生变化后要同步到全局变量Conf
viper.OnConfigChange(func(in fsnotify.Event) {
fmt.Println("配置文件被修改啦...")
if err = viper.Unmarshal(Conf); err != nil {
fmt.Printf("viper.Unmarshal failed, new_error:%v\n", err)
}
//fmt.Println(Conf)
})
return err
}
func GetPort() string {
s := strconv.Itoa(Conf.ServerSetting.HttpPort)
return ":" + s
}
{
// The tab key will cycle through the settings when first created
// Visit http://wbond.net/sublime_packages/sftp/settings for help
// sftp, ftp or ftps
"type": "sftp",
"save_before_upload": true,
"upload_on_save": true,
"sync_down_on_open": false,
"sync_skip_deletes": false,
"sync_same_age": true,
"confirm_downloads": false,
"confirm_sync": true,
"confirm_overwrite_newer": true,
"host": "39.96.85.45",
"user": "root",
"password": "dbc_root123",
"port": "22",
"remote_path": "/docker/system_pay",
"ignore_regexes": [
"\\.sublime-(project|workspace)", "sftp-config(-alt\\d?)?\\.json",
"sftp-settings\\.json", "/venv/", "\\.svn/", "\\.hg/", "\\.git/",
"\\.bzr", "_darcs", "CVS", "\\.DS_Store", "Thumbs\\.db", "desktop\\.ini"
],
//"file_permissions": "664",
//"dir_permissions": "775",
//"extra_list_connections": 0,
"connect_timeout": 30,
//"keepalive": 120,
//"ftp_passive_mode": true,
//"ftp_obey_passive_host": false,
//"ssh_key_file": "~/.ssh/id_rsa",
//"sftp_flags": ["-F", "/path/to/ssh_config"],
//"preserve_modification_times": false,
//"remote_time_offset_in_hours": 0,
//"remote_encoding": "utf-8",
//"remote_locale": "C",
//"allow_config_upload": false,
}
package utils
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/base64"
"fmt"
"io"
"strings"
)
//Utf8ToGBK is will encoding utf8 to gbk
//func Utf8ToGBK(content string) string {
// enc := mahonia.NewEncoder("gbk")
// return enc.ConvertString(content)
//}
//MD55 will create str out md5
func MD55(str string) string {
m := md5.New()
io.WriteString(m, str)
return strings.ToLower(fmt.Sprintf("%x", m.Sum(nil)))
}
//Aes 对称加密
func AesEncrypt(origData, key []byte) (string, error) {
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
result := base64.StdEncoding.EncodeToString(crypted)
return result, nil
}
//Aes 对称解密
func AesDecrypt(crypted, key []byte) (string, error) {
ciphertext := strings.Replace(string(crypted), " ", "", -1)
cryptedOri, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(cryptedOri))
blockMode.CryptBlocks(origData, cryptedOri)
origData = PKCS7UnPadding(origData)
return string(origData), nil
}
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
package utils
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"go.uber.org/zap"
"system_pay/setting"
)
//利用秘钥通过DES算法实现明文的加密
//利用秘钥通过DES算法实现密文的解密
//在加密和解密之前,首先需要补码和去码的操作
// PKCS5Padding 补码
func PKCS5Padding(orgData []byte, blockSize int) []byte {
//abc55555
padding := blockSize - len(orgData)%8
padtxt := bytes.Repeat([]byte{byte(padding)}, padding)
return append(orgData, padtxt...)
}
// PKCS5UnPadding 去码
func PKCS5UnPadding(cipherTxt []byte) []byte {
length := len(cipherTxt)
unpadding := int(cipherTxt[length-1])
return cipherTxt[:length-unpadding]
//cipherTxt[:4]
}
// DesEncrypt DES加密,加密会用到补码
func DesEncrypt(orig []byte, key []byte) []byte {
//首先检验秘钥是否合法
//DES加密算法,秘钥的长度必须为8bit block.BlockSize() = 8;
block, _ := des.NewCipher(key)
//补码
origData := PKCS5Padding(orig, block.BlockSize())
//设置加密方式
blockMode := cipher.NewCBCEncrypter(block, key)
//加密处理
crypted := make([]byte, len(origData)) //存放加密后的密文
blockMode.CryptBlocks(crypted, origData)
return crypted
}
// DesDecrypt DES解密,解密要用到去码
func DesDecrypt(cipherTxt []byte, key []byte) []byte {
//校验key的有效性
block, _ := des.NewCipher(key)
//设置解码方式
blockMode := cipher.NewCBCDecrypter(block, key)
//创建缓冲,存放解密后的数据
orgData := make([]byte, len(cipherTxt))
//开始解密
blockMode.CryptBlocks(orgData, cipherTxt)
//去掉编码
orgData = PKCS5UnPadding(orgData)
return orgData
}
// GetEncryptDes 进行des加密
func GetEncryptDes(s string) string {
return base64.StdEncoding.EncodeToString(DesEncrypt([]byte(s), []byte(setting.Conf.DesKey)))
// 通过base64处理秘文 打印成string
// base64.StdEncoding.EncodeToString(cipherTxt)
}
// ToDesDecrypt des对称解密
func ToDesDecrypt(cipherTxt string) string {
decodeString, err := base64.StdEncoding.DecodeString(cipherTxt)
if err != nil {
zap.L().Error("解密错误")
}
return string(DesDecrypt(decodeString, []byte(setting.Conf.DesKey)))
}
This diff is collapsed.
package utils
import (
"github.com/dgrijalva/jwt-go"
"github.com/pkg/errors"
"system_pay/conf"
"system_pay/setting"
"time"
)
// MyClaims 自定义声明结构体并内嵌jwt.StandardClaims
// jwt包自带的jwt.StandardClaims只包含了官方字段
// 我们这里需要额外记录一个username字段,所以要自定义结构体
// 如果想要保存更多信息,都可以添加到这个结构体中
type MyClaims struct {
UserName string `json:"user_name" description:"用户名称"` // 用户名称
UserId string `json:"user_id" description:"用户ID"` // 用户ID
PhoneMob string `json:"phone_mob" description:"用户手机号"` // 用户手机号
//HospitalCode string `json:"hospital_code" description:"医院唯一码"` // 医院唯一码
//ChainCode string `json:"chain_code" description:"连锁码"` // 连锁码
//HospitalID string `json:"hospital_id" description:"医院ID"` // 医院ID
//HospitalName string `json:"hospital_name" description:"医院名称"` // 医院名称
//ChainID string `json:"chain_id" description:"连锁ID"` // 连锁ID
jwt.StandardClaims
}
var MySecret = []byte(setting.Conf.JwtSecret)
//const TokenExpireDuration = time.Hour * 24 * 7
// ParseToken 解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {
// 解析token
token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
return MySecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token
return claims, nil
}
return nil, errors.New("invalid token")
}
// GetToken 生成JWT
func GetToken(phoneMob, userId, userName string) (string, error) {
// 进行des加密
desUserName := GetEncryptDes(userName)
desUserId := GetEncryptDes(userId)
desPhoneMob := GetEncryptDes(phoneMob)
//desHospitalCode := GetEncryptDes(hospitalCode)
//
//desChainCode := GetEncryptDes(chainCode)
//
//desHospitalName := GetEncryptDes(hospitalName)
//
//strHospitalID := strconv.Itoa(hospitalID)
//
//desHospitalID := GetEncryptDes(strHospitalID)
//
//strChainID := strconv.Itoa(chainID)
//
//desChainID := GetEncryptDes(strChainID)
// 创建一个我们自己的声明
c := MyClaims{
desUserName, // 自定义字段
desUserId, // 自定义字段
desPhoneMob, // 自定义字段
//"", // 自定义字段
//"", // 自定义字段
//"",
//"",
//"", // 自定义字段
jwt.StandardClaims{
ExpiresAt: time.Now().Add(conf.TokenExpireDuration).Unix(), // 过期时间
Issuer: "system_pay", // 签发人
},
}
//使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
//使用指定的secret签名并获得完整的编码后的字符串token
return token.SignedString(MySecret)
}
// GetToken 生成JWT
//func GetToken(userPhone, hospitalCode, chainCode, hospitalName string, hospitalID int, chainID int) (string, error) {
//
// // 进行des加密
// desUserPhone := GetEncryptDes(userPhone)
//
// desHospitalCode := GetEncryptDes(hospitalCode)
//
// desChainCode := GetEncryptDes(chainCode)
//
// desHospitalName := GetEncryptDes(hospitalName)
//
// strHospitalID := strconv.Itoa(hospitalID)
//
// desHospitalID := GetEncryptDes(strHospitalID)
//
// strChainID := strconv.Itoa(chainID)
//
// desChainID := GetEncryptDes(strChainID)
//
// // 创建一个我们自己的声明
// c := MyClaims{
// desUserPhone, // 自定义字段
// desHospitalCode, // 自定义字段
// desChainCode, // 自定义字段
// desHospitalID,
// desHospitalName,
// desChainID, // 自定义字段
// jwt.StandardClaims{
// ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
// Issuer: "system_pay", // 签发人
// },
// }
// //使用指定的签名方法创建签名对象
// token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// //使用指定的secret签名并获得完整的编码后的字符串token
// return token.SignedString(MySecret)
//
//}
// GetTheInformationCarriedInTheToken 获取token中信息
//func GetTheInformationCarriedInTheToken(token string) (userPhone string, chainCode string, err error) {
//
// parseToken, err := ParseToken(token)
// if err != nil {
// zap.L().Error("解析token失败")
// return "", "", err
// }
//
// return ToDesDecrypt(parseToken.UserPhone), ToDesDecrypt(parseToken.HospitalCode), nil
//
//}
package utils
import (
"crypto/md5"
"encoding/hex"
)
// EncodeMD5 md5 encryption
func EncodeMD5(value string) string {
m := md5.New()
m.Write([]byte(value))
return hex.EncodeToString(m.Sum(nil))
}
// MD5 md5加密
func MD5(s string) string {
h := md5.New()
h.Write([]byte(s))
x := h.Sum(nil)
y := make([]byte, 32)
hex.Encode(y, x)
return string(y)
}
package utils
import (
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"system_pay/setting"
"time"
)
var(
//setting
//accessKeyID = setting.Conf.JwtSecret
//endPoint = setting.Conf.endPoint
//bucket = setting.Conf.bucket
//accessKeySecret = setting.Conf.accessKeySecret
//accessKeyID = setting.Conf.Oss.AccessKeyID
//accessKeySecret = setting.Conf.Oss.AccessKeySecret
//endPoint = setting.Conf.Oss.EndPoint
//bucket = setting.Conf.Oss.Bucket
//accessKeyID = "LTAIDfwPBC9AnsRt"
//endPoint = "Z6FtUptrAk0Sl6H8vrVBGZLbBzXEpO"
//bucket = "oss-cn-beijing.aliyuncs.com"
//accessKeySecret = "dbc-static"
Buckets *oss.Bucket
)
func GetOssBucket() (*oss.Bucket, error) {
// oss
accessKeyID := setting.Conf.Oss.AccessKeyID
accessKeySecret := setting.Conf.Oss.AccessKeySecret
endPoint := setting.Conf.Oss.EndPoint
bucket := setting.Conf.Oss.Bucket
if Buckets == nil {
client, err := oss.New(endPoint, accessKeyID, accessKeySecret)
if err != nil {
return nil, err
}
// 获取存储空间。
Buckets, err = client.Bucket(bucket)
if err != nil {
return nil, err
}
}
return Buckets, nil
}
func GetDate() string {
year := time.Now().Format("2006")
month := time.Now().Format("01")
day := time.Now().Format("02")
return year + month + day
}
This diff is collapsed.
package utils
import (
"regexp"
)
//检查手机号格式
func CheckPhoneNo(phone_no string)(bool) {
reg := `^1\d{10}$`
rgx := regexp.MustCompile(reg)
if (!rgx.MatchString(phone_no)) {
return false
}
return true
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment