فهرست منبع

Merge branch 'master' of http://192.168.3.207:10080/group3/SwordFish_Interface_Service

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

+ 2 - 2
api/v1/projects.go

@@ -42,7 +42,7 @@ func getProjectsList(c *gin.Context) {
 	global.Logger.Info("api getProjectList:", zap.Any("productID:", productID), zap.Any("appID", appID), zap.Any("param:", param))
 	if projectName != "" || winner != "" {
 		utils.Check(appID, productID, c, func() ([]map[string]interface{}, int, error) {
-			return service.ProjectListData(projectName, winner, bidTime, false)
+			return service.ProjectListData(productID, appID, projectName, winner, bidTime, false)
 		}, param, requestIP)
 	}
 }
@@ -61,7 +61,7 @@ func getProjectsListDetail(c *gin.Context) {
 	global.Logger.Info("api getProjectList:", zap.Any("productID:", productID), zap.Any("appID", appID), zap.Any("param:", param))
 	if winner != "" {
 		utils.Check(appID, productID, c, func() ([]map[string]interface{}, int, error) {
-			return service.ProjectListData("", winner, "", true)
+			return service.ProjectListData(productID, appID, "", winner, "", true)
 		}, param, requestIP)
 	}
 }

+ 7 - 3
api/v1/userRecharge.go

