wanghuidong 4 سال پیش
والد
کامیت
cb0f3b2867

+ 35 - 9
manage/product/product.go

@@ -3,6 +3,7 @@ package product
 import (
 	"github.com/gin-gonic/gin"
 	"go.uber.org/zap"
+	"net/http"
 	"sfbase/global"
 	"sfis/model"
 	"sfis/model/response"
@@ -26,22 +27,32 @@ func productCreate(context *gin.Context) {
 	var product model.Product
 	if err := context.ShouldBind(&product); err != nil {
 		global.Logger.Error("productCreate Bind Error", zap.Any("error", err))
-		response.FailWithMessage("参数错误", context)
+		response.FailWithDetailed(response.ParamError, nil, "参数错误", context)
 		return
 	}
-	service.CreateProduct(product, context)
+	err := service.CreateProduct(product)
+	if err != nil {
+		response.FailWithMessage(err.Error(), context)
+	} else {
+		response.OkWithMessage("创建成功", context)
+	}
+
 }
 
 // 删除产品
 func productDelete(context *gin.Context) {
 	var product model.Product
 	if err := context.ShouldBind(&product); err != nil {
-		response.FailWithMessage("参数错误", context)
+		response.FailWithDetailed(response.ParamError, nil, "参数错误", context)
 		global.Logger.Error("productDelete Bind Error", zap.Any("error", err))
 		return
 	}
-	service.DeleteProduct(product, context)
-
+	err := service.DeleteProduct(product)
+	if err != nil {
+		response.FailWithMessage(err.Error(), context)
+	} else {
+		response.OkWithMessage("删除成功", context)
+	}
 }
 
 //更新产品信息
@@ -54,7 +65,7 @@ func productUpdate(context *gin.Context) {
 	productType := context.PostForm("product_type")
 	testNum := context.PostForm("test_num")
 	if id_ == "" {
-		response.FailWithMessage("缺少id", context)
+		response.FailWithDetailed(response.ParamError, nil, "参数错误", context)
 		return
 	}
 	id, _ := strconv.Atoi(id_)
@@ -66,8 +77,13 @@ func productUpdate(context *gin.Context) {
 		"product_type": productType,
 		"test_num":     testNum}
 
-	global.Logger.Info("api userProjectChoose参数:", zap.Any("param", p))
-	service.UpdateProduct(p, id, context)
+	global.Logger.Info("api userProjectChoose参数:", zap.Any("param", p), zap.Any("id", id))
+	err := service.UpdateProduct(p, id)
+	if err != nil {
+		response.FailWithMessage(err.Error(), context)
+	} else {
+		response.OkWithMessage("更新成功", context)
+	}
 }
 
 // 产品信息列表
@@ -90,5 +106,15 @@ func productList(context *gin.Context) {
 		"product_type": productType,
 		"test_num":     testNum,
 	}
-	service.ListProduct(condMap, page, limit, context)
+	productList, totalCount, err := service.ListProduct(condMap, page, limit)
+	if err != nil {
+		response.FailWithMessage(err.Error(), context)
+	} else {
+		context.JSON(http.StatusOK, gin.H{
+			"code":       response.SUCCESS,
+			"data":       productList,
+			"msg":        "查询成功",
+			"totalCount": totalCount,
+		})
+	}
 }

+ 44 - 32
manage/user/user.go

@@ -4,15 +4,14 @@ import (
 	"encoding/json"
 	"github.com/gin-gonic/gin"
 	"go.uber.org/zap"
+	"io/ioutil"
 	"log"
 	"sfbase/global"
-
 	sutils "sfbase/utils"
 	"sfis/model"
 	"sfis/model/response"
 	"sfis/service"
 	"sfis/utils"
-	"strconv"
 	"time"
 )
 
@@ -23,6 +22,8 @@ func DevUserManageRegister(router *gin.Engine) {
 		userGroup.POST("/create", userCreate)
 		userGroup.POST("/userProductChoose", userProductChoose)
 		userGroup.POST("/userProductList", userProductList)
+		userGroup.POST("/moneyRecharge", moneyRecharge)
+		userGroup.POST("/productRecharge", productRecharge)
 	}
 }
 
