feat: 会员中心 hgcloud 主题初始化 + drone 部署步骤
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- 解压官方默认主题 default_yfMBA.tar.gz 到 clientarea/hgcloud/ - .gitignore 排除压缩包和临时解压目录 - drone 新增步骤: 同步 hgcloud 到 /clientarea/template/pc/
This commit is contained in:
@@ -0,0 +1,423 @@
|
||||
const securityVerification = {
|
||||
template: `
|
||||
<div>
|
||||
|
||||
<el-dialog width="6rem" :visible.sync="securityVisible" @close="closeSecurityDialog" custom-class="security-dialog"
|
||||
:show-close="false">
|
||||
<div class="security-title">
|
||||
<span class="title-text">安全验证</span>
|
||||
<span class="close-btn" @click="closeSecurityDialog">
|
||||
<i class="el-icon-close"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="security-content">
|
||||
<el-form label-width="80px" ref="securityForm" :model="securityForm" label-position="top" :rules="currentRules">
|
||||
<el-form-item :label="lang.security_verify_text2" prop="method_id">
|
||||
<el-select v-model="securityForm.method_id" style="width: 100%;" @change="methodChange" :placeholder="lang.security_verify_text7">
|
||||
<el-option v-for="item in availableMethods" :key="item.value" :value="item.value" :label="item.label">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="calcCurrentMethod?.label" v-if="securityForm.method_id === 'phone_code'" prop="phone_code">
|
||||
<div style="display: flex; align-items: center;gap: 10px;">
|
||||
<el-input v-model="securityForm.phone_code" :placeholder="calcCurrentMethod?.tip">
|
||||
</el-input>
|
||||
<count-down-button ref="securityPhoneCodeBtnRef" :loading="phoneCodeLoading" @click.native="sendPhoneCode" my-class="code-btn" >
|
||||
</count-down-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="calcCurrentMethod?.label" v-if="securityForm.method_id === 'email_code'" prop="email_code">
|
||||
<div style="display: flex; align-items: center;gap: 10px;">
|
||||
<el-input v-model="securityForm.email_code" :placeholder="calcCurrentMethod?.tip">
|
||||
</el-input>
|
||||
<count-down-button ref="securityEmailCodeBtnRef" :loading="emailCodeLoading" @click.native="sendEmailCode" my-class="code-btn" >
|
||||
</count-down-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="calcCurrentMethod?.label" v-if="securityForm.method_id === 'operate_password'" prop="operate_password">
|
||||
<el-input v-model="securityForm.operate_password" :placeholder="calcCurrentMethod?.placeholder"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="calcCurrentMethod?.label" v-if="securityForm.method_id === 'certification'" prop="certification">
|
||||
<div class="realname-verify-box">
|
||||
<div ref="realnameVerifyRef" id="realnameVerify" style="display: flex; align-items: center; justify-content: center;"></div>
|
||||
<p style="text-align: center;margin-top: 10px;">{{calcCurrentMethod?.tip}}</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="security-footer">
|
||||
<el-button type="primary" @click="confirmSecurity" :loading="confirmSecurityLoading">{{lang.finance_btn8}}</el-button>
|
||||
<el-button type="info" class="cancel-btn" @click="closeSecurityDialog">{{lang.finance_btn7}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<captcha-dialog :is-show-captcha="isShowCaptcha" ref="securityCaptchaRef" captcha-id="security-captcha"
|
||||
@get-captcha-data="getData" @captcha-cancel="captchaCancel">
|
||||
</captcha-dialog>
|
||||
</div>
|
||||
|
||||
`,
|
||||
components: {
|
||||
captchaDialog,
|
||||
countDownButton,
|
||||
},
|
||||
props: {
|
||||
actionType: {
|
||||
type: String,
|
||||
default: "exception_login",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
commonData: {},
|
||||
phoneCodeLoading: false, // 手机验证码loading
|
||||
emailCodeLoading: false, // 邮箱验证码loading
|
||||
securityVisible: false, // 安全验证弹窗是否显示
|
||||
confirmSecurityLoading: false, // 确认按钮loading
|
||||
realnameStatus: false, // true通过 false未通过
|
||||
verifying: false, // 是否正在验证
|
||||
pollingTimer: null, // 轮询定时器
|
||||
pollingTimeout: null, // 轮询超时定时器
|
||||
securityForm: {
|
||||
method_id: "", // 验证方式
|
||||
phone_code: "", // 手机验证码
|
||||
email_code: "", // 邮箱验证码
|
||||
operate_password: "", // 操作密码
|
||||
certification: "", // 实名验证
|
||||
},
|
||||
callbackFun: "", // 回调函数名称
|
||||
availableMethods: [], // 可用验证方式
|
||||
certify_id: "", // 认证ID
|
||||
certify_url: "", // 认证URL
|
||||
isShowCaptcha: false, //登录是否显示验证码弹窗
|
||||
codeAction: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentRules() {
|
||||
const {method_id} = this.securityForm;
|
||||
const base = {
|
||||
method_id: [{required: true, message: lang.security_verify_text7}],
|
||||
};
|
||||
if (method_id === "phone_code") {
|
||||
base.phone_code = [
|
||||
{required: true, message: lang.security_verify_text8},
|
||||
];
|
||||
}
|
||||
if (method_id === "email_code") {
|
||||
base.email_code = [
|
||||
{required: true, message: lang.security_verify_text9},
|
||||
];
|
||||
}
|
||||
if (method_id === "operate_password") {
|
||||
base.operate_password = [
|
||||
{required: true, message: lang.security_verify_text10},
|
||||
];
|
||||
}
|
||||
if (method_id === "certification") {
|
||||
base.certification = [
|
||||
{required: true, message: lang.security_verify_text11},
|
||||
];
|
||||
}
|
||||
return base;
|
||||
},
|
||||
calcCurrentMethod() {
|
||||
return (
|
||||
this.availableMethods.find(
|
||||
(item) => item.value === this.securityForm.method_id
|
||||
) || {}
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @param {String} callbackFun 回调函数名称
|
||||
*/
|
||||
openDialog(callbackFun, availableMethods = []) {
|
||||
this.callbackFun = callbackFun;
|
||||
this.availableMethods = availableMethods;
|
||||
this.account = availableMethods[0]?.account || "";
|
||||
this.phone_code = availableMethods[0]?.phone_code || "";
|
||||
this.confirmSecurityLoading = false;
|
||||
this.securityForm = {
|
||||
method_id: availableMethods[0]?.value || "",
|
||||
phone_code: "",
|
||||
email_code: "",
|
||||
operate_password: "",
|
||||
certification: "",
|
||||
};
|
||||
this.stopPolling();
|
||||
this.realnameStatus = false; // 重置为未通过状态
|
||||
this.verifying = false; // 重置为未验证状态
|
||||
this.securityVisible = true; // 显示安全验证弹窗
|
||||
this.$nextTick(() => {
|
||||
this.methodChange(availableMethods[0]?.value || "");
|
||||
});
|
||||
},
|
||||
closeSecurityDialog() {
|
||||
this.$refs.securityForm.resetFields();
|
||||
if (this.$refs.realnameVerifyRef) {
|
||||
this.$refs.realnameVerifyRef.innerHTML = "";
|
||||
}
|
||||
this.securityVisible = false;
|
||||
this.stopPolling();
|
||||
},
|
||||
confirmSecurity() {
|
||||
this.$refs.securityForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.securityForm.method_id === "certification") {
|
||||
// 判断实名状态
|
||||
if (!this.realnameStatus) {
|
||||
this.$message.error(lang.security_verify_text11);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.confirmSecurityLoading = true;
|
||||
this.$emit("confirm", this.callbackFun, {
|
||||
security_verify_method: this.securityForm.method_id,
|
||||
security_verify_value:
|
||||
this.securityForm[this.securityForm.method_id],
|
||||
certify_id:
|
||||
this.securityForm.method_id === "certification"
|
||||
? this.certify_id
|
||||
: "",
|
||||
security_verify_token:
|
||||
this.calcCurrentMethod?.security_verify_token || "",
|
||||
});
|
||||
this.confirmSecurityLoading = false;
|
||||
this.closeSecurityDialog();
|
||||
}
|
||||
});
|
||||
},
|
||||
methodChange(value) {
|
||||
this.stopPolling();
|
||||
this.securityForm.phone_code = "";
|
||||
this.securityForm.email_code = "";
|
||||
this.securityForm.operate_password = "";
|
||||
this.securityForm.certification = "";
|
||||
this.account =
|
||||
this.availableMethods.find((item) => item.value === value)?.account ||
|
||||
"";
|
||||
this.phone_code =
|
||||
this.availableMethods.find((item) => item.value === value)
|
||||
?.phone_code || "";
|
||||
if (value === "certification") {
|
||||
this.$nextTick(async () => {
|
||||
try {
|
||||
const res = await apiCreateCertification({
|
||||
account: this.account,
|
||||
phone_code: this.phone_code,
|
||||
security_verify_token:
|
||||
this.calcCurrentMethod?.security_verify_token || "",
|
||||
});
|
||||
this.certify_id = res.data.data.certify_id;
|
||||
this.certify_url = res.data.data.certify_url;
|
||||
this.generateQRCode(this.certify_url);
|
||||
this.startPolling();
|
||||
} catch (error) {
|
||||
console.error("创建认证失败:", error);
|
||||
this.$message.error(error?.data?.msg || "创建认证失败,请重试");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
sendPhoneCode(isAuto = false) {
|
||||
if (this.phoneCodeLoading) return;
|
||||
if (isAuto !== true) {
|
||||
this.token = "";
|
||||
this.captcha = "";
|
||||
}
|
||||
if (
|
||||
this.commonData.captcha_client_security_verify == 1 &&
|
||||
!this.captcha
|
||||
) {
|
||||
this.codeAction = "phoneCode";
|
||||
this.isShowCaptcha = true;
|
||||
this.$refs.securityCaptchaRef.doGetCaptcha();
|
||||
return;
|
||||
}
|
||||
|
||||
this.phoneCodeLoading = true;
|
||||
const params = {
|
||||
action: this.actionType,
|
||||
phone_code: this.phone_code ?? undefined,
|
||||
phone: this.account ?? undefined,
|
||||
token: this.token,
|
||||
captcha: this.captcha,
|
||||
};
|
||||
phoneCode(params)
|
||||
.then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.phoneCodeLoading = false;
|
||||
// 执行倒计时
|
||||
this.$refs.securityPhoneCodeBtnRef.countDown();
|
||||
this.$message.success(res.data.msg);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.phoneCodeLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
sendEmailCode(isAuto = false) {
|
||||
if (this.emailCodeLoading) return;
|
||||
if (isAuto !== true) {
|
||||
this.token = "";
|
||||
this.captcha = "";
|
||||
}
|
||||
if (
|
||||
this.commonData.captcha_client_security_verify == 1 &&
|
||||
!this.captcha
|
||||
) {
|
||||
this.codeAction = "emailCode";
|
||||
this.isShowCaptcha = true;
|
||||
this.$refs.securityCaptchaRef.doGetCaptcha();
|
||||
return;
|
||||
}
|
||||
this.emailCodeLoading = true;
|
||||
const params = {
|
||||
action: this.actionType,
|
||||
email: this.account,
|
||||
token: this.token,
|
||||
captcha: this.captcha,
|
||||
};
|
||||
emailCode(params)
|
||||
.then((res) => {
|
||||
this.$message.success(res.data.msg);
|
||||
this.emailCodeLoading = false;
|
||||
this.$refs.securityEmailCodeBtnRef.countDown();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.emailCodeLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
|
||||
loadQRCodeLib() {
|
||||
return new Promise((resolve) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = `${url}js/common/qrcode.min.js`;
|
||||
script.onload = resolve;
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
},
|
||||
|
||||
// 生成二维码
|
||||
generateQRCode(url) {
|
||||
if (!url) return;
|
||||
|
||||
// 清空之前的二维码
|
||||
const container = this.$refs.realnameVerifyRef;
|
||||
if (container) {
|
||||
// 显示加载状态
|
||||
container.innerHTML =
|
||||
'<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #999;">生成中...</div>';
|
||||
|
||||
try {
|
||||
// 使用QRCode.js库生成二维码(需要确保已引入)
|
||||
if (typeof QRCode !== "undefined") {
|
||||
container.innerHTML = "";
|
||||
new QRCode(container, {
|
||||
text: url,
|
||||
width: 200,
|
||||
height: 200,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.M,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("二维码生成错误:", error);
|
||||
container.innerHTML =
|
||||
'<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #f56c6c;">二维码生成失败</div>';
|
||||
}
|
||||
}
|
||||
},
|
||||
// 开始轮询认证状态
|
||||
startPolling() {
|
||||
this.verifying = true;
|
||||
this.realnameStatus = false; // 重置为未通过状态
|
||||
// 清除之前的轮询
|
||||
if (this.pollingTimer) {
|
||||
clearInterval(this.pollingTimer);
|
||||
}
|
||||
// 开始轮询,每3秒检查一次
|
||||
this.pollingTimer = setInterval(async () => {
|
||||
try {
|
||||
const result = await apiGetCertificationStatus({
|
||||
certify_id: this.certify_id,
|
||||
account: this.account,
|
||||
phone_code: this.phone_code,
|
||||
security_verify_token:
|
||||
this.calcCurrentMethod?.security_verify_token || "",
|
||||
});
|
||||
|
||||
if (result?.data?.data?.verify_status === 1) {
|
||||
// 认证成功
|
||||
this.realnameStatus = true;
|
||||
this.verifying = false;
|
||||
this.stopPolling();
|
||||
this.securityForm.certification = this.certify_id;
|
||||
this.confirmSecurity();
|
||||
}
|
||||
} catch (error) {
|
||||
this.verifying = false;
|
||||
this.stopPolling();
|
||||
this.$message.error("认证状态检查失败");
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// 设置最大轮询时间(5分钟后自动停止)
|
||||
this.pollingTimeout = setTimeout(() => {
|
||||
if (this.pollingTimer) {
|
||||
this.stopPolling();
|
||||
this.verifying = false;
|
||||
this.realnameStatus = false;
|
||||
this.$message.warning("认证超时,请重试");
|
||||
}
|
||||
}, 300000);
|
||||
},
|
||||
|
||||
// 停止轮询
|
||||
stopPolling() {
|
||||
if (this.pollingTimer) {
|
||||
clearInterval(this.pollingTimer);
|
||||
this.pollingTimer = null;
|
||||
}
|
||||
if (this.pollingTimeout) {
|
||||
clearTimeout(this.pollingTimeout);
|
||||
this.pollingTimeout = null;
|
||||
}
|
||||
},
|
||||
|
||||
// 获取通用配置
|
||||
getCommonData() {
|
||||
this.commonData = JSON.parse(
|
||||
localStorage.getItem("common_set_before") || "{}"
|
||||
);
|
||||
},
|
||||
// 验证码验证成功后的回调
|
||||
getData(captchaCode, token) {
|
||||
this.isShowCaptcha = false;
|
||||
this.token = token;
|
||||
this.captcha = captchaCode;
|
||||
if (this.codeAction === "emailCode") {
|
||||
this.sendEmailCode(true);
|
||||
} else if (this.codeAction === "phoneCode") {
|
||||
this.sendPhoneCode(true);
|
||||
}
|
||||
},
|
||||
// 验证码 关闭
|
||||
captchaCancel() {
|
||||
this.isShowCaptcha = false;
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.getCommonData();
|
||||
await this.loadQRCodeLib();
|
||||
},
|
||||
// 组件销毁时清理定时器
|
||||
beforeDestroy() {
|
||||
this.stopPolling();
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user