@@ -3,6 +3,8 @@ package v1
 import (
 	"encoding/json"
 	"sfbase/global"
+	"sfis/service"
+	"strconv"
 
 	"github.com/gin-gonic/gin"
 	"go.uber.org/zap"
@@ -21,7 +23,7 @@ func RechargeApiRegister(router *gin.Engine) {
 //余额充值接口
 func moneyRecharge(c *gin.Context) {
 	appid := c.PostForm("appid")
-	money := c.PostForm("money")
+	money, _ := strconv.Atoi(c.PostForm("money"))
 	p := gin.H{
 		"appid": appid,
 		"money": money,
@@ -29,13 +31,14 @@ func moneyRecharge(c *gin.Context) {
 	bs, _ := json.Marshal(p)
 	param := string(bs)
 	global.Logger.Info("api moneyRecharge:", zap.Any("param:", param))
+	service.MoneyRecharge(appid, money, c)
 }
 
 //产品剩余量充值接口
 func productRecharge(c *gin.Context) {
 	appid := c.PostForm("appid")
-	productId := c.PostForm("productId")
-	rechargeNum := c.PostForm("rechargeNum")
+	productId, _ := strconv.Atoi(c.PostForm("productId"))
+	rechargeNum, _ := strconv.Atoi(c.PostForm("rechargeNum"))
 	endTime := c.PostForm("endTime")
 
 	p := gin.H{
@@ -47,4 +50,5 @@ func productRecharge(c *gin.Context) {
 	bs, _ := json.Marshal(p)
 	param := string(bs)
 	global.Logger.Info("api productRecharge:", zap.Any("param:", param))
+	service.ProductRecharge(appid, productId, rechargeNum, endTime, c)
 }

+ 102 - 0
manage/product/product.go

@@ -1 +1,103 @@
 package product
+
+import (
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+	"sfbase/global"
+	"sfis/db"
+	"sfis/model"
+	"sfis/model/response"
+	"sfis/service"
+	"strconv"
+)
+
+func ProductManageRegister(router *gin.Engine) {
+	productGroup := router.Group("/manage/product/")
+	productGroup.Use()
+	{
+		productGroup.POST("/create", productCreate)
+		productGroup.POST("/delete", productDelete)
+		productGroup.POST("/update", productUpdate)
+		productGroup.POST("/list", productList)
+	}
+}
+
+// 创建产品
+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.Fail(context)
+		return
+	}
+	result := db.GetSFISDB().Create(&product)
+	if result.Error != nil {
+		global.Logger.Error("productCreate Error", zap.Any("product", product), zap.Any("error", result.Error))
+		response.Fail(context)
+	} else {
+		global.Logger.Info("productCreate Success", zap.Any("product", product))
+		response.OkWithData(product, context)
+	}
+
+}
+
+// 删除产品
+func productDelete(context *gin.Context) {
+	var product model.Product
+	if err := context.ShouldBind(&product); err != nil {
+		response.Fail(context)
+		global.Logger.Error("productDelete Bind Error", zap.Any("error", err))
+		return
+	}
+	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.Fail(context)
+	} else {
+		global.Logger.Info("productDelete Success", zap.Any("id", product.ID))
+		response.OkWithData(product, context)
+	}
+}
+
+//更新产品信息
+func productUpdate(context *gin.Context) {
+	var product model.Product
+	if err := context.ShouldBind(&product); err != nil {
+		global.Logger.Error("productUpdate Bind Error", zap.Any("error", err))
+		response.Fail(context)
+		return
+	}
+
+	result := db.GetSFISDB().Table("product").Where("id = ?", product.ID).Updates(map[string]interface{}{"name": product.Name, "url": product.Path, "unit_price": product.UnitPrice, "min_unit": product.MinUnit, "product_type": product.ProductType, "test_num": product.TestNum})
+	if result.Error != nil {
+		global.Logger.Error("productUpdate Error", zap.Any("product", product), zap.Any("error", result.Error))
+		response.Fail(context)
+	} else {
+		global.Logger.Info("productUpdate Success", zap.Any("product", product))
+		response.OkWithData(product, context)
+	}
+}
+
+// 产品信息列表
+func productList(context *gin.Context) {
+
+	page, _ := strconv.Atoi(context.Query("page"))
+	limit, _ := strconv.Atoi(context.Query("limit"))
+	id := context.PostForm("id")
+	name := context.PostForm("name")
+	url := context.PostForm("url")
+	unitPrice := context.PostForm("unit_price")
+	minUnit := context.PostForm("min_unit")
+	productType := context.PostForm("product_type")
+	testNum := context.PostForm("test_num")
+	condMap := map[string]interface{}{
+		"id":           id,
+		"name":         name,
+		"url":          url,
+		"unit_price":   unitPrice,
+		"min_unit":     minUnit,
+		"product_type": productType,
+		"test_num":     testNum,
+	}
+	service.ListProduct(condMap,page,limit,context)
+}

+ 77 - 1
manage/user/user.go

@@ -1,9 +1,22 @@
 package user
 
 import (
+	"encoding/json"
 	"github.com/gin-gonic/gin"
 	"go.uber.org/zap"
+	"log"
 	"sfbase/global"
+
+	sutils "sfbase/utils"
+	"sfis/db"
+	"sfis/lock"
+	"sfis/model"
+	"sfis/model/response"
+	"sfis/service"
+	"sfis/utils"
+	"strconv"
+	"sync"
+	"time"
 )
 
 func DevUserManageRegister(router *gin.Engine) {
@@ -11,9 +24,72 @@ func DevUserManageRegister(router *gin.Engine) {
 	userGroup.Use()
 	{
 		userGroup.POST("/create", userCreate)
+		userGroup.POST("/userProjectChoose", userProjectChoose)
+		userGroup.POST("/userProjectList", userProjectList)
 	}
 }
 
+// 创建用户
 func userCreate(context *gin.Context) {
-	global.Logger.Info("创建user", zap.Any("app_id:", "yhet6332h"), zap.Any("secret_key", "ffh2273hjd"))
+	var user model.User
+	if err := context.ShouldBind(&user); err != nil {
+		response.Fail(context)
+		return
+	}
+	t := time.Now()
+	appId := utils.GetAppID(t.Unix())
+	key := sutils.GetComplexRandom(8, 3, 5)
+	user.SecretKey = key
+	user.AppID = appId
+	result := db.GetSFISDB().Create(&user)
+	if result.Error != nil {
+		global.Logger.Error("userCreate Error", zap.Any("user", user), zap.Any("error", result.Error))
+		response.Fail(context)
+	} else {
+		global.Logger.Info("userCreate Success", zap.Any("user", user))
+		// 生全局内存锁
+		lock.MainLock.Lock()
+		lock.UserLockMap[appId] = &sync.Mutex{}
+		lock.MainLock.Unlock()
+		response.OkWithData(user, context)
+	}
+
+}
+
+func userProjectChoose(c *gin.Context) {
+	appId := c.PostForm("appId")
+	projectIds := c.PostForm("projectIds")
+	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"))
+	historyUnitPrice, _ := strconv.Atoi(c.PostForm("historyUnitPrice"))
+	log.Println("tradeMoney", tradeMoney)
+	p := gin.H{
+		"appId":             appId,
+		"projectIds":        projectIds,
+		"startTime":         startTime,
+		"endTime":           endTime,
+		"leftNum":           leftNum,
+		"costModel":         costModel,
+		"interfaceStatus":   interfaceStatus,
+		"callTimesLimitDay": callTimesLimitDay,
+		"dataNumOneTimes":   dataNumOneTimes,
+	}
+	bs, _ := json.Marshal(p)
+	param := string(bs)
+	global.Logger.Info("api userProjectChoose参数:", zap.Any("param", param))
+	service.UserProject(projectIds, appId, startTime, endTime, leftNum, costModel, interfaceStatus, callTimesLimitDay, dataNumOneTimes, tradeMoney, buyType, historyUnitPrice, c)
+}
+
+func userProjectList(c *gin.Context) {
+	appId := c.PostForm("appId")
+	global.Logger.Info("manage userProjectList接口参数:", zap.Any("appId", appId))
+	service.UserProjectList(appId, c)
 }

+ 7 - 6
model/product.go

@@ -4,12 +4,13 @@ import "time"
 
 type Product struct {
 	BaseModel
-	Name        string `json:"name"`
-	Path        string `json:"url" gorm:"column:url"`
-	UnitPrice   int    `json:"unit_price"`   //单价
-	MinUnit     int    `json:"min_unit"`     //最小单位
-	ProductType int    `json:"product_type"` //产品类型 按次-0,按条-1
-	TestNum     int    `json:"test_num"`     //试用量
+	ID          int    `json:"id" form:"id" gorm:"primaryKey" binding:"required"`
+	Name        string `json:"name" form:"name"`
+	Path        string `json:"url" gorm:"column:url" form:"url"`
+	UnitPrice   int    `json:"unit_price" form:"unit_price"`     //单价
+	MinUnit     int    `json:"min_unit" form:"min_unit"`         //最小单位
+	ProductType int    `json:"product_type" form:"product_type"` //产品类型 按次-0,按条-1
+	TestNum     int    `json:"test_num" form:"test_num"`         //试用量
 }
 
 func (p *Product) TableName() string {

+ 23 - 17
model/user.go

@@ -1,12 +1,16 @@
 package model
 
+import (
+	"time"
+)
+
 type User struct {
 	BaseModel
-	Name        string `json:"name"`
-	Phone       string `json:"phone"`
+	Name        string `json:"name" form:"name" binding:"required"`
+	Phone       string `json:"phone" form:"phone"`
 	AppID       string `json:"app_id"`
 	SecretKey   string `json:"secret_key"`
-	IpWhiteList string `json:"ip_white_list"`
+	IpWhiteList string `json:"ip_white_list" form:"ip_white_list"`
 }
 
 func (user *User) TableName() string {
@@ -24,11 +28,12 @@ func (p *UserAccount) TableName() string {
 }
 
 type UserMoneyRecord struct {
-	ID         int    `json:"id" gorm:"primaryKey"`
-	AppID      string `json:"app_id"`
-	Before     int    `json:"before"`
-	After      int    `json:"after"`
-	TradeMoney int    `json:"tarde_money"`
+	ID         int       `json:"id" gorm:"primaryKey"`
+	AppID      string    `json:"app_id"`
+	Before     int       `json:"before"`
+	After      int       `json:"after"`
+	TradeMoney int       `json:"tarde_money"`
+	CreateAt   time.Time `json:"-" gorm:"autoCreateTime"`
 }
 
 func (p *UserMoneyRecord) TableName() string {
@@ -36,15 +41,16 @@ func (p *UserMoneyRecord) TableName() string {
 }
 
 type UserBuyRecord struct {
-	ID               int    `json:"id" gorm:"primaryKey"`
-	AppID            string `json:"app_id"`
-	ProductId        int    `json:"product_id"`
-	UserProductId    int    `json:"user_product_id"`
-	Before           int    `json:"before"`
-	After            int    `json:"after"`
-	TradeMoney       int    `json:"tarde_money"`
-	BuyType          int    `json:"buy_type"`
-	HistoryUnitPrice int    `json:"history_unit_price"`
+	ID               int       `json:"id" gorm:"primaryKey"`
+	AppID            string    `json:"app_id"`
+	ProductId        int       `json:"product_id"`
+	UserProductId    int       `json:"user_product_id"`
+	Before           int       `json:"before"`
+	After            int       `json:"after"`
+	TradeMoney       int       `json:"tarde_money"`
+	BuyType          int       `json:"buy_type"`
+	HistoryUnitPrice int       `json:"history_unit_price"`
+	CreateAt         time.Time `json:"-" gorm:"autoCreateTime"`
 }
 
 func (p *UserBuyRecord) TableName() string {

+ 5 - 1
router/route.go

@@ -1,9 +1,11 @@
 package router
 
 import (
-	"github.com/gin-gonic/gin"
 	v1 "sfis/api/v1"
+	"sfis/manage/product"
 	"sfis/manage/user"
+
+	"github.com/gin-gonic/gin"
 )
 
 func InitRouter(middleware ...gin.HandlerFunc) *gin.Engine {
@@ -15,6 +17,8 @@ func InitRouter(middleware ...gin.HandlerFunc) *gin.Engine {
 		})
 	})
 	v1.ProjectApiRegister(router)
+	v1.RechargeApiRegister(router)
 	user.DevUserManageRegister(router)
+	product.ProductManageRegister(router)
 	return router
 }

+ 45 - 0
service/product.go

@@ -0,0 +1,45 @@
+package service
+
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+	"sfbase/global"
+	"sfis/db"
+	"sfis/model"
+	"sfis/model/response"
+	"strings"
+)
+
+func ListProduct(condMap map[string]interface{},page int,limit int,context *gin.Context) {
+	// 拼查询sql
+	var products []model.Product
+	var key []string
+	var param []interface{}
+	for k, v := range condMap {
+		if v == "" {
+			continue
+		}
+		var kStr string
+		if k=="name" || k=="url"{
+			kStr = fmt.Sprintf("%s like ?",k)
+			v = "%"+v.(string)+"%"
+		}else {
+			kStr = fmt.Sprintf("%s = ?", k)
+		}
+		key = append(key,kStr)
+		param = append(param,v)
+	}
+	sql := strings.Join(key," and ")
+	var totalCount int64
+	result := db.GetSFISDB().Table("product").Where(sql,param...).Limit(limit).Offset((page - 1) * limit).Find(&products)
+	db.GetSFISDB().Table("product").Where(sql,param...).Count(&totalCount)
+	if result.Error != nil {
+		global.Logger.Error("productList Error", zap.Any("condMap", condMap), zap.Any("error", result.Error))
+		response.Fail(context)
+	} else {
+		global.Logger.Info("productList Success", zap.Any("condMap", condMap))
+		response.OkWithData(products, context)
+	}
+
+}

+ 8 - 4
service/projects.go

@@ -3,15 +3,17 @@ package service
 import (
 	"errors"
 	"fmt"
-	"go.uber.org/zap"
 	"sfbase/core"
 	"sfbase/elastic"
 	"sfbase/global"
 	"sfbase/utils"
 	"sfis/db"
+	"sfis/model"
 	"strconv"
 	"strings"
 	"time"
+
+	"go.uber.org/zap"
 )
 
 var (
@@ -27,7 +29,7 @@ var (
 	highlightStr = `%s: {"fragment_size": %d,"number_of_fragments": 1}`
 )
 
-func ProjectListData(projectName, winner, times string, isDetail bool) (data []map[string]interface{}, httpStatus int, err error) {
+func ProjectListData(productId int, appid, projectName, winner, times string, isDetail bool) (data []map[string]interface{}, httpStatus int, err error) {
 	times = strings.TrimSpace(times)
 	winner = strings.TrimSpace(winner)
 	pjt_name := strings.TrimSpace(projectName)
@@ -77,7 +79,9 @@ func ProjectListData(projectName, winner, times string, isDetail bool) (data []m
 	} else {
 		fields = pjt_field
 	}
-	repl := GetAllByNgram(Es, INDEX, TYPE, qstr, "", pjt_sort, fields, 0, pjt_count, 0, false)
+	userProduct := &model.UserProduct{}
+	db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appid, ProductID: productId})
+	repl := GetAllByNgram(Es, INDEX, TYPE, qstr, "", pjt_sort, fields, 0, userProduct.DataNumLimitOneTimes, 0, false)
 	if repl != nil && len(*repl) > 0 {
 		data = *repl
 		for _, i := range data {
@@ -106,7 +110,7 @@ func GetAllByNgram(Es *elastic.Elastic, index, itype, qstr, findfields, order, f
 		if start > -1 {
 			qstr = qstr[:len(qstr)-1] + `,"from":` + strconv.Itoa(start) + `,"size":` + strconv.Itoa(limit) + "}"
 		}
-		global.Logger.Info("GetAllByNgram方法es查询",zap.Any("es语句",qstr))
+		global.Logger.Info("GetAllByNgram方法es查询", zap.Any("es语句", qstr))
 		return Es.Get(index, itype, qstr)
 	} else {
 		return nil

+ 102 - 0
service/user.go

@@ -0,0 +1,102 @@
+package service
+
+import (
+	"github.com/gin-gonic/gin"
+	"gorm.io/gorm"
+	"log"
+	"sfis/db"
+	"sfis/model"
+	"sfis/model/response"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func UserProject(projectIds, appId, startTime, endTime string, leftNum, costModel, interfaceStatus, callTimesLimitDay, dataNumOneTimes, tradeMoney, buyType, historyUnitPrice int, c *gin.Context) {
+	projectIdsArr := strings.Split(projectIds, ",")
+	if len(projectIdsArr) > 0 {
+		var errs error
+		for _, v := range projectIdsArr {
+			userProject := &model.UserProduct{}
+			userProject.AppID = appId
+			userProject.StartAt, _ = time.ParseInLocation("2006-01-02 15:04:05", startTime, time.Local)
+			userProject.EndAt, _ = time.ParseInLocation("2006-01-02 15:04:05", endTime, time.Local)
+			userProject.LeftNum = leftNum
+			userProject.CostModel = costModel
+			userProject.InterfaceStatus = interfaceStatus
+			userProject.CallTimesLimitDay = callTimesLimitDay
+			userProject.DataNumLimitOneTimes = dataNumOneTimes
+			id, _ := strconv.Atoi(v)
+			userProject.ProductID = id
+			userProjectInfo := []model.UserProduct{}
+			err := db.GetSFISDB().Where("product_id = ? and app_id = ?", id, appId).Find(&userProjectInfo).Error
+			if err != nil {
+				response.FailWithMessage("查询用户产品信息出错", c)
+				return
+			}
+			if len(userProjectInfo) > 0 {
+				before := userProjectInfo[0].LeftNum
+				after := userProjectInfo[0].LeftNum + leftNum
+				userProjectId := userProjectInfo[0].ID
+				errs = db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
+					//更新用户产品信息
+					userProject.LeftNum = userProjectInfo[0].LeftNum + leftNum
+					err := tx.Exec("update user_product set left_num = 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 = ?", leftNum, startTime, endTime, costModel, interfaceStatus, callTimesLimitDay, dataNumOneTimes, id, appId).Error
+					if err != nil {
+						log.Printf("appID:[%s],projectId:[%d] execute cost user_account error:[%v]", appId, id, err)
+						tx.Rollback()
+						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, id, userProjectId, before, after, tradeMoney, buyType, historyUnitPrice).Error
+					if err != nil {
+						log.Printf("appID:[%s],projectId[%d],trade_money:[%d] execute insert into user_buy_record error:[%v]", appId, id, tradeMoney, err)
+						tx.Rollback()
+						return err
+					}
+					return nil
+				})
+			} else {
+				errs = db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
+					//生用户产品
+					err := tx.Create(userProject).Error
+					if err != nil {
+						log.Printf("appID:[%s],projectId:[%d] insert user_project error:[%v]", appId, id, err)
+						tx.Rollback()
+						return tx.Error
+					}
+					userProjectId := userProject.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, id, userProjectId, 0, leftNum, tradeMoney, buyType, historyUnitPrice).Error
+					if err != nil {
+						log.Printf("appID:[%s],projectId[%d],trade_money:[%d] execute insert into user_buy_record error:[%v]", appId, id, tradeMoney, err)
+						tx.Rollback()
+						return err
+					}
+					return nil
+				})
+			}
+
+		}
+		if errs == nil {
+			response.Ok(c)
+			return
+		} else {
+			response.FailWithMessage("购买产品失败", c)
+			return
+		}
+
+	}
+	response.FailWithMessage("缺少参数", c)
+}
+
+func UserProjectList(appId string, c *gin.Context) {
+	userProject := []model.UserProduct{}
+	err := db.GetSFISDB().Where("app_id = ? and ", appId).Find(&userProject).Error
+	if err != nil {
+		log.Printf("appID:[%s] find into user_project error:[%v]", appId, err)
+		response.FailWithMessage("查询出错", c)
+	} else {
+		response.OkWithData(userProject, c)
+	}
+}

+ 114 - 0
service/userRecharge.go

@@ -0,0 +1,114 @@
+package service
+
+import (
+	"sfbase/global"
+	"sfis/db"
+	"sfis/lock"
+	"sfis/model"
+	"sfis/model/response"
+
+	"github.com/gin-gonic/gin"
+
+	"log"
+	"sfis/utils"
+	"time"
+
+	"go.uber.org/zap"
+	"gorm.io/gorm"
+)
+
+func MoneyRecharge(appid string, money int, context *gin.Context) {
+	//取出用户锁
+	lock.MainLock.Lock()
+	userLock := lock.UserLockMap[appid]
+	lock.MainLock.Unlock()
+	userLock.Lock()
+	defer userLock.Unlock()
+	//查用户当前余额
+	userAccount := &model.UserAccount{}
+	db.GetSFISDB().First(userAccount, &model.UserAccount{AppID: appid})
+	errs := db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
+		moneyBefore := userAccount.Money
+		moneyAfter := userAccount.Money + money
+		//充值
+		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, money).Error
+		if err != nil {
+			log.Printf("appID:[%s],trade_money:[%d] execute insert into user_money_record error:[%v]", appid, money, err)
+			tx.Rollback()
+			return err
+		}
+		return nil
+	})
+	if errs == nil {
+		response.Ok(context)
+	} else {
+		global.Logger.Error("数据库操作失败", zap.Any("error:", errs))
+		response.FailWithMessage("充值失败", context)
+	}
+}
+
+func ProductRecharge(appid string, productId, rechargeNum int, endTime string, context *gin.Context) {
+	//取出用户锁
+	lock.MainLock.Lock()
+	userLock := lock.UserLockMap[appid]
+	lock.MainLock.Unlock()
+	userLock.Lock()
+	defer userLock.Unlock()
+	endTimes := ""
+	if endTime != "" {
+		end := endTime + " 23:59:59"
+		loc, _ := time.LoadLocation("Local")
+		if ends, err := time.ParseInLocation("2006-01-02 15:04:05", end, loc); err == nil {
+			endTimes = ends.Local().Format("2006-01-02 15:04:05")
+		}
+	}
+	//查用户当前剩余量
+	userProduct := &model.UserProduct{}
+	db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appid, ProductID: productId})
+	product := &model.Product{}
+	if products, ok := utils.ProductCaches.Map.Load(productId); ok {
+		product = products.(*model.Product)
+	}
+	errs := db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
+		before := userProduct.LeftNum
+		after := userProduct.LeftNum + rechargeNum
+		//充值
+		var err error
+		if endTimes != "" {
+			err = tx.Exec("update user_product set left_num = ?,end_at = ? WHERE `app_id` = ? and product_id = ?", after, endTimes, appid, productId).Error
+			if err != nil {
+				log.Printf("appID:[%s],left_num:[%d],endtime:[%s] execute cost user_product error:[%v]", appid, after, endTimes, err)
+				tx.Rollback()
+				return err
+			}
+		} else {
+			err = tx.Exec("update user_product set left_num = ? WHERE `app_id` = ? and product_id = ?", after, appid, productId).Error
+			if err != nil {
+				log.Printf("appID:[%s],left_num:[%d] execute cost user_product error:[%v]", appid, after, err)
+				tx.Rollback()
+				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)
+			tx.Rollback()
+			return err
+		}
+		return nil
+	})
+	if errs == nil {
+		response.Ok(context)
+	} else {
+		global.Logger.Error("数据库操作失败", zap.Any("error:", errs))
+		response.FailWithMessage("充值失败", context)
+	}
+}

