瀏覽代碼

feat: 上下班打卡

2637309949 4 年之前
父節點
當前提交
7f2d017727

+ 9 - 0
i2bill.api

@@ -95,6 +95,12 @@ type infoResponse {
 	ErpRoleType int64  `json:"erpRoleType"`
 }
 
+type punchClockRequest {
+	Lat     string `json:"lat"`
+	Address string `json:"address"`
+	Type    int64  `json:"type"`
+}
+
 type Response {
 	Code int         `json:"code"`
 	Msg  string      `json:"msg"`
@@ -126,6 +132,9 @@ service i2bill-api {
 	@handler GetUser
 	get /api/user/info returns(infoResponse)
 	
+	@handler PunchClock
+	post /api/user/punchClock(punchClockRequest) returns(Response)
+	
 	@handler  PartTimeUserAd
 	post /api/v1/part_time_user/add (partTimeUserAddRequest) returns(Response)
 }

+ 7 - 2
internal/handler/routes.go

@@ -4,8 +4,8 @@ package handler
 import (
 	"net/http"
 
-	"git.i2edu.net/i2/i2-bill-api/internal/handler/auth"
-	"git.i2edu.net/i2/i2-bill-api/internal/handler/user"
+	auth "git.i2edu.net/i2/i2-bill-api/internal/handler/auth"
+	user "git.i2edu.net/i2/i2-bill-api/internal/handler/user"
 	"git.i2edu.net/i2/i2-bill-api/internal/svc"
 
 	"git.i2edu.net/i2/go-zero/rest"
@@ -44,6 +44,11 @@ func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
 				Path:    "/api/user/info",
 				Handler: user.GetUserHandler(serverCtx),
 			},
+			{
+				Method:  http.MethodPost,
+				Path:    "/api/user/punchClock",
+				Handler: user.PunchClockHandler(serverCtx),
+			},
 			{
 				Method:  http.MethodPost,
 				Path:    "/api/v1/part_time_user/add",

+ 35 - 0
internal/handler/user/punchclockhandler.go

@@ -0,0 +1,35 @@
+package user
+
+import (
+	"net/http"
+
+	"git.i2edu.net/i2/go-zero/rest/httpx"
+	"git.i2edu.net/i2/i2-bill-api/internal/logic/user"
+	"git.i2edu.net/i2/i2-bill-api/internal/svc"
+	"git.i2edu.net/i2/i2-bill-api/internal/types"
+	"git.i2edu.net/i2/i2-bill-api/internal/utils"
+)
+
+func PunchClockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		uid, skey, err := ctx.GetClaims(r)
+		if err != nil {
+			httpx.OkJson(w, utils.ReturnHTTPFail(err))
+			return
+		}
+		var req types.PunchClockRequest
+		if err := httpx.Parse(r, &req); err != nil {
+			httpx.OkJson(w, utils.ReturnHTTPFail(err))
+			return
+		}
+		l := user.NewPunchClockLogic(r.Context(), ctx)
+		l.UserId = uid
+		l.SessionKey = skey
+		resp, err := l.PunchClock(req)
+		if err != nil {
+			httpx.OkJson(w, utils.ReturnHTTPFail(err))
+		} else {
+			httpx.OkJson(w, utils.ReturnHTTPSuccess(resp))
+		}
+	}
+}

+ 74 - 0
internal/logic/user/punchclocklogic.go

