|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
|
|
"time"
|
|
|
|
v1 "vistor/api/v1"
|
|
|
|
"vistor/internal/consts"
|
|
|
|
"vistor/internal/dao"
|
|
|
|
"vistor/internal/model"
|
|
|
|
)
|
|
|
|
|
|
|
|
type visitorService struct{}
|
|
|
|
|
|
|
|
var Visitor = visitorService{}
|
|
|
|
|
|
|
|
//var statisticType = g.Map{
|
|
|
|
// "day":
|
|
|
|
//}
|
|
|
|
|
|
|
|
type IVisitor interface {
|
|
|
|
VisitorAccess(ctx context.Context, req *v1.VisitorAccessReq) error
|
|
|
|
VisitorStatistic(ctx context.Context, req *v1.VisitorAccessReq) (res *v1.VisitorAccessRes, err error)
|
|
|
|
GetDiffDays(t1, t2 time.Time) int
|
|
|
|
VisitorList(ctx context.Context, req *v1.VisitorListReq) (res *v1.VisitorListRes, err error)
|
|
|
|
GetDingDepartmentList(ctx context.Context, req *v1.GetDepartmentListReq) (res *v1.GetDepartmentListRes, err error)
|
|
|
|
GetDingUserList(ctx context.Context, req *v1.GetDingUserReq) (res *v1.GetDingUserRes, err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) sendDingMsgByUserId(ctx context.Context, userId string, departmentName string, visitorName string, visitorPhone string, visitAt int) (err error) {
|
|
|
|
accessToken, err := s.getAccessToken(ctx)
|
|
|
|
if err != nil || accessToken == "" {
|
|
|
|
return gerror.Newf(fmt.Sprintf("%s 发送钉钉通知失败, err:获取access_token失败", userId))
|
|
|
|
}
|
|
|
|
|
|
|
|
agentId, _ := g.Cfg().Get(ctx, "ding.agentId")
|
|
|
|
|
|
|
|
if agentId.String() == "" {
|
|
|
|
return gerror.Newf(fmt.Sprintf("%s 发送钉钉通知失败, agentId:%s, appKey:%s, secret:%s", userId, agentId))
|
|
|
|
}
|
|
|
|
|
|
|
|
param := g.Map{
|
|
|
|
"agent_id": agentId,
|
|
|
|
"userid_list": userId,
|
|
|
|
"msg": g.Map{
|
|
|
|
"msgtype": "text",
|
|
|
|
"text": g.Map{
|
|
|
|
"content": fmt.Sprintf("来自 %s 访客 %s (电话:%s),将于 %s 来访,请做好接待工作 ^_^ ", departmentName, visitorName, visitorPhone, gtime.New(visitAt).Format("Y-m-d H:i:s")),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=%s", accessToken)
|
|
|
|
r, err := g.Client().Post(ctx, url, param)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer r.Close()
|
|
|
|
var dingMsgResp model.DingMsgResp
|
|
|
|
resStr := r.ReadAllString()
|
|
|
|
|
|
|
|
err = json.Unmarshal(gconv.Bytes(resStr), &dingMsgResp)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if dingMsgResp.ErrCode != 0 {
|
|
|
|
return gerror.Newf(dingMsgResp.ErrMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) GetDingUserList(ctx context.Context, req *v1.GetDingUserReq) (res *v1.GetDingUserRes, err error) {
|
|
|
|
accessToken, err := s.getAccessToken(ctx)
|
|
|
|
if err != nil || accessToken == "" {
|
|
|
|
return nil, gerror.Newf("获取用户列表失败")
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor := (req.PageNum - 1) * req.PageSize
|
|
|
|
|
|
|
|
condition := g.Map{
|
|
|
|
"language": "zh_CN",
|
|
|
|
"cursor": cursor,
|
|
|
|
"size": req.PageSize,
|
|
|
|
"dept_id": req.DeptId,
|
|
|
|
"contain_access_limit": true,
|
|
|
|
}
|
|
|
|
|
|
|
|
url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/user/listsimple?access_token=%s", accessToken)
|
|
|
|
r, err := g.Client().Post(ctx, url, condition)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer r.Close()
|
|
|
|
var userResp model.UserListResp
|
|
|
|
resStr := r.ReadAllString()
|
|
|
|
|
|
|
|
err = json.Unmarshal(gconv.Bytes(resStr), &userResp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if userResp.ErrCode != 0 {
|
|
|
|
return nil, gerror.Newf(userResp.ErrMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &v1.GetDingUserRes{
|
|
|
|
List: userResp.Result,
|
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) getAccessToken(ctx context.Context) (accessToken string, err error) {
|
|
|
|
cacheKey, _ := g.Cfg().Get(ctx, "ding.cacheKey")
|
|
|
|
|
|
|
|
//有缓存
|
|
|
|
cache, _ := g.Redis().Do(ctx, "GET", cacheKey)
|
|
|
|
|
|
|
|
if cache.String() != "" {
|
|
|
|
return cache.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//无缓存
|
|
|
|
key, _ := g.Cfg().Get(ctx, "ding.key")
|
|
|
|
secret, _ := g.Cfg().Get(ctx, "ding.secret")
|
|
|
|
url := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", key, secret)
|
|
|
|
r, err := g.Client().Get(ctx, url)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
defer r.Close()
|
|
|
|
var accessTokenRes model.AccessTokenResp
|
|
|
|
resStr := r.ReadAllString()
|
|
|
|
|
|
|
|
err = json.Unmarshal(gconv.Bytes(resStr), &accessTokenRes)
|
|
|
|
if err != nil {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if accessTokenRes.ErrCode != 0 {
|
|
|
|
return "", gerror.Newf(accessTokenRes.ErrMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
if accessTokenRes.AccessToken != "" && accessTokenRes.ExpiresIn > 0 {
|
|
|
|
_, _ = g.Redis().Do(ctx, "SET", cacheKey, accessTokenRes.AccessToken)
|
|
|
|
_, _ = g.Redis().Do(ctx, "EXPIRE", cacheKey, accessTokenRes.ExpiresIn-60)
|
|
|
|
}
|
|
|
|
|
|
|
|
return accessTokenRes.AccessToken, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) GetDingDepartmentList(ctx context.Context, req *v1.GetDepartmentListReq) (res *v1.GetDepartmentListRes, err error) {
|
|
|
|
accessToken, err := s.getAccessToken(ctx)
|
|
|
|
if err != nil || accessToken == "" {
|
|
|
|
return nil, gerror.Newf("获取部门列表失败")
|
|
|
|
}
|
|
|
|
|
|
|
|
condition := g.Map{
|
|
|
|
"language": "zh_CN",
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.DeptId != 0 {
|
|
|
|
condition["dept_id"] = req.DeptId
|
|
|
|
}
|
|
|
|
|
|
|
|
url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=%s", accessToken)
|
|
|
|
r, err := g.Client().Post(ctx, url, condition)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer r.Close()
|
|
|
|
var deptResp model.DeptListResp
|
|
|
|
resStr := r.ReadAllString()
|
|
|
|
|
|
|
|
err = json.Unmarshal(gconv.Bytes(resStr), &deptResp)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if deptResp.ErrCode != 0 {
|
|
|
|
return nil, gerror.Newf(deptResp.ErrMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &v1.GetDepartmentListRes{
|
|
|
|
List: deptResp.Result,
|
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) VisitorList(ctx context.Context, req *v1.VisitorListReq) (res *v1.VisitorListRes, err error) {
|
|
|
|
condition := g.Map{}
|
|
|
|
var records []*model.VisitorRecord
|
|
|
|
|
|
|
|
if req.PageNum == 0 {
|
|
|
|
req.PageNum = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.PageSize == 0 {
|
|
|
|
req.PageSize = 15
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.VisitorName != "" {
|
|
|
|
condition["visitor_name like ?"] = "%" + req.VisitorName + "%"
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.VisitorIdentity != "" {
|
|
|
|
condition["visitor_identity like ?"] = "%" + req.VisitorIdentity + "%"
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.VisitorPhone != "" {
|
|
|
|
condition["visitor_phone like ?"] = "%" + req.VisitorPhone + "%"
|
|
|
|
}
|
|
|
|
|
|
|
|
query := dao.VisitorRecord.Ctx(ctx).Where(condition)
|
|
|
|
|
|
|
|
if req.StartDate != 0 || req.EndDate != 0 {
|
|
|
|
query = query.WhereBetween(dao.VisitorRecord.Columns().VisitAt, req.StartDate, req.EndDate)
|
|
|
|
}
|
|
|
|
|
|
|
|
total, err := query.Count()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = query.Page(req.PageNum, req.PageSize).Order("id desc").Scan(&records)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &v1.VisitorListRes{
|
|
|
|
List: records,
|
|
|
|
Total: total,
|
|
|
|
Current: req.PageNum,
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) VisitorAccess(ctx context.Context, req *v1.VisitorAccessReq) error {
|
|
|
|
insert, err := dao.VisitorRecord.Ctx(ctx).Data(req).Insert()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
affected, err := insert.RowsAffected()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if affected == 0 {
|
|
|
|
return gerror.Newf("提交失败,请重试")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.sendDingMsgByUserId(ctx, req.DstUserId, req.VisitorDepartment, req.VisitorName, req.VisitorPhone, req.VisitAt)
|
|
|
|
if err != nil {
|
|
|
|
g.Log().Info(ctx, fmt.Sprintf("sendDingMsgByUserId err------------------ %s", err.Error()))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) VisitorStatistic(ctx context.Context, req *v1.VisitorStatisticReq) (res *v1.VisitorStatisticRes, err error) {
|
|
|
|
var (
|
|
|
|
resRecords []*model.ResRecord
|
|
|
|
)
|
|
|
|
db := g.DB()
|
|
|
|
xAxis := g.SliceStr{}
|
|
|
|
yAxis := g.SliceStr{}
|
|
|
|
|
|
|
|
condition := g.Map{}
|
|
|
|
if req.VisitorName != "" {
|
|
|
|
condition["vr.visitor_name like ?"] = "%" + req.VisitorName + "%"
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.VisitorIdentity != "" {
|
|
|
|
condition["vr.visitor_identity like ?"] = "%" + req.VisitorIdentity + "%"
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.VisitorPhone != "" {
|
|
|
|
condition["vr.visitor_phone like ?"] = "%" + req.VisitorPhone + "%"
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.StatisticType == consts.StatisticTypeDay {
|
|
|
|
diff := s.GetDiffDays(gtime.New(req.EndDate).Time, gtime.New(req.StartDate).Time)
|
|
|
|
duration := gconv.Int(diff) + 1
|
|
|
|
|
|
|
|
if duration > 30 {
|
|
|
|
return nil, gerror.Newf("请选择30天内日期进行查询")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; duration > i; i++ {
|
|
|
|
xAxis = append(xAxis, gtime.New(req.StartDate).AddDate(0, 0, i).Format("Y-m-d"))
|
|
|
|
}
|
|
|
|
|
|
|
|
fields := "id,visitor_name,visitor_identity,visitor_phone,visit_at,from_unixtime(visit_at,'%Y-%m-%d') visit_date"
|
|
|
|
subQuery := db.Model("visitor_record vr").
|
|
|
|
Where(condition).
|
|
|
|
WhereBetween("vr.visit_at", req.StartDate, req.EndDate).
|
|
|
|
Fields(fields)
|
|
|
|
|
|
|
|
mainQuery := db.Model("? as v", subQuery)
|
|
|
|
err = mainQuery.
|
|
|
|
Fields("count(v.id) y_axis, v.visit_date x_axis").
|
|
|
|
Group("x_axis").
|
|
|
|
Order("x_axis").
|
|
|
|
Scan(&resRecords)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, x := range xAxis {
|
|
|
|
y := "0"
|
|
|
|
for _, record := range resRecords {
|
|
|
|
if record.XAxis == x {
|
|
|
|
y = record.YAxis
|
|
|
|
}
|
|
|
|
}
|
|
|
|
yAxis = append(yAxis, y)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var weekNum, monthNum, yearNum int
|
|
|
|
|
|
|
|
if req.StatisticType == consts.StatisticTypeWeek {
|
|
|
|
switch req.SubType {
|
|
|
|
case consts.SubTypeLast4Week:
|
|
|
|
weekNum = 4
|
|
|
|
case consts.SubTypeLast8Week:
|
|
|
|
weekNum = 8
|
|
|
|
case consts.SubTypeLast12Week:
|
|
|
|
weekNum = 12
|
|
|
|
}
|
|
|
|
//获取按周统计数据
|
|
|
|
xAxis, yAxis = s.getWeekStatistic(ctx, weekNum, condition)
|
|
|
|
} else if req.StatisticType == consts.StatisticTypeMonth {
|
|
|
|
switch req.SubType {
|
|
|
|
case consts.SubTypeLast4Month:
|
|
|
|
monthNum = 4
|
|
|
|
case consts.SubTypeLast8Month:
|
|
|
|
monthNum = 8
|
|
|
|
case consts.SubTypeLast12Month:
|
|
|
|
monthNum = 12
|
|
|
|
}
|
|
|
|
//获取按月统计数据
|
|
|
|
xAxis, yAxis = s.getMonthStatistic(ctx, monthNum, condition)
|
|
|
|
} else if req.StatisticType == consts.StatisticTypeYear {
|
|
|
|
switch req.SubType {
|
|
|
|
case consts.SubTypeLastYear:
|
|
|
|
yearNum = 1
|
|
|
|
case consts.SubTypeLast2Year:
|
|
|
|
yearNum = 2
|
|
|
|
case consts.SubTypeLast3Year:
|
|
|
|
yearNum = 3
|
|
|
|
}
|
|
|
|
//获取按年统计数据
|
|
|
|
xAxis, yAxis = s.getYearStatistic(ctx, yearNum, condition)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &v1.VisitorStatisticRes{
|
|
|
|
XAxis: xAxis,
|
|
|
|
YAxis: yAxis,
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDiffDays 获取两个时间相差的天数,0表同一天,正数表t1>t2,负数表t1<t2
|
|
|
|
func (s *visitorService) GetDiffDays(t1, t2 time.Time) int {
|
|
|
|
t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.Local)
|
|
|
|
t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, time.Local)
|
|
|
|
|
|
|
|
return int(t1.Sub(t2).Hours() / 24)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) getYearStatistic(ctx context.Context, lastYearNum int, condition g.Map) (xAxis g.SliceStr, yAxis g.SliceStr) {
|
|
|
|
for ; 1 <= lastYearNum; lastYearNum-- {
|
|
|
|
//获取当年第一天
|
|
|
|
yearStart := gtime.New(gtime.Now().AddDate(-(lastYearNum - 1), 0, 0).Format("Y-01-01 00:00:00")).Unix()
|
|
|
|
yearEnd := gtime.New(gtime.Now().AddDate(-(lastYearNum - 2), 0, 0).Format("Y-01-01 00:00:00")).Unix()
|
|
|
|
|
|
|
|
count, err := dao.VisitorRecord.Ctx(ctx).As("vr").Where(condition).WhereBetween(dao.VisitorRecord.Columns().VisitAt, yearStart, yearEnd).Count()
|
|
|
|
if err != nil {
|
|
|
|
return g.SliceStr{}, g.SliceStr{}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取统计数据
|
|
|
|
xAxis = append(xAxis, gtime.New(yearStart).Format("Y"))
|
|
|
|
yAxis = append(yAxis, gconv.String(count))
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) getMonthStatistic(ctx context.Context, lastMonthNum int, condition g.Map) (xAxis g.SliceStr, yAxis g.SliceStr) {
|
|
|
|
for ; 1 <= lastMonthNum; lastMonthNum-- {
|
|
|
|
//获取当月第一天
|
|
|
|
monthStart := gtime.New(gtime.Now().AddDate(0, -(lastMonthNum - 1), 0).Format("Y-m-01 00:00:00")).Unix()
|
|
|
|
monthEnd := gtime.New(gtime.Now().AddDate(0, -(lastMonthNum - 2), 0).Format("Y-m-01 00:00:00")).Unix()
|
|
|
|
|
|
|
|
count, err := dao.VisitorRecord.Ctx(ctx).As("vr").Where(condition).WhereBetween(dao.VisitorRecord.Columns().VisitAt, monthStart, monthEnd).Count()
|
|
|
|
if err != nil {
|
|
|
|
return g.SliceStr{}, g.SliceStr{}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取统计数据
|
|
|
|
xAxis = append(xAxis, gtime.New(monthStart).Format("Y-m"))
|
|
|
|
yAxis = append(yAxis, gconv.String(count))
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *visitorService) getWeekStatistic(ctx context.Context, lastWeekNum int, condition g.Map) (xAxis g.SliceStr, yAxis g.SliceStr) {
|
|
|
|
for ; 1 <= lastWeekNum; lastWeekNum-- {
|
|
|
|
weekDate, startTimestamp := s.getLastWeekFirstDate(lastWeekNum)
|
|
|
|
endTimestamp := gtime.New(weekDate).AddDate(0, 0, 7).Unix()
|
|
|
|
|
|
|
|
count, err := dao.VisitorRecord.Ctx(ctx).As("vr").Where(condition).WhereBetween(dao.VisitorRecord.Columns().VisitAt, startTimestamp, endTimestamp).Count()
|
|
|
|
if err != nil {
|
|
|
|
return g.SliceStr{}, g.SliceStr{}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取第几周
|
|
|
|
_, weekNum := gtime.New(weekDate).ISOWeek()
|
|
|
|
xAxis = append(xAxis, fmt.Sprintf("第%d周", weekNum))
|
|
|
|
yAxis = append(yAxis, gconv.String(count))
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
|
|
|
|
获取本周周一的日期
|
|
|
|
*/
|
|
|
|
func (s *visitorService) getFirstDateOfWeek() (weekMonday string, dateTimestamp int64) {
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
offset := int(time.Monday - now.Weekday())
|
|
|
|
if offset > 0 {
|
|
|
|
offset = -6
|
|
|
|
}
|
|
|
|
|
|
|
|
weekStartDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
|
|
|
|
weekMonday = weekStartDate.Format("2006-01-02")
|
|
|
|
dateTimestamp = gtime.New(weekMonday).Unix()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
|
|
|
|
获取本周周一的日期
|
|
|
|
*/
|
|
|
|
func (s *visitorService) getLastWeekFirstDate(weekNum int) (weekMonday string, dateTimestamp int64) {
|
|
|
|
thisWeekMonday, _ := s.getFirstDateOfWeek()
|
|
|
|
TimeMonday, _ := time.Parse("2006-01-02", thisWeekMonday)
|
|
|
|
lastWeekMonday := TimeMonday.AddDate(0, 0, -7*(weekNum-1))
|
|
|
|
weekMonday = lastWeekMonday.Format("2006-01-02")
|
|
|
|
dateTimestamp = gtime.New(weekMonday).Unix()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|