+ 97 - 0
test/manage/product_test.go

@@ -0,0 +1,97 @@
+package manage
+
+import (
+	"log"
+	"net/url"
+	sutil "sfbase/utils"
+	"sfis/model"
+	"strconv"
+	"testing"
+)
+
+// 新增产品测试用例
+func Test_CreateProduct(t *testing.T) {
+	product1 := &model.Product{
+		ID:          2006,
+		Name:        "行业中标数据",
+		Path:        "/path2002",
+		UnitPrice:   50, //单价精确到分  5毛
+		MinUnit:     1,  //最小单位1,即 5毛/条
+		ProductType: 1,  //产品类型 0-按次 1-按条
+		TestNum:     200,
+	}
+	log.Println("productCreate testing......")
+	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)}
+
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/product/create", map[string]string{}, data)
+	log.Print(string(bs))
+}
+
+// 删除产品 测试用例
+func Test_DeleteProduct(t *testing.T) {
+	productId := "2002"
+	log.Println("productDelete testing......")
+	data := make(url.Values)
+	data["id"] = []string{productId}
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/product/delete", map[string]string{}, data)
+	log.Print(string(bs))
+}
+
+// 修改产品信息测试
+func Test_UpdateProduct(t *testing.T) {
+	log.Println("productUpdate testing......")
+	product1 := &model.Product{
+		ID:          2001,
+		Name:        "行业中标数据",
+		Path:        "/pathUpdate1",
+		UnitPrice:   50, //单价精确到分  5毛
+		MinUnit:     1,  //最小单位1,即 5毛/条
+		ProductType: 0,  //产品类型 0-按次 1-按条
+		TestNum:     200,
+	}
+	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)}
+
+
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/product/update", map[string]string{}, data)
+	log.Print(string(bs))
+}
+
+func Test_ListProduct(t *testing.T) {
+	log.Println("productList testing......")
+	//product1 := &model.Product{
+	//	ID:          2001,
+	//	Name:        "行业中标",
+	//	Path:        "/pathUpdate1",
+	//	UnitPrice:   50, //单价精确到分  5毛
+	//	MinUnit:     1,  //最小单位1,即 5毛/条
+	//	ProductType: 0,  //产品类型 0-按次 1-按条
+	//	TestNum:     200,
+	//}
+	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)}
+
+
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/product/list?page=1&&limit=3", map[string]string{}, data)
+	log.Print(string(bs))
+}
+

