From 96c3d0cd93cbe8d9de6109d1abb156d5a8ec9564 Mon Sep 17 00:00:00 2001 From: dongth Date: Wed, 31 Jul 2024 15:48:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20weapp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weapp/message.go | 24 ++ weapp/plan.go | 946 +++++++++++++++++++++++++++++++++++++++++++++++ weapp/setting.go | 297 +++++++++++++++ weapp/wxfile.go | 47 +++ weapp/wxmp.go | 87 +++++ 5 files changed, 1401 insertions(+) create mode 100644 weapp/message.go create mode 100644 weapp/plan.go create mode 100644 weapp/setting.go create mode 100644 weapp/wxfile.go create mode 100644 weapp/wxmp.go diff --git a/weapp/message.go b/weapp/message.go new file mode 100644 index 0000000..3210b7b --- /dev/null +++ b/weapp/message.go @@ -0,0 +1,24 @@ +package weapp + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/shockliu/logger" +) + +// 小程序客服通知消息鉴权 +func CheckSign(c *gin.Context) { + /* 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示: + 参数 描述 + signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 + timestamp 时间戳 + nonce 随机数 + echostr 随机字符串 + */ + //signature:=c.Query("signature") + //nonce:=c.Query("nonce") + echostr := c.Query("echostr") + logger.Debugf("微信小程序消息推送鉴权%s\n", echostr) + c.String(http.StatusOK, echostr) +} diff --git a/weapp/plan.go b/weapp/plan.go new file mode 100644 index 0000000..ab58a98 --- /dev/null +++ b/weapp/plan.go @@ -0,0 +1,946 @@ +package weapp + +import ( + "fmt" + "hc/dbop" + "math" + "net/http" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/shockliu/logger" +) + +func UpdatePlan(c *gin.Context) { + //uid := c.MustGet("TK_User").(int) + uid := 10000014 + + type plancation struct { + ActionId int `json:"action_id"` + Seri int `json:"action_seri"` + Dur int `json:"action_dur"` + } + + type tmp struct { + PlanId int `json:"plan_id"` + FreqType string `json:"freq_type"` + Plist []plancation `json:"plist"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + logger.Debugf(err.Error()) + return + } + + ts, err := dbop.MDb.Begin() + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + logger.Debugf(err.Error()) + return + } + + if len(data.FreqType) > 0 { + _, err = ts.Exec("update user_actplan set freq_type = ?,modify_time = now() where action_type = 2 and user_id = ?;", data.FreqType, uid) + if err != nil { + ts.Rollback() + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + logger.Debugf(err.Error()) + return + } + } + + if len(data.Plist) > 0 { + _, err = ts.Exec("delete from user_plan where user_id=? and play_type = 2;", uid) + if err != nil { + ts.Rollback() + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + logger.Debugf(err.Error()) + return + } + + for _, v := range data.Plist { + action_id := v.ActionId + if v.ActionId < 0 { //新增的动作 + + } + + _, err = ts.Exec("insert into user_plan (user_id,play_type,action_id,action_seri,creat_time,action_dur) values (?,2,?,?,now(),?);", uid, action_id, v.Seri, v.Dur) + if err != nil { + ts.Rollback() + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + logger.Debugf(err.Error()) + return + } + } + } + + ts.Commit() + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) +} + +func PlanList(c *gin.Context) { + uid := c.MustGet("TK_User").(int) + //uid := 10000014 + code := 0 + //BEGIN: + var record_id, grade int + var ts, optime string + err := dbop.MDb.QueryRow("select id,IFNULL(grade,-1),timeSimp,create_time from record where DATE(NOW())=DATE(create_time) and action_type = 2 and user_id = ? ORDER BY create_time DESC limit 1", uid).Scan(&record_id, &grade, &ts, &optime) + + type tmp struct { + ScoreId int `json:"score_id"` + Status int `json:"status"` + } + + uncmp_plan := make(map[int]tmp) + if grade != -1 { //今日最后一次正常结束 + record_id = 0 + } else { + rows, err := dbop.MDb.Query("select id, action_id,result,`status` from action_score where record_id=?;", record_id) + if err != nil { + logger.Warnf("数据查询错误%s\n", err) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": err.Error(), + }) + return + } + defer rows.Close() + for rows.Next() { + var action_id, result, status, score_id int + err = rows.Scan(&score_id, &action_id, &result, &status) + vk, ok := uncmp_plan[action_id] + var cur tmp + cur.ScoreId = score_id + + if ok { + if vk.Status == 0 { + uncmp_plan[action_id] = cur + } + } else { + uncmp_plan[action_id] = cur + } + + } + + // if len(uncmp_plan) == 0 { //无动作的记录,可删除,重新查找 + // logger.Debugf("删除无效记录 %d", record_id) + // code = 1 + // dbop.MDb.Exec("delete from record where id = ?", record_id) + // goto BEGIN + // } + + } + + var plan_id, relax_time int + var freq_type string + err = dbop.MDb.QueryRow("select plan_id,freq_type,relax_time from user_actplan where user_id = ? and action_type = 2;", uid).Scan(&plan_id, &freq_type, &relax_time) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": err.Error(), + }) + return + } + + rows, err := dbop.MDb.Query("select p.action_seri,b.action_id,b.url_type,b.action_name,b.action_url,b.isonline,ifnull(p.action_dur,0),b.action_dur,b.author from user_plan p LEFT JOIN brain_action b on p.action_id=b.action_id where p.user_id = ? and p.play_type = 2 and b.`show`=1 ORDER BY p.action_seri;", uid) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": err.Error(), + }) + return + } + defer rows.Close() + var rst []gin.H + for rows.Next() { + var action_url, action_name, author string + var action_seri, action_id, url_type, isonline, action_dur, def_dur int + err = rows.Scan(&action_seri, &action_id, &url_type, &action_name, &action_url, &isonline, &action_dur, &def_dur, &author) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + if action_dur == 0 { + action_dur = def_dur + } + + act_status := 0 + score_id := 0 + if record_id != 0 { + kv, ok := uncmp_plan[action_id] + if ok == true { //值存在 + act_status = kv.Status + score_id = kv.ScoreId + delete(uncmp_plan, action_id) + } + } + + rst = append(rst, gin.H{"action_seri": action_seri, "action_id": action_id, "url_type": url_type, "action_name": action_name, "action_url": action_url, "isonline": isonline, "action_dur": action_dur, "author": author, "status": act_status, "score_id": score_id}) + } + + logger.Debugf("%#v", rst) + + c.JSON(http.StatusOK, gin.H{ + "code": code, + "data": gin.H{ + "plan_id": plan_id, + "freq_type": freq_type, + "record_id": record_id, + "timestamp": ts, + "optime": optime, + "relax_time": relax_time, + "plist": rst, + }, + "msg": "succ", + }) +} + +func TrainHistory(c *gin.Context) { + //uid := c.MustGet("TK_User").(int) + uid := 10000014 + + type tmp struct { + Month string `json:"month"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + rows, err := dbop.MDb.Query("select id,action_type,ifnull(grade,-1),ifnull(duration,0),DATE_FORMAT(create_time,'%Y-%m-%d %H:%i:%s') as create_time,ifnull(`desc`,'') from record where user_id=? and ? = DATE_FORMAT(create_time, '%Y%m') ORDER BY create_time DESC", uid, data.Month) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + defer rows.Close() + var rst []gin.H + for rows.Next() { + var create_time, desc string + var record_id, action_type, grade, dur int + err = rows.Scan(&record_id, &action_type, &grade, &dur, &create_time, &desc) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + if action_type == 1 { + desc = "快速检测" + } else if action_type == 2 { + desc = "日常训练" + } + + rst = append(rst, gin.H{"record_id": record_id, "action_type": action_type, "grade": grade, "dur": dur, "create_time": create_time, "desc": desc}) + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": rst, + "msg": "succ", + }) +} + +func TrainResult(c *gin.Context) { + type tmp struct { + RecordId int `json:"record_id"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + rows, err := dbop.MDb.Query("select b.url_type, b.action_name,ifnull(s.beginTime,''),IFNULL(s.endTime,''),b.action_url,ifnull(s.result,-1) rs,s.status,s.actionDur from action_score s LEFT JOIN brain_action b on b.action_id = s.action_id where s.record_id = ? ORDER BY rs DESC;", data.RecordId) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + defer rows.Close() + var rst []gin.H + var tol_result, tol_times, action_type int + var all_beg, all_end string + for rows.Next() { + var action_name, action_url, beg_time, end_time string + var result, status, dur int + err = rows.Scan(&action_type, &action_name, &beg_time, &end_time, &action_url, &result, &status, &dur) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + var act_type string + switch action_type { //视觉1、听觉2,触觉3,味觉4,嗅觉5 + case 1: + act_type = "视觉听觉" + break + case 2: + act_type = "听觉" + break + case 3: + act_type = "触觉" + break + case 4: + act_type = "味觉" + break + case 5: + act_type = "嗅觉" + break + case 6: + act_type = "自定动作" + break + } + + rst = append(rst, gin.H{"action_name": action_name, "action_type": act_type, "action_url": action_url, "result": result, "dur": dur, "status": status, "beg_time": beg_time, "end_time": end_time}) + + if status == 1 { + tol_result += result + tol_times++ + } + + if len(all_beg) > 0 { + if beg_time < all_beg { + all_beg = beg_time + } + + } else { + all_beg = beg_time + } + + if len(all_end) > 0 { + if end_time > all_end { + all_end = end_time + } + + } else { + all_end = end_time + } + + } + + grade := 0 + if tol_times != 0 { + grade = tol_result / tol_times + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": gin.H{ + "plist": rst, + "grade": grade, + "beg_time": all_beg, + "end_time": all_end, + }, + "msg": "succ", + }) +} + +func ActionList(c *gin.Context) { + uid := c.MustGet("TK_User").(int) + rows, err := dbop.MDb.Query("select action_id,url_type,action_name,action_url,action_dur,author from brain_action where user_id in (0,?) and `show` = 1 ORDER BY url_type;", uid) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + defer rows.Close() + var vlist, mlist, olist, rst []gin.H + for rows.Next() { + var action_name, action_url, author string + var action_id, url_type, action_dur int + err = rows.Scan(&action_id, &url_type, &action_name, &action_url, &action_dur, &author) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + switch url_type { //视觉1、听觉2,触觉3,味觉4,嗅觉5 + case 1: + //vlist = append(vlist, gin.H{"action_id": action_id, "action_name": action_name, "action_url": action_url, "author": author, "action_dur": action_dur}) + vlist = append(vlist, gin.H{"value": action_id, "text": action_name}) + break + case 2: + //mlist = append(mlist, gin.H{"action_id": action_id, "action_name": action_name, "action_url": action_url, "author": author, "action_dur": action_dur}) + mlist = append(mlist, gin.H{"value": action_id, "text": action_name}) + break + case 3, 4, 5, 6: + //olist = append(olist, gin.H{"action_id": action_id, "action_name": action_name, "action_url": action_url, "author": author, "action_dur": action_dur}) + olist = append(olist, gin.H{"value": action_id, "text": action_name}) + break + } + } + rst = append(rst, gin.H{"value": 0, "text": "视频", "children": vlist}) + rst = append(rst, gin.H{"value": 1, "text": "音乐", "children": mlist}) + rst = append(rst, gin.H{"value": 2, "text": "感官", "children": olist}) + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": rst, + "msg": "succ", + }) +} + +func ActionDetail(c *gin.Context) { + type tmp struct { + ActionId int `json:"action_id"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + var action_name, action_url, author string + var action_id, url_type, action_dur int + err := dbop.MDb.QueryRow("select action_id,url_type,action_name,action_url,action_dur,author from brain_action where action_id = ? and `show` = 1 ORDER BY url_type;", data.ActionId).Scan(&action_id, &url_type, &action_name, &action_url, &action_dur, &author) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": gin.H{ + "action_id": action_id, + "url_type": url_type, + "action_name": action_name, + "action_url": action_url, + "action_dur": action_dur, + "author": author, + }, + "msg": "succ", + }) +} + +func CreateTrain(c *gin.Context) { + uid := c.MustGet("TK_User").(int) + type tmp struct { + Ts string `json:"timestamp"` + Action_type int `json:"action_type"` + DevMac string `json:"devmac,omitempty"` + DevSn string `json:"devsn,omitempty"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + _, err := dbop.MDb.Exec("insert into record (action_type,user_id,timeSimp,create_time,status,facility_sn,facility_mac) values (?,?,?,now(),0,?,?)", data.Action_type, uid, data.Ts, data.DevSn, data.DevMac) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + var record_id int + err = dbop.MDb.QueryRow("select id from record where timeSimp = ?;", data.Ts).Scan(&record_id) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + logger.Debugf("用户 %d 创建新训练,id %d,timestamp:%s", uid, record_id, data.Ts) + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": gin.H{ + "record_id": record_id, + "timestamp": data.Ts, + }, + "msg": "succ", + }) +} + +// 计算给定数据集的方差 +func variance(data []float64) (int, int, int, int, int) { + sum := 0.0 + avg := 0.0 + variance := 0.0 + max := 0.0 + min := 100000.0 + + // 计算数据集的均值 + for _, val := range data { + sum += val + if val > max { + max = val + } + if val < min { + min = val + } + } + avg = sum / float64(len(data)) + + // 计算方差 + for _, val := range data { + variance += math.Pow((val - avg), 2) + } + variance = variance / float64(len(data)-1) + return int(variance * 100), int(sum * 100), int(avg * 100), int(max * 100), int(min * 100) +} + +func updateActionValue(act_rel, act_abs []float64, score_id, band_type int) { + + undulate_rel, _, avg_rel, max_rel, min_rel := variance(act_rel) //相对 + undulate_abs, eng_abs, avg_abs, max_abs, min_abs := variance(act_abs) //绝对 + + strsql := fmt.Sprintf("insert into action_band_info (score_id,band_type,status,undulate_rel, avg_rel, max_rel, min_rel,undulate_abs, eng_abs, avg_abs, max_abs, min_abs) values (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", score_id, band_type, 1, undulate_rel, avg_rel, max_rel, min_rel, undulate_abs, eng_abs, avg_abs, max_abs, min_abs) + logger.Debugf("%s", strsql) + + _, err := dbop.MDb.Exec(strsql) + if err != nil { + logger.Warnf("%s", err.Error()) + } +} + +func updateTotalValue(rest_rel, rest_abs, act_rel, act_abs []float64, score_id, band_type int) int { + + base_undul_rel, _, base_rel, _, _ := variance(rest_rel) //空闲期相对值 + base_undul_abs, base_eng_abs, base_abs, _, _ := variance(rest_abs) //空闲期绝对值 + undulate_rel, _, avg_rel, max_rel, min_rel := variance(act_rel) //相对 + undulate_abs, eng_abs, avg_abs, max_abs, min_abs := variance(act_abs) //绝对 + + strsql := fmt.Sprintf("insert into action_band_info (score_id,band_type,status,base_undul_rel,base_rel,base_undul_abs, base_eng_abs, base_abs,undulate_rel, avg_rel, max_rel, min_rel,undulate_abs, eng_abs, avg_abs, max_abs, min_abs) values (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", score_id, band_type, 0, base_undul_rel, base_rel, base_undul_abs, base_eng_abs, base_abs, undulate_rel, avg_rel, max_rel, min_rel, undulate_abs, eng_abs, avg_abs, max_abs, min_abs) + logger.Debugf("%s", strsql) + + _, err := dbop.MDb.Exec(strsql) + if err != nil { + logger.Warnf("%s", err.Error()) + } + + return int(undulate_abs * 100 / base_undul_abs) +} + +func UploadAction(c *gin.Context) { + uid := c.MustGet("TK_User").(int) + + type tmp struct { + Ts string `json:"timestamp"` + RecordId int `json:"record_id"` + ActionId int `json:"action_id"` + ScoreId int `json:"score_id"` + RestBeg string `json:"rest_beg"` + ActionBeg string `json:"action_beg"` + ActionEnd string `json:"action_end"` + Dur int `json:"dur"` + Last bool `json:"last,omitempty"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + logger.Warnf("%s", err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + logger.Debugf("上传训练记录 %#v", data) + + scoreId := data.ScoreId + if scoreId == 0 { + _, err := dbop.MDb.Exec("insert into action_score (user_id,record_id,action_id,result,status,timeSimp,beginTime,endTime,actionDur) values (?,?,?,0,0,?,?,?,?)", uid, data.RecordId, data.ActionId, data.Ts, data.ActionBeg, data.ActionEnd, data.Dur) + if err != nil { + logger.Warnf("%s", err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + err = dbop.MDb.QueryRow("select id from action_score where timeSimp = ? and beginTime = ?;", data.Ts, data.ActionBeg).Scan(&scoreId) + if err != nil { + logger.Warnf("%s", err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + logger.Debugf("创建新 action_score id %d", scoreId) + } + + if data.Last == false { + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) + } + + //下面进行计算和更新 + logger.Debugf("开始计算,beg:%s,end:%s,split:%s,ts:%s", data.RestBeg, data.ActionEnd, data.ActionBeg, data.Ts) + //strsql := fmt.Sprintf("select data,DATE_FORMAT(create_time,'%s') from url_band where is_error = 0 and create_time > '%s' and create_time < '%s' and timeSimp = '%s';", "%Y-%m-%d %h:%m:%s", data.RestBeg, data.ActionEnd, data.Ts) + //logger.Debugf("sql:%s", strsql) + //rows, err := dbop.MDb.Query(strsql) + rows, err := dbop.MDb.Query("select data,create_time from url_band where is_error = 0 and create_time > ? and create_time < ? and timeSimp = ?;", data.RestBeg, data.ActionEnd, data.Ts) + if err != nil { + logger.Warnf("%s", err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + defer rows.Close() + var c_time, banddata string + r_deltaRelative := make([]float64, 0) + r_thetaRelative := make([]float64, 0) + r_alphaRelative := make([]float64, 0) + r_betaRelative := make([]float64, 0) + r_gammaRelative := make([]float64, 0) + r_deltaAbsolute := make([]float64, 0) + r_thetaAbsolute := make([]float64, 0) + r_alphaAbsolute := make([]float64, 0) + r_betaAbsolute := make([]float64, 0) + r_gammaAbsolute := make([]float64, 0) + + a_deltaRelative := make([]float64, 0) + a_thetaRelative := make([]float64, 0) + a_alphaRelative := make([]float64, 0) + a_betaRelative := make([]float64, 0) + a_gammaRelative := make([]float64, 0) + a_deltaAbsolute := make([]float64, 0) + a_thetaAbsolute := make([]float64, 0) + a_alphaAbsolute := make([]float64, 0) + a_betaAbsolute := make([]float64, 0) + a_gammaAbsolute := make([]float64, 0) + + var had_rest, had_action bool + for rows.Next() { + err = rows.Scan(&banddata, &c_time) + if err != nil { + logger.Debugf("%s", err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + c_time = strings.Replace(c_time, "T", " ", -1) + c_time = strings.Replace(c_time, "Z", "", -1) + /* + target.energy.deltaRelative, target.energy.thetaRelative, target.energy.alphaRelative, target.energy.betaRelative, target.energy.gammaRelative, + target.mindfullness, target.focus, target.emotion, target.fatigue, target.stress, + target.energy.deltaAbsolute, target.energy.thetaAbsolute, target.energy.alphaAbsolute, target.energy.betaAbsolute, target.energy.gammaAbsolute, + */ + ds := strings.Split(banddata, "|") + //logger.Debugf("%#v", ds) + //logger.Debugf("%s %s", c_time, data.ActionBeg) + if c_time < data.ActionBeg { //空闲期 + had_rest = true + f_data, err := strconv.ParseFloat(ds[0], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_deltaRelative = append(r_deltaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[1], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_thetaRelative = append(r_thetaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[2], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_alphaRelative = append(r_alphaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[3], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_betaRelative = append(r_betaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[4], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_gammaRelative = append(r_gammaRelative, f_data) + + f_data, err = strconv.ParseFloat(ds[10], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_deltaAbsolute = append(r_deltaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[11], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_thetaAbsolute = append(r_thetaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[12], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_alphaAbsolute = append(r_alphaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[13], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_betaAbsolute = append(r_betaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[14], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + r_gammaAbsolute = append(r_gammaAbsolute, f_data) + } else { //动作期 + had_action = true + f_data, err := strconv.ParseFloat(ds[0], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_deltaRelative = append(a_deltaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[1], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_thetaRelative = append(a_thetaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[2], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_alphaRelative = append(a_alphaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[3], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_betaRelative = append(a_betaRelative, f_data) + f_data, err = strconv.ParseFloat(ds[4], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_gammaRelative = append(a_gammaRelative, f_data) + + f_data, err = strconv.ParseFloat(ds[10], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_deltaAbsolute = append(a_deltaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[11], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_thetaAbsolute = append(a_thetaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[12], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_alphaAbsolute = append(a_alphaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[13], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_betaAbsolute = append(a_betaAbsolute, f_data) + f_data, err = strconv.ParseFloat(ds[14], 64) + if err != nil { + logger.Debugf("%s", err.Error()) + } + a_gammaAbsolute = append(a_gammaAbsolute, f_data) + } + } + + var sql_update_action_score string + if had_action && had_rest { //rest+action期都有 + logger.Debugf(" action_score %d 有数据,%s", scoreId, data.Ts) + result_delta := updateTotalValue(r_deltaRelative, r_deltaAbsolute, a_deltaRelative, a_deltaAbsolute, scoreId, 1) + result_theta := updateTotalValue(r_thetaRelative, r_thetaAbsolute, a_thetaRelative, a_thetaAbsolute, scoreId, 2) + result_alpha := updateTotalValue(r_alphaRelative, r_alphaAbsolute, a_alphaRelative, a_alphaAbsolute, scoreId, 3) + result_beta := updateTotalValue(r_betaRelative, r_betaAbsolute, a_betaRelative, a_betaAbsolute, scoreId, 4) + result_gamma := updateTotalValue(r_gammaRelative, r_gammaAbsolute, a_gammaRelative, a_gammaAbsolute, scoreId, 5) + + sql_update_action_score = fmt.Sprintf("update action_score set result_delta = %d,result_theta = %d,result_alpha = %d,result_beta = %d,result_gamma = %d,result = %d,`status` = 1 where id = %d", result_delta, result_theta, result_alpha, result_beta, result_gamma, result_alpha, scoreId) + + } else if had_action { //action期,有 + logger.Warnf(" action_score %d 只有动作期数据,%s", scoreId, data.Ts) + updateActionValue(a_deltaRelative, a_deltaAbsolute, scoreId, 1) + updateActionValue(a_thetaRelative, a_thetaAbsolute, scoreId, 2) + updateActionValue(a_alphaRelative, a_alphaAbsolute, scoreId, 3) + updateActionValue(a_betaRelative, a_betaAbsolute, scoreId, 4) + updateActionValue(a_gammaRelative, a_gammaAbsolute, scoreId, 5) + sql_update_action_score = fmt.Sprintf("update action_score set result = 0,`status` = 1 where id = %d", scoreId) + } else { + //这就没法用了 + logger.Warnf(" action_score %d 无可用数据,%s", scoreId, data.Ts) + sql_update_action_score = fmt.Sprintf("update action_score set result = 0,`status` = 0 where id = %d", scoreId) + } + logger.Debugf("%s", sql_update_action_score) + _, err = dbop.MDb.Exec(sql_update_action_score) + if err != nil { + logger.Warnf("%s", err.Error()) + } + + if data.Last { + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) + } + +} + +/* +计算总体成绩 +*/ +func AnalyseResult(c *gin.Context) { + type tmp struct { + RecordId int `json:"record_id"` + Desc string `json:"desc,omitempty"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + logger.Debugf("上传训练记录 %#v", data) + + rows, err := dbop.MDb.Query("select result,status,beginTime,endTime from action_score where record_id = ?", data.RecordId) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + defer rows.Close() + var result, status, total_score, total_count int + var beginTime, endTime, s_beg, s_end string + for rows.Next() { + err = rows.Scan(&result, &status, &beginTime, &endTime) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + total_count++ + total_score += result + + if len(s_beg) == 0 { + s_beg = beginTime + } else { + if beginTime < s_beg { + s_beg = beginTime + } + } + + if len(s_end) == 0 { + s_end = endTime + } else { + if endTime > s_end { + s_end = endTime + } + } + } + var grade int + var desc string + if total_count > 0 { + grade = total_score / total_count + + } else { + logger.Warnf("record %d 训练全为空", data.RecordId) + } + + loc, _ := time.LoadLocation("Local") //重要:获取时区 + //logger.Debugf("beg %s,end %s", s_beg, s_end) + var t_beg, t_end int64 + if len(s_beg) > 0 { + theTime, _ := time.ParseInLocation("2006-01-02T15:04:05Z", s_beg, loc) //使用模板在对应时区转化为time.time类型 + t_beg = theTime.Unix() + } + + if len(s_end) > 0 { + theTime, _ := time.ParseInLocation("2006-01-02T15:04:05Z", s_end, loc) //使用模板在对应时区转化为time.time类型 + t_end = theTime.Unix() + } + + if len(data.Desc) > 0 { + desc = data.Desc + } + + logger.Debugf("grade %d,duration:%d,desc:%s,id:%d", grade, t_end-t_beg, desc, data.RecordId) + _, err = dbop.MDb.Exec("update record set `status` = ?,grade = ?,duration=?,`desc`=? where id = ?", 1, grade, t_end-t_beg, desc, data.RecordId) + if err != nil { + logger.Debug(err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) + +} diff --git a/weapp/setting.go b/weapp/setting.go new file mode 100644 index 0000000..a677f87 --- /dev/null +++ b/weapp/setting.go @@ -0,0 +1,297 @@ +package weapp + +import ( + "bytes" + "encoding/json" + "fmt" + "hc/dbop" + "io" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/shockliu/logger" +) + +func Opt(c *gin.Context) { + rows, err := dbop.MDb.Query("select union_id,open_id from wechat_member") + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": err.Error(), + }) + return + } + + defer rows.Close() + for rows.Next() { + var oid, uid string + err = rows.Scan(&uid, &oid) + if err != nil { + continue + } + fmt.Println(oid, uid) + _, err := dbop.MDb.Exec("update user_account set open_id = ? where uuID = ?;", oid, uid) + if err != nil { + logger.Debugf("%s", err.Error()) + } + + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": err.Error(), + }) +} + +func UnlinkDev(c *gin.Context) { + //uid := c.MustGet("TK_User").(int) + uid := 10000014 + + type tmp struct { + DevId int `json:"dev_id"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + _, err := dbop.MDb.Exec("update user_device_bind set user_id = 0 where device_id = ? and user_id = ?;", data.DevId, uid) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) +} + +func BindDev(c *gin.Context) { + uid := c.MustGet("TK_User").(int) + //uid := 10000014 + + type tmp struct { + Devsn string `json:"devsn"` + DevMac string `json:"devmac"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + ts, _ := dbop.MDb.Begin() + var dev_id, dev_personal, binded_user int + is_new := false + err := ts.QueryRow("select d.device_id,d.bind_status,b.user_id from health_device d LEFT JOIN user_device_bind b on d.device_id=b.device_id where d.device_sn = ?;", data.Devsn).Scan(&dev_id, &dev_personal, &binded_user) + if err != nil { //不存在,新增 + _, err = ts.Exec("insert into health_device (device_name,device_sn,device_mac,dev_type,create_time) values(?,?,?,6,now())", data.Devsn, data.Devsn, data.DevMac) + if err != nil { + ts.Rollback() + logger.Debugf(err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + ts.QueryRow("select device_id from health_device where device_sn = ?;", data.Devsn).Scan(&dev_id) + is_new = true + _, err = ts.Exec("insert into user_device_bind (device_id,user_id) values (?,?)", dev_id, uid) + if err != nil { + ts.Rollback() + logger.Debugf(err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -2, + "msg": "设备已经绑定,请先解除", + }) + return + } + } + + if !is_new { + if dev_personal == 0 && binded_user != 0 { //个人用户 + ts.Rollback() + c.JSON(http.StatusOK, gin.H{ + "code": -2, + "msg": "设备已经被绑定,请先解除", + }) + return + } + + _, err = ts.Exec("update user_device_bind set user_id = ? where device_id = ?;", uid, dev_id) + if err != nil { + ts.Rollback() + logger.Debugf(err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -2, + "msg": "设备绑定失败", + }) + return + } + } + + ts.Commit() + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) +} + +func ReportNotify(c *gin.Context) { + type tmp struct { + UId int `json:"uid"` + } + var data tmp + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + + var open_id, uname string + err := dbop.MDb.QueryRow("select open_id,user_name from user_account where user_id = ?", data.UId).Scan(&open_id, &uname) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": err.Error(), + }) + return + } + + //微信小程序id + appId := "wxe9c749a836dee2a8" + //微信小程序密钥 + appSecret := "51cbc34547a97c661af7e8855a48d808" + //模板id + templateId := "FIggb-ZTIa_-NxV7-OS_OFEPWBFHv5TI0RGbqDJGelM" + //跳转页面地址 + pageUrl := "pages/home/home" + //获取token接口 + getTokenUrl := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret + //发送消息接口 + sendWxUserMsgUrl := "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + + resp, err := http.Get(getTokenUrl) + if err != nil { + logger.Warnf(err.Error()) + return + } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + //fmt.Println(string(body)) + //{"access_token":"74_dSxu74890Vf1YvMkVzSafUgLgBLIBdBH_CegGeD8OWTuiCq7Lda3ddVdvkW-LdB-sKIigNwgXIA9J4DBp7G_7jbF-X4hk6bT3kgWooNv98zwWDvv3QeWSM0_4X4TLPhAHAJBF","expires_in":7200} + var access_token string + if len(body) > 0 { + c2j := make(map[string]any) + err = json.Unmarshal(body, &c2j) + access_token = c2j["access_token"].(string) + logger.Debugf("access_token %s", access_token) + + tmp1 := gin.H{"value": uname} + tmp2 := gin.H{"value": time.Now().Format("2006-01-02 15:04:05")} + tmp3 := gin.H{"value": "进入【我的报告】可查看详情"} + tmp4 := gin.H{"value": "训练效果脑波分析报告"} + n_data := gin.H{"time2": tmp2, "thing3": tmp3, "thing4": tmp1, "thing5": tmp4} + client := &http.Client{} + ctx := gin.H{ + "touser": open_id, + "template_id": templateId, + "page": pageUrl, + "miniprogram_state": "formal", //跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 + "lang": "zh_CN", + "data": n_data, + } + bytesData, err := json.Marshal(ctx) + if err != nil { + logger.Warnf("数据处理失败%s\n", err) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": "数据处理失败", + }) + return + } + req, _ := http.NewRequest("POST", fmt.Sprintf("%s%s", sendWxUserMsgUrl, access_token), bytes.NewReader(bytesData)) + resp, err := client.Do(req) + if err != nil { + logger.Warnf(err.Error()) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": "下发失败", + }) + return + } + body, err = io.ReadAll(resp.Body) + logger.Debugf("响应 %s", string(body)) + if err != nil { + logger.Warnf("接口返回失败%s\n", err) + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": "下发失败", + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "msg": "succ", + }) + + } else { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": "信号发送失败", + }) + } + +} + +func DevList(c *gin.Context) { + //uid := c.MustGet("TK_User").(int) + uid := 10000014 + + rows, err := dbop.MDb.Query("select d.device_id,d.device_sn,d.dev_type from health_device d left join user_device_bind b on d.device_id = b.device_id where b.user_id = ?", uid) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "message": err.Error(), + }) + return + } + + defer rows.Close() + var rst []gin.H + for rows.Next() { + var dev_id, dev_name string + var dev_type int + err = rows.Scan(&dev_id, &dev_name, &dev_type) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "code": -1, + "msg": err.Error(), + }) + return + } + rst = append(rst, gin.H{"dev_id": dev_id, "dev_name": dev_name, "dev_type": dev_type}) + } + + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": rst, + "msg": "succ", + }) +} diff --git a/weapp/wxfile.go b/weapp/wxfile.go new file mode 100644 index 0000000..71af60d --- /dev/null +++ b/weapp/wxfile.go @@ -0,0 +1,47 @@ +package weapp + +import ( + "io" + "net/http" + "net/url" + "os" + "strconv" + "strings" + + "github.com/shockliu/logger" +) + +// 下载链接 https://www.daymele.com/mapp/download/recharge.xls +func Download(w http.ResponseWriter, req *http.Request) { + if req.RequestURI == "/favicon.ico" { + return + } + pos := strings.LastIndex(req.RequestURI, "/") + 1 + logger.Debugf("Download:%s\n", req.RequestURI) + filename := req.RequestURI[pos:] + enEscapeUrl, err := url.QueryUnescape(filename) + if err != nil { + logger.Errorf("下载文件获取文件名失败:%s\n", err) + w.Write([]byte("暂时无法下载您所需要的文件,请确认文件名称或联系管理员")) + return + } + logger.Debugf("Content:%s\n", enEscapeUrl) + f, err := os.Open("/home/share/" + enEscapeUrl) + if err != nil { + logger.Errorf("下载文件打开失败:%s\n", err) + w.Write([]byte("暂时无法下载您所需要的文件,请确认文件名称或联系管理员")) + return + } + info, err := f.Stat() + if err != nil { + logger.Errorf("下载文件状态失败:%s\n", err) + w.Write([]byte("暂时无法下载您所需要的文件,请确认文件名称或联系管理员")) + return + } + contentType := "application/octet-stream" + w.Header().Set("content-Disposition", "attachment;filename="+filename) + w.Header().Set("Content-Type", contentType) + w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10)) + f.Seek(0, 0) + io.Copy(w, f) +} diff --git a/weapp/wxmp.go b/weapp/wxmp.go new file mode 100644 index 0000000..52cb0b7 --- /dev/null +++ b/weapp/wxmp.go @@ -0,0 +1,87 @@ +package weapp + +import ( + "hc/dbop" + + log "github.com/sirupsen/logrus" + + "github.com/shockliu/logger" + wechat "github.com/silenceper/wechat/v2" + + "github.com/silenceper/wechat/v2/miniprogram" + "github.com/silenceper/wechat/v2/miniprogram/auth" + "github.com/silenceper/wechat/v2/miniprogram/qrcode" + + miniConfig "github.com/silenceper/wechat/v2/miniprogram/config" + + //"github.com/silenceper/wechat/v2/officialaccount/material" + minimsg "github.com/silenceper/wechat/v2/miniprogram/message" +) + +var ( + // openID chan string + // oa *officialaccount.OfficialAccount + // kf *message.Manager + // tm *message.Template + //mt *material.Material + // miniprogram + mp *miniprogram.MiniProgram + au *auth.Auth + qr *qrcode.QRCode + cm *minimsg.Manager // 维护小程序 +) + +func init() { + // 设置log "github.com/sirupsen/logrus"的日志级别 + // log.SetLevel(log.WarnLevel) + log.SetLevel(log.InfoLevel) + // openID = make(chan string, 10) + wc := wechat.NewWechat() + //这里本地内存保存access_token,也可选择redismemcache或者自定cache + // redisOpts := &cache.RedisOpts{ + // Host: "127.0.0.1:6379", // redis host + // Password: "DqklFshop8848", //redis password + // Database: 1, // redis db + // MaxActive: 10, // 连接池最大活跃连接数 + // MaxIdle: 10, //连接池最大空闲连接数 + // IdleTimeout: 60, //空闲连接超时时间,单位:second + // } + // redisCache := cache.NewRedis(context.Background(), redisOpts) + // //memory := cache.NewMemory() + // // 事集公众号相关配置 + // cfg := &offConfig.Config{ + // AppID: "wx0d77e0af930eacc1", + // AppSecret: "119554764ba746d8d6e882c098bf78fe", + // Token: "DqklShijiWLSC8848", + // EncodingAESKey: "Sujw4wE0mbxfiDx40A0gLAzvRhgVnT4Y2KSTyVMVKoH", + // Cache: redisCache, + // } + // oa = wc.GetOfficialAccount(cfg) + // kf = oa.GetCustomerMessageManager() + // tm = oa.GetTemplate() + // //mt = oa.GetMaterial() + // go UserInit() + + // 康养小程序 + SelfCache := dbop.NewSelfCache("HCWXMAPP:") + minicfg := &miniConfig.Config{ + AppID: "wxe9c749a836dee2a8", + AppSecret: "51cbc34547a97c661af7e8855a48d808", + Cache: SelfCache, + } + mp = wc.GetMiniProgram(minicfg) + au = mp.GetAuth() + qr = mp.GetQRCode() + cm = mp.GetCustomerMessage() // 康养小程序客服信息 + +} + +func GetAuth(code string) (string, string, string, bool) { + rst, err := au.Code2Session(code) + if err != nil { + logger.Warnf("Code2Session Err:%s\n", err) + return "", "", "", false + } else { + return rst.SessionKey, rst.OpenID, rst.UnionID, true + } +}