@@ -0,0 +1,74 @@
+package user
+
+import (
+	"context"
+	"database/sql"
+	"fmt"
+	"time"
+
+	"git.i2edu.net/i2/i2-bill-api/internal/svc"
+	"git.i2edu.net/i2/i2-bill-api/internal/types"
+	"git.i2edu.net/i2/i2-bill-api/internal/utils"
+	"git.i2edu.net/i2/i2-bill-api/model"
+
+	"git.i2edu.net/i2/go-zero/core/logx"
+	"git.i2edu.net/i2/go-zero/core/stores/sqlc"
+)
+
+type PunchClockLogic struct {
+	logx.Logger
+	ctx        context.Context
+	svcCtx     *svc.ServiceContext
+	UserId     int64
+	SessionKey string
+}
+
+func NewPunchClockLogic(ctx context.Context, svcCtx *svc.ServiceContext) PunchClockLogic {
+	return PunchClockLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+	}
+}
+
+func (l *PunchClockLogic) PunchClock(req types.PunchClockRequest) (*types.Response, error) {
+	var aar model.I2billAcquirerAttendanceRecord
+	err := l.svcCtx.SqlConn.QueryRowPartial(&aar, fmt.Sprintf("select %s from i2bill_acquirer_attendance_record where `user_id` = ? and TO_DAYS(create_time)=TO_DAYS(NOW()  limit 1", model.I2billAcquirerAttendanceRecordRows), l.UserId)
+	if err == sqlc.ErrNotFound {
+		aar.DelFlag = sql.NullInt64{Int64: 0, Valid: true}
+		aar.UserId = sql.NullInt64{Int64: l.UserId, Valid: true}
+		aar.CreateTime = sql.NullTime{Time: time.Now(), Valid: true}
+	}
+	// 上班卡
+	if req.Type == 1 && !utils.ValidTime(aar.StartTime.Time) {
+		aar.StartTime = sql.NullTime{Time: time.Now(), Valid: true}
+		aar.StartLat = sql.NullString{String: req.Lat, Valid: true}
+		aar.StartAddress = sql.NullString{String: req.Address, Valid: true}
+	} else if req.Type == 2 && !utils.ValidTime(aar.EndTime.Time) {
+		// 下班卡
+		aar.EndTime = sql.NullTime{Time: time.Now(), Valid: true}
+		aar.EndLat = sql.NullString{String: req.Lat, Valid: true}
+		aar.EndAddress = sql.NullString{String: req.Address, Valid: true}
+	}
+	if aar.Id == 0 {
+		_, err = l.svcCtx.SqlConn.Exec(`
+		INSERT INTO i2bill_acquirer_attendance_record
+		(user_id,start_lat,start_address,end_lat,end_address,start_time,end_time,create_time,del_flag)
+		VALUES
+		(?,?,?,?,?,?,?,?,?)`,
+			aar.UserId, aar.StartLat, aar.StartAddress, aar.EndLat, aar.EndAddress, aar.StartTime, aar.EndTime, aar.CreateTime, aar.DelFlag)
+		if err != nil {
+			logx.Error(err)
+			return nil, err
+		}
+	}
+	_, err = l.svcCtx.SqlConn.Exec(`update i2bill_acquirer_attendance_record set 
+	user_id = ?, start_lat = ?, start_address = ?, end_lat = ?, end_address = ?, start_time = ?, end_time = ?, create_time = ?, del_flag = ? where id = ?`, 
+	aar.UserId, aar.StartLat, aar.StartAddress, aar.EndLat, aar.EndAddress, aar.StartTime, aar.EndTime, aar.CreateTime, aar.DelFlag
+	l.UserId)
+	if err != nil {
+		logx.Error(err)
+		return nil, err
+	}
+	return utils.ReturnHTTPSuccess("ok"), nil
+}

+ 1 - 1
internal/svc/servicecontext.go

@@ -150,7 +150,7 @@ func (wc *Wechat) GenQrCode(scene, page string) (string, error) {
 		return "", err
 	}
 	req := utils.Post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token)