@@ -30,7 +31,7 @@ func DevUserManageRegister(router *gin.Engine) {
 func userCreate(c *gin.Context) {
 	var user model.User
 	if err := c.ShouldBind(&user); err != nil {
-		response.FailWithMessage("参数错误",c)
+		response.FailWithMessage("参数错误", c)
 		return
 	}
 	global.Logger.Info("manage userCreate接口参数:", zap.Any("param", user))
@@ -39,39 +40,50 @@ func userCreate(c *gin.Context) {
 	key := sutils.GetComplexRandom(8, 3, 5)
 	user.SecretKey = key
 	user.AppID = appId
-	service.CreateUser(user,c)
-
+	// 创建用户
+	userData, err := service.CreateUser(user)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+	} else {
+		response.OkWithData(userData, c)
+	}
 }
 
 func userProductChoose(c *gin.Context) {
-	appId := c.PostForm("appId")
-	productIds := c.PostForm("productIds")
-	startTime := c.PostForm("startTime") //时间格式2021-01-11 16:50:06
-	endTime := c.PostForm("endTime")
-	leftNum, _ := strconv.Atoi(c.PostForm("leftNum"))
-	costModel, _ := strconv.Atoi(c.PostForm("costModel"))
-	interfaceStatus, _ := strconv.Atoi(c.PostForm("interfaceStatus"))
-	callTimesLimitDay, _ := strconv.Atoi(c.PostForm("callTimesLimitDay"))
-	dataNumOneTimes, _ := strconv.Atoi(c.PostForm("dataNumOneTimes"))
-	tradeMoney, _ := strconv.Atoi(c.PostForm("tradeMoney"))
-	tradeMoney = tradeMoney * 100
-	buyType, _ := strconv.Atoi(c.PostForm("buyType"))
-	log.Println("tradeMoney", tradeMoney)
-	p := gin.H{
-		"appId":             appId,
-		"ProductIds":        productIds,
-		"startTime":         startTime,
-		"endTime":           endTime,
-		"leftNum":           leftNum,
-		"costModel":         costModel,
-		"interfaceStatus":   interfaceStatus,
-		"callTimesLimitDay": callTimesLimitDay,
-		"dataNumOneTimes":   dataNumOneTimes,
+	bs, err := ioutil.ReadAll(c.Request.Body)
+	if err != nil {
+		panic(err)
+		response.FailWithMessage("读取参数出错", c)
+		return
+	}
+	var dataMap map[string]interface{}
+	json.Unmarshal([]byte(bs), &dataMap)
+	log.Println("获取前端参数:", dataMap)
+	appId := sutils.ObjToString(dataMap["appId"])
+	buyType := sutils.IntAll(dataMap["buyType"])
+	products := dataMap["products"]
+	productArr := make([]map[string]interface{}, 0)
+	if _products, ok := products.([]interface{}); ok {
+		productArr = sutils.ObjArrToMapArr(_products)
+		log.Println(productArr)
+	}
+	log.Println("appid", appId)
+	log.Println(len(productArr), appId)
+	if appId != "" && len(productArr) > 0 {
+		status, haveProductId, err := service.CreateUserProduct(appId, productArr, buyType)
+		log.Println(status, haveProductId, err)
+		if status == 1 && err == nil {
+			if haveProductId != "" {
+				response.OkWithMessage("用户已购买过"+haveProductId+"产品,请去充值", c)
+			} else {
+				response.Ok(c)
+			}
+		} else {
+			response.Fail(c)
+		}
+	} else {
+		response.FailWithMessage("缺少参数", c)
 	}
-	bs, _ := json.Marshal(p)
-	param := string(bs)
-	global.Logger.Info("api userProductChoose参数:", zap.Any("param", param))
-	service.UserProduct(productIds, appId, startTime, endTime, leftNum, costModel, interfaceStatus, callTimesLimitDay, dataNumOneTimes, tradeMoney, buyType, c)
 }
 
 func userProductList(c *gin.Context) {

+ 19 - 20
api/v1/userRecharge.go → manage/user/userRecharge.go

@@ -1,7 +1,6 @@
-package v1
+package user
 
 import (
-	"encoding/json"
 	"sfbase/global"
 	"sfis/model/response"
 	"sfis/service"
@@ -11,31 +10,26 @@ import (
 	"go.uber.org/zap"
 )
 
-//充值相关接口服务
-func RechargeApiRegister(router *gin.Engine) {
-	routerGroup := router.Group("/sfis/api/v1/user/")
-	routerGroup.Use()
-	{
-		routerGroup.POST("/moneyRecharge", moneyRecharge)
-		routerGroup.POST("/productRecharge", productRecharge)
-	}
-}
-
 //余额充值接口
 func moneyRecharge(c *gin.Context) {
 	appid := c.PostForm("appid")
 	money, err := strconv.Atoi(c.PostForm("money"))
 	if err != nil {
 		response.FailWithDetailed(response.ParamError, nil, "参数错误", c)
+		return
 	}
 	p := gin.H{
 		"appid": appid,
 		"money": money,
 	}
-	bs, _ := json.Marshal(p)
-	param := string(bs)
-	global.Logger.Info("api moneyRecharge:", zap.Any("param:", param))
-	service.MoneyRecharge(appid, money, c)
+	global.Logger.Info("api moneyRecharge:", zap.Any("param:", p))
+	errs := service.MoneyRecharge(appid, money, c)
+	if errs == nil {
+		response.Ok(c)
+	} else {
+		global.Logger.Error("数据库操作失败", zap.Any("error:", errs))
+		response.FailWithMessage("充值失败", c)
+	}
 }
 
 //产品剩余量充值接口
@@ -46,6 +40,7 @@ func productRecharge(c *gin.Context) {
 	endTime := c.PostForm("endTime")
 	if err != nil || errs != nil {
 		response.FailWithDetailed(response.ParamError, nil, "参数错误", c)
+		return
 	}
 	p := gin.H{
 		"appid":       appid,
@@ -53,8 +48,12 @@ func productRecharge(c *gin.Context) {
 		"rechargeNum": rechargeNum,
 		"endTime":     endTime,
 	}
-	bs, _ := json.Marshal(p)
-	param := string(bs)
-	global.Logger.Info("api productRecharge:", zap.Any("param:", param))
-	service.ProductRecharge(appid, productId, rechargeNum, endTime, c)
+	global.Logger.Info("api productRecharge:", zap.Any("param:", p))
+	errss := service.ProductRecharge(appid, productId, rechargeNum, endTime, c)
+	if errs == nil {
+		response.Ok(c)
+	} else {
+		global.Logger.Error("数据库操作失败", zap.Any("error:", errss))
+		response.FailWithMessage("充值失败", c)
+	}
 }

+ 0 - 26
middleware/auth.go

@@ -3,10 +3,7 @@ package middleware
 import (
 	"fmt"
 	"sfbase/global"
-	"sfbase/redis"
 	sutils "sfbase/utils"
-	"sfis/db"
-	"sfis/model"
 	"sfis/model/response"
 	"sfis/utils"
 	"strconv"
@@ -95,29 +92,6 @@ func TokenAuth() gin.HandlerFunc {
 			context.Abort()
 			return
 		}
-
-		userProduct := &model.UserProduct{}
-		db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appID, ProductID: productID})
-		//校验是否过期
-		end := userProduct.EndAt
-		if now > end.Unix() {
-			response.FailWithDetailed(response.InterfaceExpired, nil, "剩余量已过期", context)
-			context.Abort()
-			return
-		}
-		//校验每日调用上限
-		limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), productID, appID)
-		limittoday := redis.GetInt("limit", limittodaykey)
-		if limittoday >= userProduct.CallTimesLimitDay { //当天调用超过次数
-			response.FailWithDetailed(response.MoreThanEveryDayDataNumberLimit, nil, "请求超过每日调用总量限制", context)
-			context.Abort()
-			return
-		} else {
-			if limittoday == 0 {
-				_, max := sutils.GetDayMinMax(time.Now())
-				redis.Put("limit", limittodaykey, 0, int(max-now))
-			}
-		}
 		context.Set("appID", appID)
 		context.Set("productID", productID)
 		context.Set("requestIP", requestIP)

+ 10 - 13
model/response/response.go

@@ -8,26 +8,26 @@ import (
 
 const (
 	ERROR   int = -1
-	SUCCESS int = 1000
+	SUCCESS int = 0
 	//服务级错误码
 	EmptyResult                  int = 201  //查询无结果
-	ParamError                   int = 4001 //参数错误
+	ParamError                   int = 202 //参数错误
 	ParamEmpty                       = 203  //参数为空
 	ParamLenInValid              int = 204  //参数长度小于4
 	Waiting                      int = 205  //等待处理中
 	MoreThanQueryDataNumberLimit int = 206  //请求数据的条数超过上限
-	LeftNumEmpty                     = 4003 //余额不足
-	QueryError                   int = 4004 //系统查询异常,请联系客服
+	LeftNumEmpty                     = 207 //余额不足
+	QueryError                   int = 299 //系统查询异常,请联系客服
 
 	//系统级错误码
-	InValidKey    = 101 //当前KEY无效
-	RemainingLack = 102 //当前KEY余额|余量不足
-	DeleteKey     = 103 //当前Key被暂停使用,请联系管理员
-	TokenInvalid  = 104 //身份验证错误
-	TokenExpired  = 107 //身份验证已过期
+	InValidKey    = 101  //当前KEY无效
+	RemainingLack = 102  //当前KEY余额|余量不足
+	DeleteKey     = 103  //当前Key被暂停使用,请联系管理员
+	TokenInvalid  = 4000 //身份验证错误
+	TokenExpired  = 4002 //身份验证已过期
 
 	//105非法请求过多,请联系管理员
-	IpInvalid                       = 4005 //被禁止的IP
+	IpInvalid                       = 108 //被禁止的IP
 	MoreThanEveryDayQueryTimesLimit = 109  //请求超过每日系统限制
 	//108当前相同查询连续出错,请等2小时后重试
 	InterfaceRightInvalid           = 110 //接口权限未开通
@@ -35,9 +35,6 @@ const (
 	InterfaceDeleted                = 112 //接口已停用,请联系管理员
 	MoreThanEveryDayDataNumberLimit = 113 //请求超过每日调用总量限制
 	OtherError                      = 199 //系统未知错误,请联系技术客服
-	//
-	SignError   = 4000 //签名错误
-	SignExpired = 4002 //签名过期
 )
 
 type Response struct {

+ 2 - 2
model/user.go

@@ -7,10 +7,10 @@ import (
 type User struct {
 	BaseModel
 	Name        string `json:"name" form:"name" binding:"required"`
-	Phone       string `json:"phone" form:"phone"`
+	Phone       string `json:"phone" form:"phone" binding:"required"`
 	AppID       string `json:"app_id"`
 	SecretKey   string `json:"secret_key"`
-	IpWhiteList string `json:"ip_white_list" form:"ip_white_list"`
+	IpWhiteList string `json:"ip_white_list" form:"ip_white_list" binding:"required"`
 }
 
 func (user *User) TableName() string {

+ 15 - 0
router/pageRouter.go

@@ -9,9 +9,24 @@ func pageRouterRegister(router *gin.Engine) {
 	//pageRouterGroup.Use(middleware.JwtAuth())
 	{
 		pageRouterGroup.GET("/login", login)
+		pageRouterGroup.GET("/chooseProductPage", chooseProductPage)
+		pageRouterGroup.GET("/createUser", createUser)
+		pageRouterGroup.GET("/userRecharge", userRechargePage)
 	}
 }
 
 func login(context *gin.Context) {
 	context.HTML(200, "login.html", nil)
+	context.HTML(200, "login.html", nil)
+}
+
+func chooseProductPage(context *gin.Context) {
+	context.HTML(200, "chooseProduct.html", nil)
+}
+func createUser(context *gin.Context) {
+	context.HTML(200, "create_user.html", nil)
+}
+
+func userRechargePage(context *gin.Context) {
+	context.HTML(200, "userRecharge.html", nil)
 }

+ 0 - 1
router/route.go

@@ -17,7 +17,6 @@ func InitRouter(middleware ...gin.HandlerFunc) *gin.Engine {
 		})
 	})
 	v1.ProjectApiRegister(router)
-	v1.RechargeApiRegister(router)
 	user.DevUserManageRegister(router)
 	product.ProductManageRegister(router)
 	return router

+ 24 - 42
service/product.go

@@ -1,52 +1,49 @@
 package service
 
 import (
+	"errors"
 	"fmt"
-	"github.com/gin-gonic/gin"
 	"go.uber.org/zap"
-	"net/http"
 	"sfbase/global"
 	"sfis/db"
 	"sfis/model"
-	"sfis/model/response"
 	"strconv"
 	"strings"
 )
 
 // 创建产品
-func CreateProduct(product model.Product, context *gin.Context) {
-	var tempProduct model.Product
+func CreateProduct(product model.Product) error {
+	var count int64
 	// 判断用产品id是否重复
-	db.GetSFISDB().Where("id = ?", product.ID).Find(&tempProduct)
-	fmt.Println(tempProduct)
-	if tempProduct.ID > 0 {
-		response.FailWithMessage("产品id重复", context)
-		return
+	db.GetSFISDB().Table("product").Where("id = ?", product.ID).Count(&count)
+	fmt.Println(count, product.ID)
+	if count > 0 {
+		return errors.New("产品id重复")
 	}
 	result := db.GetSFISDB().Create(&product)
 	if result.Error != nil {
 		global.Logger.Error("productCreate Error", zap.Any("product", product), zap.Any("error", result.Error))
-		response.FailWithMessage("产品创建失败", context)
+		return errors.New("产品创建失败")
 	} else {
 		global.Logger.Info("productCreate Success", zap.Any("product", product))
-		response.OkWithMessage("产品创建成功", context)
+		return nil
 	}
 }
 
 // 删除产品
-func DeleteProduct(product model.Product, context *gin.Context) {
+func DeleteProduct(product model.Product) error {
 	result := db.GetSFISDB().Delete(&product)
 	if result.Error != nil {
 		global.Logger.Error("productDelete Error", zap.Any("id", product.ID), zap.Any("error", result.Error))
-		response.FailWithMessage("产品删除失败", context)
+		return errors.New("产品删除失败")
 	} else {
 		global.Logger.Info("productDelete Success", zap.Any("id", product.ID))
-		response.OkWithMessage("产品删除成功", context)
+		return nil
 	}
 }
 
 //更新产品
-func UpdateProduct(updateMap map[string]interface{}, id int, context *gin.Context) {
+func UpdateProduct(updateMap map[string]interface{}, id int) error {
 	//移除map中为空串的key
 	for k, v := range updateMap {
 		if v == "" {
@@ -56,19 +53,18 @@ func UpdateProduct(updateMap map[string]interface{}, id int, context *gin.Contex
 			updateMap[k] = strV
 		}
 	}
-
 	result := db.GetSFISDB().Table("product").Where("id = ?", id).Updates(updateMap)
 	if result.Error != nil {
 		global.Logger.Error("productUpdate Error", zap.Any("updateMap", updateMap), zap.Any("error", result.Error))
-		response.FailWithMessage("产品更新失败", context)
+		return errors.New("更新失败")
 	} else {
 		global.Logger.Info("productUpdate Success", zap.Any("updateMap", updateMap))
-		response.OkWithMessage("产品更新成功", context)
+		return nil
 	}
 }
 
 // 查询产品
-func ListProduct(condMap map[string]interface{}, page int, limit int, context *gin.Context) {
+func ListProduct(condMap map[string]interface{}, page int, limit int) ([]model.Product, int64, error) {
 	// 拼查询sql
 	var products []model.Product
 	var key []string
@@ -89,35 +85,21 @@ func ListProduct(condMap map[string]interface{}, page int, limit int, context *g
 	}
 	sql := strings.Join(key, " and ")
 	var totalCount int64
-	errors := db.GetSFISDB().Table("product").Where(sql, param...).Count(&totalCount).Error
-	if errors != nil {
-		global.Logger.Error("productList search count Error", zap.Any("condMap", condMap), zap.Any("error", errors))
-		response.FailWithMessage("产品信息查询失败", context)
+	// 查询
+	err := db.GetSFISDB().Table("product").Where(sql, param...).Find(&products).Count(&totalCount).Error
+	if err != nil {
+		global.Logger.Error("productList search count Error", zap.Any("condMap", condMap), zap.Any("error", err))
+		return products, 0, errors.New("产品信息查询失败")
 	}
 	if totalCount == 0 {
-		context.JSON(http.StatusOK, map[string]interface{}{
-			"data":        products,
-			"msg":         "查询成功",
-			"total_count": 0,
-			"code":        response.SUCCESS,
-		})
-		//response.OkWithData(products, context)
-		return
+		return products, 0, nil
 	}
 	result := db.GetSFISDB().Table("product").Where(sql, param...).Limit(limit).Offset((page - 1) * limit).Find(&products)
 	if result.Error != nil {
 		global.Logger.Error("productList Error", zap.Any("condMap", condMap), zap.Any("error", result.Error))
-		response.FailWithMessage("产品信息查询失败", context)
+		return products, 0, errors.New("产品信息查询失败")
 	} else {
 		global.Logger.Info("productList Success", zap.Any("condMap", condMap))
-		//response.OkWithData(products, context)
-		response.OkWithData(products, context)
-		context.JSON(http.StatusOK, map[string]interface{}{
-			"data":        products,
-			"msg":         "查询成功",
-			"total_count": totalCount,
-			"code":        response.SUCCESS,
-		})
+		return products, totalCount, nil
 	}
-
 }

+ 103 - 149
service/user.go

@@ -1,186 +1,134 @@
 package service
 
 import (
+	"errors"
 	"github.com/gin-gonic/gin"
 	"go.uber.org/zap"
 	"gorm.io/gorm"
 	"log"
 	"sfbase/global"
+	"sfbase/utils"
 	"sfis/db"
 	"sfis/lock"
 	"sfis/model"
 	"sfis/model/response"
 	"strconv"
-	"strings"
 	"sync"
 	"time"
 )
 
-func UserProduct(productIds, appId, startTime, endTime string, leftNum, costModel, interfaceStatus, callTimesLimitDay, dataNumOneTimes, tradeMoney, buyType int, c *gin.Context) {
+func CreateUserProduct(appId string, productArr []map[string]interface{}, buyType int) (status int, haveProductId string, err error) {
 	//取出用户锁
 	lock.MainLock.Lock()
 	userLock := lock.UserLockMap[appId]
 	lock.MainLock.Unlock()
 	userLock.Lock()
 	defer userLock.Unlock()
-	productIdsArr := strings.Split(productIds, ",")
-	if len(productIdsArr) > 0 {
-		var errs error
-		for _, v := range productIdsArr {
-			productId, _ := strconv.Atoi(v)
-			userProduct := &model.UserProduct{}
-			userProduct.AppID = appId
-			userProduct.StartAt, _ = time.ParseInLocation("2006-01-02 15:04:05", startTime, time.Local)
-			userProduct.EndAt, _ = time.ParseInLocation("2006-01-02 15:04:05", endTime, time.Local)
-			userProduct.LeftNum = leftNum
-			userProduct.CostModel = costModel
-			userProduct.InterfaceStatus = interfaceStatus
-			userProduct.CallTimesLimitDay = callTimesLimitDay
-			userProduct.DataNumLimitOneTimes = dataNumOneTimes
-			userProduct.ProductID = productId
-			userProductInfo := model.UserProduct{}
-			product := model.Product{}
-			//查询产品信息,获取购买时候产品单价、试用次数
-			err := db.GetSFISDB().Where("id = ?", productId).Find(&product).Error
-			if err != nil {
-				response.FailWithMessage("查询产品信息出错", c)
-				return
-			}
-			historyUnitPrice := product.UnitPrice
-			err = db.GetSFISDB().Where("product_id = ? and app_id = ?", productId, appId).Find(&userProductInfo).Error
-			if err != nil {
-				response.FailWithMessage("查询用户产品信息出错", c)
-				return
-			}
-			//已选择过该产品--更新用户产品信息
-			if userProductInfo.ID != 0 {
-				before := userProductInfo.LeftNum
-				after := userProductInfo.LeftNum + leftNum
-				userProductId := userProductInfo.ID
-				errs = db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
-					//更新用户产品信息
-					userProduct.LeftNum = userProductInfo.LeftNum + leftNum
-					userProduct.UpdateAt = time.Now()
-					log.Println(userProduct.UpdateAt, "++++++++++++++++++++")
-					err := tx.Exec("update user_product set left_num = ?, start_at = ?,end_at = ?,cost_model = ?,interface_status = ?,call_times_limit_day=?,data_num_limit_one_times=? where product_id = ? and app_id = ?", after, startTime, endTime, costModel, interfaceStatus, callTimesLimitDay, dataNumOneTimes, productId, appId).Error
+	var errs error
+	haveProductId = "" //已经购买过的产品id
+	for _, val := range productArr {
+		productId := utils.IntAll(val["productId"])
+		costModel := utils.IntAll(val["costModel"])
+		leftNum := utils.IntAll(val["leftNum"])
+		tradeMoney := utils.IntAll(val["tradeMoney"]) * 100
+		userProduct := &model.UserProduct{}
+		userProduct.AppID = appId
+		userProduct.StartAt, _ = time.ParseInLocation("2006-01-02 15:04:05", utils.ObjToString(val["startTime"]), time.Local)
+		userProduct.EndAt, _ = time.ParseInLocation("2006-01-02 15:04:05", utils.ObjToString(val["endTime"]), time.Local)
+		userProduct.LeftNum = leftNum
+		userProduct.CostModel = costModel
+		userProduct.InterfaceStatus = utils.IntAll(val["interfaceStatus"])
+		userProduct.CallTimesLimitDay = utils.IntAll(val["callTimesLimitDay"])
+		userProduct.DataNumLimitOneTimes = utils.IntAll(val["dataNumOneTimes"])
+		userProduct.ProductID = productId
+		userProductInfo := model.UserProduct{}
+		product := model.Product{}
+		//查询产品信息,获取购买时候产品单价、试用次数
+		err := db.GetSFISDB().Where("id = ?", productId).Find(&product).Error
+		if err != nil {
+			global.Logger.Error("CreateUserProduct查询product表出错:", zap.Any("err:", err))
+			return 0, haveProductId, err
+		}
+		historyUnitPrice := product.UnitPrice
+		err = db.GetSFISDB().Where("product_id = ? and app_id = ?", productId, appId).Find(&userProductInfo).Error
+		if err != nil {
+			global.Logger.Error("CreateUserProduct查询user_product表出错:", zap.Any("err:", err))
+			return 0, haveProductId, err
+		}
+		//用户第一次购买产品
+		if userProductInfo.ID == 0 {
+			errs = db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
+				rechargeAmount := 0
+				remark := ""
+				//第一次购买产品赠送试用量
+				testNum := product.TestNum
+				//扣费类型为扣余额,user_buy_record中tradeMoney金额为0
+				if costModel == 0 {
+					rechargeAmount = tradeMoney
+					leftNum += testNum
+				} else if costModel == 1 {
+					leftNum = 0
+					//扣余额,把赠送量转化成金额
+					freeMoney := testNum * product.UnitPrice
+					log.Println(freeMoney, "freeMoney")
+					remark = "充值金额为:" + strconv.Itoa(tradeMoney) + ",赠送金额为:" + strconv.Itoa(freeMoney)
+					tradeMoney += freeMoney
+				}
+				userProduct.LeftNum = leftNum
+				//生用户产品
+				err := tx.Create(userProduct).Error
+				if err != nil {
+					log.Printf("appID:[%s],productId:[%d] execute insert user_product error:[%v]", appId, productId, err)
+					tx.Rollback()
+					return err
+				}
+				userProductId := userProduct.ID
+				//生成购买产品记录
+				err = tx.Exec("insert into user_buy_record (`app_id`,`product_id`,`user_product_id`,`before`,`after`,`trade_money`,`buy_type`,`history_unit_price`) values (?,?,?,?,?,?,?,?)", appId, productId, userProductId, 0, leftNum, rechargeAmount, buyType, historyUnitPrice).Error
+				if err != nil {
+					log.Printf("appID:[%s],productId[%d],trade_money:[%d] execute insert into user_buy_record error:[%v]", appId, productId, tradeMoney, err)
+					tx.Rollback()
+					return err
+				}
+				//扣费类型是扣余额,充值用户余额
+				if costModel == 1 {
+					userAccount := model.UserAccount{}
+					err = tx.First(&userAccount, model.UserAccount{AppID: appId}).Error
 					if err != nil {
-						log.Printf("appID:[%s],productId:[%d] update user_product error:[%v]", appId, productId, err)
+						log.Printf("appID:[%s],productId[%d],trade_money:[%d] execute find user_account error:[%v]", appId, productId, tradeMoney, err)
 						tx.Rollback()
 						return err
 					}
-					//生成购买产品记录
-					//扣费类型为扣余额,user_buy_record中tradeMoney金额为0
-					rechargeAmount := 0
-					if costModel == 0 {
-						rechargeAmount = tradeMoney
-					}
-					err = tx.Exec("insert into user_buy_record (`app_id`,`product_id`,`user_product_id`,`before`,`after`,`trade_money`,`buy_type`,`history_unit_price`) values (?,?,?,?,?,?,?,?)", appId, productId, userProductId, before, after, rechargeAmount, buyType, historyUnitPrice).Error
+					moneyBefore := userAccount.Money
+					moneyAfter := userAccount.Money + tradeMoney
+					//充值
+					err := tx.Exec("update user_account set money = ? WHERE `app_id` = ?", moneyAfter, appId).Error
 					if err != nil {
-						log.Printf("appID:[%s],productId[%d],trade_money:[%d] execute insert into user_buy_record error:[%v]", appId, productId, tradeMoney, err)
+						log.Printf("appID:[%s],money:[%d] execute update user_account error:[%v]", appId, moneyAfter, err)
 						tx.Rollback()
 						return err
 					}
-					//扣费类型是扣余额,充值用户余额
-					if costModel == 1 {
-						userAccount := model.UserAccount{}
-						err = tx.First(&userAccount, model.UserAccount{AppID: appId}).Error
-						if err != nil {
-							log.Printf("appID:[%s],productId[%d],trade_money:[%d] execute find user_account error:[%v]", appId, productId, tradeMoney, err)
-							tx.Rollback()
-							return err
-						}
-						moneyBefore := userAccount.Money
-						moneyAfter := userAccount.Money + tradeMoney
-						//充值
-						err := tx.Exec("update user_account set money = ? WHERE `app_id` = ?", moneyAfter, appId).Error
-						if err != nil {
-							log.Printf("appID:[%s],money:[%d] execute cost user_account error:[%v]", appId, moneyAfter, err)
-							tx.Rollback()
-							return err
-						}
-						//生充值记录
-						err = tx.Exec("insert into user_money_record (app_id,`before`,`after`,trade_money) values (?,?,?,?)", appId, moneyBefore, moneyAfter, tradeMoney).Error
-						if err != nil {
-							log.Printf("appID:[%s],trade_money:[%d] execute insert into user_money_record error:[%v]", appId, tradeMoney, err)
-							tx.Rollback()
-							return err
-						}
-					}
-					return nil
-				})
-			} else { //用户没有购买过改产品
-				errs = db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
-					//扣费类型为扣余额,user_buy_record中tradeMoney金额为0
-					rechargeAmount := 0
-					//第一次购买产品赠送试用量
-					testNum := product.TestNum
-					remark := ""
-					if costModel == 0 {
-						rechargeAmount = tradeMoney
-						leftNum += testNum
-					} else if costModel == 1 {
-						//扣余额,把赠送量转化成金额
-						freeMoney := testNum * product.UnitPrice
-						tradeMoney += freeMoney
-						remark = "充值金额为:" + strconv.Itoa(tradeMoney) + "赠送金额为:" + strconv.Itoa(freeMoney)
-					}
-					userProduct.LeftNum = leftNum
-					//生用户产品
-					err := tx.Create(userProduct).Error
-					if err != nil {
-						log.Printf("appID:[%s],productId:[%d] insert user_product error:[%v]", appId, productId, err)
-						tx.Rollback()
-						return tx.Error
-					}
-					userProductId := userProduct.ID
-					//生成购买产品记录
-					err = tx.Exec("insert into user_buy_record (`app_id`,`product_id`,`user_product_id`,`before`,`after`,`trade_money`,`buy_type`,`history_unit_price`) values (?,?,?,?,?,?,?,?)", appId, productId, userProductId, 0, leftNum, rechargeAmount, buyType, historyUnitPrice).Error
+					//生充值记录
+					err = tx.Exec("insert into user_money_record (app_id,`before`,`after`,trade_money,remark) values (?,?,?,?,?)", appId, moneyBefore, moneyAfter, tradeMoney, remark).Error
 					if err != nil {
-						log.Printf("appID:[%s],productId[%d],trade_money:[%d] execute insert into user_buy_record error:[%v]", appId, productId, tradeMoney, err)
+						log.Printf("appID:[%s],trade_money:[%d] execute insert into user_money_record error:[%v]", appId, tradeMoney, err)
 						tx.Rollback()
 						return err
 					}
-					//扣费类型是扣余额,充值用户余额
-					if costModel == 1 {
-						//第一次购买产品赠送免费次数
-						userAccount := model.UserAccount{}
-						err = tx.First(&userAccount, model.UserAccount{AppID: appId}).Error
-						if err != nil {
-							log.Printf("appID:[%s],productId[%d],trade_money:[%d] execute find user_account error:[%v]", appId, productId, tradeMoney, err)
-							tx.Rollback()
-							return err
-						}
-						moneyBefore := userAccount.Money
-						moneyAfter := userAccount.Money + tradeMoney
-						//充值
-						err := tx.Exec("update user_account set money = ? WHERE `app_id` = ?", moneyAfter, appId).Error
-						if err != nil {
-							log.Printf("appID:[%s],money:[%d] execute cost user_account error:[%v]", appId, moneyAfter, err)
-							tx.Rollback()
-							return err
-						}
-						//生充值记录
-						err = tx.Exec("insert into user_money_record (app_id,`before`,`after`,trade_money,remark) values (?,?,?,?,?)", appId, moneyBefore, moneyAfter, tradeMoney, remark).Error
-						if err != nil {
-							log.Printf("appID:[%s],trade_money:[%d] execute insert into user_money_record error:[%v]", appId, tradeMoney, err)
-							tx.Rollback()
-							return err
-						}
-					}
-					return nil
-				})
+				}
+				return nil
+			})
+			if errs == nil {
+				global.Logger.Info("用户已购买产品失败:", zap.Any("appId:", appId), zap.Any("productId:", productId))
+				continue
 			}
-		}
-		if errs == nil {
-			response.Ok(c)
-			return
 		} else {
-			response.FailWithMessage("购买产品失败", c)
-			return
+			haveProductId += "[" + strconv.Itoa(productId) + "]"
+			global.Logger.Info("用户已购买过该产品", zap.Any("appId:", appId), zap.Any("productId:", productId))
+			continue
 		}
-
 	}
-	response.FailWithMessage("缺少参数", c)
+	return 1, haveProductId, nil
 }
 
 func UserProductList(appId string, c *gin.Context) {
@@ -195,14 +143,20 @@ func UserProductList(appId string, c *gin.Context) {
 }
 
 //创建用户
-func CreateUser(user model.User, c *gin.Context) {
+func CreateUser(user model.User) (model.User, error) {
 	var tempUser []model.User
 	// 判断用户名是否重复
 	db.GetSFISDB().Where("name = ?", user.Name).Find(&tempUser)
 	if len(tempUser) > 0 {
-		response.FailWithMessage("用户名已存在", c)
 		global.Logger.Error("userCreate Error", zap.Any("user", user), zap.Any("error", "用户名已存在"))
-		return
+		return user, errors.New("用户名已存在")
+	}
+	// 判断手机号是否重复
+	var tempUser_ []model.User
+	db.GetSFISDB().Where("phone = ?", user.Phone).Find(&tempUser_)
+	if len(tempUser_) > 0 {
+		global.Logger.Error("userCreate Error", zap.Any("user", user), zap.Any("error", "手机号已存在"))
+		return user, errors.New("手机号已存在")
 	}
 	errs := db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
 		// 新增用户
@@ -224,14 +178,14 @@ func CreateUser(user model.User, c *gin.Context) {
 	})
 	if errs != nil {
 		global.Logger.Error("userCreate Error", zap.Any("user", user), zap.Any("error", errs))
-		response.FailWithMessage("创建失败", c)
+		return user, errors.New("创建失败")
 	} else {
 		global.Logger.Info("userCreate Success", zap.Any("user", user))
 		// 生全局内存锁
 		lock.MainLock.Lock()
 		lock.UserLockMap[user.AppID] = &sync.Mutex{}
 		lock.MainLock.Unlock()
-		response.OkWithDetailed(user, "创建成功", c)
+		return user, nil
 	}
 
 }

+ 5 - 18
service/userRecharge.go

@@ -1,11 +1,9 @@
 package service
 
 import (
-	"sfbase/global"
 	"sfis/db"
 	"sfis/lock"
 	"sfis/model"
-	"sfis/model/response"
 
 	"github.com/gin-gonic/gin"
 
@@ -13,11 +11,10 @@ import (
 	"sfis/utils"
 	"time"
 
-	"go.uber.org/zap"
 	"gorm.io/gorm"
 )
 
-func MoneyRecharge(appid string, money int, context *gin.Context) {
+func MoneyRecharge(appid string, money int, context *gin.Context) error {
 	//取出用户锁
 	lock.MainLock.Lock()
 	userLock := lock.UserLockMap[appid]
@@ -46,15 +43,10 @@ func MoneyRecharge(appid string, money int, context *gin.Context) {
 		}
 		return nil
 	})
-	if errs == nil {
-		response.Ok(context)
-	} else {
-		global.Logger.Error("数据库操作失败", zap.Any("error:", errs))
-		response.FailWithMessage("充值失败", context)
-	}
+	return errs
 }
 
-func ProductRecharge(appid string, productId, rechargeNum int, endTime string, context *gin.Context) {
+func ProductRecharge(appid string, productId, rechargeNum int, endTime string, context *gin.Context) error {
 	//取出用户锁
 	lock.MainLock.Lock()
 	userLock := lock.UserLockMap[appid]
@@ -96,7 +88,7 @@ func ProductRecharge(appid string, productId, rechargeNum int, endTime string, c
 				return err
 			}
 		}
-		//生充值记录
+		//生购买记录
 		err = tx.Exec("insert into user_buy_record (app_id,product_id,user_product_id,`before`,`after`,trade_money,buy_type,history_unit_price) values (?,?,?,?,?,?,?,?)", appid, productId, userProduct.ID, before, after, product.UnitPrice*rechargeNum, 1, product.UnitPrice).Error
 		if err != nil {
 			log.Printf("appID:[%s],product_id:[%d],user_product_id:[%d],after:[%d],trade_money:[%d] execute insert into user_buy_record error:[%v]", appid, productId, userProduct.ID, after, product.UnitPrice*rechargeNum, err)
@@ -105,10 +97,5 @@ func ProductRecharge(appid string, productId, rechargeNum int, endTime string, c
 		}
 		return nil
 	})
-	if errs == nil {
-		response.Ok(context)
-	} else {
-		global.Logger.Error("数据库操作失败", zap.Any("error:", errs))
-		response.FailWithMessage("充值失败", context)
-	}
+	return errs
 }

+ 149 - 0
static/templates/chooseProduct.html

@@ -0,0 +1,149 @@
+{{define "chooseProduct.html"}}
+    <!DOCTYPE html>
+    <html lang="en">
+    <head>
+        <meta charset="UTF-8">
+        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
+        <script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script>
+        <title>用户选择产品页面</title>
+    </head>
+    <body>
+    <table border="0" id="tableId">
+        <thead>
+        <tr class="tableTitle">
+            <th style="width: 20px"><input type="checkbox" name="item">
+            </td></th>
+            <th style="width: 50px">序号</th>
+            <th style="width: 100px">产品名称</th>
+            <th style="width: 200px">url</th>
+            <th style="width: 100px">产品单价</th>
+            <th style="width: 100px">产品类型</th>
+            <th style="width: 100px">最小单位</th>
+            <th style="width: 100px">试用次数</th>
+            {{/*            <th style="width: 100px">开始时间</th>*/}}
+            {{/*            <th style="width: 100px">结束时间</th>*/}}
+            {{/*            <th style="width: 100px">结束时间</th>*/}}
+        </tr>
+        </thead>
+        <tbody class="box">
+
+        </tbody>
+    </table>
+    <div style="margin-top: 20px">
+        开始时间:<input id="startTime" type="text">
+        结束时间:<input id="endTime" type="text" name="" id=""><br>
+        扣费模式:<select id="costModel" style="width: 165px;height: 25px;margin-top: 10px">
+            <option value="0">剩余量</option>
+            <option value="1">余额</option>
+        </select>
+        充值量:<input id="leftNum" type="text"><br>
+        充值金额:<input id="money" type="text">
+        产品状态:<select id="interfaceStatus" style="width: 165px;height: 25px;margin-top: 10px">
+            <option value="0">开启</option>
+            <option value="1">关闭</option>
+        </select><br>
+        每日调用次数:<input id="dayLimit" type="text">
+        每次获取数据量:<input id="oneLimit" type="text">
+        用户appid:<input id="appId" type="text">
+    </div>
+    <div style="margin-top: 10px">
+        <button type="submit" onclick="submit()" style="width: 80px;height: 30px;">提交</button>
+    </div>
+
+    <div>
+        <p class="result"></p>
+    </div>
+
+    </body>
+    </html>
+    <script>
+        productList()
+
+        function productList() {
+            $.ajax({
+                url: "/manage/product/list",
+                type: "POST",
+                dataType: "json",
+                async: false,
+                success: function (r) {
+                    if (r.code === 0) {
+                        console.log(r.data)
+                        var str = ""
+                        for (var i = 0; i < r.data.length; i++) {
+                            var item = r.data[i];
+                            str += '<tr>';
+                            str += '<td style="width: 20px"><input id=' + item["id"] + ' value=' + item["id"] + ' type="radio" name="item"></td>';
+                            str += '<td style="width: 50px">' + (i + 1) + '</td>';
+                            str += '<td style="width: 100px">' + item.name + '</td>';
+                            str += '<td style="width: 200px">' + item.url + '</td>';
+                            str += '<td style="width: 100px">' + item.unit_price + '</td>';
+                            if (item.product_type === 0) {
+                                str += '<td style="width: 100px">按次</td>';
+                            } else {
+                                str += '<td style="width: 100px">按条</td>';
+                            }
+
+                            str += '<td style="width: 100px">' + item.min_unit + '</td>';
+                            str += '<td style="width: 100px">' + item.test_num + '</td>';
+                            str += '</tr>';
+                        }
+                        $('.box').html(str);
+                    } else {
+
+                    }
+                }
+            })
+        }
+
+        function submit() {
+            var productId = $("input[name='item']:checked").val();
+            var startTime = $("#startTime").val();
+            var endTime = $("#endTime").val();
+            var leftNum = $("#leftNum").val();
+            var money = $("#money").val();
+            var costModel = $("#costModel").find("option:selected").val();
+            var interfaceStatus = $("#interfaceStatus").find("option:selected").val();
+            var dayLimit = $("#dayLimit").val();
+            var oneLimit = $("#oneLimit").val();
+            var appId = $("#appId").val();
+            var product = {}
+            product["productId"] = productId
+            product["startTime"] = startTime
+            product["endTime"] = endTime
+            product["leftNum"] = leftNum
+            product["tradeMoney"] = money
+            product["costModel"] = costModel
+            product["interfaceStatus"] = interfaceStatus
+            product["callTimesLimitDay"] = dayLimit
+            product["dataNumOneTimes"] = oneLimit
+            var products = []
+            products.push(product)
+            param = {
+                "products": products,
+                "appId": appId,
+                "buyType": 1,
+            }
+            console.log("参数:", param)
+            /*if (productId === undefined || productId === "") {
+                return
+            }*/
+            $.ajax({
+                url: "/manage/user/userProductChoose",
+                data: JSON.stringify(param),
+                type: "POST",
+                dataType: "json",
+                async: false,
+                success: function (r) {
+                    var a = JSON.stringify(r)
+                    $(".result").html(a);
+                    /*if (r.code == 0) {
+                        $(".result").html("请求成功!" + r.msg);
+                    } else {
+                        $(".result").html("购买产品失败!" + r.msg);
+                    }
+*/
+                }
+            })
+        }
+    </script>
+{{end}}

+ 75 - 0
static/templates/create_user.html

@@ -0,0 +1,75 @@
+{{define "create_user.html"}}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
+    <title>创建用户</title>
+</head>
+<body>
+<div style="margin: auto;width: 30%">
+    <p>创建用户</p>
+    <form>
+        <table>
+            <tr>
+                <td>用户名:</td>
+                <td><input type="text" name="name" id="name" placeholder="请输入用户名"></td>
+            </tr>
+            <tr>
+                <td>手机号:</td>
+                <td><input type="text" name="phone" id="phone" placeholder="请输入手机号"></td>
+            </tr>
+            <tr>
+                <td>ip白名单:</td>
+                <td><input type="text" name="ip_white_list" id="ip_white_list" placeholder="请输入ip白名单">
+                </td>
+            </tr>
+            <tr>
+                <td></td>
+                <td style="text-align: right"><input type="button" value="提交" onclick="createUser()">
+                </td>
+            </tr>
+        </table>
+        <br>
+    </form>
+    结果: <br>
+
+    <code id="message"></code>
+
+</div>
+<script>
+    const createUserUrl = "/manage/user/create";
+
+    <!--创建用户-->
+    function createUser() {
+        $("#message").text("")
+        let param = {
+            "name": $("#name").val(),
+            "phone": $("#phone").val(),
+            "ip_white_list": $("#ip_white_list").val(),
+        }
+        $.ajax({
+            url: createUserUrl,
+            type: "post",
+            data: param,
+            success: function (r) {
+                if (r.code == 0) {
+                    // $("#id").text(r.data.id)
+                    // $("#app_id").text(r.data.app_id)
+                    // $("#secret_key").text(r.data.secret_key)
+                    $("#message").text(JSON.stringify(r))
+
+                } else {
+                    $("#message").text(JSON.stringify(r))
+
+                }
+
+
+            }
+        })
+    }
+
+</script>
+</body>
+</html>
+{{end}}

+ 101 - 1
static/templates/login.html

@@ -3,10 +3,110 @@
     <html lang="en">
     <head>
         <meta charset="UTF-8">
+        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
+        <script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script>
         <title>接口服务平台后台管理系统</title>
     </head>
+    <style>
+
+    </style>
     <body>
-    接口服务平台后台管理系统
+        <dev id="main">
+            <h1>对外接口</h1>
+            <dev>
+                <a onclick="$('#projectList').show();$('#main').hide();">1.项目列表</a>
+                <a onclick="$('#projectListDetail').show();$('#main').hide();">2.项目列表及详情</a>
+            </dev>
+             <h1><a href="/page/userRecharge">充值接口</a></h1>
+            <h1>内部接口</h1>
+            <dev>
+                <a href="/page/createUser">1.创建用户</a>
+            </dev>
+            <h1>产品接口</h1>
+            <dev>
+                <a href="/page/chooseProductPage">1.选择产品</a>
+                <a>2.余额充值</a>
+                <a>3.产品充值</a>
+            </dev>
+        </dev>
+        <dev id="projectList" style="display: none;">
+            <input type="text" id="projectName" placeholder="请输入项目名">
+            <input type="text" id="winner" placeholder="请输入中标企业名">
+            <input type="text" id="bidTime" placeholder="请输入中标日期">
+            <button type="button" id="projectListBtn">提交</button>
+        </dev>
+        <dev id="projectListDetail" style="display: none;">
+            <input type="text" id="winners" placeholder="请输入中标企业名">
+            <button type="button" id="projectListDetailBtn">提交</button>
+        </dev>
+        <dev id="resultContent"></dev>
+        <script>
+            var appid = "sfGSVYRQMAAgkGBAUBJg4f";
+            var key = "364xw909";
+            function submit(param,rType,url,hearders,str){
+                $.ajax({
+                    url: url,
+                    type: rType,
+                    headers: hearders,
+                    data: param,
+                    success:function(r){
+                    	if(r.data){
+                            $("#resultContent").text("");
+                            for (var i in r.data){
+                                var html = `
+                                    <div>
+                                        <p>序号: ${i+1}</p>
+                                        <p>项目标识: ${r.data[i]["project_id"]}</p>
+                                        <p>项目名称: ${r.data[i]["projectname"]}</p>
+                                        <p>采购单位: ${r.data[i]["buyer"]}</p>
+                                        <p>采购单位行业: ${r.data[i]["buyerclass"]}</p>
+                                        <p>招标日期: ${r.data[i]["zbtime"]}</p>
+                                        <p>中标日期: ${r.data[i]["jgtime"]}</p>
+                                    </div>
+                                `
+                                $("#resultContent").append(html);
+                            } 
+                    	}else{
+                    		$("#resultContent").text(r.msg);
+                    	}
+                    }
+                })
+            }
+            
+            $("#projectListBtn").on("click", function(){
+                var param = {
+                    "app_id": appid,
+                    "project_name": $("#projectName").val(),
+                    "winner": $("#winner").val(),
+                    "bid_time": $("#bidTime").val()
+                };
+                var url = "/sfis/api/v1/projectList";
+                var rType = "post";
+                var now = new Date().getTime();
+                var token = md5(appid+Math.round(now/1000)+key);
+                var hearders = {
+                    "timestamp": ""+Math.round(now/1000),
+                    "token": token
+                }
+                submit(param,rType,url,hearders,"list");
+            })
+            
+            $("#projectListDetailBtn").on("click", function(){
+                var param = {
+                    "app_id": appid,
+                    "winner": $("#winners").val()
+                };
+                var url = "/sfis/api/v1/projectListDetail";
+                var rType = "post";
+                var now = new Date().getTime();
+                var token = md5(appid+Math.round(now/1000)+key);
+                var hearders = {
+                    "timestamp": ""+Math.round(now/1000),
+                    "token": token
+                }
+                submit(param,rType,url,hearders,"listDetail");
+            })
+    </script>
     </body>
     </html>
 {{end}}

+ 72 - 0
static/templates/userRecharge.html

@@ -0,0 +1,72 @@
+{{define "userRecharge.html"}}
+    <!DOCTYPE html>
+    <html lang="en">
+    <head>
+        <meta charset="UTF-8">
+        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
+        <title>接口服务平台后台管理系统</title>
+    </head>
+    <style>
+      
+    </style>
+    <body>
+        <dev id="main">
+            <h1>充值接口</h1>
+            <dev>
+                <a onclick="$('#money').show();$('#main').hide();">1.余额充值</a>
+                <a onclick="$('#product').show();$('#main').hide();">2.剩余量充值</a>
+            </dev>
+        </dev>
+        <dev id="money" style="display: none;">
+            <input type="number" id="moneys" placeholder="请输入充值金额">
+            <button type="button" id="moneyBtn">提交</button>
+        </dev>
+        <dev id="product" style="display: none;">
+            <input type="number" id="productId" placeholder="请输入产品id">
+            <input type="number" id="rechargeNum" placeholder="请输入充值次数">
+            <input type="text" id="endTime" placeholder="请输入结束时间">
+            <button type="button" id="productBtn">提交</button>
+        </dev>
+        <dev id="resultContent"></dev>
+        <script>
+            var appid = "sfGSVYRQMAAgkGBAUBJg4f";
+            function submit(param,rType,url,hearders){
+                $.ajax({
+                    url: url,
+                    type: rType,
+                    headers: hearders,
+                    data: param,
+                    success:function(r){
+                    	if(r.code === 1000){
+                            $("#resultContent").text(r.msg);
+                    	}else{
+                    		$("#resultContent").text(r.msg);
+                    	}
+                    }
+                })
+            }
+            $("#moneyBtn").on("click", function(){
+                var param = {
+                    "appid": appid,
+                    "money": $("#moneys").val(),
+                };
+                var url = "/manage/user/moneyRecharge";
+                var rType = "post";
+                submit(param,rType,url);
+            })
+            
+            $("#productBtn").on("click", function(){
+                var param = {
+                    "appid": appid,
+                    "rechargeNum": $("#rechargeNum").val(),
+                    "productId": $("#productId").val(),
+                    "endTime": $("#endTime").val()
+                };
+                var url = "/manage/user/productRecharge";
+                var rType = "post";
+                submit(param,rType,url);
+            })
+        </script>
+    </body>
+    </html>
+{{end}}

+ 47 - 0
sword_base/utils/stringutil.go

@@ -6,7 +6,9 @@ import (
 	"encoding/hex"
 	"fmt"
 	"io"
+	"math/big"
 	"math/rand"
+	"strconv"
 	"strings"
 	"time"
 
@@ -149,6 +151,51 @@ func ObjToString(old interface{}) string {
 	}
 }
 
+func IntAll(num interface{}) int {
+	return IntAllDef(num, 0)
+}
+
+func IntAllDef(num interface{}, defaultNum int) int {
+	if i, ok := num.(int); ok {
+		return int(i)
+	} else if i0, ok0 := num.(int32); ok0 {
+		return int(i0)
+	} else if i1, ok1 := num.(float64); ok1 {
+		return int(i1)
+	} else if i2, ok2 := num.(int64); ok2 {
+		return int(i2)
+	} else if i3, ok3 := num.(float32); ok3 {
+		return int(i3)
+	} else if i4, ok4 := num.(string); ok4 {
+		in, _ := strconv.Atoi(i4)
+		return int(in)
+	} else if i5, ok5 := num.(int16); ok5 {
+		return int(i5)
+	} else if i6, ok6 := num.(int8); ok6 {
+		return int(i6)
+	} else if i7, ok7 := num.(*big.Int); ok7 {
+		in, _ := strconv.Atoi(fmt.Sprint(i7))
+		return int(in)
+	} else if i8, ok8 := num.(*big.Float); ok8 {
+		in, _ := strconv.Atoi(fmt.Sprint(i8))
+		return int(in)
+	} else {
+		return defaultNum
+	}
+}
+
+func ObjArrToMapArr(old []interface{}) []map[string]interface{} {
+	if old != nil {
+		new := make([]map[string]interface{}, len(old))
+		for i, v := range old {
+			new[i], _ = v.(map[string]interface{})
+		}
+		return new
+	} else {
+		return nil
+	}
+}
+
 /**
 产生一般订单编号方法
 */

+ 11 - 14
test/manage/product_test.go

@@ -36,7 +36,7 @@ func Test_CreateProduct(t *testing.T) {
 
 // 删除产品 测试用例
 func Test_DeleteProduct(t *testing.T) {
-	productId := "2012"
+	productId := "2013"
 	log.Println("productDelete testing......")
 	data := make(url.Values)
 	data["id"] = []string{productId}
@@ -48,23 +48,22 @@ func Test_DeleteProduct(t *testing.T) {
 func Test_UpdateProduct(t *testing.T) {
 	log.Println("productUpdate testing......")
 	product1 := &model.Product{
-		ID:          2012,
-		Name:        "行业数据",
+		ID:          2013,
+		Name:        "医疗行业数据",
 		Path:        "/pathUpdate2",
 		UnitPrice:   50, //单价精确到分  5毛
-		//MinUnit:     1,  //最小单位1,即 5毛/条
-		//ProductType: 1,  //产品类型 0-按次 1-按条
+		MinUnit:     1,  //最小单位1,即 5毛/条
+		ProductType: 1,  //产品类型 0-按次 1-按条
 		TestNum:     500,
 	}
 	data := make(url.Values)
 	data["id"] = []string{strconv.Itoa(product1.ID)}
 	data["name"] = []string{product1.Name}
 	data["url"] = []string{product1.Path}
-	data["unit_price"] = []string{strconv.Itoa(product1.UnitPrice)}
-	data["min_unit"] = []string{strconv.Itoa(product1.MinUnit)}
-	data["product_type"] = []string{strconv.Itoa(product1.ProductType)}
-	data["test_num"] = []string{strconv.Itoa(product1.TestNum)}
-
+	//data["unit_price"] = []string{strconv.Itoa(product1.UnitPrice)}
+	//data["min_unit"] = []string{strconv.Itoa(product1.MinUnit)}
+	//data["product_type"] = []string{strconv.Itoa(product1.ProductType)}
+	//data["test_num"] = []string{strconv.Itoa(product1.TestNum)}
 
 	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/product/update", map[string]string{}, data)
 	log.Print(string(bs))
@@ -83,15 +82,13 @@ func Test_ListProduct(t *testing.T) {
 	}
 	data := make(url.Values)
 	//data["id"] = []string{strconv.Itoa(product1.ID)}
-	data["name"] = []string{product1.Name}
+	//data["name"] = []string{product1.Name}
 	//data["url"] = []string{product1.Path}
-	//data["unit_price"] = []string{strconv.Itoa(product1.UnitPrice)}
+	data["unit_price"] = []string{strconv.Itoa(product1.UnitPrice)}
 	//data["min_unit"] = []string{strconv.Itoa(product1.MinUnit)}
 	//data["product_type"] = []string{strconv.Itoa(product1.ProductType)}
 	//data["test_num"] = []string{strconv.Itoa(product1.TestNum)}
 
-
 	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/product/list", map[string]string{}, data)
 	log.Print(string(bs))
 }
-

+ 38 - 5
test/manage/user_test.go

@@ -43,7 +43,7 @@ func Test_CreateUser(t *testing.T) {
 	//secretKey := sutil.GetComplexRandom(8, 3, 5)
 
 	data := make(url.Values)
-	data["name"] = []string{"拓普公司测试2"}
+	data["name"] = []string{"拓普公司测试3"}
 	data["phone"] = []string{"18238182402"}
 	data["ip_white_list"] = []string{"*"}
 
@@ -61,7 +61,7 @@ func Test_CreateUser(t *testing.T) {
 	//tradeMoney := 1 * 100 * 10000 //充值1万块钱
 }
 func Test_UserProductChoose(t *testing.T) {
-	appId := "sfGSRYRQMABwMAAgcBHjQt"
+	/*appId := "sfGSRYRQMABwMAAgcBHjQt"
 	productIds := "1000"
 	startTime := "2022-01-11 00:00:00"
 	endTime := "2024-01-11 00:00:00"
@@ -81,11 +81,44 @@ func Test_UserProductChoose(t *testing.T) {
 	data["callTimesLimitDay"] = []string{callTimesLimitDay}
 	data["dataNumOneTimes"] = []string{dataNumOneTimes}
 	data["tradeMoney"] = []string{"10000"}
-	data["buyType"] = []string{"1"}
+	data["buyType"] = []string{"1"}*/
 	//data["historyUnitPrice"] = []string{"18"}
+	appId := "sfGSRYRQMABwMAAgcBHjQt"
+	buyType := 1
+	products := make([]map[string]interface{}, 0)
+	p := map[string]interface{}{
+		"productId":         1001,
+		"costModel":         1,
+		"leftNum":           1000,
+		"tradeMoney":        100,
+		"startTime":         "2022-01-11 00:00:00",
+		"endTime":           "2023-01-11 00:00:00",
+		"interfaceStatus":   0,
+		"callTimesLimitDay": 100,
+		"dataNumOneTimes":   1000,
+	}
+	p2 := map[string]interface{}{
+		"productId":         1002,
+		"costModel":         1,
+		"leftNum":           1000,
+		"tradeMoney":        100,
+		"startTime":         "2022-01-11 00:00:00",
+		"endTime":           "2023-01-11 00:00:00",
+		"interfaceStatus":   0,
+		"callTimesLimitDay": 100,
+		"dataNumOneTimes":   1000,
+	}
+	products = append(products, p, p2)
+	data := map[string]interface{}{}
+	data["appId"] = appId
+	data["buyType"] = buyType
+	data["products"] = products
+	buf, _ := json.MarshalIndent(data, "", "")
 
-	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/user/userProductChoose", map[string]string{}, data)
-	log.Print(string(bs))
+	bs, _ := sutil.HttpPostJson("http://localhost:8080/manage/user/userProductChoose", string(buf))
+	dataMap := map[string]interface{}{}
+	json.Unmarshal(bs, &dataMap)
+	log.Print("结果:", dataMap)
 }
 
 func Test_UserProductList(t *testing.T) {

+ 20 - 0
utils/api_util.go

@@ -6,6 +6,7 @@ import (
 	"log"
 	"sfbase/global"
 	"sfbase/redis"
+	"sfbase/utils"
 	"sfis/db"
 	"sfis/lock"
 	"sfis/model"
@@ -40,6 +41,25 @@ func Check(appID string, productID int, c *gin.Context, getData func() ([]map[st
 		response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口暂不提供服务", c)
 		return
 	}
+	//校验是否过期
+	now := time.Now().Unix()
+	end := userProduct.EndAt
+	if now > end.Unix() {
+		response.FailWithDetailed(response.InterfaceExpired, nil, "剩余量已过期", c)
+		return
+	}
+	//校验每日调用上限
+	limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), productID, appID)
+	limittoday := redis.GetInt("limit", limittodaykey)
+	if limittoday >= userProduct.CallTimesLimitDay { //当天调用超过次数
+		response.FailWithDetailed(response.MoreThanEveryDayDataNumberLimit, nil, "请求超过每日调用总量限制", c)
+		return
+	} else {
+		if limittoday == 0 {
+			_, max := utils.GetDayMinMax(time.Now())
+			redis.Put("limit", limittodaykey, 0, int(max-now))
+		}
+	}
 	//2.2 取用户(产品余量|钱包账户余额)校验-必须加锁
 	costModel := userProduct.CostModel //扣费模式 0扣余量,1-扣余额
 	product := GetProductByID(productID)