:coding:完成totp适配

This commit is contained in:
sunxiaolong
2023-11-20 15:47:51 +08:00
parent b250213626
commit 80a581486c
21 changed files with 641 additions and 247 deletions

8
config/config.go Normal file
View File

@@ -0,0 +1,8 @@
package config
import "github.com/beego/beego/v2/server/web"
func GetGatewayHost() string {
host, _ := web.AppConfig.String("gateway::host")
return host
}

View File

@@ -1,3 +1,5 @@
package controllers
/***************************************************
** @Desc : c file for ...
** @Time : 2019/8/19 18:13
@@ -7,7 +9,6 @@
** @Last Modified time: 2019/8/19 18:13
** @Software: GoLand
****************************************************/
package controllers
import (
"boss/common"
@@ -29,9 +30,7 @@ type AddController struct {
BaseController
}
/*
* 添加一级菜单
*/
// AddMenu 添加一级菜单
func (c *AddController) AddMenu() {
oneMenu := c.GetString("oneMenu")
userID := c.GetSession("userID").(string)
@@ -40,9 +39,7 @@ func (c *AddController) AddMenu() {
c.GenerateJSON(dataJSON)
}
/*
* 添加二级菜单
*/
// AddSecondMenu 添加二级菜单
func (c *AddController) AddSecondMenu() {
firstMenuUid := c.GetString("preMenuUid")
secondMenu := c.GetString("secondMenu")

View File

@@ -1,3 +1,5 @@
package controllers
/***************************************************
** @Desc : c file for ...
** @Time : 2019/8/21 11:18
@@ -7,7 +9,6 @@
** @Last Modified time: 2019/8/21 11:18
** @Software: GoLand
****************************************************/
package controllers
import (
"boss/common"

View File

@@ -5,6 +5,7 @@ import (
"boss/datas"
"boss/models/user"
"boss/utils"
"boss/utils/mfa"
"github.com/beego/beego/v2/adapter/validation"
"github.com/beego/beego/v2/core/logs"
beego "github.com/beego/beego/v2/server/web"
@@ -15,7 +16,6 @@ type LoginController struct {
}
func (c *LoginController) Prepare() {
}
func (c *LoginController) Login() {
@@ -23,6 +23,7 @@ func (c *LoginController) Login() {
userID := c.GetString("userID")
passWD := c.GetString("passwd")
code := c.GetString("Code")
totpCode := c.GetString("totpCode")
dataJSON := new(datas.KeyDataJSON)
@@ -44,7 +45,19 @@ func (c *LoginController) Login() {
if userInfo.UserId == "" {
dataJSON.Key = "userID"
dataJSON.Msg = "用户不存在,请求联系管理员!"
} else if userInfo.OtpSecret != "" && totpCode == "" {
dataJSON.Key = "userID"
dataJSON.Msg = "需要输入二次验证!"
} else {
// 如果验证失败
if userInfo.OtpSecret != "" && !mfa.ValidCode(totpCode, userInfo.OtpSecret) {
dataJSON.Key = "userID"
dataJSON.Msg = "二次验证不正确,请输入二次验证!"
c.Data["json"] = dataJSON
_ = c.ServeJSON()
return
}
codeInterface := c.GetSession("verifyCode")
if userInfo.Passwd != utils.GetMD5Upper(passWD) {
dataJSON.Key = "passWD"
@@ -92,9 +105,7 @@ func (c *LoginController) Logout() {
_ = c.ServeJSON()
}
/*
* 验证码获取如果获取成功并将验证码存到session中
*/
// GetVerifyImg 验证码获取如果获取成功并将验证码存到session中
func (c *LoginController) GetVerifyImg() {
Image, verifyCode := utils.GenerateVerifyCodeImg()
if Image == nil || len(verifyCode) != common.VERIFY_CODE_LEN {

View File

@@ -0,0 +1,121 @@
package controllers
import (
"boss/datas"
"boss/models/user"
"boss/utils/mfa"
"github.com/beego/beego/v2/server/web"
)
type TotpQuery struct {
web.Controller
}
func (c *TotpQuery) GenTotp() {
userID, ok := c.GetSession("userID").(string)
if !ok {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "提交信息错误",
}
_ = c.ServeJSON()
return
}
userInfo := user.GetUserInfoByUserID(userID)
if userInfo.UserId == "" {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "当前用户不存在",
}
_ = c.ServeJSON()
return
}
otp, err := mfa.GetOtp(userInfo.UserId, userInfo.Nick)
if err != nil {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "当前用户不存在",
}
_ = c.ServeJSON()
return
}
c.Data["json"] = datas.KeyDataJSON2{
KeyDataJSON: datas.KeyDataJSON{
Code: 0,
Msg: "成功",
Key: "",
},
Data: otp,
}
_ = c.ServeJSON()
}
func (c *TotpQuery) SaveTotp() {
code := c.GetString("code")
secret := c.GetString("secret")
if code == "" || secret == "" {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "提交消息不准确",
}
_ = c.ServeJSON()
return
}
userID, ok := c.GetSession("userID").(string)
if !ok {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "提交信息错误",
}
_ = c.ServeJSON()
return
}
userInfo := user.GetUserInfoByUserID(userID)
if userInfo.UserId == "" {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "当前用户不存在",
}
_ = c.ServeJSON()
return
}
ok = mfa.ValidCode(code, secret)
if !ok {
c.Data["json"] = datas.KeyDataJSON{
Code: -1,
Msg: "code验证错误",
}
_ = c.ServeJSON()
return
}
err2 := user.UpdateOtpByUserID(userInfo.UserId, secret)
if err2 != nil {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "更新totp失败",
}
_ = c.ServeJSON()
return
}
c.Data["json"] = datas.KeyDataJSON{
Code: 0,
Msg: "success",
}
_ = c.ServeJSON()
}

View File

@@ -14,6 +14,7 @@ import (
"boss/models/user"
"boss/service"
"boss/utils"
"boss/utils/mfa"
"github.com/beego/beego/v2/core/validation"
"strings"
)
@@ -197,9 +198,7 @@ func (c *UpdateController) ResetAgentPassword() {
c.GenerateJSON(se.ResetAgentPassword(agentUid, newPassword, newVertifyPassword))
}
/*
* 手动选择了打款通道
*/
// ChoosePayForRoad 手动选择了打款通道
func (c *UpdateController) ChoosePayForRoad() {
roadName := strings.TrimSpace(c.GetString("roadName"))
bankOrderId := strings.TrimSpace(c.GetString("bankOrderId"))
@@ -211,9 +210,7 @@ func (c *UpdateController) ChoosePayForRoad() {
c.GenerateJSON(se.ChoosePayForRoad(confirmType, roadName, bankOrderId, remark))
}
/*
* 处理打款结果的处理
*/
// ResultPayFor 处理打款结果的处理
func (c *UpdateController) ResultPayFor() {
resultType := strings.TrimSpace(c.GetString("resultType"))
bankOrderId := strings.TrimSpace(c.GetString("bankOrderId"))
@@ -227,6 +224,37 @@ func (c *UpdateController) UpdateOrderStatus() {
bankOrderId := strings.TrimSpace(c.GetString("bankOrderId"))
solveType := strings.TrimSpace(c.GetString("solveType"))
operator := strings.TrimSpace(c.GetString("operator"))
code := strings.TrimSpace(c.GetString("totpCode"))
userID, ok := c.GetSession("userID").(string)
if !ok {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "提交信息错误",
}
_ = c.ServeJSON()
return
}
userInfo := user.GetUserInfoByUserID(userID)
if userInfo.UserId == "" {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "当前用户不存在",
}
_ = c.ServeJSON()
return
}
if !mfa.ValidCode(code, userInfo.OtpSecret) {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "二次验证失败",
}
_ = c.ServeJSON()
return
}
se := new(service.UpdateService)

View File

@@ -22,6 +22,11 @@ type KeyDataJSON struct {
Key string
}
type KeyDataJSON2 struct {
KeyDataJSON
Data interface{}
}
type MenuDataJSON struct {
StartIndex int
DisplayCount int

2
go.mod
View File

@@ -7,4 +7,6 @@ require (
github.com/go-sql-driver/mysql v1.6.0
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/rs/xid v1.2.1
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/xlzd/gotp v0.1.0 // indirect
)

4
go.sum
View File

@@ -316,6 +316,8 @@ github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@@ -340,6 +342,8 @@ github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnD
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po=
github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=

View File

@@ -1,3 +1,5 @@
package user
/***************************************************
** @Desc : This file for ...
** @Time : 2019/8/9 14:02
@@ -7,7 +9,6 @@
** @Last Modified time: 2019/8/9 14:02
** @Software: GoLand
****************************************************/
package user
import (
"github.com/beego/beego/v2/client/orm"
@@ -30,6 +31,7 @@ type UserInfo struct {
RoleName string
CreateTime string
UpdateTime string
OtpSecret string
}
func GetUserInfoByUserID(userID string) UserInfo {
@@ -42,6 +44,19 @@ func GetUserInfoByUserID(userID string) UserInfo {
return userInfo
}
func UpdateOtpByUserID(userID, totpSecret string) error {
o := orm.NewOrm()
_, err := o.QueryTable(USERINFO).Exclude("status", "delete").
Filter("user_id", userID).
Update(orm.Params{"otp_secret": totpSecret})
if err != nil {
logs.Error("更新totp失败", err)
}
return err
}
func GetOperatorByMap(params map[string]string, displayCount, offset int) []UserInfo {
o := orm.NewOrm()
var userInfo []UserInfo

View File

@@ -107,4 +107,7 @@ func init() {
web.Router("/result/payfor", &controllers.UpdateController{}, "*:ResultPayFor")
web.Router("/send/notify", &controllers.SendNotify{}, "*:SendNotifyToMerchant")
web.Router("/self/send/notify", &controllers.SendNotify{}, "*:SelfSendNotify")
web.Router("/user/genTotp", &controllers.TotpQuery{}, "*:GenTotp")
web.Router("/user/saveTotp", &controllers.TotpQuery{}, "*:SaveTotp")
}

View File

@@ -206,7 +206,6 @@ func (c *DeleteService) DeleteMerchant(merchantUid string) *datas.KeyDataJSON {
func (c *DeleteService) DeleteAccount(accountUid string) *datas.BaseDataJSON {
dataJSON := new(datas.BaseDataJSON)
merchant.IsExistByMerchantUid(accountUid)
if merchant.IsExistByMerchantUid(accountUid) || agent.IsExistByAgentUid(accountUid) {
dataJSON.Code = -1
dataJSON.Msg = "用户还存在,不能删除"

View File

@@ -2,6 +2,7 @@ package service
import (
"boss/common"
"boss/config"
"boss/datas"
"boss/models"
"boss/models/accounts"
@@ -376,7 +377,7 @@ func (c *UpdateService) ChoosePayForRoad(confirmType, roadName, bankOrderId, rem
func (c *UpdateService) UpdateOrderStatus(bankOrderId, solveType, operator string) *datas.KeyDataJSON {
keyDataJSON := new(datas.KeyDataJSON)
updateOrderUrl, _ := web.AppConfig.String("gateway::host")
updateOrderUrl := config.GetGatewayHost()
res, err := httplib.Get(updateOrderUrl + "gateway/update/order" + "?bankOrderId=" + bankOrderId + "&solveType=" + solveType + "&operator=" + operator).String()
if err != nil {

View File

@@ -1,3 +1,5 @@
package utils
/***************************************************
** @Desc : This file for ...
** @Time : 2018-8-30 13:50
@@ -7,7 +9,6 @@
** @Last Modified time: 2018-8-30 13:50
** @Software: GoLand
****************************************************/
package utils
import (
"bytes"
@@ -17,12 +18,10 @@ import (
"github.com/beego/beego/v2/core/logs"
)
/*
aes解码
crypted:要加密的字符串
key:用来加密的密钥 密钥长度可以是128bit、192bit、256bit中的任意一个
16位key对应128bit
*/
// AesDecrypt aes解码
// crypted:要加密的字符串
// key:用来加密的密钥 密钥长度可以是128bit、192bit、256bit中的任意一个
// 16位key对应128bit
func AesDecrypt(src, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {

View File

@@ -1,3 +1,5 @@
package utils
/***************************************************
** @Desc : This file for ...
** @Time : 2019/8/21 10:21
@@ -7,7 +9,6 @@
** @Last Modified time: 2019/8/21 10:21
** @Software: GoLand
****************************************************/
package utils
import "time"

View File

@@ -12,7 +12,7 @@ type Js struct {
data interface{}
}
// Initialize the json configruation
// Json Initialize the json configruation
func Json(data string) *Js {
j := new(Js)
var f interface{}
@@ -24,7 +24,7 @@ func Json(data string) *Js {
return j
}
// According to the key of the returned data information,return js.data
// Get According to the key of the returned data information,return js.data
func (j *Js) Get(key string) *Js {
m := j.Getdata()
if v, ok := m[key]; ok {
@@ -35,7 +35,7 @@ func (j *Js) Get(key string) *Js {
return j
}
// 判断是否有郊
// IsValid 判断是否有郊
func (j *Js) IsValid() bool {
if nil == j.data {
return false
@@ -44,7 +44,7 @@ func (j *Js) IsValid() bool {
}
}
// return json data
// Getdata return json data
func (j *Js) Getdata() map[string]interface{} {
if m, ok := (j.data).(map[string]interface{}); ok {
return m
@@ -94,7 +94,7 @@ func (j *Js) Getindex(i int) *Js {
return j
}
// When the data {"result":["username","password"]} can use arrayindex(1) get the username
// Arrayindex When the data {"result":["username","password"]} can use arrayindex(1) get the username
func (j *Js) Arrayindex(i int) string {
num := i - 1
if i > len((j.data).([]interface{})) {
@@ -121,7 +121,7 @@ func (j *Js) Arrayindex(i int) string {
}
// The data must be []interface{} ,According to your custom number to return your key and array data
// Getkey The data must be []interface{} ,According to your custom number to return your key and array data
func (j *Js) Getkey(key string, i int) *Js {
num := i - 1
if i > len((j.data).([]interface{})) {
@@ -140,7 +140,7 @@ func (j *Js) Getkey(key string, i int) *Js {
return j
}
// According to the custom of the PATH to find the PATH
// Getpath According to the custom of the PATH to find the PATH
func (j *Js) Getpath(args ...string) *Js {
d := j
for i := range args {

40
utils/mfa/mfa.go Normal file
View File

@@ -0,0 +1,40 @@
package mfa
import (
"bytes"
"encoding/base64"
"strconv"
"time"
"github.com/skip2/go-qrcode"
"github.com/xlzd/gotp"
)
const secretLength = 16
type Otp struct {
Secret string `json:"secret"`
QrImage string `json:"qrImage"`
}
func GetOtp(userId, username string) (otp Otp, err error) {
secret := gotp.RandomSecret(secretLength)
otp.Secret = secret
totp := gotp.NewDefaultTOTP(secret)
uri := totp.ProvisioningUri(userId, "kami "+username)
subImg, err := qrcode.Encode(uri, qrcode.Medium, 256)
dist := make([]byte, 3000)
base64.StdEncoding.Encode(dist, subImg)
index := bytes.IndexByte(dist, 0)
baseImage := dist[0:index]
otp.QrImage = "data:image/png;base64," + string(baseImage)
return
}
func ValidCode(code string, secret string) bool {
totp := gotp.NewDefaultTOTP(secret)
now := time.Now().Unix()
strInt64 := strconv.FormatInt(now, 10)
id16, _ := strconv.Atoi(strInt64)
return totp.Verify(code, int64(id16))
}

71
utils/ntp/ntp.go Normal file
View File

@@ -0,0 +1,71 @@
package ntp
import (
"encoding/binary"
"fmt"
"net"
"runtime"
"time"
"github.com/gogf/gf/os/gproc"
)
const ntpEpochOffset = 2208988800
type packet struct {
Settings uint8
Stratum uint8
Poll int8
Precision int8
RootDelay uint32
RootDispersion uint32
ReferenceID uint32
RefTimeSec uint32
RefTimeFrac uint32
OrigTimeSec uint32
OrigTimeFrac uint32
RxTimeSec uint32
RxTimeFrac uint32
TxTimeSec uint32
TxTimeFrac uint32
}
func Getremotetime() (time.Time, error) {
conn, err := net.Dial("udp", "pool.ntp.org:123")
if err != nil {
return time.Time{}, fmt.Errorf("failed to connect: %v", err)
}
defer conn.Close()
if err := conn.SetDeadline(time.Now().Add(15 * time.Second)); err != nil {
return time.Time{}, fmt.Errorf("failed to set deadline: %v", err)
}
req := &packet{Settings: 0x1B}
if err := binary.Write(conn, binary.BigEndian, req); err != nil {
return time.Time{}, fmt.Errorf("failed to set request: %v", err)
}
rsp := &packet{}
if err := binary.Read(conn, binary.BigEndian, rsp); err != nil {
return time.Time{}, fmt.Errorf("failed to read server response: %v", err)
}
secs := float64(rsp.TxTimeSec) - ntpEpochOffset
nanos := (int64(rsp.TxTimeFrac) * 1e9) >> 32
showtime := time.Unix(int64(secs), nanos)
return showtime, nil
}
func UpdateSystemDate(dateTime string) error {
system := runtime.GOOS
if system == "linux" {
if _, err := gproc.ShellExec(`date -s "` + dateTime + `"`); err != nil {
return fmt.Errorf("update system date failed, err: %v", err)
}
return nil
}
return fmt.Errorf("The current system architecture does not support synchronization")
}

View File

@@ -161,7 +161,6 @@
<input class="new-password" type="password" name=""> <span class="color-red">*</span>
</div>
<div class="col-xs-4 color-red new-error">
</div>
</div>
<div class="row margin-top-20">
@@ -184,6 +183,41 @@
</div>
</div>
</div>
<div class="modal fade" id="totpModal" tabindex="-1" role="dialog" aria-labelledby="myTotpLabel" data-keyboard="false">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="totpLabel">TOTP二次验证</h4>
</div>
<div class="modal-body">
<div class="row margin-top-20">
<div class="col-xs-5">
<label>请输入二次验证:
<input id="totp-value" type="text" name="">
</label>
</div>
</div>
<div class="row">
<div id="totp-img">
<img src="" alt="" srcset="">
<input value="" id="totp-secret" hidden>
</div>
</div>
<div class="col-xs-4 color-red totp-new-error">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default totp-cancal cancal-save" data-dismiss="modal">取消
</button>
<button type="button" class="btn btn-primary totp-save">保存</button>
</div>
</div>
</div>
</div>
<!-- 导航栏 -->
<div class="self-nav">
@@ -205,7 +239,10 @@
<a href="#" style="text-align: center;" data-toggle="modal" data-target="#logoutModal"> <i
class="glyphicon glyphicon-cog change-password"></i> 更改密码</a>
</li>
<li>
<a href="#" style="text-align: center;" data-toggle="modal" data-target="#totpModal"> <i
class="glyphicon glyphicon-cog totp"></i>二次验证</a>
</li>
<li role="separator" class="divider"></li>
<li>
<a href="#" style="text-align: center;" class="logout"> <i
@@ -468,7 +505,6 @@
});
});
$(".logout").click(function () {
$.ajax({
url: "/logout",
@@ -519,6 +555,52 @@
$(".breadcrumb").html("");
let secondTile = $(this).text();
});
$("#totpModal").on('show.bs.modal', function () {
$.ajax({
url: "/user/genTotp",
method: "post",
success: (res) => {
if (res.Code === 0) {
$("#totp-img img").attr("src", res.Data.qrImage);
$("#totp-secret").attr("value", res.Data.secret);
} else {
alert(res.Msg)
}
},
})
});
$(".totp-save").click(function (event) {
// 获取secret
const secret = $("#totp-secret").val();
const code = $("#totp-value").val();
if (secret === "" || code === "") {
setError(".totp-new-error", "信息填写不完整,需要重新填写");
return;
}
$.ajax({
url: "/user/saveTotp",
method: "post",
data: {
code: code,
secret: secret,
},
success: (res) => {
if (res.Code === 0) {
$("#totp-secret").val("");
$("#totp-value").val("");
$(".cancal-save").trigger('click');
alert("保存成功!")
} else {
setError(".totp-new-error", res.Msg);
}
},
error: (err) => {
setError(".totp-new-error", err);
}
})
})
</script>
</html>

View File

@@ -1,7 +1,10 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="lt-ie9" lang="en"> <![endif]-->
<!--[if lt IE 7]>
<html class="lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]>
<html class="lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 8]>
<html class="lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!-->
<html lang="en">
<!--<![endif]-->
@@ -13,7 +16,8 @@
<link rel="stylesheet" href="../static/css/login.css">
<script src="../static/js/jquery.min.js"></script>
<script src="../static/js/filter.js"></script>
<!--[if lt IE 9]><script src="../static/js/html5.js"></script><![endif]-->
<!--[if lt IE 9]>
<script src="../static/js/html5.js"></script><![endif]-->
</head>
<body>
@@ -21,9 +25,12 @@
<div class="login">
<h1>管理员登录</h1>
<p><input type="text" name="login" class="userID" value="" placeholder="注册手机号"></p>
<p>
<input type="text" name="login" class="userID" value="" placeholder="注册手机号">
</p>
<div class="userIDERROR" style="color: red;margin-left: 10px; font-size: small"></div>
<p><input type="password" name="password" class="passwd" value="" placeholder="密码"></p>
<p><input type="text" name="totp" class="totp" value="" placeholder="二次验证(如果设置了就需要填写)"></p>
<div class="passwdDERROR" style="color: red;margin-left: 10px; font-size: small"></div>
<div class="verify">
<div class="left_f">
@@ -64,6 +71,8 @@
let userID = $.trim($(".userID").val());
let passwd = $.trim($(".passwd").val());
let Code = $(".verifyText").val();
let totp = $(".totp").val();
Code = $.trim(Code);
if (userID.length <= 0) {
$(".userIDERROR").text("").append("* 登录手机号不能为空!");
@@ -87,7 +96,8 @@
data: {
userID: userID,
passwd: passwd,
Code: Code
Code: Code,
totpCode: totp,
},
success: function (data) {
if (data.Key === "userID") {

View File

@@ -113,7 +113,7 @@
<option value="JD_SYT">京东收银台</option>
</select>
</label>
<label for="">
<label>
冻结状态:
<select name="" id="search-order-free-status">
<option value="">请选择</option>
@@ -143,7 +143,6 @@
<th>商户名称</th>
<th>商户订单号</th>
<th>本系统订单号</th>
<th>实付金额</th>
<th>卡密信息</th>
<th>支付状态</th>
@@ -243,14 +242,22 @@
<div class="modal-header">
<h4 class="modal-title">订单处理</h4>
</div>
<div class="modal-body modal-body-order-solve">
<div>
<input type="radio" name="order-solve-radio" value="success" style="margin-left: 10%;"><span
style="color: blue;">处理成功</span>
<input type="radio" name="order-solve-radio" value="fail" style="margin-left: 15%;"><span
style="color: red;">处理失败</span>
<input type="text" hidden value="" id="order-solve-bank-order-id">
</div>
<div>
<label>
二次验证:
<input type="text" value="" id="order-info-totp">
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default save-order-solve">确定</button>
<button type="button" class="btn btn-default cancel-order-solve" data-dismiss="modal">取消</button>
@@ -258,6 +265,29 @@
</div>
</div>
</div>
<div class="modal fade" id="totp-order-solve" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
data-keyboard="false" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">二次验证</h4>
</div>
<div class="modal-body modal-body-order-solve">
<input type="text" hidden value="" id="totp-solve-bank-order-id">
<input type="text" hidden value="" id="totp-solveType">
<label>
二次验证:
<input type="text" value="" id="totp-orderInfo">
</label>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default save-totp-solve">确定</button>
<button type="button" class="btn btn-default cancel-order-solve" data-dismiss="modal">取消</button>
</div>
</div>
</div>
</div>
</div>
<script>
//将上游通道供应商写入
@@ -344,7 +374,7 @@
"<th>" + v.MerchantName + "</th>" + "<th>" + v.MerchantOrderId + "</th>" +
"<th>" + v.BankOrderId + "</th>" +
"<th>" + v.FactAmount + "</th>" +
"<th>" + v.CardData + "</th>" +
"<th>" + v.ExValue + "</th>" +
"<th>" + v.Status + "</th>";
if (v.Freeze == "yes") {
tmp = tmp + "<th style='color: red;'>" + "已经冻结" + "</th>"
@@ -368,14 +398,13 @@
if (v.Status == "success" || v.Status == "fail") {
tmp = tmp + '<button type="button" class="btn btn-primary" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="orderNotify(this.value);">' + "回调" + '</button>';
if (v.Freeze == "yes") {
tmp = tmp + '<button type="button" class="btn btn-default" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="unfreeze(this.value);">' + "解冻" + '</button>';
tmp = tmp + '<button type="button" class="btn btn-danger" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="refund(this.value);">' + "退款" + '</button>';
tmp = tmp + '<button type="button" class="btn btn-default" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="solveTotpResult(this.value, `unfreeze_amount`);">' + "解冻" + '</button>';
tmp = tmp + '<button type="button" class="btn btn-danger" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="solveTotpResult(this.value, `refund`);">' + "退款" + '</button>';
} else {
if (v.Refund != "yes") {
tmp = tmp + '<button type="button" class="btn btn-warning" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="freeze(this.value);">' + "冻结" + '</button>'
tmp = tmp + '<button type="button" class="btn btn-warning" style="padding: 0;margin-right: 5px;" value="' + v.BankOrderId + '" onclick="solveTotpResult(this.value, `freeze_amount`);">' + "冻结" + '</button>'
}
}
if (v.Refund == "yes") {
tmp = tmp + '<button type="button" class="btn btn-default" style="padding: 0;" value="' + v.BankOrderId + '" onclick="orderRoll(this.value);">' + "回滚" + '</button>';
}
@@ -388,78 +417,6 @@
$("#order-table-body").html(str);
}
function freeze(bankOrderId) {
$.ajax({
url: "/update/order/status",
data: {
"bankOrderId": bankOrderId,
"solveType": "freeze_amount"
},
success: function (res) {
if (res.Code === 404) {
window.parent.location = "/login.html";
return
} else if (res.Msg === "success") {
alert("处理成功");
} else {
alert("可能订单未完成支付,不能进行此项操作!")
}
AjaxOrderList(getOrderSearchValues());
},
error: function () {
alert("系统异常请稍后再试2");
}
});
}
function unfreeze(bankOrderId) {
$.ajax({
url: "/update/order/status",
data: {
"bankOrderId": bankOrderId,
"solveType": "unfreeze_amount"
},
success: function (res) {
if (res.Code == 404) {
window.parent.location = "/login.html";
return
} else if (res.Code == 200) {
alert("解冻成功")
} else {
alert("解冻失败")
}
AjaxOrderList(getOrderSearchValues());
},
error: function () {
alert("系统异常请稍后再试3")
}
});
}
function refund(bankOrderId) {
$.ajax({
url: "/update/order/status",
data: {
'bankOrderId': bankOrderId,
"solveType": "refund"
},
success: function (res) {
if (res.Code == 404) {
window.parent.location = "/login.html";
return
} else if (res.Code == 200) {
alert("退款成功");
} else {
alert("退款失败");
}
AjaxOrderList(getOrderSearchValues());
},
error: function () {
alert("系统异常请稍后再试4");
}
});
}
function orderRoll(bankOrderId) {
$.ajax({
url: "/update/order/status",
@@ -489,24 +446,29 @@
$("#order-solve").modal();
}
function solveTotpResult(bankOrderId, solveType) {
$("#totp-solve-bank-order-id").val(bankOrderId);
$("#totp-solveType").val(solveType);
$("#totp-order-solve").modal();
}
$(".save-order-solve").click(function () {
let bankOrderId = $("#order-solve-bank-order-id").val();
let solveType = $("input[name='order-solve-radio']:checked").val();
if (solveType != "success" && solveType != "fail") {
alert("没有选择那种处理方式");
return;
} else {
let totpCode = $("#order-info-totp").val();
$.ajax({
url: "/update/order/status",
data: {
"bankOrderId": bankOrderId,
"solveType": solveType
bankOrderId: bankOrderId,
solveType: solveType,
totpCode: totpCode,
},
success: function (res) {
if (res.Code == 404) {
if (res.Code === 404) {
window.parent.location = "/login.html";
return;
} else if (res.Code == 200) {
} else if (res.Code === 200) {
alert("受理成功")
} else {
alert("受理失败");
@@ -518,7 +480,40 @@
alert("系统异常请稍后再试6");
}
});
$("#order-info-totp").setAttr("value", "");
});
$(".save-totp-solve").click(function () {
let bankOrderId = $("#totp-solve-bank-order-id").val();
let solveType = $("#totp-solveType").val();
let totpCode = $("#totp-orderInfo").val();
$.ajax({
url: "/update/order/status",
data: {
bankOrderId: bankOrderId,
solveType: solveType,
totpCode: totpCode
},
success: function (res) {
if (res.Code === 404) {
window.parent.location = "/login.html";
return;
} else if (res.Code === 200) {
alert("受理成功")
} else {
alert("受理失败失败原因:" + res.Msg);
}
$(".cancel-order-solve").trigger('click');
AjaxOrderList(getOrderSearchValues());
},
error: function () {
alert("系统异常请稍后再试6");
}
})
$("#totp-solve-bank-order-id").setAttr("value", "");
$("#totp-solveType").setAttr("value", "");
$("#totp-orderInfo").setAttr("value", "")
});
function orderNotify(bankOrderId) {
@@ -616,9 +611,9 @@
url: "/get/order",
data: dataJSON,
success: function (res) {
if (res.Code == 404) {
if (res.Code === 404) {
window.parent.location = "/login.html";
} else if (res.Code == -1) {
} else if (res.Code === -1) {
} else {
showOrderList(res);
@@ -677,6 +672,7 @@
let dataJSON = getOrderSearchValues();
AjaxOrderList(dataJSON);
});
</script>
</body>
</html>