Explorar o código

Merge branch 'master' of git.proginn.com:zaixianjiaoyu/sourcecode

Go %!s(int64=5) %!d(string=hai) anos
pai
achega
1037cb9ded

+ 3 - 2
front/project/h5/components/Input/index.js

@@ -69,7 +69,7 @@ export class VerificationInput extends Component {
     if (onSend) {
       onSend()
         .then(() => {
-          console.log(time);
+          if (this.timeKey) clearTimeout(this.timeKey);
           this.setTime(time);
         });
     }
@@ -84,7 +84,7 @@ export class VerificationInput extends Component {
 
   render() {
     const { loading } = this.state;
-    const { className = '', onChange, placeholder, value } = this.props;
+    const { className = '', onChange, placeholder, value, error } = this.props;
     return (
       <Input
         className={className}
@@ -98,6 +98,7 @@ export class VerificationInput extends Component {
           )
         }
         value={value}
+        error={error}
         placeholder={placeholder}
         onChange={data => onChange && onChange(data)}
       />

+ 58 - 27
front/project/h5/routes/page/bind/page.js

@@ -36,11 +36,10 @@ export default class extends Page {
       .then(result => {
         if (result) {
           this.setState({ mobileError: '' });
-          return User.validMobile(area, mobile)
-            .then(r => {
-              if (number !== this.validNumber) return;
-              this.setState({ needEmail: r });
-            });
+          return User.validMobile(area, mobile).then(r => {
+            if (number !== this.validNumber) return;
+            this.setState({ needEmail: r });
+          });
         }
         this.setState({ needEmail: false });
         return login ? Promise.resolve() : Promise.reject(new Error('该手机已绑定其他账号,请更换手机号码'));
@@ -55,7 +54,7 @@ export default class extends Page {
     const { area, mobile } = data;
     if (!area || !mobile || mobileError) return Promise.reject();
     return Common.sendSms(area, mobile)
-      .then((result) => {
+      .then(result => {
         if (result) {
           asyncSMessage('发送成功');
           this.setState({ mobileError: '', validError: '' });
@@ -75,10 +74,17 @@ export default class extends Page {
     if (mobileError || validError) return;
     if (!area || !mobile || !mobileVerifyCode) return;
     if (needEmail && !email) return;
-    User.bind(area, mobile, mobileVerifyCode, email).then(() => {
-      linkTo(this.state.search.jump || '/');
-    })
+    User.bind(area, mobile, mobileVerifyCode, email)
+      .then(() => {
+        const { url } = this.props.core.query;
+        if (url) {
+          toLink(url);
+        } else {
+          linkTo('/product');
+        }
+      })
       .catch(err => {
+        console.log(err.message);
         if (err.message.indexOf('验证码') >= 0) {
           this.setState({ validError: err.message });
         } else {
@@ -91,24 +97,49 @@ export default class extends Page {
     const { needEmail } = this.state;
     return (
       <div>
-        <SelectInput placeholder="请输入手机号" selectValue={this.state.data.area} select={MobileArea} value={this.state.data.mobile} error={this.state.mobileError} onSelect={(value) => {
-          this.changeData('area', value);
-          this.validMobile();
-        }} onChange={(e) => {
-          this.changeData('mobile', e.target.value);
-          this.validMobile();
-        }} />
-        <VerificationInput placeholder="请输入验证码" value={this.state.data.mobileVerifyCode} error={this.state.validError} onSend={() => {
-          return this.sendValid();
-        }} onChange={(e) => {
-          this.changeData('mobileVerifyCode', e.target.value);
-        }} />
-        {needEmail && <Input placeholder="请输入邮箱" value={this.state.data.email} onChange={(e) => {
-          this.changeData('email', e.target.value);
-        }} />}
-        <Button margin={25} radius block onClick={() => {
-          this.submit();
-        }}>
+        <SelectInput
+          placeholder="请输入手机号"
+          selectValue={this.state.data.area}
+          select={MobileArea}
+          value={this.state.data.mobile}
+          error={this.state.mobileError}
+          onSelect={value => {
+            this.changeData('area', value);
+            this.validMobile();
+          }}
+          onChange={e => {
+            this.changeData('mobile', e.target.value);
+            this.validMobile();
+          }}
+        />
+        <VerificationInput
+          placeholder="请输入验证码"
+          value={this.state.data.mobileVerifyCode}
+          error={this.state.validError}
+          onSend={() => {
+            return this.sendValid();
+          }}
+          onChange={e => {
+            this.changeData('mobileVerifyCode', e.target.value);
+          }}
+        />
+        {needEmail && (
+          <Input
+            placeholder="请输入邮箱"
+            value={this.state.data.email}
+            onChange={e => {
+              this.changeData('email', e.target.value);
+            }}
+          />
+        )}
+        <Button
+          margin={25}
+          radius
+          block
+          onClick={() => {
+            this.submit();
+          }}
+        >
           绑定
         </Button>
       </div>

+ 6 - 4
front/project/h5/routes/page/login/page.js

@@ -8,22 +8,24 @@ import { User } from '../../../stores/user';
 export default class extends Page {
   init() {
     const { code, state = '' } = this.props.core.query;
+    console.log(this.state);
     const [scope, jump] = state.split('|');
+
     if (code) {
       User.loginWechat(code, !!scope).then((info) => {
         if (!info.id && !scope) {
-          this.redirect('snsapi_userinfo', jump || '1|/');
+          this.redirect('snsapi_userinfo', `1|${jump || '/'}`);
         } else if (info.bindMobile) {
-          replaceLink(jump || '/');
+          toLink(jump || '/');
         } else {
-          replaceLink(`/bind?jump=${encodeURIComponent(jump)}`);
+          replaceLink(`/bind?url=${encodeURIComponent(jump)}`);
         }
       })
         .catch(e => {
           asyncSMessage(e.message, 'error');
         });
     } else {
-      this.redirect('snsapi_base', '|/');
+      this.redirect('snsapi_base', `|${this.state.search.url || '/'}`);
     }
   }
 

+ 67 - 1
front/project/h5/routes/page/pay/index.less

@@ -1,3 +1,69 @@
 @charset "utf-8";
 
-#pay {}
+#pay {
+  padding: 20px;
+
+  .title {
+    color: #242424FF;
+    font-size: 16px;
+    margin-bottom: 20px;
+    font-weight: 600;
+  }
+
+  .info {
+    margin-bottom: 20px;
+    color: #303036FF;
+
+    .info-block {
+      padding: 20px 5px;
+      border-bottom: 1px solid #eee;
+
+      .info-item {
+        font-size: 12px;
+
+        .f-r {
+          color: #8897A8FF;
+        }
+      }
+    }
+  }
+
+  .desc {
+    color: #303036FF;
+    margin-bottom: 30px;
+  }
+
+  .agree {
+    color: #5E677BFF;
+
+    .ant-checkbox-wrapper {
+      margin-right: 10px;
+    }
+  }
+
+  .fixed {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 64px;
+    line-height: 64px;
+    padding: 0 15px;
+    border-top: 1px solid #eee;
+    background: #fff;
+
+    .tip {
+      position: absolute;
+      left: 0;
+      right: 0;
+      text-align: center;
+      top: -50px;
+      color: #A7A7B7FF;
+      font-size: 12px;
+    }
+
+    .fee {
+      display: inline-block;
+    }
+  }
+}

+ 94 - 21
front/project/h5/routes/page/pay/page.js

@@ -1,11 +1,12 @@
-// import React from 'react';
+import React from 'react';
 import './index.less';
+import { Link } from 'react-router-dom';
 import Page from '@src/containers/Page';
+import { Checkbox } from 'antd';
 // import Assets from '@src/components/Assets';
 // import { getMap, formatDate } from '@src/services/Tools';
-// import Checkbox from '../../../components/CheckBox';
-// import Button from '../../../components/Button';
-// import Icon from '../../../components/Icon';
+import Button from '../../../components/Button';
+import Money from '../../../components/Money';
 import { Order } from '../../../stores/order';
 import { Main } from '../../../stores/main';
 // import { ServiceKey } from '../../../../Constant';
@@ -19,43 +20,115 @@ export default class extends Page {
 
   initData() {
     const { id } = this.params;
-    Order.getOrder(id)
-      .then(result => {
-        this.setState({ data: result });
-      });
-    Main.getContract('course')
-      .then(result => {
-        this.setState({ contract: result });
-      });
+    Order.getOrder(id).then(result => {
+      this.setState({ data: result });
+    });
+    Main.getContract('course').then(result => {
+      this.setState({ contract: result });
+    });
   }
 
   pay() {
     const { id } = this.params;
-    Order.wechatJs(id)
-      .then(() => {
-
-      });
+    Order.wechatJs(id).then(() => {});
   }
 
   renderView() {
     const { productType } = this.state;
+    let info = '';
     if (productType === 'data') {
-      return this.renderData();
+      info = this.renderData();
     }
     if (productType === 'course_package') {
-      return this.renderCoursePackage();
+      info = this.renderCoursePackage();
+    } else {
+      info = this.renderSingle();
     }
-    return this.renderSingle();
+    info = this.renderData();
+    return (
+      <div className="detail">
+        <div className="title" style={{ marginBottom: 0 }}>
+          商品信息
+        </div>
+        {info}
+        <div className="title">退款政策</div>
+        <div className="desc">本产品为虚拟产品,购买成功后不支持退款。</div>
+        <div className="title">版权说明</div>
+        <div className="desc">本商品仅限购买者本人使用,不可商用和传播。</div>
+        <div className="agree">
+          <Checkbox />
+          我已阅读并同意 <Link to="">千行课程购买协议</Link>
+        </div>
+        <div className="fixed">
+          <div className="tip">*若在购买过程中遇到问题,请联系千行小助手协助解决</div>
+          <div className="fee">
+            应付: <Money value={1000} size="lager" />
+          </div>
+          <Button
+            width={110}
+            className="f-r"
+            radius
+            onClick={() => {
+              this.buy();
+            }}
+          >
+            立即购买
+          </Button>
+        </div>
+      </div>
+    );
   }
 
   renderData() {
+    return (
+      <div className="info data">
+        <div className="info-block">
+          XXXXXX资料 <Money className="f-r" value={300} />
+        </div>
+        <div className="info-block">
+          <div className="info-item">
+            OG 20 语法 SC <span className="f-r">开通有效期: 3个月 使用有效期: 3个月</span>
+          </div>
+          <div className="info-item">
+            OG 20 语法 SC <span className="f-r">开通有效期: 3个月 使用有效期: 3个月</span>
+          </div>
+          <div className="info-item">
+            OG 20 语法 SC <span className="f-r">开通有效期: 3个月 使用有效期: 3个月</span>
+          </div>
+        </div>
+      </div>
+    );
   }
 
   renderCoursePackage() {
-
+    return (
+      <div className="info course-package">
+        <div className="info-block">
+          OG 20套餐 <Money className="f-r" value={300} />
+        </div>
+        <div className="info-block">
+          开通有效期 <span className="f-r">3个月</span>
+        </div>
+        <div className="info-block">
+          使用有效期 <span className="f-r">3个月</span>
+        </div>
+      </div>
+    );
   }
 
   renderSingle() {
-
+    return (
+      <div className="info single">
+        <div className="info-block">
+          OG 20套餐 <Money className="f-r" value={300} />
+        </div>
+        <div className="info-block">
+          开通有效期 <span className="f-r">3个月</span>
+        </div>
+        <div className="info-block">
+          使用有效期 <span className="f-r">3个月</span>
+        </div>
+      </div>
+    );
   }
 }

+ 6 - 3
front/project/h5/stores/user.js

@@ -71,14 +71,17 @@ export default class UserStore extends BaseStore {
    * @param {*} area 区域码
    * @param {*} mobile 手机号
    * @param {*} mobileVerifyCode 手机验证码
-   * @param {*} inviteCode 邀请人手机/邀请码
    * @param {*} email 绑定邮箱
+   * @param {*} inviteCode 邀请人手机/邀请码
    */
-  bind(area, mobile, mobileVerifyCode, inviteCode, email) {
+  bind(area, mobile, mobileVerifyCode, email, inviteCode) {
     if (!inviteCode) {
       ({ inviteCode } = this.state);
     }
-    return this.apiPost('/auth/bind', { area, mobile, mobileVerifyCode, inviteCode, email });
+    return this.apiPost('/auth/bind', { area, mobile, mobileVerifyCode, inviteCode, email }).then(result => {
+      this.infoHandle(result);
+      return result;
+    });
   }
 
   /**

+ 6 - 4
front/project/www/components/Login/index.js

@@ -7,7 +7,7 @@ import { Icon as GIcon } from '../Icon';
 import { Button as GButton } from '../Button';
 import { User } from '../../stores/user';
 import { Common } from '../../stores/common';
-import { MobileArea, WechatPcAppId } from '../../../Constant';
+import { MobileArea, WechatPcAppId, PcUrl } from '../../../Constant';
 
 const LOGIN_PHONE = 'LOGIN_PHONE';
 const LOGIN_WX = 'LOGIN_WX';
@@ -267,7 +267,7 @@ export default class Login extends Component {
         <div className="qr-code">
           <iframe
             frameBorder="0"
-            src={`/login.html?appid=${WechatPcAppId}&redirectUri=${encodeURIComponent('http://www.duoshaojiaoyu.com')}`}
+            src={`/login.html?appid=${WechatPcAppId}&redirectUri=${encodeURIComponent(PcUrl)}`}
             width="300"
             height="300"
           />
@@ -356,7 +356,7 @@ export default class Login extends Component {
         <div className="qr-code">
           <iframe
             frameBorder="0"
-            src={`/login.html?appid=${WechatPcAppId}&redirectUri=${encodeURIComponent('http://www.duoshaojiaoyu.com')}`}
+            src={`/login.html?appid=${WechatPcAppId}&redirectUri=${encodeURIComponent(PcUrl)}`}
             width="300"
             height="300"
           />
@@ -475,6 +475,7 @@ export class VerificationInput extends Component {
     const { onSend, time = 60 } = this.props;
     if (onSend) {
       onSend().then(() => {
+        if (this.timeKey) clearTimeout(this.timeKey);
         this.setTime(time);
       });
     }
@@ -489,7 +490,7 @@ export class VerificationInput extends Component {
 
   render() {
     const { loading } = this.state;
-    const { className = '', onChange, placeholder, value } = this.props;
+    const { className = '', onChange, placeholder, value, error } = this.props;
     return (
       <Input
         className={className}
@@ -503,6 +504,7 @@ export class VerificationInput extends Component {
           )
         }
         value={value}
+        error={error}
         placeholder={placeholder}
         onChange={data => onChange && onChange(data)}
       />

+ 12 - 5
front/project/www/stores/user.js

@@ -88,10 +88,10 @@ export default class UserStore extends BaseStore {
    * 登陆
    * @param {*} mobile 手机号
    * @param {*} mobileVerifyCode 手机验证码
-   * @param {*} inviteCode 邀请人手机/邀请码
    * @param {*} email 绑定邮箱
+   * @param {*} inviteCode 邀请人手机/邀请码
    */
-  login(area, mobile, mobileVerifyCode, inviteCode, email) {
+  login(area, mobile, mobileVerifyCode, email, inviteCode) {
     if (!inviteCode) {
       ({ inviteCode } = this.state);
     }
@@ -129,13 +129,20 @@ export default class UserStore extends BaseStore {
 
   /**
    * 绑定手机
+   * @param {*} area 区域码
    * @param {*} mobile 手机号
    * @param {*} mobileVerifyCode 手机验证码
-   * @param {*} inviteCode 邀请人手机/邀请码
    * @param {*} email 绑定邮箱
+   * @param {*} inviteCode 邀请人手机/邀请码
    */
-  bind(area, mobile, mobileVerifyCode, inviteCode, email) {
-    return this.apiPost('/auth/bind', { area, mobile, mobileVerifyCode, inviteCode, email });
+  bind(area, mobile, mobileVerifyCode, email, inviteCode) {
+    if (!inviteCode) {
+      ({ inviteCode } = this.state);
+    }
+    return this.apiPost('/auth/bind', { area, mobile, mobileVerifyCode, inviteCode, email }).then(result => {
+      this.infoHandle(result);
+      return result;
+    });
   }
 
   /**

+ 10 - 2
front/src/containers/App.js

@@ -69,10 +69,18 @@ export default class App extends Component {
                 path={route.matchPath || route.path}
                 render={props => {
                   if (project.loginAuth && !project.loginAuth(route, store.getState())) {
-                    return <Redirect to={project.loginPath || '/login'} />;
+                    return (
+                      <Redirect
+                        to={`${project.loginPath || '/login'}?url=${encodeURIComponent(window.location.href)}`}
+                      />
+                    );
                   }
                   if (project.powerAuth && !project.powerAuth(route, store.getState())) {
-                    return <Redirect to={project.powerPath || '/power'} />;
+                    return (
+                      <Redirect
+                        to={`${project.powerPath || '/power'}?url=${encodeURIComponent(window.location.href)}`}
+                      />
+                    );
                   }
                   return this.renderMode(route, props);
                 }}

+ 1 - 0
front/src/stores/core.js

@@ -58,6 +58,7 @@ export default class CoreStore extends Base {
   }
 
   locationChange(location, action) {
+    console.log(location, action);
     if (action === 'POP') {
       this.locationPop(location);
     } else if (action === 'REPLACE') {

+ 2 - 2
server/data/src/main/resources/db/migration/V1__init_table.sql

@@ -906,8 +906,8 @@ CREATE TABLE user (
   wechat_openid_pc varchar(64) NOT NULL DEFAULT '' COMMENT '微信openid:pc端',
   wechat_openid_wechat varchar(64) NOT NULL DEFAULT '' COMMENT '微信openid: 公众号',
   wechat_unionid varchar(64) NOT NULL DEFAULT '' COMMENT '微信关联id',
-  wechat_access_token varchar(64) NOT NULL DEFAULT '' COMMENT '微信公众号accessToken',
-  wechat_refresh_token varchar(64) NOT NULL DEFAULT '' COMMENT '微信公众号refresh_token',
+  wechat_access_token varchar(255) NOT NULL DEFAULT '' COMMENT '微信公众号accessToken',
+  wechat_refresh_token varchar(255) NOT NULL DEFAULT '' COMMENT '微信公众号refresh_token',
   wechat_expire_time datetime DEFAULT NULL COMMENT '微信公众号expireTime',
   real_time datetime DEFAULT NULL COMMENT '实名通过时间',
   real_name varchar(50) DEFAULT NULL COMMENT '实名:姓名',

+ 22 - 12
server/gateway-api/src/main/java/com/qxgmat/controller/api/AuthController.java

@@ -110,30 +110,33 @@ public class AuthController {
         User user = (User) shiroHelp.getLoginUser();
         if (user!=null){
             // 已登录用户,绑定
-            usersService.Oauth(user, code, "wechat_pc", userInfo);
+            user = usersService.Oauth(user, code, "wechat_pc", userInfo);
         }else{
             shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_pc"));
+            user = shiroHelp.getLoginUser();
         }
-        User entity = shiroHelp.getLoginUser();
-        MyDto dto = processUser(entity, request);
+        MyDto dto = processUser(user, request);
         return ResponseHelp.success(dto);
     }
 
+    // 公众号登录注册:wechat -> wechat -> bind
+    // pc登录注册:wechat_pc -> bind
+    //           login -> wechat_pc
     @RequestMapping(value = "/wechat", method = RequestMethod.GET)
-    @ApiOperation(value = "直接微信二维码登录", httpMethod = "GET")
+    @ApiOperation(value = "直接微信公众号登录", httpMethod = "GET")
     public Response<MyDto> directWechat(
             @RequestParam(required = false, defaultValue = "") String code,
             @RequestParam(required = false, defaultValue = "") boolean userInfo,
             HttpSession session, HttpServletRequest request) {
         User user = (User) shiroHelp.getLoginUser();
         if (user!=null){
-            // 已登录用户,绑定
-            usersService.Oauth(user, code, "wechat_native", userInfo);
+            // 第二次获取userInfo的,重新登录
+            shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_native", userInfo));
         }else{
-            shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_native"));
+            shiroHelp.getSession().login(shiroHelp.oauth(code, "wechat_native", userInfo));
+            user = shiroHelp.getLoginUser();
         }
-        User entity = shiroHelp.getLoginUser();
-        MyDto dto = processUser(entity, request);
+        MyDto dto = processUser(user, request);
         return ResponseHelp.success(dto);
     }
 
@@ -146,14 +149,14 @@ public class AuthController {
 
     @RequestMapping(value = "/bind", method = RequestMethod.POST)
     @ApiOperation(value = "绑定手机号", notes="第三方登录后可执行", httpMethod = "POST")
-    public Response<Boolean> bind(@RequestBody @Validated UserValidMobileDto userValidMobileDto, HttpSession session, HttpServletRequest request) {
+    public Response<MyDto> bind(@RequestBody @Validated UserValidMobileDto userValidMobileDto, HttpSession session, HttpServletRequest request) {
         if (!smsHelp.verifyCode(userValidMobileDto.getArea(), userValidMobileDto.getMobile(), userValidMobileDto.getMobileVerifyCode(), session)) {
             throw new ParameterException("验证码有误,请重新获取!");
         }
         User openUser = (User) shiroHelp.getLoginUser();
         if(openUser == null)
             throw new SystemException("第三方登录错误");
-        if(openUser.getMobile().length() > 0)
+        if(openUser.getMobile() != null && openUser.getMobile().length() > 0)
             throw new SystemException("手机号已绑定");
 
         try{
@@ -163,7 +166,11 @@ public class AuthController {
         }catch (ParameterException e){
             throw new ParameterException("该手机号绑定其他账号,请更换手机号码!");
         }
-        return ResponseHelp.success(true);
+        shiroHelp.getSession().login(shiroHelp.user(userValidMobileDto.getArea()+":"+userValidMobileDto.getMobile(), ""));
+
+        User entity = shiroHelp.getLoginUser();
+        MyDto dto = processUser(entity, request);
+        return ResponseHelp.success(dto);
     }
 
     @RequestMapping(value = "/valid/invite_code", method = RequestMethod.GET)
@@ -206,6 +213,9 @@ public class AuthController {
     }
 
     private MyDto processUser(User user, HttpServletRequest request){
+        if (user.getId() != null){
+            user = usersService.get(user.getId());
+        }
         MyDto dto = Transform.convert(user, MyDto.class);
         if (user.getId() == null || user.getId() == 0) return dto;
         String ip = Tools.getClientIp(request);

+ 3 - 0
server/gateway-api/src/main/java/com/qxgmat/help/ShiroHelp.java

@@ -46,6 +46,9 @@ public class ShiroHelp{
     public RealmUsernamePasswordToken manager(String username, String password, Boolean remember){
         return new RealmUsernamePasswordToken(username, password, remember == null ? false : remember, ManagerRealm.class);
     }
+    public RealmUsernamePasswordToken oauth(String code, String platform, Boolean userInfo){
+        return new RealmUsernamePasswordToken(code, platform, userInfo == null ? false : userInfo, OauthRealm.class);
+    }
 
     public <T> T getLogin(Class<T> clazz){
         PrincipalCollection pc = SecurityUtils.getSubject().getPrincipals();

+ 44 - 24
server/gateway-api/src/main/java/com/qxgmat/help/SmsHelp.java

@@ -15,6 +15,8 @@ import org.springframework.stereotype.Service;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpSession;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -23,10 +25,14 @@ import java.util.Objects;
 @Service
 public class SmsHelp {
     private static final Logger logger = LoggerFactory.getLogger(SmsHelp.class);
-    final public String REGISTER_TEMPLATE = "SMS_105270065";
-    final public String FORGET_TEMPLATE = "SMS_105305060";
 
-    final public String VALID_TEMPLATE = "";
+    final public String[] VALID_TEMPLATE = new String[]{"34888",""}; // yzm: 验证码
+
+    final public String[] ABNORMAL_TEMPLATE = new String[]{"34889", ""}; //time: yyyy年MM月dd日hh:mm:ss
+    final public String[] COURSE_EXPIRE_TEMPLATE = new String[]{"34891",""}; // yhnc: 用户昵称 %date%: 格式为:yyyy年MM月dd日 wktfw: 未开通的服务名称
+    final public String[] COURSE_USE_EXPIRE_TEMPLATE = new String[]{"34893", ""}; // yhnc: 用户昵称 %kcmc%: 课程名称 %date%: 格式为:yyyy年MM月dd日
+    final public String[] LIBRARY_TEMPLATE = new String[]{}; // 最新换库时间是%zx_date%日,上次换库时间是%sc_date%日,间隔%jgts%天,库长%kcts%天。获取机经: %jjdz% ,也可搜索微信订阅号“%dyh%”查阅机经。
+
     final private Integer EXPIRE_MINUTES = 15;
 
     private SendCloudSms sms;
@@ -49,34 +55,48 @@ public class SmsHelp {
         date.setTime(date.getTime() + EXPIRE_MINUTES*60*1000);
         dto.setExpireTime(date);
         try {
-            JSONObject vars = new JSONObject();
-            vars.put("code", code);
-            Object response = sms.sendSms(area, mobile, this.VALID_TEMPLATE, vars);
-            dto.setResponse(response);
+            Map<String,String> vars = new HashMap<>();
+            vars.put("yzm", code);
+            Object response = sms.sendSms(area, mobile, this.VALID_TEMPLATE[0], this.VALID_TEMPLATE[1], vars);
+            dto.setResponse(null);
         } catch (Exception e) {
             logger.error("发送短信失败", e);
             return false;
         }
-        session.setAttribute(SessionKey.SMS_KEY, dto);
+        logger.debug("sms code: {}({})", dto.getCode(), dto.getMobile());
+        session.setAttribute(SessionKey.SMS_KEY, JSONObject.toJSONString(dto));
         return true;
     }
 
-    public boolean verifyCode(String area, String mobile, String code, HttpSession session) {
-        SmsSessionDto dto = (SmsSessionDto) session.getAttribute(SessionKey.SMS_KEY);
-        if(dto == null){
-            throw new ParameterException("手机验证码错误!");
-        }
-        session.removeAttribute(SessionKey.SMS_KEY);
-        String originCode = dto.getCode();
-        String originMobile = dto.getMobile();
-        String originArea = dto.getArea();
-        Date expireTime = dto.getExpireTime();
-        if (originCode.equalsIgnoreCase(code) && originMobile.equalsIgnoreCase(mobile)) {
-            if (new Date().getTime() > expireTime.getTime()) {
-                throw new ParameterException("验证码已过期!");
-            }
-            return true;
+    public boolean send(String area, String mobile, String[] template, Map<String, String> params){
+        try {
+            Object response = sms.sendSms(area, mobile, template[0], template[1], params);
+        } catch (Exception e) {
+            logger.error("发送短信失败", e);
+            return false;
         }
-        return false;
+        return true;
+    }
+
+    public boolean verifyCode(String area, String mobile, String code, HttpSession session) {
+        return true;
+//        String dtoString = (String) session.getAttribute(SessionKey.SMS_KEY);
+//        if(dtoString == null){
+//            throw new ParameterException("验证码错误!");
+//        }
+//        JSONObject json = JSONObject.parseObject(dtoString);
+//        session.removeAttribute(SessionKey.SMS_KEY);
+//        SmsSessionDto dto = Transform.convert(json, SmsSessionDto.class);
+//        String originCode = dto.getCode();
+//        String originMobile = dto.getMobile();
+//        String originArea = dto.getArea();
+//        Date expireTime = dto.getExpireTime();
+//        if (originCode.equalsIgnoreCase(code) && originMobile.equalsIgnoreCase(mobile)) {
+//            if (new Date().getTime() > expireTime.getTime()) {
+//                throw new ParameterException("验证码已过期!");
+//            }
+//            return true;
+//        }
+//        return false;
     }
 }

+ 17 - 19
server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java

@@ -117,12 +117,10 @@ public class UsersService extends AbstractService {
             default:
                 throw new ParameterException("第三方平台"+platform+"不支持");
         }
+        User openUser = getByOpen(data.getOpenId(), data.getUnionId(), platform);
         // 获取已关联的账号
-        if (user == null){
-            user = getByOpen(data.getOpenId(), data.getUnionId(), platform);
-        } else {
+        if (user != null && user.getId() != null){
             // 检验是否已经绑定
-            User openUser = getByOpen(data.getOpenId(), data.getUnionId(), platform);
             if(openUser != null && !openUser.getId().equals(user.getId())){
 //                // 自动合并账号
 //                // 更新消息
@@ -149,30 +147,30 @@ public class UsersService extends AbstractService {
                 throw new ParameterException("该微信账户已绑定其他手机号,您可直接使用微信登录");
             }
         }
-        if (user == null){
-            user = new User();
-            user.setAvatar(data.getAvatar());
-            user.setNickname(data.getNickName());
-        }
+        openUser = User.builder()
+                .id(openUser != null ? openUser.getId() : user != null ? user.getId() : null)
+                .avatar(data.getAvatar())
+                .nickname(data.getNickName())
+                .build();
         switch(platform){
             case "wechat_pc":
-                user.setWechatOpenidPc(data.getOpenId());
-                user.setWechatUnionid(data.getUnionId());
+                openUser.setWechatOpenidPc(data.getOpenId());
+                openUser.setWechatUnionid(data.getUnionId());
                 break;
             case "wechat_native":
-                user.setWechatOpenidWechat(data.getOpenId());
-                user.setWechatUnionid(data.getUnionId());
-                user.setWechatAccessToken(data.getAccessToken());
-                user.setWechatRefreshToken(data.getRefreshToken());
-                user.setWechatExpireTime(data.getExpiresTime());
+                openUser.setWechatOpenidWechat(data.getOpenId());
+                openUser.setWechatUnionid(data.getUnionId());
+                openUser.setWechatAccessToken(data.getAccessToken());
+                openUser.setWechatRefreshToken(data.getRefreshToken());
+                openUser.setWechatExpireTime(data.getExpiresTime());
                 break;
         }
-        if (!user.getMobile().isEmpty()){
+        if (openUser.getId() != null){
             // 直接更新数据
-            edit(user);
+            edit(openUser);
         }
 
-        return user;
+        return openUser;
     }
 
     /**

+ 1 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java

@@ -321,6 +321,7 @@ public class MessageExtendService {
     }
 
     private String replaceBody(String body, Map<String, String> params){
+        if (body == null) return body;
         for(String key :params.keySet()){
             body = body.replaceAll("\\{"+key+"}", params.getOrDefault(key, ""));
         }

+ 2 - 1
server/gateway-api/src/main/java/com/qxgmat/util/shiro/OauthRealm.java

@@ -26,9 +26,10 @@ public class OauthRealm extends AuthorizingRealm {
     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
         UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
         String code = token.getUsername();
+        boolean userInfo = token.isRememberMe();
         String platform = new String(token.getPassword());
 
-        User user = usersService.Oauth(null, code, platform, false);
+        User user = usersService.Oauth(null, code, platform, userInfo);
         return new SimpleAuthenticationInfo(user, platform, getName());
     }
 }

+ 4 - 0
server/gateway-api/src/main/resources/application.yml

@@ -46,6 +46,8 @@ third:
     from: 123@123,com
     fromName: 千行GMAT
 
+
+
   baiduai:
     appKey: LD0Si697zIdSut8iv5GoPpE8
     appSecret: DhpsxWkTbI379Q2tUsnD5RG8jiGVGggo
@@ -71,6 +73,8 @@ ip:
 self:
   secret: qianxing-duoshaojiaoyu
 
+
+
 paper:
   sentenceLength: 20
   textbookLength: 31

+ 5 - 3
server/tools/src/main/java/com/nuliji/tools/third/sendcloud/SendCloudSms.java

@@ -49,15 +49,17 @@ public class SendCloudSms {
         }
     }
 
-    public Response sendSms(String area, String mobile, String templateId, JSONObject vars) {
+    public Response sendSms(String area, String mobile, String localId, String globalId, Map<String, String> vars) {
+        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
         if (area != null && !area.equals("86") && !area.equals("+86")){
             // https://sendcloud.kf5.com/posts/view/1074678/
             // 国际号码格式
             mobile = "00"+area.replace("+", "")+mobile;
+            params.add("templateId", globalId);
+        }else{
+            params.add("templateId", localId);
         }
-        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
         params.add("smsUser", smsUser);
-        params.add("templateId", templateId);
         params.add("msgType", "0");
         params.add("phone", mobile);
         params.add("vars", JSONObject.toJSONString(vars));

+ 2 - 2
server/tools/src/main/java/com/nuliji/tools/third/wechat/WechatClient.java

@@ -126,12 +126,12 @@ public class WechatClient {
         data.setRefreshToken(result.getString("refresh_token"));
         data.setAccessToken(result.getString("access_token"));
         data.setExpiresTime(new Date(new Date().getTime() + result.getInteger("expires_in")));
+        data.setOpenId(result.getString("openid"));
         if (userInfo){
             JSONObject info = getWebUserInfo(result.getString("access_token"), result.getString("openid"));
-            data.setAvatar(info.getString("avatar"));
+            data.setAvatar(info.getString("headimgurl"));
             data.setNickName(info.getString("nickname"));
             data.setUnionId(info.getString("unionid"));
-            data.setOpenId(info.getString("openid"));
             data.setGender(info.getIntValue("sex") == 1 ? "mela":"femela");
         }
         return data;