diff --git a/Web12306/Web12306.csproj b/Web12306/Web12306.csproj index 29d72f6..2893bdc 100644 --- a/Web12306/Web12306.csproj +++ b/Web12306/Web12306.csproj @@ -149,6 +149,7 @@ + @@ -164,6 +165,7 @@ + @@ -173,11 +175,9 @@ - - - - + + @@ -191,6 +191,8 @@ + + Web.config diff --git a/Web12306/css/buttons.css b/Web12306/css/buttons.css index a5cfb55..6d18427 100644 --- a/Web12306/css/buttons.css +++ b/Web12306/css/buttons.css @@ -1,71 +1,76 @@ -button, input { - font-family: inherit; -} - - button:focus { - outline: none; - } - -.button { - border-radius: 3px; - box-shadow: #ECEBEB 1px 1px 2px; - line-height: 26px; - padding: 4px 10px 4px 10px; - cursor: pointer; - color: #898989; - display: inline-block; - box-sizing: border-box; -} - -.button-default { - background: linear-gradient(to bottom, #f4f4f4, #e8e8e8); - border: 1px solid #d3d3d3; -} - - .button-default:hover { - background: linear-gradient(to bottom, #fefefe, #dddcdc); - } - - .button-default:active { - background: linear-gradient(to bottom, #fefdfd, #d4d1d1); - } - -.button-primary { - background: linear-gradient(to top, #ff7e08, #ff9e14); - color: #fff; - border: 1px solid #ec8b00; - font-weight: bold; -} - - .button-primary:hover { - background: linear-gradient(to top, #ff912d, #ffb72e); - } - - .button-primary:active { - background: linear-gradient(to top, #ee7609, #ff9712); - } - - -.button-block { - display: block; - width: 100%; -} - -.button-large { - font-size: 18px; - line-height: 40px; -} - -.text { - border-radius: 4px; - border: 1px solid #b7b7b7; - background-color: #ffffff; - box-shadow: inset 0 0 10px rgba(160, 160, 160, 0.5); - padding: 10px; -} - -.text-block { - display: block; - width: 100%; - box-sizing: border-box; -} +button, input { + font-family: inherit; +} + + button:focus { + outline: none; + } + +.button { + border-radius: 3px; + box-shadow: #ECEBEB 1px 1px 2px; + line-height: 26px; + padding: 4px 10px 4px 10px; + cursor: pointer; + color: #898989; + display: inline-block; + box-sizing: border-box; +} + + .button:disabled, .button:hover:disabled { + border: 1px solid #cbcbcb; + background: linear-gradient(to top, #cbcbcb, #cfcfcf); + } + +.button-default { + background: linear-gradient(to bottom, #f4f4f4, #e8e8e8); + border: 1px solid #d3d3d3; +} + + .button-default:hover { + background: linear-gradient(to bottom, #fefefe, #dddcdc); + } + + .button-default:active { + background: linear-gradient(to bottom, #fefdfd, #d4d1d1); + } + +.button-primary { + background: linear-gradient(to top, #ff7e08, #ff9e14); + color: #fff; + border: 1px solid #ec8b00; + font-weight: bold; +} + + .button-primary:hover { + background: linear-gradient(to top, #ff912d, #ffb72e); + } + + .button-primary:active { + background: linear-gradient(to top, #ee7609, #ff9712); + } + + +.button-block { + display: block; + width: 100%; +} + +.button-large { + font-size: 18px; + line-height: 40px; +} + +.text { + border-radius: 4px; + border: 1px solid #b7b7b7; + background-color: #ffffff; + box-shadow: inset 0 0 10px rgba(160, 160, 160, 0.5); + padding: 10px; +} + +.text-block { + display: block; + width: 100%; + box-sizing: border-box; +} diff --git a/Web12306/css/index.css b/Web12306/css/index.css index a44a676..c466f21 100644 --- a/Web12306/css/index.css +++ b/Web12306/css/index.css @@ -1,27 +1,28 @@ -@import url('base.css'); -@import url('buttons.css'); -@import url('fa/css/font-awesome.css'); -@import url('ui/widget.css'); -@import url('ui/index-search-base.css'); -@import url('ui/options-param.css'); -@import url('ui/city-selector.css'); -@import url('ui/date-popup.css'); -@import url("ui/passenger-selector.css"); -@import url('ui/query-result.css'); -@import url('ui/travel-method.css'); -@import url('ui/train-stops.css'); -@import url('ui/widget-login.css'); -@import url('ui/widget-ticketsubmit.css'); - - - - - - - - - -.icon { - background: url(../images/icon.png) no-repeat; -} - +@import url('base.css'); +@import url('buttons.css'); +@import url('fa/css/font-awesome.css'); +@import url('ui/widget.css'); +@import url('ui/widget-message-popup.css'); +@import url('ui/index-search-base.css'); +@import url('ui/options-param.css'); +@import url('ui/city-selector.css'); +@import url('ui/date-popup.css'); +@import url("ui/passenger-selector.css"); +@import url('ui/query-result.css'); +@import url('ui/travel-method.css'); +@import url('ui/train-stops.css'); +@import url('ui/widget-login.css'); +@import url('ui/widget-ticketsubmit.css'); + + + + + + + + + +.icon { + background: url(../images/icon.png) no-repeat; +} + diff --git a/Web12306/css/ui/index-search-base.css b/Web12306/css/ui/index-search-base.css index 332c511..48900c0 100644 --- a/Web12306/css/ui/index-search-base.css +++ b/Web12306/css/ui/index-search-base.css @@ -1,288 +1,292 @@ -.search-box { - height: 193px; - margin-top: 27px; - padding-top: 15px; - background: url(../../images/search-box-bg.png) repeat-x; -} - - .search-box .label-desc { - color: #984d00; - margin-bottom: 12px; - display: block; - } - - .search-box .search-box-l, - .search-box .search-box-r { - width: 10px; - height: 199px; - background: url(../../images/css-sprite.png) no-repeat; - position: absolute; - top: 0; - } - - .search-box .search-box-r { - right: 0; - background-position: -12px 0; - } - - .search-box .search-box-hings-l, - .search-box .search-box-hings-r { - width: 14px; - height: 31px; - background-position: 0 -459px; - position: absolute; - bottom: -8px; - } - - .search-box .search-box-hings-l { - left: 188px; - } - - .search-box .search-box-hings-r { - right: 188px; - } - - .search-box .search-tips { - margin-left: 23px; - height: 32px; - font-size: 16px; - line-height: 29px; - color: #fff; - padding-left: 34px; - background-position: 0 -321px; - } - - .search-box .search-tips span { - display: inline-block; - } - - .search-box .search-tips .reset-btn { - width: 87px; - height: 30px; - background: url(../../images/css-sprite.png) no-repeat; - background-position: -24px 0; - font-size: 0; - top: -7px; - position: relative; - margin: 0 39px 0 16px; - cursor: pointer; - } - .search-box .search-tips .reset-btn:hover { - background-position: -110px 0; - } - .search-box .search-tips .reset-btn:active { - background-position: -199px 0; - } - .search-box .search-tips .order-ring { - top: 3px; - position: relative; - background-position: 0 -360px; - width: 19px; - height: 19px; - margin-right: 37px; - } - - .search-box .search-tips .order-ring .order-num { - position: absolute; - top: -10px; - left: 20px; - background: #ff3e43; - font-size: 8px; - border-radius: 200px; - padding: 0 4px; - } - - .search-box .search-tips-container { - background: #f8f8f8; - border: 1px solid #bdbdbd; - border-radius: 4px; - padding: 10px 10px 10px 10px; - z-index: 10; - position: absolute; - color: #666; - font-size: 12px; - right: 60px; - top: 0; - width: 300px; - box-shadow: 5px 5px 10px rgba(110, 110, 110, 0.4); - } - - .search-box .search-tips-container:before, - .search-box .search-tips-container:after { - position: absolute; - content: ''; - height: 0; - width: 0; - border-left: 5px solid #bdbdbd; - border-top: 5px solid transparent; - border-bottom: 5px solid transparent; - right: -5px; - top: 20px; - } - .search-box .search-tips-container:after { - border-left-color: #f8f8f8; - right: -4px; - } - - .search-box .search-tips-container header { - font-weight: bold; - color: #9b540b; - line-height: 100%; - } - - .search-box .search-tips-container header .fr { - color: #999999; - cursor: pointer; - } - .search-box .search-tips-container header .fr:hover { - color: #ff3e43; - } - - .search-box .search-form-wrap { - margin: 38px 0 0 44px; - } - - .search-box .search-form { - overflow: hidden; - } - - .search-box .search-form li { - float: left; - } - - .search-box .search-form-city, - .search-box .search-form-date { - width: 134px; - height: 37px; - padding: 0 30px 0 10px; - background: url(../../images/css-sprite.png) no-repeat; - border: none; - -webkit-appearance: none; - background-position: -24px -72px; - } - - .search-box .search-form-city:focus, - .search-box .search-form-date:focus { - background-position: -203px -72px; - } - - .search-box .search-form-date { - background-position: -24px -117px; - } - - .search-box .search-form-date:focus { - background-position: -203px -117px; - } - - .search-box .transfer-city { - margin: 0 6px; - } - - .search-box .transfer-city .transfer-city-btn { - width: 39px; - height: 39px; - background: url(../../images/css-sprite.png) no-repeat; - background-position: -24px -158px; - margin-top: 27px; - cursor: pointer; - } - - .search-box .transfer-city .transfer-city-btn:hover { - background-position: -73px -158px; - } - - .search-box .transfer-city .transfer-city-btn:active { - background-position: -123px -158px; - } - - .search-box .select-date { - margin: 0 70px 0 40px; - } - - .search-box .submit-btn { - width: 133px; - height: 43px; - display: block; - margin-top: 5px; - line-height: 43px; - color: #fff; - font-size: 17px; - cursor: pointer; - border: 1px solid #2c961a; - border-radius: 4px; - -webkit-appearance: none; - background: linear-gradient(to bottom, #3bc412, #33a810); - } - - .search-box .submit-btn:hover { - border-color: #176f0a; - background: linear-gradient(to bottom, #33cd19, #3b9d2a); - } - - .search-box .submit-btn:active { - border-color: #176f0a; - background: linear-gradient(to bottom, #41b12f, #1f8a0c); - } - - .search-box .identity label { - display: block; - line-height: 28px; - margin-right: 30px; - color: #984d00; - } - - .search-box .identity label input { - position: relative; - top: -1px; - } - -.search-more-option:link { - border-top: 1px solid#e9e8e2; - border-right: 1px solid#e9e8e2; - border-bottom: 1px solid#e9e8e2; - background-color: #fbfbfb; - position: absolute; - right: 5px; - color: #898989; - padding: 8px 8px 8px 15px; - text-decoration: underline; -} - -.search-more-option:hover { - color: #f67922; -} - -.search-more-option:active { - color: #9b540b; -} - -.search-more-option:before { - content: ''; - position: absolute; - left: 0px; - width: 1px; - height: 0; - border-top: 16px #e9e8e2 solid; - border-left: 7px solid #fdfbf2; - top: 0; - border-bottom: 16px #e9e8e2 solid; -} - -.search-more-option:after { - content: ''; - position: absolute; - left: 1px; - width: 0; - height: 0; - top: 0; - border-top: 16px #fbfbfb solid; - border-left: 7px solid transparent; - border-bottom: 16px #fbfbfb solid; -} - -button#btnResetOptions { - position: absolute; - right: 10px; - bottom: 10px; -} - +.search-box { + height: 193px; + margin-top: 27px; + padding-top: 15px; + background: url(../../images/search-box-bg.png) repeat-x; +} + + .search-box .label-desc { + color: #984d00; + margin-bottom: 12px; + display: block; + } + + .search-box .search-box-l, + .search-box .search-box-r { + width: 10px; + height: 199px; + background: url(../../images/css-sprite.png) no-repeat; + position: absolute; + top: 0; + } + + .search-box .search-box-r { + right: 0; + background-position: -12px 0; + } + + .search-box .search-box-hings-l, + .search-box .search-box-hings-r { + width: 14px; + height: 31px; + background-position: 0 -459px; + position: absolute; + bottom: -8px; + } + + .search-box .search-box-hings-l { + left: 188px; + } + + .search-box .search-box-hings-r { + right: 188px; + } + + .search-box .search-tips { + margin-left: 23px; + height: 32px; + font-size: 16px; + line-height: 29px; + color: #fff; + padding-left: 34px; + background-position: 0 -321px; + } + + .search-box .search-tips span { + display: inline-block; + cursor: pointer; + } + + .search-box .search-tips .reset-btn { + width: 87px; + height: 30px; + background: url(../../images/css-sprite.png) no-repeat; + background-position: -24px 0; + font-size: 0; + top: -7px; + position: relative; + margin: 0 39px 0 16px; + cursor: pointer; + } + .search-box .search-tips .reset-btn:hover { + background-position: -110px 0; + } + .search-box .search-tips .reset-btn:active { + background-position: -199px 0; + } + .search-box .search-tips .order-ring { + top: 3px; + position: relative; + background-position: 0 -360px; + width: 19px; + height: 19px; + margin-right: 37px; + } + + .search-box .search-tips .order-ring .order-num { + position: absolute; + left: 20px; + background: #ff3e43; + font-size: 12px; + border-radius: 20px; + width: 20px; + height: 20px; + line-height: 20px; + text-align: center; + } + + .search-box .search-tips-container { + background: #f8f8f8; + border: 1px solid #bdbdbd; + border-radius: 4px; + padding: 10px 10px 10px 10px; + z-index: 10; + position: absolute; + color: #666; + font-size: 12px; + right: 60px; + top: 0; + width: 300px; + box-shadow: 5px 5px 10px rgba(110, 110, 110, 0.4); + display: none; + } + + .search-box .search-tips-container:before, + .search-box .search-tips-container:after { + position: absolute; + content: ''; + height: 0; + width: 0; + border-left: 5px solid #bdbdbd; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + right: -5px; + top: 20px; + } + .search-box .search-tips-container:after { + border-left-color: #f8f8f8; + right: -4px; + } + + .search-box .search-tips-container header { + font-weight: bold; + color: #9b540b; + line-height: 100%; + } + + .search-box .search-tips-container header .fr { + color: #999999; + cursor: pointer; + } + .search-box .search-tips-container header .fr:hover { + color: #ff3e43; + } + + .search-box .search-form-wrap { + margin: 38px 0 0 44px; + } + + .search-box .search-form { + overflow: hidden; + } + + .search-box .search-form li { + float: left; + } + + .search-box .search-form-city, + .search-box .search-form-date { + width: 134px; + height: 37px; + padding: 0 30px 0 10px; + background: url(../../images/css-sprite.png) no-repeat; + border: none; + -webkit-appearance: none; + background-position: -24px -72px; + } + + .search-box .search-form-city:focus, + .search-box .search-form-date:focus { + background-position: -203px -72px; + } + + .search-box .search-form-date { + background-position: -24px -117px; + } + + .search-box .search-form-date:focus { + background-position: -203px -117px; + } + + .search-box .transfer-city { + margin: 0 6px; + } + + .search-box .transfer-city .transfer-city-btn { + width: 39px; + height: 39px; + background: url(../../images/css-sprite.png) no-repeat; + background-position: -24px -158px; + margin-top: 27px; + cursor: pointer; + } + + .search-box .transfer-city .transfer-city-btn:hover { + background-position: -73px -158px; + } + + .search-box .transfer-city .transfer-city-btn:active { + background-position: -123px -158px; + } + + .search-box .select-date { + margin: 0 70px 0 40px; + } + + .search-box .submit-btn { + width: 133px; + height: 43px; + display: block; + margin-top: 5px; + line-height: 43px; + color: #fff; + font-size: 17px; + cursor: pointer; + border: 1px solid #2c961a; + border-radius: 4px; + -webkit-appearance: none; + background: linear-gradient(to bottom, #3bc412, #33a810); + } + + .search-box .submit-btn:hover { + border-color: #176f0a; + background: linear-gradient(to bottom, #33cd19, #3b9d2a); + } + + .search-box .submit-btn:active { + border-color: #176f0a; + background: linear-gradient(to bottom, #41b12f, #1f8a0c); + } + + .search-box .identity label { + display: block; + line-height: 28px; + margin-right: 30px; + color: #984d00; + } + + .search-box .identity label input { + position: relative; + top: -1px; + } + +.search-more-option:link { + border-top: 1px solid#e9e8e2; + border-right: 1px solid#e9e8e2; + border-bottom: 1px solid#e9e8e2; + background-color: #fbfbfb; + position: absolute; + right: 5px; + color: #898989; + padding: 8px 8px 8px 15px; + text-decoration: underline; +} + +.search-more-option:hover { + color: #f67922; +} + +.search-more-option:active { + color: #9b540b; +} + +.search-more-option:before { + content: ''; + position: absolute; + left: 0px; + width: 1px; + height: 0; + border-top: 16px #e9e8e2 solid; + border-left: 7px solid #fdfbf2; + top: 0; + border-bottom: 16px #e9e8e2 solid; +} + +.search-more-option:after { + content: ''; + position: absolute; + left: 1px; + width: 0; + height: 0; + top: 0; + border-top: 16px #fbfbfb solid; + border-left: 7px solid transparent; + border-bottom: 16px #fbfbfb solid; +} + +button#btnResetOptions { + position: absolute; + right: 10px; + bottom: 10px; +} + diff --git a/Web12306/css/ui/widget-login.css b/Web12306/css/ui/widget-login.css index e5ddf6d..76ec912 100644 --- a/Web12306/css/ui/widget-login.css +++ b/Web12306/css/ui/widget-login.css @@ -1,107 +1,109 @@ -#user-login-dialog { - width: 440px; - border-radius: 5px; - border: 1px solid #5b5b5b; - box-shadow: 5px 5px 20px rgba(100, 100, 100, 0.6); -} - - #user-login-dialog header { - height: 113px; - background: linear-gradient(to right, #fc9600, #ef4302); - position: relative; - } - - #user-login-dialog header span { - display: block; - width: 100%; - height: 100%; - background: url('../../images/logo12306.png') 50% 50% no-repeat; - } - - #user-login-dialog header i { - position: absolute; - right: 15px; - top: 15px; - color: #f9b59a; - } - - #user-login-dialog header i:hover { - color: #ffffff; - } - - #user-login-dialog .login-info { - margin: 20px 45px; - border: 1px solid #b6b6b6; - border-radius: 2px; - position: relative; - } - - #user-login-dialog .login-info input { - padding: 12px; - display: block; - border: none; - line-height: 14px; - width: 100%; - box-sizing: border-box; - margin: 0; - color: #a3a3a3; - } - - #user-login-dialog .login-info input:not(:first-child) { - border-top: 1px solid #dbdbdb; - } - - #user-login-dialog .login-info a { - position: absolute; - right: 15px; - bottom: 12px; - color: #2c90ed; - text-decoration: underline; - } - - #user-login-dialog .login-info a:hover { - color: #1988ee; - } - - #user-login-dialog .verify-code { - margin: 0 45px 20px 45px; - padding: 0; - overflow: hidden; - } - - #user-login-dialog .verify-code input { - float: left; - padding: 12px; - line-height: 14px; - border: 1px solid #bfbfbf; - width: 90px; - margin: 0; - } - - #user-login-dialog .verify-code span { - border: 1px solid #bebebe; - background-color: #fff; - width: 86px; - height: 40px; - display: block; - float: left; - margin-left: 10px; - background-repeat: no-repeat; - background-image: url(../../images/loading.gif); - background-position: 50% 50%; - } - - #user-login-dialog .verify-code a { - display: block; - width: auto; - line-height: 16px; - margin-top: 24px; - float: left; - margin-left: 10px; - color: #2c90ed; - text-decoration: underline; - } - - #user-login-dialog .verify-code a:hover { - color: #1988ee; - } +#user-login-dialog { + width: 440px; + border-radius: 5px; + border: 1px solid #5b5b5b; + box-shadow: 5px 5px 20px rgba(100, 100, 100, 0.6); +} + + #user-login-dialog header { + height: 113px; + background: linear-gradient(to right, #fc9600, #ef4302); + position: relative; + } + + #user-login-dialog header span { + display: block; + width: 100%; + height: 100%; + background: url('../../images/logo12306.png') 50% 50% no-repeat; + } + + #user-login-dialog header i { + position: absolute; + right: 15px; + top: 15px; + color: #f9b59a; + } + + #user-login-dialog header i:hover { + color: #ffffff; + } + + #user-login-dialog .login-info { + margin: 20px 45px; + border: 1px solid #b6b6b6; + border-radius: 2px; + position: relative; + } + + #user-login-dialog .login-info input { + padding: 12px; + display: block; + border: none; + line-height: 14px; + width: 100%; + box-sizing: border-box; + margin: 0; + color: #a3a3a3; + } + + #user-login-dialog .login-info input:not(:first-child) { + border-top: 1px solid #dbdbdb; + } + + #user-login-dialog .login-info a { + position: absolute; + right: 15px; + bottom: 12px; + color: #2c90ed; + text-decoration: underline; + } + + #user-login-dialog .login-info a:hover { + color: #1988ee; + } + + #user-login-dialog .verify-code { + margin: 0 45px 20px 45px; + padding: 0; + overflow: hidden; + } + + #user-login-dialog .verify-code input { + float: left; + padding: 12px; + line-height: 14px; + border: 1px solid #bfbfbf; + width: 90px; + margin: 0; + } + + #user-login-dialog .verify-code span { + border: 1px solid #bebebe; + background-color: #fff; + width: 86px; + height: 40px; + display: block; + float: left; + margin-left: 10px; + background-repeat: no-repeat; + background-image: url(../../images/loading.gif); + background-position: 50% 50%; + background-size: auto; + cursor: pointer; + } + + #user-login-dialog .verify-code a { + display: block; + width: auto; + line-height: 16px; + margin-top: 24px; + float: left; + margin-left: 10px; + color: #2c90ed; + text-decoration: underline; + } + + #user-login-dialog .verify-code a:hover { + color: #1988ee; + } diff --git a/Web12306/css/ui/widget-message-popup.css b/Web12306/css/ui/widget-message-popup.css new file mode 100644 index 0000000..221e2be --- /dev/null +++ b/Web12306/css/ui/widget-message-popup.css @@ -0,0 +1,49 @@ +.message-popup { + border: 5px solid #ccc; + position: fixed; + z-index: 100001; + left: 50%; + top: 50%; + opacity: 0; + box-shadow: 3px 3px 6px rgba(200,200,200,0.6); +} + + .message-popup .message-popup-inner { + padding: 15px 20px; + border: 1px solid #aaa; + } + +.message-popup-warn { + border-color: #fadfbc; +} + + .message-popup-warn .message-popup-inner { + border-color: #BD8D51; + background: linear-gradient(to bottom, #fff0cf, #fee7c4); + color: #b2632b; + } + +.message-popup-error { + border-color: rgb(233, 202, 202); +} + + .message-popup-error .message-popup-inner { + border-color: rgb(175, 94, 94); + background: #FFF7F7; + color: rgb(175, 94, 94); + } +.message-popup-ok { + border-color: #DCF1DE; +} + + .message-popup-ok .message-popup-inner { + border-color: #8FC08D; + background: #F2FFF3; + color: #3d6d3d; + } + +.message-popup-loading { + background: linear-gradient(to bottom, #fff, #fafafa); + border-color: #cccccc; + color: #444; +} diff --git a/Web12306/index.html b/Web12306/index.html index c82a6a9..e21e167 100644 --- a/Web12306/index.html +++ b/Web12306/index.html @@ -55,7 +55,7 @@ 已分配到畅通的网络环境,为你提速80%:乌鲁木齐 还原到默认 今日可预定:9月10日-10月2日的火车票 - 1 + 1
@@ -435,9 +435,9 @@ -
+
看不清?换一张 @@ -502,6 +502,7 @@

+ diff --git a/Web12306/js/account/keepalive.js b/Web12306/js/account/keepalive.js new file mode 100644 index 0000000..61e53cf --- /dev/null +++ b/Web12306/js/account/keepalive.js @@ -0,0 +1,38 @@ +define(function (require, exports, module) { + var ajax = require("../platform/webRequest.js"); + var interval = 1 * 60 * 1000; + var timer = null; + + var checkUser = function() { + ajax.sendPost("login/checkUser", "login/init", null, "json", function () { + var m = this.model; + + if (!m || !m.status) { + setTimeout(checkUser, interval); + } + else if (!m.data || !m.data.flag) { + //登录无效 + document.dispatchEvent(new CustomEvent("loginInvalid")); + } + else { + ajax.userAtts = m.data.attributes; + setTimeout(checkUser, interval); + } + }, function () { + setTimeout(checkUser, interval); + }); + }; + + // + exports.start = function() { + if (!timer) + checkUser(); + return true; + }; + + exports.stop = function() { + if (timer) + clearTimeout(timer); + return true; + }; +}); diff --git a/Web12306/js/account/sessionMgr.js b/Web12306/js/account/sessionMgr.js index ea76b63..59aa0fc 100644 --- a/Web12306/js/account/sessionMgr.js +++ b/Web12306/js/account/sessionMgr.js @@ -1,8 +1,9 @@ define(function (require, exports, module) { var session = null; var ev = require("../platform/EventObject.js"); - var widget = require("../ui/widget.js"); var ajax = require("../platform/webRequest.js"); + var storage = require("../platform/storage.js"); + var keepAlive = require("../account/keepalive.js"); //var LoginUser = require("./LoginUser.js"); @@ -10,17 +11,7 @@ var that = this; ev.apply(this, arguments); - that.showLogin = function () { - if (that.current != null) return; - widget.showFloatDialog($("#user-login-dialog")); - }; - that.loadLoginVcImage = function (target) { - - }; - that.loginAsync = function (callback) { - - }; that.checkLoginState = function (callback) { ajax.sendGet("modifyUser/initQueryUserInfo", "", null, "text", function () { if (this.text.indexOf("登录名:") !== -1) { @@ -28,11 +19,12 @@ } else { var m = /姓名:.*[\r\n]+]+>([^<]+)<\/div>/i.exec(this.text) && RegExp.$1; var status = /核验状态:[\w\W]+?>([^<>]+?)<\/div>/.exec(this.text) && RegExp.$1; + var un = /userDTO\.loginUserDTO\.user_name.*?value=['"]([^'"]+)['"]/.exec(this.text) && RegExp.$1; if (!m || !status) callback({ logined: false }); else { - callback({ logined: true, realName: m, status: status, isChecked: status === '已通过' }); + callback({ logined: true, realName: m, status: status, isChecked: status === '已通过', username: un }); } } @@ -40,6 +32,41 @@ }); }; + that.loadProfile = function (username, checkData) { + var profile = storage.obj("12306_user_" + username) || { username: username, passengers: [], savedProfile: {}, currentProfile: {}, rawPassenger: [], options: {} }; + that.current = profile; + + if (checkData) { + that.current.dispname = checkData.realName; + that.fireEvent("userInfoUpdated"); + + if (!checkData.isChecked) + that.fireEvent("userNotChecked"); + } else { + that.checkLoginState(function (data) { + that.current.dispname = data.realName; + that.fireEvent("userInfoUpdated"); + + if (!data.isChecked) + that.fireEvent("userNotChecked"); + }); + } + }; + that.resetProfile = function () { + session = null; + }; + that.loadPassengers = function(force) { + if (!that.isLogined) + return; + + }; + that.save = function () { + if (!that.current) + return; + + var key = "12306_user_" + that.current.username; + storage.put(key, that.current); + }; Object.defineProperty(this, "current", { get: function () { @@ -48,10 +75,35 @@ set: function (v) { if (session === v) return; - session = v; + if (v) session = v; + else { + that.resetProfile(); + } that.fireEvent("sessionChanged"); + + + (that.isLogined && keepAlive.start()) || keepAlive.stop(); } }); + Object.defineProperty(this, "isLogined", { + get: function () { + return session && session.username || false; + } + }); + + //主动检测 + that.checkLoginState(function (data) { + if (data.logined) { + that.loadProfile(data.username, data); + } + }); + document.addEventListener("loginInvalid", function () { + if (that.isLogined) { + document.dispatchEvent(new CustomEvent("userForcedOut")); + that.fireEvent("userForcedOut"); + } + that.resetProfile(); + }); return this; }; diff --git a/Web12306/js/boot.js b/Web12306/js/boot.js index 9f2a809..2e1004c 100644 --- a/Web12306/js/boot.js +++ b/Web12306/js/boot.js @@ -25,19 +25,39 @@ } }); - loadScript("modules/seajs/sea.js", function () { - seajs.config({ - base: basePath, - alias: { - "jquery": "modules/jquery/jquery.js", - "underscore": "modules/underscore/underscore.js" - }, - vars: { - 'locale': 'zh-cn' - }, - charset: "utf-8", - debug: true + //确保内容脚本启动 + var start = $.Deferred(); + start.done(function() { + loadScript("modules/seajs/sea.js", function() { + seajs.config({ + base: basePath, + alias: { + "jquery": "modules/jquery/jquery.js", + "underscore": "modules/underscore/underscore.js" + }, + vars: { + 'locale': 'zh-cn' + }, + charset: "utf-8", + debug: true + }); + seajs.use("ui/" + pagename); }); - seajs.use("ui/" + pagename); }); + start.fail(function() { + alert("没有安装扩展!"); + }); + + if (document.body.dataset["mobileSupportInitialized"]) { + start.resolve(); + } else { + var timer = setTimeout(function() { + start.reject(); + }, 3000); + document.addEventListener("mobileSupportInitialized", function () { + window.clearTimeout(timer); + start.resolve(); + }); + } + })(window, document); diff --git a/Web12306/js/passenger/Passenger.js b/Web12306/js/passenger/Passenger.js deleted file mode 100644 index 9712170..0000000 --- a/Web12306/js/passenger/Passenger.js +++ /dev/null @@ -1,46 +0,0 @@ -define(function (require) { - var eo = require("../platform/EventObject.js"); - var $ = require("jquery"); - - - - function Passenger(name, type, typename, idtype, idtypename, id, firstLetter) { - this.name = name; - this.type = type; - this.idtype = idtype; - this.id = id; - this.key = type + "$" + name + "$" + idtype + "$" + this.id; - this.save = false; - this.firstLetter = firstLetter; - this.idtypeName = idtypename; - this.typename = typename; - var __ = this; - - this.toString = function () { - return name; - }; - this.toHtml = function (removeFlag) { - return ""; - }; - //e.passengers.push(new Passenger(this.passenger_name, this.passenger_type, this.passenger_id_type_code, this.passenger_id_no, this.first_letter)); - this.toRawPassenger = function () { - return { - passenger_name: __.name, - passenger_type: __.type, - passenger_id_type_code: __.idtype, - passenger_id_no: __.id, - passenger_first_letter: __.firstLetter, - mobile_no: "", - passenger_id_type_name: __.idtypeName, - passenger_type_name: __.typename - }; - }; - - return this; - }; - - Passenger.prototype = Object.create(eo); - Passenger.constructor = Passenger; - - return Passenger; -}); \ No newline at end of file diff --git a/Web12306/js/passenger/PassengerList.js b/Web12306/js/passenger/PassengerList.js deleted file mode 100644 index a202028..0000000 --- a/Web12306/js/passenger/PassengerList.js +++ /dev/null @@ -1,3 +0,0 @@ -define(function() { - -}); \ No newline at end of file diff --git a/Web12306/js/platform/extensionConnect.js b/Web12306/js/platform/extensionConnect.js deleted file mode 100644 index 14013af..0000000 --- a/Web12306/js/platform/extensionConnect.js +++ /dev/null @@ -1,43 +0,0 @@ -define(function (require, exports, module) { - var EventObject = require("EventObject"); - - var Connector = function () { - var token = 0; - var callback = {}; - - this.send = function (type, data, cb, target) { - /// 发送消息到后台 - - var args = { type: type, data: data, token: token++ }; - if (cb) - callback[args.token] = { func: cb, target: target, arg: args }; - window.postMessage({ command: "ccontentScriptConnection", data: args }); - }; - - - //回调 - window.addEventListener("message", function (event) { - if (!event.data || !event.data.command || event.data.command !== "contentScriptConnection") - return; - - var data = event.data; - var result = data.result; - var destToken = data.token; - - if (callback[destToken]) { - var cb = callback[destToken]; - delete callback[destToken]; - if (cb.target) { - cb.func.apply(cb.target, [result, cb.arg]); - } else { - cb.func(result, cb.arg); - } - } - }); - }; - - Connector.prototype = Object.create(EventObject); - Connector.constructor = Connector; - - return Object.create(Connector); -}); diff --git a/Web12306/js/platform/extensionPort.js b/Web12306/js/platform/extensionPort.js new file mode 100644 index 0000000..af9f1e5 --- /dev/null +++ b/Web12306/js/platform/extensionPort.js @@ -0,0 +1,28 @@ +define(function (require, exports, module) { + var targetExtension = [ + "bpbefagpafkfgoihbmcgeileodldkpnf", + "gkbheeokbgmmnbjhhlphckobccejghjn" + ]; + exports.targetId = null; + for (var id in targetExtension) { + var port = chrome.runtime.connect(targetExtension[id]); + try { + port.postMessage(""); + port.disconnect(); + + exports.targetId = targetExtension[id]; + break; + } catch (e) { + + } + } + if (!exports.targetId) + document.dispatchEvent(new CustomEvent("supportError")); + + exports.sendMessage = function(m, response) { + if (!exports.targetId) + throw "extension not connected."; + + chrome.runtime.sendMessage(exports.targetId, m, response || function () { }); + }; +}); diff --git a/Web12306/js/platform/parser.js b/Web12306/js/platform/parser.js new file mode 100644 index 0000000..2a847f9 --- /dev/null +++ b/Web12306/js/platform/parser.js @@ -0,0 +1,17 @@ +define(function (require, exports) { + + exports.getError = function (data) { + /// 获得指定返回数据中的错误信息 + + if (data.messages && data.messages instanceof Array) { + return { message: data.messages.join(";") }; + } + if (data.data && data.data.isRelogin) { + return { message: "登录状态异常,请重新登录。", relogin: true }; + } + + return { message: "未知错误信息" }; + }; + + +}); \ No newline at end of file diff --git a/Web12306/js/platform/paser.js b/Web12306/js/platform/paser.js deleted file mode 100644 index 9202c6c..0000000 --- a/Web12306/js/platform/paser.js +++ /dev/null @@ -1,6 +0,0 @@ -define(function(require, exports) { - var _ = require("../modules/underscore/underscore.js"); - var $ = require("jquery"); - - -}); \ No newline at end of file diff --git a/Web12306/js/platform/storage.js b/Web12306/js/platform/storage.js index cac7259..7e99c56 100644 --- a/Web12306/js/platform/storage.js +++ b/Web12306/js/platform/storage.js @@ -1,22 +1,40 @@ -define(function (require) { - var EventObject = require("./EventObject.js"); - - var Storage = function () { - var __ = this; - - this.get = function(key) { - return localStorage[key] || ""; - }; - this.put = function(key, value) { - localStorage[key] = value + ''; - }; - this.remove = function(key) { - localStorage.remove(key); - }; - Object.defineProperty(this, ""); - }; - Storage.prototype = Object.create(EventObject); - Storage.constructor = Storage; - - return Object.create(Storage); -}); +define(function (require) { + var EventObject = require("./EventObject.js"); + var extension = require("./extensionPort.js"); + + var Storage = function () { + var __ = this; + var st = {}; + + EventObject.apply(this, Array.prototype.slice.call(arguments)); + + this.get = function (key) { + return st[key] || ""; + }; + this.put = function (key, value) { + if (typeof (value) !== 'string') { + value = JSON.stringify(value); + } + st[key] = value + ''; + extension.sendMessage({ action: "setStorage", detail: { key: value } }); + }; + this.remove = function (key) { + delete st[key]; + }; + this.obj=function(key) { + var value = __.get(key); + if (!value) + return null; + + return JSON.parse(value); + } + + extension.sendMessage({ action: "getStorage" }, function (m) { + st = m.detail; + }); + }; + Storage.prototype = Object.create(EventObject); + Storage.constructor = Storage; + + return new Storage(); +}); diff --git a/Web12306/js/platform/webRequest.js b/Web12306/js/platform/webRequest.js index 36318f4..a4495e8 100644 --- a/Web12306/js/platform/webRequest.js +++ b/Web12306/js/platform/webRequest.js @@ -2,20 +2,26 @@ define(function (require, exports, module) { var EventObject = require("../platform/EventObject.js"); var config = require("../data.js"); - - var WebRequest = function() { + + var WebRequest = function () { var that = this; var requestMap = {}; var ajaxCount = 0; + var jsonAtt = null; EventObject.apply(this, arguments); - this.getFullUri= function (url) { + this.getFullUri = function (url) { /// 获得完整地址 if (url[4] === ":" || url[5] === ":") return url; return config.baseUri + url; }; - this.send = function (method, url, refer, data, responseType, done, failed) { + this.send = function (method, url, refer, data, responseType, done, failed, ignoreGlobalAtt) { + if (!ignoreGlobalAtt && jsonAtt) { + data = $.extend({ + _json_att: jsonAtt + }, data); + } var xhrData = { url: that.getFullUri(url), data: data, @@ -33,7 +39,19 @@ define(function (require, exports, module) { }; return; } else { - that.fireEvent("requestSupportError"); + document.dispatchEvent(new CustomEvent("requestSupportError")); + } + }; + this.loadImage = function (url, refer, done, failed) { + var e = new CustomEvent("ajaxLoadVerifyCode", { detail: { url: that.getFullUri(url), refer: that.getFullUri(url), index: ajaxCount++ }, cancelable: true }); + if (!document.dispatchEvent(e)) { + requestMap[e.detail.index] = { + done: done, + fail: failed + }; + return; + } else { + document.dispatchEvent(new CustomEvent("requestSupportError")); } }; this.sendGet = function (url, refer, data, responseType, done, failed) { @@ -47,7 +65,7 @@ define(function (require, exports, module) { that.send("GET", url, refer, data, responseType, done, failed); }; this.sendPost = function (url, refer, data, responseType, done, failed) { - that.send("GET", url, refer, data, responseType, done, failed); + that.send("POST", url, refer, data, responseType, done, failed); }; document.addEventListener("ajaxproxyfinished", function (e) { @@ -56,8 +74,20 @@ define(function (require, exports, module) { var param = requestMap[data.index]; delete requestMap[data.index]; + data.success ? param.done.call(data) : param.fail.call(data); }); + + Object.defineProperties(this, { + "userAtts": { + get: function () { + return jsonAtt; + }, + set: function (value) { + jsonAtt = value; + } + } + }); }; WebRequest.prototype = Object.create(EventObject); diff --git a/Web12306/js/ui/index.js b/Web12306/js/ui/index.js index d4cc60e..61d2a76 100644 --- a/Web12306/js/ui/index.js +++ b/Web12306/js/ui/index.js @@ -4,6 +4,7 @@ var storage = require('../platform/storage.js'); var widget = require("./widget.js"); var sessMgr = require("../account/sessionMgr.js"); + var mp = require("./widget_message_popup.js"); //初始化UI (function() { @@ -25,19 +26,28 @@ //初始化日期 require("./widget_datedropdown.js").init("input.ui-date"); require("./widget_cityselector.js").init("input.ui-cityselector"); + require("./widget_verifycode.js").init(); //加载各模块 var ui_login = require("./ui-login.js"); + //界面交互初始化 + (function() { + $("#index-tip-body").click(function() { + $(this).next().fadeIn(); + }); + $("section.search-tips-container i.fa-times").click(function() { + $(this).closest("section.search-tips-container").fadeOut(); + }); + //登录失效 + sessMgr.on("userForcedOut", function() { + mp.showMessagePopup("error", "您的登录出现了问题,请重新登录"); + }); + })(); + //初始化 $("#J-search-form").submit(function() { return false; }); - - setTimeout(function () { - sessMgr.checkLoginState(function(a) { - console.log(a) - }); - }, 1000); }); diff --git a/Web12306/js/ui/ui-login.js b/Web12306/js/ui/ui-login.js index a5408be..0498cb1 100644 --- a/Web12306/js/ui/ui-login.js +++ b/Web12306/js/ui/ui-login.js @@ -1,26 +1,186 @@ define(function (require, exports, module) { var sessionMgr = require("../account/sessionMgr.js"); var ev = require("../platform/EventObject.js"); + var mp = require("./widget_message_popup.js"); + var parser = require("../platform/parser.js"); + var ajax = require("../platform/webRequest.js"); + var vc = require("../ui/widget_verifycode.js"); + var widget = require("../ui/widget.js"); + var storage = require("../platform/storage.js"); + var UiWidgetLogin = function () { + var that = this; + var dlg = $("#user-login-dialog"); + var btn = dlg.find("button.button-primary"); + ev.apply(this, arguments); + this.showLoginDialog = function () { + var info = storage.obj("12306_lastUser"); + if (info) { + $("#user-login-dialog input:password").val(info.pwd); + $("#user-login-dialog input:text:first").val(info.name); + } + $("#user-login-dialog input:text:last").val(""); + vc.autoLoad(dlg); + widget.showFloatDialog(dlg); + }; + this.closeLoginDialog = function () { + widget.hideFloatDialog(dlg); + }; + that.logout = function() { + var tip = new mp.MessagePopup("loading", "正在退出中..."); + tip.show(); + + ajax.sendGet("login/loginOut", "login/init", null, "text", function () { + sessionMgr.resetProfile(); + tip.setState("ok", "您已经成功注销了登录..."); + tip.delayClose(); + }, function () { + mp.alert("提示", "似乎看起来出了点网络错误...请刷新页面.....", function() { + self.location.reload(); + }); + }); + }; + this.loginAsync = function (preventError) { + var inputs = $("#user-login-dialog input:text"); + var un = inputs[0].value; + var pwd = $("#user-login-dialog input:password").val(); + var randcode = inputs[1].value; + + if (!un) { + if (!preventError) + mp.showMessagePopup("warn", "客官您的【用户名】没填..."); + return; + } + if (!pwd) { + if (!preventError) + mp.showMessagePopup("warn", "客官您的【密码】没填..."); + return; + } + if (!randcode) { + if (!preventError) + mp.showMessagePopup("warn", "客官您的【验证码】没填..."); + return; + } + btn.prop("disabled", true); + var loginTip = new mp.MessagePopup("loading", "正在登录中..."); + loginTip.show(); + + var loadLoginAsyncSuggest = function () { + that.fireEvent("loadSuggest"); + + loginTip.setState("loading", "正在获得登录随机码..."); + ajax.sendPost("login/loginAysnSuggest", "login/init", { + "loginUserDTO.user_name": un, + "userDTO.password": pwd, + "randCode": randcode + }, "json", function () { + if (this.model.data === null || this.model.data.loginCheck !== 'Y') { + loginFailed(parser.getError(this.model).message); + } else { + submitLoginInfo(); + } + }, function () { + loginFailed("无法加载随机码"); + }); + }; + var submitLoginInfo = function () { + that.fireEvent("checkUserInfo"); + + loginTip.setState("loading", "正在登录中..."); + + ajax.sendPost("login/checkUser", "login/init", null, "json", function () { + var m = this.model; + + if (!m || !m.status || !m.data || !m.data.flag) + loginFailed(parser.getError(m).message); + else { + ajax.userAtts = m.data.attributes; + postLogin(); + } + }, function () { + loginFailed("无法获得用户信息"); + }); + }; + var postLogin = function () { + that.fireEvent("postLogin"); + + loginTip.setState("loading", "正在登录中..."); + + ajax.sendPost("login/userLogin", "login/init", null, "json", function () { + loginSuccess(); + }, function () { + loginSuccess(); + }); + + }; + var loginFailed = function (msg) { + btn.prop("disabled", false); + vc.refresh(dlg); + $("#user-login-dialog input:text:last").val(""); + + loginTip.content = msg; + loginTip.type = "error"; + + loginTip.delayClose(); + }; + var loginSuccess = function () { + btn.prop("disabled", false); + that.closeLoginDialog(); + loginTip.setState("ok", "您已成功登录!"); + loginTip.delayClose(); + + //TODO 没有保存密码的选项! + storage.put("12306_lastUser", { + name: un, + pwd: pwd + }); + sessionMgr.loadProfile(un); + }; + + loadLoginAsyncSuggest(); + }; sessionMgr.on("sessionChanged", function () { if (sessionMgr.current) { $(".non-login").hide(); $(".user-logined").show(); + $("div.user-nav-user").html(sessionMgr.current.dispname); } else { $(".non-login").show(); $(".user-logined").hide(); + $("div.user-nav-user").html("未登录"); } }); + sessionMgr.on("userInfoUpdated", function() { + $("div.user-nav-user").html(sessionMgr.current.dispname); + }); + sessionMgr.on("userNotChecked", function () { + mp.alert("用户尚未通过审核!"); + }); //界面事件绑定 $("#acc_login").click(function () { - sessionMgr.showLogin(); + that.showLoginDialog(); + }); + $("#user-login-dialog button.button-primary").click(function () { + that.loginAsync(); + }); + $("#user-login-dialog input:text:last").keyup(function () { + if (this.value.length === 4) + that.loginAsync(true); + }); + $("#acc_logout").click(function () { + mp.confirm("退出?", "确定要退出登录吗?", function() { + that.logout(); + }, function() { + + }); + }); //初始化显示 diff --git a/Web12306/js/ui/widget_message_popup.js b/Web12306/js/ui/widget_message_popup.js new file mode 100644 index 0000000..c957701 --- /dev/null +++ b/Web12306/js/ui/widget_message_popup.js @@ -0,0 +1,111 @@ +define(function (require, exports, module) { + var htmlTemplate = '
'; + var iconMap = { + warn: "warning", + ok: "check", + error: "times-circle", + loading: "spinner" + }; + + var MessagePopup = function (type, content, options) { + var that = this; + var html = $(htmlTemplate); + var shown = false; + options = $.extend({ closeAfter: null }, options); + $("body").append(html); + + var centerElement = function (ele) { + ele = ele || html; + + var width = ele.width(); + var height = ele.height(); + + ele.css({ + "margin-left": "-" + (width / 2) + "px", + "margin-top": "-" + (height / 2 - 40) + "px" + }); + }; + this.show = function () { + html.animate({ "margin-top": "-=20px", opacity: "1" }, "fast", "linear", function () { + shown = true; + if (options.closeAfter) { + that.delayClose(); + } + }); + }; + this.close = function () { + html.animate({ "margin-top": "-=20px", opacity: "hide" }, "fast", "linear", function () { + html.remove(); + }); + }; + this.delayClose = function (timeout) { + if (that.shown) + setTimeout(that.close, timeout || options.closeAfter); + else { + options.closeAfter = timeout || options.closeAfter || 1000; + } + }; + that.setState = function (type, content) { + that.type = type; + that.content = content; + }; + Object.defineProperties(this, { + "content": { + get: function () { + return html.find("span").html(); + }, + set: function (value) { + html.find("span").html(value); + centerElement(); + } + }, + "type": { + get: function () { + return html.attr("data-type"); + }, + set: function (value) { + html.attr("data-type", value); + html.removeClass().addClass("message-popup message-popup-" + value); + html.find("b").removeClass().addClass("fa fa-" + iconMap[value] + (value === "loading" ? " fa-spin" : "")); + } + }, + "shown": { + get: function () { + return shown; + } + } + }); + this.content = content; + this.type = type; + + return this; + }; + + exports.MessagePopup = MessagePopup; + + exports.showMessagePopup = function (icon, content, options) { + options = $.extend({ closeAfter: 1000 }, options); + + var popup = new MessagePopup(icon, content, options); + popup.show(); + return popup; + }; + + exports.confirm = function (title, content, yes, no) { + //TODO 确认界面 + if (confirm(content)) + yes && yes(); + else no && no(); + }; + exports.alert = function (title, content, callback) { + //TODO 确认界面 + alert(content); + callback && callback(); + }; + + //捕捉一些通用的事件 + document.addEventListener("requestSupportError", function () { + exports.showMessagePopup("error", "无法执行网络请求,似乎没有安装12306订票助手哦。", { closeAfter: null }); + }); + +}); diff --git a/Web12306/js/ui/widget_verifycode.js b/Web12306/js/ui/widget_verifycode.js new file mode 100644 index 0000000..934313f --- /dev/null +++ b/Web12306/js/ui/widget_verifycode.js @@ -0,0 +1,45 @@ +define(function (require, exports, module) { + var ajax = require("../platform/webRequest.js"); + + exports.data = { + login: { + url: "passcodeNew/getPassCodeNew?module=login&rand=sjrand", + refer: "login/init" + }, + order: { + url: "", + refer: "" + } + }; + exports.autoLoad = function(target) { + if (target.is(".verify-code")) + exports.load(target); + else { + target.find(".verify-code").each(function() { exports.load($(this)); }); + } + }; + exports.load = function (target) { + var type = target.attr("data-target"); + var config = exports.data[type]; + var imageEle = target.find("span"); + + imageEle.css({ "background-image": "url(../../images/loading.gif", "background-size": "auto" }); + ajax.loadImage(config.url, config.refer, function (e) { + imageEle.css({ "background-image": "url(" + this.url + ")", "background-size": "100% 100%" }); + }, function () { + imageEle.css({ "background-image": "url(../../images/loading.gif", "background-size": "auto" }); + }); + }; + exports.refresh = function (target) { + if(target.is(".verify-code")) + exports.load(target); + else { + target.find(".verify-code").each(function() { exports.load($(this)); }); + } + }; + exports.init = function () { + $(document).on("click", ".verify-code span, .verify-code .refresh-vc", function () { + exports.load($(this).closest(".verify-code")); + }); + }; +}); \ No newline at end of file