🐛 fix bug
parent
26220f0276
commit
433ff17755
@ -0,0 +1,132 @@
|
|||||||
|
aliyun-oss:
|
||||||
|
endpoint: oss-cn-chengdu.aliyuncs.com
|
||||||
|
access-key-id: LTAI5tFHes6HBWJFUjuPwHso
|
||||||
|
access-key-secret: qXuWtEJvYEQvj9yhkmLYfRxHShheYa
|
||||||
|
bucket-name: jmyl-app
|
||||||
|
bucket-url: https://jmyl-app.oss-cn-chengdu.aliyuncs.com
|
||||||
|
base-path: miniapp
|
||||||
|
autocode:
|
||||||
|
server-model: /model/%s
|
||||||
|
server-router: /router/%s
|
||||||
|
server: /server.exe.exe
|
||||||
|
server-api: /api/v1/%s
|
||||||
|
server-plug: /plugin/%s
|
||||||
|
server-initialize: /initialize
|
||||||
|
root: C:\Users\Administrator\Desktop
|
||||||
|
web-table: /view
|
||||||
|
web: /web/src
|
||||||
|
server-service: /service/%s
|
||||||
|
server-request: /model/%s/request/
|
||||||
|
web-api: /api
|
||||||
|
web-form: /view
|
||||||
|
transfer-restart: true
|
||||||
|
captcha:
|
||||||
|
key-long: 4
|
||||||
|
img-width: 240
|
||||||
|
img-height: 80
|
||||||
|
open-captcha: 0
|
||||||
|
open-captcha-timeout: 3600
|
||||||
|
cors:
|
||||||
|
mode: strict-whitelist
|
||||||
|
whitelist:
|
||||||
|
- allow-origin: example1.com
|
||||||
|
allow-methods: POST, GET
|
||||||
|
allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id
|
||||||
|
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||||
|
allow-credentials: true
|
||||||
|
- allow-origin: example2.com
|
||||||
|
allow-methods: GET, POST
|
||||||
|
allow-headers: content-type
|
||||||
|
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
|
||||||
|
allow-credentials: true
|
||||||
|
db-list:
|
||||||
|
- type: ""
|
||||||
|
alias-name: ""
|
||||||
|
prefix: ""
|
||||||
|
port: ""
|
||||||
|
config: ""
|
||||||
|
db-name: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
path: ""
|
||||||
|
engine: ""
|
||||||
|
log-mode: ""
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
singular: false
|
||||||
|
log-zap: false
|
||||||
|
disable: true
|
||||||
|
email:
|
||||||
|
to: xxx@qq.com
|
||||||
|
from: xxx@163.com
|
||||||
|
host: smtp.163.com
|
||||||
|
secret: xxx
|
||||||
|
nickname: test
|
||||||
|
port: 465
|
||||||
|
is-ssl: true
|
||||||
|
excel:
|
||||||
|
dir: ./resource/excel/
|
||||||
|
jwt:
|
||||||
|
signing-key: f2b1b2af-c8f1-43cf-88e4-40b0a64b5487
|
||||||
|
expires-time: 7d
|
||||||
|
buffer-time: 1d
|
||||||
|
issuer: qmPlus
|
||||||
|
local:
|
||||||
|
path: uploads/file
|
||||||
|
store-path: uploads/file
|
||||||
|
mini-app:
|
||||||
|
app-id: wxaaf66dbb5c3983b3
|
||||||
|
app-secret: 0abba24dbff43febba1e551651f693b4
|
||||||
|
mysql:
|
||||||
|
prefix: ""
|
||||||
|
port: "3307"
|
||||||
|
config: charset=utf8mb4&parseTime=True&loc=Local
|
||||||
|
db-name: mini_app
|
||||||
|
username: root
|
||||||
|
password: Jmyl123123
|
||||||
|
path: 47.113.103.195
|
||||||
|
engine: ""
|
||||||
|
log-mode: error
|
||||||
|
max-idle-conns: 10
|
||||||
|
max-open-conns: 100
|
||||||
|
singular: false
|
||||||
|
log-zap: false
|
||||||
|
redis:
|
||||||
|
addr: 127.0.0.1:6379
|
||||||
|
password: "Jmyl123123"
|
||||||
|
db: 0
|
||||||
|
system:
|
||||||
|
env: public
|
||||||
|
db-type: mysql
|
||||||
|
oss-type: aliyun-oss
|
||||||
|
router-prefix: ""
|
||||||
|
addr: 8888
|
||||||
|
iplimit-count: 15000
|
||||||
|
iplimit-time: 3600
|
||||||
|
use-multipoint: false
|
||||||
|
use-redis: true
|
||||||
|
timer:
|
||||||
|
spec: '@daily'
|
||||||
|
detail:
|
||||||
|
- tableName: sys_operation_records
|
||||||
|
compareField: created_at
|
||||||
|
interval: 2160h
|
||||||
|
- tableName: jwt_blacklists
|
||||||
|
compareField: created_at
|
||||||
|
interval: 168h
|
||||||
|
start: true
|
||||||
|
with_seconds: false
|
||||||
|
zap:
|
||||||
|
level: info
|
||||||
|
prefix: '[miniapp]'
|
||||||
|
format: console
|
||||||
|
director: log
|
||||||
|
encode-level: LowercaseColorLevelEncoder
|
||||||
|
stacktrace-key: stacktrace
|
||||||
|
max-age: 0
|
||||||
|
show-line: true
|
||||||
|
log-in-console: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-co-op/gocron"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var WxTask *gocron.Scheduler
|
||||||
|
|
||||||
|
func InitTask() {
|
||||||
|
WxTask = gocron.NewScheduler(time.Local)
|
||||||
|
|
||||||
|
// 每天凌晨1点执行
|
||||||
|
_, _ = WxTask.Every(1).Day().At("01:00").Do(CheckUserSurgeryDate) // 检查用户是否已到手术日期
|
||||||
|
|
||||||
|
// 开启定时任务
|
||||||
|
WxTask.StartAsync()
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"miniapp/global"
|
||||||
|
"miniapp/model/app"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CheckUserSurgeryDate 检查用户是否已到手术日期
|
||||||
|
func CheckUserSurgeryDate() {
|
||||||
|
var users []app.User
|
||||||
|
global.GVA_DB.Model(&app.User{}).Find(&users)
|
||||||
|
for _, user := range users {
|
||||||
|
parse, _ := time.Parse("2006-01-02", user.SurgeryTime)
|
||||||
|
if time.Now().Sub(parse).Hours()/24 == 0 {
|
||||||
|
global.GVA_DB.Model(&app.User{}).Where("id = ?", user.ID).Updates(app.User{IsSurgery: 1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/medivhzhan/weapp/v3"
|
||||||
|
msg "github.com/medivhzhan/weapp/v3/subscribemessage"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"miniapp/global"
|
||||||
|
"miniapp/model/app"
|
||||||
|
"miniapp/model/common"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SendMsg(userId int) {
|
||||||
|
var user app.User
|
||||||
|
err := global.GVA_DB.Model(&user).Where("id = ?", userId).Find(&user).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("获取用户信息失败:%s", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户待办列表
|
||||||
|
var userTodo []common.UserTodo
|
||||||
|
if user.IsSurgery == 0 {
|
||||||
|
err = global.GVA_DB.Model(&userTodo).Where("user_id = ? and is_finish = ? and remind_period = 0", userId, 0).Find(&userTodo).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("获取用户待办列表:%s", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = global.GVA_DB.Model(&userTodo).Where("user_id = ? and is_finish = ? and remind_period = 1", userId, 0).Find(&userTodo).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("获取用户待办列表:%s", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据用户手术信息 发送提醒消息
|
||||||
|
parse, _ := time.Parse("2006-01-02", user.SurgeryTime)
|
||||||
|
if time.Now().Sub(parse).Hours()/24 <= -3 {
|
||||||
|
for _, todo := range userTodo {
|
||||||
|
jbo, _ := WxTask.Every(1).Day().At(todo.RemindTime).Do(MiniappSendMsg, *user.WechatOpenId, todo.Content, todo.RemindPeriod, todo.RemindTime) // 检查用户待办事项
|
||||||
|
s := strings.Split("一天3次", "")[2]
|
||||||
|
// 将s转为int类型
|
||||||
|
atoi, _ := strconv.Atoi(s)
|
||||||
|
if jbo.RunCount() == atoi {
|
||||||
|
WxTask.Remove(jbo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MiniappSendMsg(openId string, context string, frequency string, remindTime string) {
|
||||||
|
sdk := weapp.NewClient(global.GVA_CONFIG.MiniApp.AppId, global.GVA_CONFIG.MiniApp.AppSecret)
|
||||||
|
|
||||||
|
msgData := msg.SendRequest{
|
||||||
|
ToUser: openId,
|
||||||
|
TemplateID: "PgxoZOOSDgBcmIGd_EVLDnYUmL3eu6NQTAZCsHQeuWY",
|
||||||
|
Page: "/page/index/todo",
|
||||||
|
MiniprogramState: msg.MiniprogramStateTrial,
|
||||||
|
Data: msg.SendData{
|
||||||
|
"thing1": msg.SendValue{Value: context},
|
||||||
|
"time2": msg.SendValue{Value: remindTime},
|
||||||
|
"short_thing17": msg.SendValue{Value: frequency},
|
||||||
|
"time15": msg.SendValue{Value: time.DateTime},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
send, err := sdk.NewSubscribeMessage().Send(&msgData)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = send.GetResponseError()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("微信返回错误: %#v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("返回结果: %#v", send)
|
||||||
|
}
|
@ -0,0 +1,190 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"miniapp/global"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//type wxMsg struct{}
|
||||||
|
//
|
||||||
|
//func WxMsgUtils() *wxMsg {
|
||||||
|
// return &wxMsg{}
|
||||||
|
//}
|
||||||
|
|
||||||
|
type Wechat struct {
|
||||||
|
appID string
|
||||||
|
secret string
|
||||||
|
templateID string
|
||||||
|
accessToken *AccessToken
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenIDResponse struct {
|
||||||
|
Openid string `json:"openid"`
|
||||||
|
SessionKey string `json:"session_key"`
|
||||||
|
Unionid string `json:"unionid"`
|
||||||
|
WxErr
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckTokenRequest struct {
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Nonce string `json:"nonce"`
|
||||||
|
Echostr string `json:"echostr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WxErr struct {
|
||||||
|
Errcode int `json:"errcode"`
|
||||||
|
Errmsg string `json:"errmsg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessToken struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
ExpiresIn int64 `json:"expires_in"`
|
||||||
|
WxErr
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendRequest struct {
|
||||||
|
Touser string `json:"touser"`
|
||||||
|
Page string `json:"page"`
|
||||||
|
Data Message `json:"data"`
|
||||||
|
EmphasisKeyword string `json:"emphasis_keyword"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Message map[string]interface{}
|
||||||
|
|
||||||
|
func (w *Wechat) SendMsg(req SendRequest) (err error) {
|
||||||
|
token, err := w.GetAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api, err := TokenAPI("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send", token)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for key := range req.Data {
|
||||||
|
req.Data[key] = Message{"value": req.Data[key]}
|
||||||
|
}
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"touser": "o9Fq_6_cYKvOWnyUM3McC11hWsTI",
|
||||||
|
"template_id": global.GVA_CONFIG.MiniApp.TemplateID,
|
||||||
|
"page": "/pages/index/todo",
|
||||||
|
"data": req.Data,
|
||||||
|
"emphasis_keyword": req.EmphasisKeyword,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res, err := http.Post(api, "application/json", strings.NewReader(string(b)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
err = errors.New("WECHAT_SERVER_ERROR")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp WxErr
|
||||||
|
if err = json.NewDecoder(res.Body).Decode(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.Errcode != 0 {
|
||||||
|
return errors.New(resp.Errmsg)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Wechat) GetAccessToken() (token string, err error) {
|
||||||
|
w.Lock()
|
||||||
|
defer w.Unlock()
|
||||||
|
if w.accessToken == nil || w.accessToken.ExpiresIn < time.Now().Unix() {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
err = w.getAccessToken()
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token = w.accessToken.AccessToken
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Wechat) CheckSignature(req CheckTokenRequest) (err error) {
|
||||||
|
if sig := w.sortSha1(req.Timestamp, req.Nonce, req.Echostr); sig != req.Signature {
|
||||||
|
err = errors.New("check signature failed.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TokenAPI(api, token string) (string, error) {
|
||||||
|
u, err := url.Parse(api)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
query := u.Query()
|
||||||
|
query.Set("access_token", token)
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Wechat) getAccessToken() (err error) {
|
||||||
|
urls, err := url.Parse("https://api.weixin.qq.com/cgi-bin/token")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
query := urls.Query()
|
||||||
|
query.Set("appid", w.appID)
|
||||||
|
query.Set("secret", w.secret)
|
||||||
|
query.Set("grant_type", "client_credential")
|
||||||
|
|
||||||
|
urls.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
res, err := http.Get(urls.String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return errors.New("wechat internal server error.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var token AccessToken
|
||||||
|
if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.Errcode != 0 {
|
||||||
|
return errors.New(token.Errmsg)
|
||||||
|
}
|
||||||
|
w.accessToken.AccessToken = token.AccessToken
|
||||||
|
w.accessToken.ExpiresIn = token.ExpiresIn
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Wechat) sortSha1(s ...string) string {
|
||||||
|
sort.Strings(s)
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(strings.Join(s, "")))
|
||||||
|
return fmt.Sprintf("%x", h.Sum(nil))
|
||||||
|
}
|
Loading…
Reference in New Issue