+ 74 - 6
test/manage/user_test.go

@@ -1,9 +1,14 @@
 package manage
 
 import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
 	"log"
+	"net/http"
+	"net/url"
 	sutil "sfbase/utils"
-	"sfis/utils"
+	"strings"
 	"testing"
 	"time"
 )
@@ -33,11 +38,19 @@ func init() {
 	//todo init connection db operation
 }
 func Test_CreateUser(t *testing.T) {
-	//log.Println("devUserCreate testing......")
-	appID := utils.GetAppID(time.Now().Unix())
-	secretKey := sutil.GetComplexRandom(8, 3, 5)
+	log.Println("devUserCreate testing......")
+	//appID := utils.GetAppID(time.Now().Unix())
+	//secretKey := sutil.GetComplexRandom(8, 3, 5)
 
-	log.Printf("create successful appID:[%s],secretKey:[%s]", appID, secretKey)
+	data := make(url.Values)
+	data["name"] = []string{"河南拓普"}
+	data["phone"] = []string{"18238182402"}
+	data["ip_white_list"] = []string{"*"}
+
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/user/create", map[string]string{}, data)
+	log.Print(string(bs))
+
+	//log.Printf("create successful appID:[%s],secretKey:[%s]", appID, secretKey)
 
 	//创建用户、给用户开通接口产品时候有以下几种情况
 	//1.线上给账户充值10000块(user_account),不去实际购买产品,无购买记录,用户产品表无剩余量(left_num为0).此时又分两种情况
@@ -47,6 +60,61 @@ func Test_CreateUser(t *testing.T) {
 	//appID := ""
 	//tradeMoney := 1 * 100 * 10000 //充值1万块钱
 }
-func chooseUserProduct(appID string, tradeMoney int) {
+func Test_UserProductChoose(t *testing.T) {
+	appId := "sfPQRYRQMAAwcGBwYBCgcA"
+	projectIds := "1009"
+	startTime := "2021-01-11 00:00:00"
+	endTime := "2022-01-11 00:00:00"
+	leftNum := "10000"
+	costModel := "0"
+	interfaceStatus := "0"
+	callTimesLimitDay := "100"
+	dataNumOneTimes := "100"
+	data := make(url.Values)
+	data["appId"] = []string{appId}
+	data["projectIds"] = []string{projectIds}
+	data["startTime"] = []string{startTime}
+	data["endTime"] = []string{endTime}
+	data["leftNum"] = []string{leftNum}
+	data["costModel"] = []string{costModel}
+	data["interfaceStatus"] = []string{interfaceStatus}
+	data["callTimesLimitDay"] = []string{callTimesLimitDay}
+	data["dataNumOneTimes"] = []string{dataNumOneTimes}
+	data["tradeMoney"] = []string{"1000"}
+	data["buyType"] = []string{"1"}
+	data["historyUnitPrice"] = []string{"18"}
+	now := time.Now().Unix()
+
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/user/userProjectChoose", map[string]string{
+		"timestamp": fmt.Sprint(now),
+	}, data)
+	log.Print(string(bs))
+}
 
