|
|
@@ -24,10 +24,18 @@
|
|
|
position: fixed; top: 0; left: 0; right: 0; z-index: 50;
|
|
|
height: var(--bar-h); padding: 0 14px;
|
|
|
background: #3c8dbc; color: #fff;
|
|
|
- display: flex; align-items: center; justify-content: space-between;
|
|
|
+ display: flex; align-items: center; justify-content: center;
|
|
|
+ }
|
|
|
+ .bar h1 {
|
|
|
+ position: absolute; left: 0; right: 0;
|
|
|
+ margin: 0; font-size: 1.05rem; font-weight: 600;
|
|
|
+ text-align: center; pointer-events: none;
|
|
|
+ }
|
|
|
+ .bar a {
|
|
|
+ margin-left: auto; position: relative; z-index: 1;
|
|
|
+ color: #fff; text-decoration: none; font-size: 13px;
|
|
|
+ padding: 5px 10px; border: 1px solid rgba(255,255,255,.6); border-radius: 6px;
|
|
|
}
|
|
|
- .bar h1 { font-size: 1.05rem; margin: 0; font-weight: 600; }
|
|
|
- .bar a { color: #fff; text-decoration: none; font-size: 13px; padding: 5px 10px; border: 1px solid rgba(255,255,255,.6); border-radius: 6px; }
|
|
|
body.layout-orders .bar-logout { display: none !important; }
|
|
|
#pane-orders {
|
|
|
position: fixed; left: 0; right: 0; z-index: 10;
|
|
|
@@ -110,12 +118,39 @@
|
|
|
.me-row { font-size: 14px; line-height: 1.7; padding: 8px 0; border-bottom: 1px solid #f0f0f0; }
|
|
|
.me-row:last-child { border-bottom: none; }
|
|
|
.me-row span { display: inline-block; min-width: 4.5em; color: #888; }
|
|
|
- .btn-me-logout {
|
|
|
+ .btn-me-pwd {
|
|
|
display: block; width: 100%; margin-top: 16px; padding: 12px;
|
|
|
- border: 1px solid #e74c3c; border-radius: 8px; background: #fff;
|
|
|
- color: #e74c3c; font-size: 15px; font-weight: 600; text-align: center;
|
|
|
- text-decoration: none; font-family: inherit;
|
|
|
+ border: 1px solid #3c8dbc; border-radius: 8px; background: #fff;
|
|
|
+ color: #3c8dbc; font-size: 15px; font-weight: 600; text-align: center;
|
|
|
+ cursor: pointer; font-family: inherit;
|
|
|
}
|
|
|
+ .btn-me-pwd:active { opacity: .85; }
|
|
|
+ .pwd-mask {
|
|
|
+ display: none; position: fixed; inset: 0; z-index: 2100;
|
|
|
+ background: rgba(0,0,0,.45); align-items: center; justify-content: center;
|
|
|
+ padding: 24px 28px; padding-bottom: calc(24px + var(--safe-bottom));
|
|
|
+ }
|
|
|
+ .pwd-mask.show { display: flex; }
|
|
|
+ .pwd-sheet {
|
|
|
+ width: 100%; max-width: 360px; background: #fff; border-radius: 14px;
|
|
|
+ padding: 18px 18px 20px; box-shadow: 0 8px 32px rgba(0,0,0,.12);
|
|
|
+ }
|
|
|
+ .pwd-sheet .pwd-head { font-size: 16px; font-weight: 600; margin: 0 0 14px; color: #222; }
|
|
|
+ .pwd-field { margin-bottom: 14px; }
|
|
|
+ .pwd-field label { display: block; font-size: 13px; color: #666; margin-bottom: 6px; }
|
|
|
+ .pwd-field input {
|
|
|
+ width: 100%; padding: 11px 12px; border: 1px solid #ddd; border-radius: 8px;
|
|
|
+ font-size: 16px; font-family: inherit; box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .pwd-field input:focus { outline: none; border-color: #3c8dbc; }
|
|
|
+ .pwd-acts { display: flex; gap: 10px; margin-top: 18px; }
|
|
|
+ .pwd-acts button {
|
|
|
+ flex: 1; padding: 12px; border-radius: 8px; font-size: 15px; border: none;
|
|
|
+ cursor: pointer; font-family: inherit;
|
|
|
+ }
|
|
|
+ .pwd-acts .pwd-cancel { background: #f0f0f0; color: #555; }
|
|
|
+ .pwd-acts .pwd-ok { background: #3c8dbc; color: #fff; font-weight: 600; }
|
|
|
+ .pwd-acts .pwd-ok:disabled { opacity: .6; }
|
|
|
.tabbar {
|
|
|
position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
|
|
|
display: flex; background: #fff; border-top: 1px solid #e5e5e5;
|
|
|
@@ -279,7 +314,7 @@
|
|
|
<div class="me-row"><span>部门</span>{$mprocProfile.department|default=''|htmlentities}</div>
|
|
|
<div class="me-row"><span>手机号</span>{$mprocProfile.phone|default=''|htmlentities}</div>
|
|
|
<div class="me-row"><span>邮箱</span>{$mprocProfile.email|default=''|htmlentities}</div>
|
|
|
- <a class="btn-me-logout" href="{:url('index/index/logout')}">退出登录</a>
|
|
|
+ <button type="button" class="btn-me-pwd" id="btn-me-change-pwd">修改密码</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -289,6 +324,27 @@
|
|
|
</nav>
|
|
|
|
|
|
<div class="toast" id="toast"></div>
|
|
|
+<div class="pwd-mask" id="pwdMask" aria-hidden="true">
|
|
|
+ <div class="pwd-sheet" id="pwdSheet">
|
|
|
+ <p class="pwd-head">修改密码</p>
|
|
|
+ <div class="pwd-field">
|
|
|
+ <label for="inp-old-pwd">原密码</label>
|
|
|
+ <input type="password" id="inp-old-pwd" autocomplete="current-password" maxlength="20">
|
|
|
+ </div>
|
|
|
+ <div class="pwd-field">
|
|
|
+ <label for="inp-new-pwd">新密码</label>
|
|
|
+ <input type="password" id="inp-new-pwd" autocomplete="new-password" maxlength="20" placeholder="8~20位,须含字母和数字">
|
|
|
+ </div>
|
|
|
+ <div class="pwd-field">
|
|
|
+ <label for="inp-renew-pwd">确认新密码</label>
|
|
|
+ <input type="password" id="inp-renew-pwd" autocomplete="new-password" maxlength="20" placeholder="再次输入新密码">
|
|
|
+ </div>
|
|
|
+ <div class="pwd-acts">
|
|
|
+ <button type="button" class="pwd-cancel" id="pwdCancel">取消</button>
|
|
|
+ <button type="button" class="pwd-ok" id="pwdSave">确定</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
<div class="confirm-mask" id="scoreMask">
|
|
|
<div class="confirm-box">
|
|
|
<div class="confirm-box-body">
|
|
|
@@ -366,6 +422,7 @@
|
|
|
var saveUrl = "{:url('index/index/inboundscoresave')}";
|
|
|
var complaintUrl = "{:url('index/index/inboundscorecomplaint')}";
|
|
|
var loginUrl = "{:url('index/index/login')}";
|
|
|
+ var changePwdUrl = "{:url('index/index/mprocChangePwd')}";
|
|
|
var token = {:json_encode(isset($mprocBootstrapToken) ? $mprocBootstrapToken : '', JSON_UNESCAPED_UNICODE)};
|
|
|
var keepHours = {$mprocBootstrapKeepHours|default=72};
|
|
|
|
|
|
@@ -383,12 +440,129 @@
|
|
|
} catch (e) {}
|
|
|
}
|
|
|
|
|
|
- document.querySelectorAll('a.btn-me-logout, a.bar-logout').forEach(function (a) {
|
|
|
+ document.querySelectorAll('a.bar-logout').forEach(function (a) {
|
|
|
a.addEventListener('click', function () {
|
|
|
clearLocalLoginToken();
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ function passwordHasSequentialRun(pwd, runLen) {
|
|
|
+ runLen = runLen || 4;
|
|
|
+ var lower = String(pwd || '').toLowerCase();
|
|
|
+ var n = lower.length;
|
|
|
+ if (n < runLen) return false;
|
|
|
+ for (var i = 0; i <= n - runLen; i++) {
|
|
|
+ var asc = true, desc = true;
|
|
|
+ for (var j = 1; j < runLen; j++) {
|
|
|
+ var prev = lower.charCodeAt(i + j - 1);
|
|
|
+ var cur = lower.charCodeAt(i + j);
|
|
|
+ if (cur !== prev + 1) asc = false;
|
|
|
+ if (cur !== prev - 1) desc = false;
|
|
|
+ if (!asc && !desc) break;
|
|
|
+ }
|
|
|
+ if (asc || desc) return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ function validateStrongPassword(pwd) {
|
|
|
+ pwd = String(pwd || '');
|
|
|
+ if (pwd.length < 8 || pwd.length > 20) return '密码长度须为8~20位';
|
|
|
+ if (/\s/.test(pwd)) return '密码不能包含空格';
|
|
|
+ if (/^\d+$/.test(pwd)) return '密码不能为纯数字,请同时包含字母';
|
|
|
+ if (/^[a-zA-Z]+$/.test(pwd)) return '密码不能为纯字母,请同时包含数字';
|
|
|
+ if (!/[a-zA-Z]/.test(pwd) || !/\d/.test(pwd)) return '密码须同时包含字母和数字';
|
|
|
+ if (/(.)\1{3,}/.test(pwd)) return '密码不能包含过多重复字符(如1111、aaaa)';
|
|
|
+ if (passwordHasSequentialRun(pwd, 4)) return '密码不能包含连续字符(如1234、abcd)';
|
|
|
+ var weak = {
|
|
|
+ '12345678': 1, '123456789': 1, '1234567890': 1, '87654321': 1, '01234567': 1,
|
|
|
+ 'password': 1, 'password1': 1, 'passw0rd': 1, 'qwerty12': 1, 'qwertyui': 1,
|
|
|
+ 'abc12345': 1, 'abcd1234': 1, 'a1b2c3d4': 1, '11111111': 1, '00000000': 1,
|
|
|
+ '88888888': 1, '66666666': 1, '11223344': 1, '1qaz2wsx': 1, 'qazwsxed': 1
|
|
|
+ };
|
|
|
+ if (weak[pwd.toLowerCase()]) return '密码过于简单,请重新设置';
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ (function bindChangePwd() {
|
|
|
+ var pwdMask = document.getElementById('pwdMask');
|
|
|
+ var pwdSheet = document.getElementById('pwdSheet');
|
|
|
+ var btnMePwd = document.getElementById('btn-me-change-pwd');
|
|
|
+ var inpOldPwd = document.getElementById('inp-old-pwd');
|
|
|
+ var inpNewPwd = document.getElementById('inp-new-pwd');
|
|
|
+ var inpRenewPwd = document.getElementById('inp-renew-pwd');
|
|
|
+ var btnPwdSave = document.getElementById('pwdSave');
|
|
|
+ var btnPwdCancel = document.getElementById('pwdCancel');
|
|
|
+ function openPwdModal() {
|
|
|
+ if (inpOldPwd) inpOldPwd.value = '';
|
|
|
+ if (inpNewPwd) inpNewPwd.value = '';
|
|
|
+ if (inpRenewPwd) inpRenewPwd.value = '';
|
|
|
+ if (pwdMask) {
|
|
|
+ pwdMask.classList.add('show');
|
|
|
+ pwdMask.setAttribute('aria-hidden', 'false');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function closePwdModal() {
|
|
|
+ if (pwdMask) {
|
|
|
+ pwdMask.classList.remove('show');
|
|
|
+ pwdMask.setAttribute('aria-hidden', 'true');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (btnMePwd) btnMePwd.addEventListener('click', openPwdModal);
|
|
|
+ if (btnPwdCancel) btnPwdCancel.addEventListener('click', closePwdModal);
|
|
|
+ if (pwdMask) {
|
|
|
+ pwdMask.addEventListener('click', function (e) {
|
|
|
+ if (e.target === pwdMask) closePwdModal();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (pwdSheet) pwdSheet.addEventListener('click', function (e) { e.stopPropagation(); });
|
|
|
+ if (btnPwdSave) {
|
|
|
+ btnPwdSave.addEventListener('click', function () {
|
|
|
+ var oldP = inpOldPwd ? inpOldPwd.value : '';
|
|
|
+ var newP = inpNewPwd ? inpNewPwd.value : '';
|
|
|
+ var renP = inpRenewPwd ? inpRenewPwd.value : '';
|
|
|
+ if (!oldP || !newP || !renP) {
|
|
|
+ showToast('请填写完整', 'err');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var tip = validateStrongPassword(newP);
|
|
|
+ if (tip) {
|
|
|
+ showToast(tip, 'err');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (newP !== renP) {
|
|
|
+ showToast('两次输入的新密码不一致', 'err');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (oldP === newP) {
|
|
|
+ showToast('新密码不能与旧密码相同', 'err');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ btnPwdSave.disabled = true;
|
|
|
+ postForm(changePwdUrl, {
|
|
|
+ old_password: oldP,
|
|
|
+ new_password: newP,
|
|
|
+ renew_password: renP
|
|
|
+ }).then(function (ret) {
|
|
|
+ btnPwdSave.disabled = false;
|
|
|
+ if (ret && (ret.code === 1 || ret.code === '1')) {
|
|
|
+ closePwdModal();
|
|
|
+ clearLocalLoginToken();
|
|
|
+ showToast(ret.msg || '密码已修改,请重新登录', 'ok');
|
|
|
+ setTimeout(function () {
|
|
|
+ window.location.href = ret.url || loginUrl;
|
|
|
+ }, 900);
|
|
|
+ } else {
|
|
|
+ showToast((ret && ret.msg) ? ret.msg : '修改失败', 'err');
|
|
|
+ }
|
|
|
+ }).catch(function () {
|
|
|
+ btnPwdSave.disabled = false;
|
|
|
+ showToast('网络错误', 'err');
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })();
|
|
|
+
|
|
|
function showToast(msg, type) {
|
|
|
var el = document.getElementById('toast');
|
|
|
if (!el) return;
|