-	req.JSONBody(map[string]interface{}{"scene": scene})
+	req.JSONBody(map[string]interface{}{"scene": scene, "page": page})
 	ph := path.Join("asserts", "qrcode", scene+".png")
 	err = req.ToFile(ph)
 	if err != nil {

+ 6 - 0
internal/types/types.go

@@ -88,6 +88,12 @@ type InfoResponse struct {
 	ErpRoleType int64  `json:"erpRoleType"`
 }
 
+type PunchClockRequest struct {
+	Lat     string `json:"lat"`
+	Address string `json:"address"`
+	Type    int64  `json:"type"`
+}
+
 type Response struct {
 	Code int         `json:"code"`
 	Msg  string      `json:"msg"`

+ 11 - 15
internal/utils/resp.go

@@ -1,31 +1,27 @@
 package utils
 
-type HTTPData struct {
-	Code int         `json:"code"`
-	Msg  string      `json:"msg,omitempty"`
-	Data interface{} `json:"data,omitempty"`
-}
+import "git.i2edu.net/i2/i2-bill-api/internal/types"
 
-func ReturnHTTPSuccess(val interface{}) HTTPData {
-	rtndata := HTTPData{
-		Code: 0,
+func ReturnHTTPSuccess(val interface{}) *types.Response {
+	rtndata := types.Response{
+		Code: 200,
 		Data: val,
 	}
-	return rtndata
+	return &rtndata
 }
 
-func ReturnHTTPFail(err error) HTTPData {
-	rtndata := HTTPData{
+func ReturnHTTPFail(err error) *types.Response {
+	rtndata := types.Response{
 		Code: 500,
 		Msg:  err.Error(),
 	}
-	return rtndata
+	return &rtndata
 }
 
-func ReturnHTTPUnauthorized(err error) HTTPData {
-	rtndata := HTTPData{
+func ReturnHTTPUnauthorized(err error) *types.Response {
+	rtndata := types.Response{
 		Code: 401,
 		Msg:  err.Error(),
 	}
-	return rtndata
+	return &rtndata
 }

+ 5 - 0
internal/utils/utils.go

@@ -19,3 +19,8 @@ func GetTimestamp() int64 {
 func Int2String(val int64) string {
 	return strconv.Itoa(int(val))
 }
+
+func ValidTime(t time.Time) bool {
+	t1970, _ := time.Parse("2006-01-02", "1970-01-01")
+	return t.After(t1970)
+}

+ 2 - 0
model/i2bill_acquirer_attendance_record.sql

@@ -3,7 +3,9 @@ DROP TABLE IF EXISTS `i2bill_acquirer_attendance_record`;
 CREATE TABLE `i2bill_acquirer_attendance_record`  (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id',
+  `start_lat` varchar(36) NULL DEFAULT NULL,
   `start_address` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '上班地址',
+  `end_lat` varchar(36) NULL DEFAULT NULL,
   `end_address` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '下班地址',
   `start_time` datetime(0) NULL DEFAULT NULL COMMENT '上班时间',
   `end_time` datetime(0) NULL DEFAULT NULL COMMENT '下班时间',

+ 17 - 15
model/i2billacquirerattendancerecordmodel.go

@@ -13,10 +13,10 @@ import (
 )
 
 var (
-	i2billAcquirerAttendanceRecordFieldNames          = builderx.RawFieldNames(&I2billAcquirerAttendanceRecord{})
-	i2billAcquirerAttendanceRecordRows                = strings.Join(i2billAcquirerAttendanceRecordFieldNames, ",")
-	i2billAcquirerAttendanceRecordRowsExpectAutoSet   = strings.Join(stringx.Remove(i2billAcquirerAttendanceRecordFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
-	i2billAcquirerAttendanceRecordRowsWithPlaceHolder = strings.Join(stringx.Remove(i2billAcquirerAttendanceRecordFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
+	I2billAcquirerAttendanceRecordFieldNames          = builderx.RawFieldNames(&I2billAcquirerAttendanceRecord{})
+	I2billAcquirerAttendanceRecordRows                = strings.Join(I2billAcquirerAttendanceRecordFieldNames, ",")
+	I2billAcquirerAttendanceRecordRowsExpectAutoSet   = strings.Join(stringx.Remove(I2billAcquirerAttendanceRecordFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
+	I2billAcquirerAttendanceRecordRowsWithPlaceHolder = strings.Join(stringx.Remove(I2billAcquirerAttendanceRecordFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
 
 	cacheI2billAcquirerAttendanceRecordIdPrefix = "cache:i2billAcquirerAttendanceRecord:id:"
 )
@@ -35,14 +35,16 @@ type (
 	}
 
 	I2billAcquirerAttendanceRecord struct {
-		Id           int64          `db:"id"`
-		UserId       sql.NullInt64  `db:"user_id"`       // 用户id
+		EndAddress   sql.NullString `db:"end_address"` // 下班地址
+		EndTime      sql.NullTime   `db:"end_time"`    // 下班时间
+		DelFlag      sql.NullInt64  `db:"del_flag"`
+		EndLat       sql.NullString `db:"end_lat"`
+		UserId       sql.NullInt64  `db:"user_id"` // 用户id
+		StartLat     sql.NullString `db:"start_lat"`
 		StartAddress sql.NullString `db:"start_address"` // 上班地址
-		EndAddress   sql.NullString `db:"end_address"`   // 下班地址
 		StartTime    sql.NullTime   `db:"start_time"`    // 上班时间
-		EndTime      sql.NullTime   `db:"end_time"`      // 下班时间
 		CreateTime   sql.NullTime   `db:"create_time"`
-		DelFlag      sql.NullInt64  `db:"del_flag"`
+		Id           int64          `db:"id"`
 	}
 )
 
@@ -54,8 +56,8 @@ func NewI2billAcquirerAttendanceRecordModel(conn sqlx.SqlConn, c cache.CacheConf
 }
 
 func (m *defaultI2billAcquirerAttendanceRecordModel) Insert(data I2billAcquirerAttendanceRecord) (sql.Result, error) {
-	query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, i2billAcquirerAttendanceRecordRowsExpectAutoSet)
-	ret, err := m.ExecNoCache(query, data.UserId, data.StartAddress, data.EndAddress, data.StartTime, data.EndTime, data.DelFlag)
+	query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?)", m.table, I2billAcquirerAttendanceRecordRowsExpectAutoSet)
+	ret, err := m.ExecNoCache(query, data.EndAddress, data.EndTime, data.DelFlag, data.EndLat, data.UserId, data.StartLat, data.StartAddress, data.StartTime)
 
 	return ret, err
 }
@@ -64,7 +66,7 @@ func (m *defaultI2billAcquirerAttendanceRecordModel) FindOne(id int64) (*I2billA
 	i2billAcquirerAttendanceRecordIdKey := fmt.Sprintf("%s%v", cacheI2billAcquirerAttendanceRecordIdPrefix, id)
 	var resp I2billAcquirerAttendanceRecord
 	err := m.QueryRow(&resp, i2billAcquirerAttendanceRecordIdKey, func(conn sqlx.SqlConn, v interface{}) error {
-		query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", i2billAcquirerAttendanceRecordRows, m.table)
+		query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", I2billAcquirerAttendanceRecordRows, m.table)
 		return conn.QueryRow(v, query, id)
 	})
 	switch err {
@@ -80,8 +82,8 @@ func (m *defaultI2billAcquirerAttendanceRecordModel) FindOne(id int64) (*I2billA
 func (m *defaultI2billAcquirerAttendanceRecordModel) Update(data I2billAcquirerAttendanceRecord) error {
 	i2billAcquirerAttendanceRecordIdKey := fmt.Sprintf("%s%v", cacheI2billAcquirerAttendanceRecordIdPrefix, data.Id)
 	_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
-		query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, i2billAcquirerAttendanceRecordRowsWithPlaceHolder)
-		return conn.Exec(query, data.UserId, data.StartAddress, data.EndAddress, data.StartTime, data.EndTime, data.DelFlag, data.Id)
+		query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, I2billAcquirerAttendanceRecordRowsWithPlaceHolder)
+		return conn.Exec(query, data.EndAddress, data.EndTime, data.DelFlag, data.EndLat, data.UserId, data.StartLat, data.StartAddress, data.StartTime, data.Id)
 	}, i2billAcquirerAttendanceRecordIdKey)
 	return err
 }
@@ -101,6 +103,6 @@ func (m *defaultI2billAcquirerAttendanceRecordModel) formatPrimary(primary inter
 }
 
 func (m *defaultI2billAcquirerAttendanceRecordModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
-	query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", i2billAcquirerAttendanceRecordRows, m.table)
+	query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", I2billAcquirerAttendanceRecordRows, m.table)
 	return conn.QueryRow(v, query, primary)
 }