+func Test_UserProjectList(t *testing.T) {
+	appId := "sfPQRYRQMAAwcGBwYBCgcA"
+	data := make(url.Values)
+	data["appId"] = []string{appId}
+	now := time.Now().Unix()
+	bs, _ := sutil.HttpPostForm("http://localhost:8080/manage/user/userProjectList", map[string]string{
+		"timestamp": fmt.Sprint(now),
+	}, data)
+	log.Print(string(bs))
+}
+
+func post(url string, form map[string]string) (data map[string]interface{}) {
+	str := ""
+	for k, v := range form {
+		str += "&" + k + "=" + v
+	}
+	log.Println(str)
+	res, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(str))
+	if err != nil {
+		log.Println("post err:", err.Error())
+	} else if res.Body != nil {
+		defer res.Body.Close()
+		bs, _ := ioutil.ReadAll(res.Body)
+		json.Unmarshal(bs, &data)
+	}
+	return
 }

+ 47 - 0
test/userRecharge/userRecharge_test.go

@@ -0,0 +1,47 @@
+package userRecharge
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"strings"
+	"testing"
+)
+
+var (
+	// apiurl = "http://127.0.0.1:8081/sfis/api/v1/user/moneyRecharge"
+	apiurl = "http://127.0.0.1:8081/sfis/api/v1/user/productRecharge"
+)
+
+func Test_Project(t *testing.T) {
+	getData()
+}
+
+func getData() {
+	data := post(apiurl, map[string]string{
+		"appid":       "sfGSVYRQMAAgkGBAUBJg4f",
+		"money":       "1000",
+		"productId":   "1000",
+		"rechargeNum": "100",
+		"endTime":     "2022-01-01",
+	})
+	log.Println(data)
+}
+
+func post(url string, form map[string]string) (data map[string]interface{}) {
+	str := ""
+	for k, v := range form {
+		str += "&" + k + "=" + v
+	}
+	log.Println(str)
+	res, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(str))
+	if err != nil {
+		log.Println("post err:", err.Error())
+	} else if res.Body != nil {
+		defer res.Body.Close()
+		bs, _ := ioutil.ReadAll(res.Body)
+		json.Unmarshal(bs, &data)
+	}
+	return
+}

+ 17 - 3
utils/api_util.go

@@ -2,12 +2,15 @@ package utils
 
 import (
 	"log"
+	"sfbase/global"
 	"sfis/db"
 	"sfis/lock"
 	"sfis/model"
 	"sfis/model/response"
+	"time"
 
 	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
 )
 
 func Check(appID string, productID int, context *gin.Context, getData func() ([]map[string]interface{}, int, error), param, ip string) {
@@ -16,6 +19,7 @@ func Check(appID string, productID int, context *gin.Context, getData func() ([]
 	lock.MainLock.Unlock()
 	var err error
 	datas := []map[string]interface{}{}
+	orderCode := ""
 	/**
 	第二步:用户接口产品校验-加锁处理
 	*/
@@ -27,7 +31,7 @@ func Check(appID string, productID int, context *gin.Context, getData func() ([]
 	if userProduct.ID == 0 {
 		response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口未购买", context)
 		return
-	}else if userProduct.InterfaceStatus != 0 {
+	} else if userProduct.InterfaceStatus != 0 {
 		response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口暂不提供服务", context)
 		return
 	}
@@ -42,18 +46,28 @@ func Check(appID string, productID int, context *gin.Context, getData func() ([]
 	switch costModel {
 	case 0:
 		//按剩余量扣费
-		datas, err = costByLeftNum(getData, appID, productID, userProduct, product, param, ip)
+		datas, orderCode, err = costByLeftNum(getData, appID, productID, userProduct, product, param, ip)
 	case 1:
 		//按账户钱包余额扣费
-		datas, err = costByAccountBalance(getData, appID, productID, userProduct, product, param, ip)
+		datas, orderCode, err = costByAccountBalance(getData, appID, productID, userProduct, product, param, ip)
 	case 2:
 		//优先扣剩余量,剩余量为0,扣钱包余额
 	}
 	userLock.Unlock()
 	log.Println(param + "解锁......")
 	if err == nil {
+		db.GetQyfw().Save("user_data", map[string]interface{}{
+			"app_id":          appID,
+			"result_num":      len(datas),
+			"result_content":  datas,
+			"order_code":      orderCode,
+			"status":          200,
+			"user_product_id": userProduct.ID,
+			"create_at":       time.Now().Unix(),
+		})
 		response.OkWithDatas(datas, context)
 	} else {
+		global.Logger.Error("数据库操作失败", zap.Any("error:", err))
 		response.FailWithDetailed(response.InterfaceDeleted, nil, "查询失败", context)
 	}
 }

+ 7 - 6
utils/cost_by_account_balance.go

@@ -18,7 +18,7 @@ import (
 /**
 扣账户余额
 */
-func costByAccountBalance(getData func() ([]map[string]interface{}, int, error), appID string, productID int, userProduct *model.UserProduct, product *model.Product, param, ip string) ([]map[string]interface{}, error) {
+func costByAccountBalance(getData func() ([]map[string]interface{}, int, error), appID string, productID int, userProduct *model.UserProduct, product *model.Product, param, ip string) ([]map[string]interface{}, string, error) {
 	productType := product.ProductType
 	//productUnit := product.UnitPrice
 	// if productType == 0 {
@@ -30,11 +30,12 @@ func costByAccountBalance(getData func() ([]map[string]interface{}, int, error),
 	// }
 	datas := []map[string]interface{}{}
 	var err error
+	orderCode := ""
 	data, statusCode, _ := execute(getData, appID, productID)
 	beforeJudge, payMoney := beforeCheck(productType, product.UnitPrice, len(data), userProduct)
 	if beforeJudge {
 		global.Logger.Info("交易金额", zap.Any("payMoney:", payMoney))
-		err = afterCheck(len(data), payMoney, userProduct, statusCode, param, ip)
+		orderCode, err = afterCheck(len(data), payMoney, userProduct, statusCode, param, ip)
 		if err != nil {
 			global.Logger.Error("数据库操作失败", getUserProductError(appID, productID, err)...)
 		} else {
@@ -43,7 +44,7 @@ func costByAccountBalance(getData func() ([]map[string]interface{}, int, error),
 	} else {
 		err = errors.New("剩余余额不足")
 	}
-	return datas, err
+	return datas, orderCode, err
 }
 
 func beforeCheck(productType, unitPrice, dataLen int, userProduct *model.UserProduct) (bool, int) {
@@ -67,13 +68,14 @@ func beforeCheck(productType, unitPrice, dataLen int, userProduct *model.UserPro
 	return true, money
 }
 
-func afterCheck(dataLen, payMoney int, userProduct *model.UserProduct, statusCode int, param, ip string) error {
+func afterCheck(dataLen, payMoney int, userProduct *model.UserProduct, statusCode int, param, ip string) (string, error) {
 	appID := userProduct.AppID
 	productID := userProduct.ProductID
 	userProductID := userProduct.ID
 	userAccount := &model.UserAccount{}
 	db.GetSFISDB().First(userAccount, &model.UserAccount{AppID: userProduct.AppID})
 	var errs error
+	orderCode := fmt.Sprint(time.Now().Year()) + fmt.Sprint(utils.GetRandom(8))
 	//按次扣费-(每调一次剩余量-1)
 	errs = db.GetSFISDB().Transaction(func(tx *gorm.DB) error {
 		orderBefore := userAccount.Money
@@ -85,7 +87,6 @@ func afterCheck(dataLen, payMoney int, userProduct *model.UserProduct, statusCod
 			tx.Rollback()
 			return err
 		}
-		orderCode := fmt.Sprint(time.Now().Year()) + fmt.Sprint(utils.GetRandom(8))
 		//生调用记录
 		err = tx.Exec("insert into user_call_record (app_id,user_product_id,status,ip,param,order_code) values (?,?,?,?,?,?)", appID, userProductID, statusCode, ip, param, orderCode).Error
 		if err != nil {
@@ -103,5 +104,5 @@ func afterCheck(dataLen, payMoney int, userProduct *model.UserProduct, statusCod
 		//存历史数据
 		return nil
 	})
-	return errs
+	return orderCode, errs
 }

+ 6 - 6
utils/cost_by_left_num.go

@@ -16,14 +16,15 @@ import (
 /**
 扣产品剩余量
 */
-func costByLeftNum(getData func() ([]map[string]interface{}, int, error), appID string, productID int, userProduct *model.UserProduct, product *model.Product, param, ip string) ([]map[string]interface{}, error) {
+func costByLeftNum(getData func() ([]map[string]interface{}, int, error), appID string, productID int, userProduct *model.UserProduct, product *model.Product, param, ip string) ([]map[string]interface{}, string, error) {
 	productType := product.ProductType
 	datas := []map[string]interface{}{}
 	var err error
+	orderCode := ""
 	beforeJudge := before(productType, userProduct)
 	if beforeJudge {
 		data, statusCode, _ := execute(getData, appID, productID)
-		err = after(productType, len(data), userProduct, statusCode, param, ip)
+		orderCode, err = after(productType, len(data), userProduct, statusCode, param, ip)
 		if err == nil && data != nil && len(data) > 0 {
 			datas = data
 		} else {
@@ -36,7 +37,7 @@ func costByLeftNum(getData func() ([]map[string]interface{}, int, error), appID
 	} else {
 		err = errors.New("剩余量不足")
 	}
-	return datas, err
+	return datas, orderCode, err
 }
 
 /**
@@ -74,7 +75,7 @@ func execute(getData func() ([]map[string]interface{}, int, error), appID string
 	return data, statusCode, nil
 }
 
-func after(productType int, dataLen int, userProduct *model.UserProduct, statusCode int, param, ip string) error {
+func after(productType int, dataLen int, userProduct *model.UserProduct, statusCode int, param, ip string) (string, error) {
 	appID := userProduct.AppID
 	productID := userProduct.ProductID
 	userProductID := userProduct.ID
@@ -101,7 +102,6 @@ func after(productType int, dataLen int, userProduct *model.UserProduct, statusC
 				return err
 			}
 			//生订单
-			orderCode := utils.GenerateSimpleToken()
 			err = tx.Exec("insert into interface_order (order_code,app_id,user_product_id,`before`,`after`,cost_model,trade_num) values (?,?,?,?,?,?,?)", orderCode, appID, userProductID, orderBefore, orderAfter, 0, 1).Error
 			if err != nil {
 				log.Printf("appID:[%s],productID:[%d] execute insert into interface_order error:[%v]", appID, productID, err)
@@ -141,5 +141,5 @@ func after(productType int, dataLen int, userProduct *model.UserProduct, statusC
 			return nil
 		})
 	}
-	return errs
+	return orderCode, errs
 }