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:
38
clientarea/hgcloud/components/asideMenu/aliAsideMenu.js
Normal file
38
clientarea/hgcloud/components/asideMenu/aliAsideMenu.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// css 样式依赖common.css
|
||||
const aliAsideMenu = {
|
||||
template: ` <el-aside width="220px">
|
||||
<img class="ali-logo" :src="logo"></img>
|
||||
<div class="menu-list-top">
|
||||
<div class="menu-item" :class="item.id === menuActiveId ? 'menu-active':''" v-for="item in menu1" :key="item.id" @click="toPage(item)">
|
||||
<img :src="item.icon" class="item-img">
|
||||
<span class="item-text">{{item.text}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-aside>`,
|
||||
data() {
|
||||
return {
|
||||
activeId: 1,
|
||||
menu1: [
|
||||
{ icon: `${url}/img/common/menu1.png`, text: lang.menu_1, url: "./index.htm", id: 1 },
|
||||
{ icon: `${url}/img/common/menu2.png`, text: lang.menu_4, url: "./account.htm", id: 2 },
|
||||
],
|
||||
logo:`${url}/img/ali/logo.png`
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log(location.href);
|
||||
|
||||
},
|
||||
methods: {
|
||||
// 页面跳转
|
||||
toPage(e) {
|
||||
location.href = e.url
|
||||
},
|
||||
},
|
||||
props: {
|
||||
menuActiveId: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
},
|
||||
}
|
||||
304
clientarea/hgcloud/components/asideMenu/asideMenu.js
Normal file
304
clientarea/hgcloud/components/asideMenu/asideMenu.js
Normal file
@@ -0,0 +1,304 @@
|
||||
// css 样式依赖common.css
|
||||
const asideMenu = {
|
||||
template: `
|
||||
<el-aside width="190px">
|
||||
<a :href="commonData.clientarea_logo_url || '/home.htm'" onclick="return false" class="menu-alink">
|
||||
<img class="ali-logo" :src="logo" @click="goHome" v-show="logo"></img>
|
||||
</a>
|
||||
<el-menu class="menu-top" :default-active="menuActiveId" @select="handleSelect" background-color="transparent"
|
||||
text-color="var(--color-menu-text)" active-text-color="var(--color-menu-text-active)">
|
||||
<template v-for="(item,index) in menu1">
|
||||
<!-- 只有一级菜单 -->
|
||||
<template v-if="!item.child || item.child?.length === 0">
|
||||
<a :href="getMenuUrl(item.id || item.url)" onclick="return false" class="menu-alink">
|
||||
<el-menu-item :key="item.id ? item.id : item.url" :index="item.id ? item.id + '' : item.url">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<!-- 有二级菜单 -->
|
||||
<el-submenu v-else :key="item.id ? item.id : item.url" :index="item.id ? item.id + '' : item.url">
|
||||
<template slot="title">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</template>
|
||||
<template v-for="child in item.child">
|
||||
<a :href="getMenuUrl(child.id || child.url)" onclick="return false" class="menu-alink">
|
||||
<el-menu-item :index="child.id + ''" :key="child.id">
|
||||
{{child.name}}
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</template>
|
||||
</el-submenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
<div class="line" v-if="hasSeparate"></div>
|
||||
<el-menu class="menu-top" :default-active="menuActiveId" @select="handleSelect" background-color="transparent"
|
||||
text-color="var(--color-menu-text)" active-text-color="#FFF">
|
||||
<template v-for="(item,index) in menu2">
|
||||
<!-- 只有一级菜单 -->
|
||||
<template v-if="!item.child || item.child?.length === 0">
|
||||
<a :href="getMenuUrl(item.id || item.url)" onclick="return false" class="menu-alink">
|
||||
<el-menu-item :key="item.id ? item.id + '' : item.url" :index="item.id ? item.id + '' : item.url">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<!-- 有二级菜单 -->
|
||||
<el-submenu v-else :key="item.id ? item.id : item.url" :index="item.id ? item.id + '' : item.url">
|
||||
<template slot="title">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</template>
|
||||
<template v-for="child in item.child">
|
||||
<a :href="getMenuUrl(child.id || child.url)" onclick="return false" class="menu-alink">
|
||||
<el-menu-item :index="child.id + ''" :key="child.id">
|
||||
{{child.name}}
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</template>
|
||||
</el-submenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
|
||||
`,
|
||||
// 云服务器 当前
|
||||
// 物理服务器 dcim
|
||||
// 通用产品
|
||||
data() {
|
||||
return {
|
||||
activeId: 1,
|
||||
menu1: [],
|
||||
menu2: [],
|
||||
logo: "",
|
||||
menuActiveId: "",
|
||||
iconsData: [],
|
||||
commonData: {},
|
||||
noRepeat: [],
|
||||
hasSeparate: false,
|
||||
originMenu: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.doGetMenu();
|
||||
// const mainLoading = document.getElementById("mainLoading");
|
||||
// if (mainLoading) {
|
||||
// mainLoading.style.display = "none";
|
||||
// }
|
||||
// if (document.getElementsByClassName("template")[0]) {
|
||||
// document.getElementsByClassName("template")[0].style.display = "block";
|
||||
// }
|
||||
},
|
||||
created() {
|
||||
this.getCommonSetting();
|
||||
},
|
||||
beforeUpdate() {},
|
||||
mixins: [mixin],
|
||||
updated() {
|
||||
// // 关闭loading
|
||||
// document.getElementsByClassName('template')[0].style.display = 'block'
|
||||
const mainLoading = document.getElementById("mainLoading");
|
||||
if (mainLoading) {
|
||||
mainLoading.style.display = "none";
|
||||
}
|
||||
if (document.getElementsByClassName("template")[0]) {
|
||||
document.getElementsByClassName("template")[0].style.display = "block";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 页面跳转
|
||||
// toPage(e) {
|
||||
// // 获取 当前点击导航的id 存入本地
|
||||
// const id = e.id
|
||||
// localStorage.setItem('frontMenusActiveId', id)
|
||||
// // 跳转到对应路径
|
||||
// location.href = '/' + e.url
|
||||
// },
|
||||
// 获取通用配置
|
||||
async getCommonSetting() {
|
||||
try {
|
||||
const res = await getCommon();
|
||||
this.commonData = res.data.data;
|
||||
localStorage.setItem(
|
||||
"common_set_before",
|
||||
JSON.stringify(res.data.data)
|
||||
);
|
||||
this.logo = this.commonData.system_logo;
|
||||
} catch (error) {}
|
||||
},
|
||||
// 判断当前菜单激活
|
||||
setActiveMenu() {
|
||||
const originUrl = location.pathname.slice(1);
|
||||
const allUrl = originUrl + location.search;
|
||||
let flag = false;
|
||||
this.originMenu.forEach((item) => {
|
||||
// 当前url下存在和导航菜单对应的路径
|
||||
if (!item.child && item.url) {
|
||||
const url = String(item.url).split("?");
|
||||
if (
|
||||
(url.length > 1 && item.url == allUrl) ||
|
||||
(url.length == 1 && item.url == originUrl)
|
||||
) {
|
||||
this.menuActiveId = item.id + "";
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
// 当前url下存在二级菜单
|
||||
if (item.child && item.child.length > 0) {
|
||||
item.child.forEach((child) => {
|
||||
const url = String(child.url).split("?");
|
||||
if (
|
||||
(url.length > 1 && child.url == allUrl) ||
|
||||
(url.length == 1 && child.url == originUrl)
|
||||
) {
|
||||
this.menuActiveId = child.id + "";
|
||||
flag = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!flag) {
|
||||
this.menuActiveId = localStorage.getItem("frontMenusActiveId") || "";
|
||||
}
|
||||
},
|
||||
goHome() {
|
||||
localStorage.frontMenusActiveId = "";
|
||||
const openUrl = this.commonData.clientarea_logo_url || "/home.htm";
|
||||
if (this.commonData.clientarea_logo_url_blank == 1) {
|
||||
window.open(openUrl);
|
||||
} else {
|
||||
location.href = openUrl;
|
||||
}
|
||||
},
|
||||
|
||||
// 获取前台导航
|
||||
doGetMenu() {
|
||||
getMenu().then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
res.data.data.menu.forEach((item) => {
|
||||
if (item.child && item.child.length > 0) {
|
||||
this.originMenu.push(...item.child);
|
||||
} else {
|
||||
this.originMenu.push(item);
|
||||
}
|
||||
});
|
||||
const menu = res.data.data.menu;
|
||||
localStorage.setItem("frontMenus", JSON.stringify(menu));
|
||||
let index = menu.findIndex((item) => item.name == "分隔符");
|
||||
if (index != -1) {
|
||||
this.hasSeparate = true;
|
||||
this.menu1 = menu.slice(0, index);
|
||||
this.menu2 = menu.slice(index + 1);
|
||||
} else {
|
||||
this.hasSeparate = false;
|
||||
this.menu1 = menu;
|
||||
}
|
||||
|
||||
this.setActiveMenu();
|
||||
}
|
||||
});
|
||||
// 获取详情
|
||||
accountDetail()
|
||||
.then((res) => {
|
||||
if (res.data.status == 200) {
|
||||
let obj = res.data.data.account;
|
||||
let id = res.data.data.account.id;
|
||||
localStorage.setItem(
|
||||
"is_sub_account",
|
||||
obj.customfield?.is_sub_account
|
||||
);
|
||||
if (obj.customfield?.is_sub_account == 1) {
|
||||
// 子账户
|
||||
accountPermissions(id).then((relust) => {
|
||||
let rule = relust.data.data.rule;
|
||||
this.$emit("getruleslist", rule);
|
||||
});
|
||||
} else {
|
||||
// 主账户
|
||||
this.$emit("getruleslist", "all");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err, "err----->");
|
||||
});
|
||||
},
|
||||
arrFun(n) {
|
||||
for (var i = 0; i < n.length; i++) {
|
||||
//用typeof判断是否是数组
|
||||
if (n[i].child && typeof n[i].child == "object") {
|
||||
let obj = JSON.parse(JSON.stringify(n[i]));
|
||||
delete obj.child;
|
||||
this.noRepeat.push(obj);
|
||||
this.arrFun(n[i].child);
|
||||
} else {
|
||||
this.noRepeat.push(n[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* 获取菜单url
|
||||
* @param {Number} id 菜单id 或者url
|
||||
* @return {String} url 菜单url
|
||||
*/
|
||||
getMenuUrl(id) {
|
||||
const temp =
|
||||
this.originMenu.find((item) => item.id == id || item.url == id) || {};
|
||||
const reg =
|
||||
/^(((ht|f)tps?):\/\/)([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/;
|
||||
let url = "/" + temp.url;
|
||||
if (reg.test(temp.url)) {
|
||||
if (temp?.second_reminder === 1) {
|
||||
url = `/transfer.htm?target=${encodeURIComponent(temp.url)}`;
|
||||
} else {
|
||||
url = temp.url;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
handleSelect(id) {
|
||||
localStorage.setItem("frontMenusActiveId", id);
|
||||
const temp =
|
||||
this.originMenu.find((item) => item.id == id || item.url == id) || {};
|
||||
const reg =
|
||||
/^(((ht|f)tps?):\/\/)([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/;
|
||||
if (reg.test(temp.url)) {
|
||||
if (temp?.second_reminder === 1) {
|
||||
return window.open(
|
||||
`/transfer.htm?target=${encodeURIComponent(temp.url)}`
|
||||
);
|
||||
} else {
|
||||
return window.open(temp.url);
|
||||
}
|
||||
}
|
||||
location.href = "/" + temp.url;
|
||||
},
|
||||
getAllIcon() {
|
||||
let url = "/upload/common/iconfont/iconfont.json";
|
||||
let _this = this;
|
||||
|
||||
// 申明一个XMLHttpRequest
|
||||
let request = new XMLHttpRequest();
|
||||
// 设置请求方法与路径
|
||||
request.open("get", url);
|
||||
// 不发送数据到服务器
|
||||
request.send(null);
|
||||
//XHR对象获取到返回信息后执行
|
||||
request.onload = function () {
|
||||
// 解析获取到的数据
|
||||
let data = JSON.parse(request.responseText);
|
||||
_this.iconsData = data.glyphs;
|
||||
_this.iconsData.map((item) => {
|
||||
item.font_class = "icon-" + item.font_class;
|
||||
});
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
148
clientarea/hgcloud/components/autoRenew/autoRenew.js
Normal file
148
clientarea/hgcloud/components/autoRenew/autoRenew.js
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 自动续费 */
|
||||
const autoRenew = {
|
||||
template: `
|
||||
<div class="com-auto-renew">
|
||||
<el-switch :value="isAutoRenew" active-color="var(--color-primary)"
|
||||
:active-value="1" :inactive-value="0" @change="autoRenewChange">
|
||||
</el-switch>
|
||||
<el-dialog :visible.sync="showRenewDialog" :show-close="false" custom-class="common-renew-dialog"
|
||||
width="6.2rem">
|
||||
<div class="dialog-title">
|
||||
{{calcTitle}}
|
||||
</div>
|
||||
<div class="con" v-loading="loading">
|
||||
<p class="item">
|
||||
<span class="label">ID:</span>
|
||||
<span class="value">{{host.id}}</span>
|
||||
</p>
|
||||
<p class="item">
|
||||
<span class="label">{{lang.auto_renew_name}}:</span>
|
||||
<span class="value">{{host.name}}</span>
|
||||
</p>
|
||||
<p class="item" v-if="host.area">
|
||||
<span class="label">{{lang.auto_renew_area}}:</span>
|
||||
<span class="value">{{host.country}}-{{host.city}}-{{host.area}}</span>
|
||||
</p>
|
||||
<p class="item" v-if="host.dedicate_ip">
|
||||
<span class="label">IP:</span>
|
||||
<span class="value">
|
||||
<span>{{host.dedicate_ip}}</span>
|
||||
<el-popover placement="top" trigger="hover" v-if="host.ip_num > 1">
|
||||
<div class="ips">
|
||||
<p v-for="(item,index) in host.allIp" :key="index">
|
||||
{{item}}
|
||||
<i class="el-icon-document-copy base-color" @click="copyIp(item)"></i>
|
||||
</p>
|
||||
</div>
|
||||
<span slot="reference" class="base-color">
|
||||
({{host.ip_num}})
|
||||
</span>
|
||||
</el-popover>
|
||||
<i class="el-icon-document-copy base-color" @click="copyIp(host.allIp)" v-if="host.ip_num > 0">
|
||||
</i>
|
||||
</span>
|
||||
</p>
|
||||
<p class="item">
|
||||
<span class="label">{{lang.auto_renew_cycle}}:</span>
|
||||
<span class="value">{{commonData.currency_prefix}}{{host.renew_amount}}/{{host.billing_cycle_name}}</span>
|
||||
</p>
|
||||
<p class="item">
|
||||
<span class="label">{{lang.auto_renew_due}}:</span>
|
||||
<span class="value">{{host.due_time | formateTime}}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<el-button class="btn-ok" @click="handleAutoRenew" :loading="submitLoading">{{lang.auto_renew_sure}}</el-button>
|
||||
<el-button class="btn-no" @click="showRenewDialog = false">{{lang.auto_renew_cancel}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
showRenewDialog: false,
|
||||
submitLoading: false,
|
||||
calcTitle: "",
|
||||
is_auto_renew: 0,
|
||||
host: {},
|
||||
loading: false,
|
||||
commonData: JSON.parse(localStorage.getItem("common_set_before")) || {},
|
||||
};
|
||||
},
|
||||
props: {
|
||||
isAutoRenew: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
id: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
formateTime(time) {
|
||||
if (time && time !== 0) {
|
||||
return formateDate(time * 1000);
|
||||
} else {
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
copyIp(ip) {
|
||||
if (typeof ip !== "string") {
|
||||
ip = ip.join(",");
|
||||
}
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = ip.replace(/,/g, "\n");
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(textarea);
|
||||
this.$message.success(lang.index_text32);
|
||||
},
|
||||
async handleAutoRenew() {
|
||||
try {
|
||||
const params = {
|
||||
id: this.host.id,
|
||||
status: this.is_auto_renew,
|
||||
};
|
||||
this.submitLoading = true;
|
||||
const res = await rennewAuto(params);
|
||||
this.$message.success(res.data.msg);
|
||||
this.showRenewDialog = false;
|
||||
this.submitLoading = false;
|
||||
this.$emit("update");
|
||||
} catch (error) {
|
||||
this.submitLoading = false;
|
||||
this.showRenewDialog = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
async autoRenewChange(val) {
|
||||
try {
|
||||
this.showRenewDialog = true;
|
||||
this.is_auto_renew = val ? 1 : 0;
|
||||
this.loading = true;
|
||||
const res = await getHostSpecific({id: this.id});
|
||||
this.host = res.data.data;
|
||||
this.host.allIp = (
|
||||
this.host.dedicate_ip +
|
||||
"," +
|
||||
this.host.assign_ip
|
||||
).split(",");
|
||||
this.calcTitle =
|
||||
lang.auto_renew_tip1 +
|
||||
(this.isAutoRenew
|
||||
? lang_obj.auto_renew_tip3
|
||||
: lang_obj.auto_renew_tip2);
|
||||
this.loading = false;
|
||||
} catch (error) {
|
||||
this.loading = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
651
clientarea/hgcloud/components/batchRenewpage/batchRenewpage.js
Normal file
651
clientarea/hgcloud/components/batchRenewpage/batchRenewpage.js
Normal file
@@ -0,0 +1,651 @@
|
||||
const batchRenewpage = {
|
||||
template: /*html */ `
|
||||
<div class="batch-op-btn">
|
||||
|
||||
<div class="search-btn" style="margin-right: 0.1rem;" v-if="show_quick_order === 1">
|
||||
<a :href="quick_order_url" style="color: #fff; text-decoration: none;" target="_blank">{{lang.new_goods}}</a>
|
||||
</div>
|
||||
|
||||
|
||||
<el-dropdown split-button type="primary" @click="handleClick" @command="handleCommand" v-show="canOp">
|
||||
{{opName}}
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-for="item in opList" :key="item.value" :command="item.value">{{item.label}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-dialog width="5.5rem" :visible.sync="confirmDialog" :title="lang.cart_tip_text15 + opName + '?'" class="branch-confirm-dialog">
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="handelOp" :loading="subLoading">{{lang.cart_tip_text9}}</el-button>
|
||||
<el-button @click="confirmDialog = false;">{{lang.cart_tip_text10}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<el-dialog width="10rem" :visible.sync="isShow" @close="rzClose" class="branch-rennew-dialog">
|
||||
<div class="dialag-content" v-loading="loading">
|
||||
<h2 class="tips-title">{{title}}</h2>
|
||||
<el-table :data="dataList" style="width: 100%" max-height="600">
|
||||
<el-table-column prop="id" label="ID" width="120">
|
||||
</el-table-column>
|
||||
<el-table-column prop="product_name" :label="lang.cart_tip_text11" min-width="180"
|
||||
:show-overflow-tooltip="true">
|
||||
</el-table-column>
|
||||
<el-table-column prop="billing_cycles" :label="lang.cart_tip_text12" min-width="180">
|
||||
<template slot-scope="{row}">
|
||||
<el-select v-model="row.select_cycles" @change="(val) =>changeCycles(row)">
|
||||
<el-option v-for="(item,index) in row.billing_cycles" :key="index" :value="index" :label=" item.customfield?.multi_language?.billing_cycle || item.billing_cycle">
|
||||
<span>{{currency_prefix + item.price}} /{{ item.customfield?.multi_language?.billing_cycle || item.billing_cycle }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="base_price" :label="lang.cart_tip_text13" width="180" align="right">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{currency_prefix + row.cur_pirce}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="total-price">{{lang.template_text87}}:
|
||||
<span class="pay-money">{{currency_prefix }} <span
|
||||
class="font-26">{{ calcDiscountPrice }}</span> </span>
|
||||
</div>
|
||||
<div class="origin-price" v-if="hasDiscount && currentDiscount > 0">
|
||||
<span class="pay-money">{{currency_prefix }} <span
|
||||
class="font-26">{{ calcTotalPrice}}</span> </span>
|
||||
</div>
|
||||
<!-- 优惠码 -->
|
||||
<div class="batch-discount-popover">
|
||||
<el-popover placement="bottom" trigger="click" v-if="hasDiscount && !promo.promo_code " v-model="visibleShow"
|
||||
:visible-arrow="false">
|
||||
<div class="discount-content">
|
||||
<div class="close-btn-img" @click="closePopver">
|
||||
<img src="${url}/img/common/close_icon.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<el-input class="discount-input" clearable v-model="discountInputVal" :placeholder="lang.login_text10"
|
||||
maxlength="9"></el-input>
|
||||
<el-button class="discount-btn" :loading="isLoading"
|
||||
@click="handelApplyPromoCode">{{lang.shoppingCar_tip_text9}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="reference" class="discount-text">{{lang.shoppingCar_tip_text12}}</span>
|
||||
</el-popover>
|
||||
<div v-if="promo.promo_code && currentDiscount > 0" class="used">
|
||||
{{ promo.promo_code }}
|
||||
<i class="el-icon-circle-close remove-discountCode" @click="removeDiscountCode"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="handelRenew" :loading="subLoading">{{lang.cart_tip_text9}}</el-button>
|
||||
<el-button @click="rzClose">{{lang.cart_tip_text10}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<!-- 重置密码弹窗 -->
|
||||
<div class="branch-repass-dialog">
|
||||
<el-dialog width="6.8rem" :visible.sync="isShowRePass" :show-close=false @close="rePassDgClose">
|
||||
<div class="dialog-title">
|
||||
{{lang.cart_tip_text28}}
|
||||
</div>
|
||||
<div class="dialog-main">
|
||||
<el-input class="pass-input" v-model="rePassData.password" :placeholder="lang.account_tips47">
|
||||
<div class="pass-btn" slot="suffix" @click="autoPass">{{lang.common_cloud_btn1}}</div>
|
||||
</el-input>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<div class="btn-ok" @click="rePassSub" v-loading="subLoading">{{lang.cart_tip_text9}}</div>
|
||||
<div class="btn-no" @click="rePassDgClose">{{lang.cart_tip_text10}}</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!-- 修改备注弹窗 -->
|
||||
<div class="branch-repass-dialog">
|
||||
<el-dialog width="6.8rem" :visible.sync="isShowNote" :show-close=false>
|
||||
<div class="dialog-title">
|
||||
{{lang.cart_tip_text30}}
|
||||
</div>
|
||||
<div class="dialog-main">
|
||||
<el-input class="pass-input" v-model="notes" :placeholder="lang.cart_tip_text31"></el-input>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<div class="btn-ok" @click="handelNoteSub" v-loading="subLoading">{{lang.cart_tip_text9}}</div>
|
||||
<div class="btn-no" @click="isShowNote = false">{{lang.cart_tip_text10}}</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<pay-dialog ref="RennwPayDialog" @payok="paySuccess" @paycancel="payCancel"></pay-dialog>
|
||||
<safe-confirm ref="safeRef" :password.sync="client_operate_password" @confirm="hadelSafeConfirm"></safe-confirm>
|
||||
</div>
|
||||
|
||||
`,
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: lang.cart_tip_text7,
|
||||
},
|
||||
ids: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "", // using expiring // overdue // deleted // ""
|
||||
},
|
||||
moduleType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
payDialog,
|
||||
safeConfirm,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currency_prefix:
|
||||
(JSON.parse(localStorage.getItem("common_set_before")) || {})
|
||||
?.currency_prefix || "¥",
|
||||
isShow: false,
|
||||
loading: false,
|
||||
subLoading: false,
|
||||
confirmDialog: false,
|
||||
dataList: [],
|
||||
opType: "renew",
|
||||
client_operate_password: "",
|
||||
allOpList: [
|
||||
{
|
||||
value: "renew",
|
||||
label: lang.cart_tip_text7,
|
||||
},
|
||||
{
|
||||
value: "on",
|
||||
label: lang.cart_tip_text16,
|
||||
},
|
||||
{
|
||||
value: "off",
|
||||
label: lang.cart_tip_text17,
|
||||
},
|
||||
{
|
||||
value: "reboot",
|
||||
label: lang.cart_tip_text18,
|
||||
},
|
||||
{
|
||||
value: "hard_off",
|
||||
label: lang.cart_tip_text19,
|
||||
},
|
||||
{
|
||||
value: "hard_reboot",
|
||||
label: lang.cart_tip_text20,
|
||||
},
|
||||
],
|
||||
cloud_moudle: ["mf_cloud", "remf_cloud", "remf_finance", "rewhmcs_cloud"],
|
||||
dcim_moudle: [
|
||||
"mf_dcim",
|
||||
"remf_dcim",
|
||||
"remf_finance_dcim",
|
||||
"rewhmcs_dcim",
|
||||
],
|
||||
ip_moudle: ["mf_cloud_ip", "mf_cloud_disk", "huawei_eip"],
|
||||
common_moudle: ["idcsmart_common"],
|
||||
show_quick_order: 0,
|
||||
quick_order_url: "",
|
||||
isShowRePass: false,
|
||||
rePassData: {
|
||||
password: "",
|
||||
},
|
||||
promo: {
|
||||
promo_code: "",
|
||||
},
|
||||
visibleShow: false,
|
||||
discountInputVal: "",
|
||||
isLoading: false,
|
||||
currentDiscount: 0,
|
||||
batchHostDiscount: {}, // 批量使用优惠码过后的折扣
|
||||
notes: "",
|
||||
isShowNote: false,
|
||||
};
|
||||
},
|
||||
mixins: [mixin],
|
||||
created() {
|
||||
const addons = document.querySelector("#addons_js");
|
||||
const addons_js_arr = JSON.parse(addons.getAttribute("addons_js")).map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
this.hasDiscount = addons_js_arr.includes("PromoCode");
|
||||
this.setQuickOrderUrl();
|
||||
},
|
||||
computed: {
|
||||
canOp() {
|
||||
return this.tab !== "deleted";
|
||||
},
|
||||
opList() {
|
||||
const isActive =
|
||||
this.tab === "using" || this.tab === "expiring" || this.tab == "";
|
||||
const isCloud = this.cloud_moudle.includes(this.moduleType);
|
||||
const isDcim = this.dcim_moudle.includes(this.moduleType);
|
||||
const isIp = this.ip_moudle.includes(this.moduleType);
|
||||
const isCommon = this.common_moudle.includes(this.moduleType);
|
||||
if (!isActive) {
|
||||
return [
|
||||
{
|
||||
value: "renew",
|
||||
label: lang.cart_tip_text7,
|
||||
},
|
||||
];
|
||||
}
|
||||
if (isIp) {
|
||||
return [
|
||||
{
|
||||
value: "renew",
|
||||
label: lang.cart_tip_text7,
|
||||
},
|
||||
{
|
||||
value: "unlink",
|
||||
label: lang.cart_tip_text21,
|
||||
},
|
||||
{
|
||||
value: "note",
|
||||
label: lang.cart_tip_text30,
|
||||
},
|
||||
];
|
||||
} else if (isCloud) {
|
||||
return [...this.allOpList, {
|
||||
value: "note",
|
||||
label: lang.cart_tip_text30,
|
||||
},];
|
||||
} else if (isDcim) {
|
||||
return [
|
||||
{
|
||||
value: "renew",
|
||||
label: lang.cart_tip_text7,
|
||||
},
|
||||
{
|
||||
value: "on",
|
||||
label: lang.cart_tip_text16,
|
||||
},
|
||||
{
|
||||
value: "off",
|
||||
label: lang.cart_tip_text17,
|
||||
},
|
||||
{
|
||||
value: "reboot",
|
||||
label: lang.cart_tip_text18,
|
||||
},
|
||||
{
|
||||
value: "note",
|
||||
label: lang.cart_tip_text30,
|
||||
},
|
||||
];
|
||||
}
|
||||
if (isCommon) {
|
||||
return [
|
||||
...this.allOpList,
|
||||
{
|
||||
value: "crack_pass",
|
||||
label: lang.cart_tip_text27,
|
||||
},
|
||||
// {
|
||||
// value: "reinstall",
|
||||
// label: lang.cart_tip_text28,
|
||||
// },
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
value: "renew",
|
||||
label: lang.cart_tip_text7,
|
||||
},
|
||||
{
|
||||
value: "note",
|
||||
label: lang.cart_tip_text30,
|
||||
},
|
||||
];
|
||||
}
|
||||
},
|
||||
idsArr() {
|
||||
return this.ids.map((item) => {
|
||||
return item.id;
|
||||
});
|
||||
},
|
||||
rewIdArr() {
|
||||
return this.dataList.map((item) => {
|
||||
return item.id;
|
||||
});
|
||||
},
|
||||
calcTotalPrice() {
|
||||
return this.dataList
|
||||
.reduce((acc, cur) => {
|
||||
return acc + cur.cur_pirce * 1;
|
||||
}, 0)
|
||||
.toFixed(2);
|
||||
},
|
||||
// 折扣价钱计算方式
|
||||
calcDiscountPrice() {
|
||||
return (this.dataList
|
||||
.reduce((acc, cur) => {
|
||||
let temp = 0;
|
||||
// 折扣价 + 已减去的循环优惠的价格 - 批量使用优惠码的折扣
|
||||
if (this.batchHostDiscount[cur.id] * 1 > 0) {
|
||||
temp = cur.cur_pirce * 1 + cur.promo_code_discount * 1 - this.batchHostDiscount[cur.id] * 1;
|
||||
} else {
|
||||
temp = cur.cur_pirce * 1;
|
||||
}
|
||||
return acc + temp;
|
||||
}, 0))
|
||||
.toFixed(2);
|
||||
},
|
||||
opName() {
|
||||
return (
|
||||
this.opList.filter((item) => item.value === this.opType)[0]?.label ||
|
||||
lang.cart_tip_text22
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
opList(val) {
|
||||
this.opType = val[0].value || "";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
removeDiscountCode() {
|
||||
this.discountInputVal = "";
|
||||
this.promo.promo_code = "";
|
||||
this.currentDiscount = 0;
|
||||
this.batchHostDiscount = {};
|
||||
},
|
||||
async handelApplyPromoCode(bol = true) {
|
||||
try {
|
||||
if (this.discountInputVal.length === 0) {
|
||||
if (bol) {
|
||||
this.$message.warning(lang.shoppingCar_tip_text13);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// this.isLoading = true;
|
||||
let discountArr = [];
|
||||
this.dataList.forEach(item => {
|
||||
const params = {
|
||||
host_id: item.id,
|
||||
product_id: item.product_id,
|
||||
amount: item.billing_cycles[item.select_cycles].base_price,
|
||||
billing_cycle_time: item.billing_cycles[item.select_cycles].duration,
|
||||
promo_code: this.discountInputVal,
|
||||
scene: "renew"
|
||||
};
|
||||
discountArr.push(params);
|
||||
});
|
||||
const res = await applyBatchRenewCode({ promo_codes: discountArr });
|
||||
this.promo.promo_code = this.discountInputVal;
|
||||
this.currentDiscount = res.data.data.discount;
|
||||
this.batchHostDiscount = res.data.data.host_discount;
|
||||
if (this.currentDiscount * 1 > 0) {
|
||||
this.$message.success(res.data.msg);
|
||||
} else {
|
||||
this.removeDiscountCode();
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
closePopver() {
|
||||
this.visibleShow = false;
|
||||
this.discountInputVal = "";
|
||||
},
|
||||
setQuickOrderUrl() {
|
||||
// 拿到当前导航完整路径 去除location.origin
|
||||
this.currentNav = location.href.replace(location.origin, "");
|
||||
const params = getUrlParams();
|
||||
let currentMenu;
|
||||
const menuList = JSON.parse(localStorage.getItem("frontMenus") || "[]");
|
||||
let isFindById = false;
|
||||
// 找到当前导航
|
||||
// 有id直接使用id
|
||||
if (params.m) {
|
||||
currentMenu = menuList.find(
|
||||
(item) =>
|
||||
item.id == params.m || item?.child?.some((el) => el.id == params.m)
|
||||
);
|
||||
isFindById = true;
|
||||
}
|
||||
if (!currentMenu) {
|
||||
currentMenu = menuList.find(
|
||||
(item) =>
|
||||
(item.url !== "" && this.currentNav.includes(item.url)) ||
|
||||
item?.child?.some(
|
||||
(el) => el.url !== "" && this.currentNav.includes(el.url)
|
||||
)
|
||||
);
|
||||
isFindById = false;
|
||||
}
|
||||
if (currentMenu?.child) {
|
||||
if (isFindById) {
|
||||
currentMenu = currentMenu?.child?.find((el) => el.id == params.m);
|
||||
} else {
|
||||
currentMenu = currentMenu.child.find(
|
||||
(el) => el.url !== "" && this.currentNav.includes(el.url)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMenu) {
|
||||
this.show_quick_order = currentMenu?.show_quick_order;
|
||||
this.quick_order_url = currentMenu?.quick_order_url;
|
||||
}
|
||||
},
|
||||
// 随机生成密码
|
||||
autoPass() {
|
||||
let passLen = 9;
|
||||
let pass =
|
||||
randomCoding(1) +
|
||||
randomCoding(1).toLocaleLowerCase() +
|
||||
0 +
|
||||
genEnCode(passLen, 1, 1, 0, 1, 0);
|
||||
this.rePassData.password = pass;
|
||||
},
|
||||
rePassSub() {
|
||||
if (!this.rePassData.password) {
|
||||
this.$message.error(lang.cart_tip_text29);
|
||||
return;
|
||||
}
|
||||
this.handelOp();
|
||||
},
|
||||
rePassDgClose() {
|
||||
this.isShowRePass = false;
|
||||
this.rePassData.password = "";
|
||||
},
|
||||
hadelSafeConfirm(val) {
|
||||
this[val]();
|
||||
},
|
||||
handleCommand(command) {
|
||||
this.opType = command;
|
||||
this.handleClick();
|
||||
},
|
||||
handleClick() {
|
||||
if (this.opType === "") {
|
||||
this.$message.warning(lang.cart_tip_text23);
|
||||
return;
|
||||
}
|
||||
if (this.idsArr.length === 0) {
|
||||
this.$message.warning(lang.cart_tip_text24);
|
||||
return;
|
||||
}
|
||||
if (this.opType === "renew") {
|
||||
this.openDia();
|
||||
return;
|
||||
}
|
||||
if (this.opType === "crack_pass") {
|
||||
this.isShowRePass = true;
|
||||
return;
|
||||
}
|
||||
if (this.opType === "note") {
|
||||
this.openNoteDia();
|
||||
return;
|
||||
}
|
||||
this.confirmDialog = true;
|
||||
},
|
||||
handelNoteSub() {
|
||||
this.subLoading = true;
|
||||
apiBatchUpdateHostNotes({ ids: this.idsArr, notes: this.notes })
|
||||
.then((res) => {
|
||||
this.$message.success(res.data.msg);
|
||||
this.subLoading = false;
|
||||
this.isShowNote = false;
|
||||
this.$emit("success");
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
this.subLoading = false;
|
||||
});
|
||||
},
|
||||
openNoteDia() {
|
||||
this.notes = "";
|
||||
this.isShowNote = true;
|
||||
},
|
||||
handelOp(e, remember_operate_password = 0) {
|
||||
// if (!this.client_operate_password) {
|
||||
// this.$refs.safeRef.openDialog("handelOp");
|
||||
// return;
|
||||
// }
|
||||
const client_operate_password = this.client_operate_password;
|
||||
this.client_operate_password = "";
|
||||
this.subLoading = true;
|
||||
const params = {
|
||||
id: this.idsArr,
|
||||
action: this.opType,
|
||||
client_operate_password,
|
||||
client_operate_methods: "handelOp",
|
||||
remember_operate_password,
|
||||
};
|
||||
if (this.opType === "crack_pass") {
|
||||
params.password = this.rePassData.password;
|
||||
}
|
||||
batchOperation(this.moduleType, params)
|
||||
.then((res) => {
|
||||
const arr = res.data.data;
|
||||
const tips = arr
|
||||
.map((item) => {
|
||||
return `<p>ID:${item.id}:${item.msg}</p>`;
|
||||
})
|
||||
.join("");
|
||||
this.$notify({
|
||||
title: lang.cart_tip_text25,
|
||||
message: tips,
|
||||
duration: 0,
|
||||
dangerouslyUseHTMLString: true,
|
||||
});
|
||||
this.$emit("success");
|
||||
this.subLoading = false;
|
||||
this.confirmDialog = false;
|
||||
|
||||
if (this.opType === "crack_pass") {
|
||||
this.isShowRePass = false;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.subLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
if (err.data.data) {
|
||||
if (
|
||||
!client_operate_password &&
|
||||
err.data.data.operate_password === 1
|
||||
) {
|
||||
this.$refs.safeRef.openDialog("handelOp");
|
||||
return;
|
||||
} else {
|
||||
return this.$message.error(err.data.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
openDia() {
|
||||
this.promo.promo_code = "";
|
||||
this.discountInputVal = "";
|
||||
this.currentDiscount = 0;
|
||||
this.batchHostDiscount = {};
|
||||
this.isShow = true;
|
||||
this.getRenewList();
|
||||
},
|
||||
changeCycles(item) {
|
||||
this.discountInputVal = this.promo.promo_code;
|
||||
this.handelApplyPromoCode(false);
|
||||
item.cur_pirce = this.calcPrice(item);
|
||||
item.promo_code_discount = this.calcPrice(item, true);
|
||||
},
|
||||
calcPrice(row, bol = false) {
|
||||
let temp = 'price';
|
||||
if (bol) {
|
||||
temp = 'promo_code_discount';
|
||||
}
|
||||
return (
|
||||
row.billing_cycles.filter(
|
||||
(item, index) => index == row.select_cycles
|
||||
)[0]?.[temp] || 0
|
||||
);
|
||||
},
|
||||
getRenewList() {
|
||||
this.loading = true;
|
||||
batchRenewList({ ids: this.idsArr })
|
||||
.then((res) => {
|
||||
this.dataList = res.data.data.list.map((item) => {
|
||||
item.select_cycles = 0;
|
||||
item.cur_pirce = item.billing_cycles[0].price;
|
||||
item.promo_code_discount = item.billing_cycles[0].promo_code_discount || 0;
|
||||
return item;
|
||||
});
|
||||
this.loading = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.loading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
rzClose() {
|
||||
this.isShow = false;
|
||||
},
|
||||
paySuccess(e) {
|
||||
this.isShow = false;
|
||||
this.$emit("success");
|
||||
},
|
||||
// 取消支付回调
|
||||
payCancel(e) { },
|
||||
handelRenew() {
|
||||
this.subLoading = true;
|
||||
const billing_cycles = {};
|
||||
this.dataList.forEach((item) => {
|
||||
billing_cycles[item.id] = item.billing_cycles.filter(
|
||||
(items, index) => index == item.select_cycles
|
||||
)[0].billing_cycle;
|
||||
});
|
||||
aipBatchRenew({
|
||||
ids: this.rewIdArr,
|
||||
billing_cycles,
|
||||
customfield: {
|
||||
promo_code: this.promo.promo_code,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
this.subLoading = false;
|
||||
if (res.data.code === "Unpaid") {
|
||||
this.$refs.RennwPayDialog.showPayDialog(res.data.data.id);
|
||||
} else {
|
||||
this.isShow = false;
|
||||
this.$emit("success");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.subLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
116
clientarea/hgcloud/components/captchaDialog/captchaDialog.js
Normal file
116
clientarea/hgcloud/components/captchaDialog/captchaDialog.js
Normal file
@@ -0,0 +1,116 @@
|
||||
// 验证码通过 - 找到当前显示的验证码实例
|
||||
function captchaCheckSuccsss(bol, captcha, token) {
|
||||
if (bol) {
|
||||
// 遍历所有注册的验证码实例,找到 DOM 中存在的那个(v-if 确保存在即可见)
|
||||
if (window.captchaInstances) {
|
||||
for (let captchaId in window.captchaInstances) {
|
||||
const element = document.getElementById(captchaId);
|
||||
// v-if 保证:元素存在 = 元素可见
|
||||
if (element) {
|
||||
const instance = window.captchaInstances[captchaId];
|
||||
if (instance && instance.getData) {
|
||||
instance.getData(captcha, token);
|
||||
break; // 找到就退出循环
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 取消验证码验证 - 找到当前显示的验证码实例
|
||||
function captchaCheckCancel() {
|
||||
if (window.captchaInstances) {
|
||||
for (let captchaId in window.captchaInstances) {
|
||||
const element = document.getElementById(captchaId);
|
||||
// v-if 保证:元素存在 = 元素可见
|
||||
if (element) {
|
||||
const instance = window.captchaInstances[captchaId];
|
||||
if (instance && instance.captchaCancel) {
|
||||
instance.captchaCancel();
|
||||
break; // 找到就退出循环
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// css 样式依赖common.css
|
||||
const captchaDialog = {
|
||||
template: `
|
||||
<div :id="captchaId" v-if="isShowCaptcha"></div>`,
|
||||
created() {
|
||||
// this.doGetCaptcha()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
captchaData: {
|
||||
token: "",
|
||||
captcha: "",
|
||||
},
|
||||
captchaHtml: "",
|
||||
};
|
||||
},
|
||||
props: {
|
||||
isShowCaptcha: {
|
||||
type: Boolean,
|
||||
},
|
||||
captchaId: {
|
||||
type: String,
|
||||
default() {
|
||||
// 生成唯一 ID,避免多实例冲突
|
||||
return `captchaHtml_${Date.now()}_${Math.random()
|
||||
.toString(36)
|
||||
.slice(2, 11)}`;
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 获取图形验证码
|
||||
doGetCaptcha() {
|
||||
try {
|
||||
getNewCaptcha().then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.captchaHtml = res.data.data.html;
|
||||
$(`#${this.captchaId}`).html(this.captchaHtml);
|
||||
$(`#${this.captchaId}`).show();
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("获取图形验证码", e);
|
||||
}
|
||||
},
|
||||
// 取消验证码
|
||||
captchaCancel() {
|
||||
this.$emit("captcha-cancel");
|
||||
},
|
||||
// 获取验证码数据
|
||||
getData(captchaCode, token) {
|
||||
this.captchaData.captcha = captchaCode;
|
||||
this.captchaData.token = token;
|
||||
this.$emit("get-captcha-data", captchaCode, token);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 创建全局实例映射对象
|
||||
if (!window.captchaInstances) {
|
||||
window.captchaInstances = {};
|
||||
}
|
||||
|
||||
// 将当前实例注册到全局映射表中,使用箭头函数保持 this 指向
|
||||
window.captchaInstances[this.captchaId] = {
|
||||
getData: (captchaCode, token) => {
|
||||
this.getData(captchaCode, token);
|
||||
},
|
||||
captchaCancel: () => {
|
||||
this.captchaCancel();
|
||||
},
|
||||
};
|
||||
},
|
||||
// 组件销毁时清理对应的实例引用
|
||||
beforeDestroy() {
|
||||
if (window.captchaInstances && window.captchaInstances[this.captchaId]) {
|
||||
delete window.captchaInstances[this.captchaId];
|
||||
}
|
||||
},
|
||||
};
|
||||
104
clientarea/hgcloud/components/cashBack/cashBack.js
Normal file
104
clientarea/hgcloud/components/cashBack/cashBack.js
Normal file
@@ -0,0 +1,104 @@
|
||||
const cashBack = {
|
||||
template: `
|
||||
<el-dialog :visible.sync="showCash" :show-close="false" custom-class="common-cashback-dialog">
|
||||
<div class="dialog-title">
|
||||
{{lang.apply_cashback}}
|
||||
</div>
|
||||
<div class="con">
|
||||
{{lang.cashback_tip1}}<span class="price">{{currency_prefix}}{{cashbackPrice | filterMoney}}</span>
|
||||
<template v-if="cashbackTime">,{{lang.cashback_tip2}} {{cashbackTime | formateTime}}</template>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<div class="tip">{{lang.cashback_tip}}</div>
|
||||
<div class="opt">
|
||||
<el-button class="btn-ok" @click="sureCashback" :loading="cashLoading">{{lang.ticket_btn6}}</el-button>
|
||||
<el-button class="btn-no" @click="cancleDialog">{{lang.finance_btn7}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
`,
|
||||
filters: {
|
||||
filterMoney(money) {
|
||||
if (isNaN(money)) {
|
||||
return "0.00";
|
||||
} else {
|
||||
const temp = `${money}`.split(".");
|
||||
return parseInt(temp[0]).toLocaleString() + "." + (temp[1] || "00");
|
||||
}
|
||||
},
|
||||
formateTime(time) {
|
||||
if (time && time !== 0) {
|
||||
return formateDate(time * 1000);
|
||||
} else {
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasCash: false, // 是否安装了插件
|
||||
isShowBtn: false, // 是否展示申请返现按钮
|
||||
cashbackPrice: null,
|
||||
cashbackTime: null,
|
||||
cashLoading: false,
|
||||
currency_prefix: (localStorage.common_set_before && JSON.parse(localStorage.common_set_before)?.currency_prefix) || "¥",
|
||||
};
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
},
|
||||
showCash: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
mixins: [mixin],
|
||||
mounted() {
|
||||
this.hasCash = this.addons_js_arr.includes("ProductCashback");
|
||||
this.hasCash && this.getCash();
|
||||
},
|
||||
created() { },
|
||||
methods: {
|
||||
async getCash() {
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
data: { cashback_support, is_cashback, expired, price },
|
||||
},
|
||||
} = await getCashbackInfo({ id: this.id });
|
||||
if (
|
||||
cashback_support &&
|
||||
!is_cashback &&
|
||||
price * 1 &&
|
||||
(expired > new Date().getTime() / 1000 || expired === 0)
|
||||
) {
|
||||
this.cashbackPrice = price;
|
||||
this.cashbackTime = expired;
|
||||
this.isShowBtn = true;
|
||||
} else {
|
||||
this.isShowBtn = false;
|
||||
}
|
||||
this.$emit("showbtn", this.isShowBtn);
|
||||
} catch (error) {
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
async sureCashback() {
|
||||
try {
|
||||
this.cashLoading = true;
|
||||
const res = await apllyCashback({ id: this.id });
|
||||
this.$message.success(res.data.msg);
|
||||
this.getCash();
|
||||
this.cashLoading = false;
|
||||
this.$emit("cancledialog", false);
|
||||
} catch (error) {
|
||||
this.cashLoading = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
cancleDialog() {
|
||||
this.$emit("cancledialog", false);
|
||||
},
|
||||
},
|
||||
};
|
||||
84
clientarea/hgcloud/components/cashCoupon/cashCoupon.js
Normal file
84
clientarea/hgcloud/components/cashCoupon/cashCoupon.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const cashCoupon = {
|
||||
template: `
|
||||
<div>
|
||||
<el-popover placement="bottom" trigger="click" v-model="visibleShow" class="discount-popover" @show="popSow" :visible-arrow="false">
|
||||
<div class="discount-content">
|
||||
<div class="close-btn-img" @click="closePopver">
|
||||
<img src="${url}/img/common/close_icon.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<el-select class="discount-input" v-model="value" clearable :placeholder="lang.shoppingCar_tip_text8" value-key="id">
|
||||
<el-option v-for="item in options" :key="item.id" :label=" item.code + '--' + currency_prefix + item.price " :value="item"></el-option>
|
||||
</el-select>
|
||||
<el-button class="discount-btn" @click="handelApplyPromoCode">{{lang.shoppingCar_tip_text9}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="reference" class="cash-code">{{lang.shoppingCar_tip_text10}}</span>
|
||||
</el-popover>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
visibleShow: false, // 是否显示代金券弹窗
|
||||
isLoading: false, // 确认按钮loading
|
||||
value: {}, // 选择的对象
|
||||
options: [], // 代金券数组
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
scene: {
|
||||
type: String, // new新购,renew续费,upgrade升降级
|
||||
required: true,
|
||||
},
|
||||
product_id: {
|
||||
type: Array, // 场景中的所有商品ID
|
||||
required: true,
|
||||
},
|
||||
price: {
|
||||
type: Number | String, // 需要支付的原价格
|
||||
required: true,
|
||||
},
|
||||
currency_prefix: {
|
||||
type: String,
|
||||
default:
|
||||
(localStorage.common_set_before &&
|
||||
JSON.parse(localStorage.common_set_before)?.currency_prefix) ||
|
||||
"¥",
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
closePopver() {
|
||||
this.visibleShow = false;
|
||||
this.value = {};
|
||||
},
|
||||
handelApplyPromoCode() {
|
||||
if (!this.value.id) {
|
||||
this.$message.warning(lang.shoppingCar_tip_text11);
|
||||
return;
|
||||
}
|
||||
this.$emit("use-cash", this.value);
|
||||
this.visibleShow = false;
|
||||
},
|
||||
popSow() {
|
||||
const params = {
|
||||
scene: this.scene,
|
||||
product_id: this.product_id,
|
||||
price: Number(this.price),
|
||||
};
|
||||
this.getEnableList(params);
|
||||
},
|
||||
getEnableList(params) {
|
||||
enableList(params)
|
||||
.then((res) => {
|
||||
this.options = res.data.data.list;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
})
|
||||
.finally(() => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
const certificationDialog = {
|
||||
template: `
|
||||
<!-- 未实名认证 dialog -->
|
||||
<div class="rz-dialog">
|
||||
<el-dialog width="10rem" :visible.sync="isShow" @close="rzClose">
|
||||
<div class="dialag-content">
|
||||
<h2 class="tips-title">您尚未进行实名认证,请先完成实名认证</h2>
|
||||
<p class="tips-text">据我国2016年11月7日全国人民代表大会常务委员会通过的《中华人民共和国网络安全法》规定,用户不提供真实身份信息的,网络运营者不得为其提供相关服务。 为了符合国家法律法规,以及不影响您参与优惠活动,请您先实名认证。实名认证信息保密工作是统一管理,请放心填写。</p>
|
||||
<div class="button-box">
|
||||
<el-button @click="goCertification">立即认证</el-button>
|
||||
<el-link @click ="rzClose()">以后再说</el-link>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rzClose() {
|
||||
this.isShow = false
|
||||
},
|
||||
goCertification() {
|
||||
location.href = `plugin/${getPluginId("IdcsmartCertification")}/authentication_select.htm`;
|
||||
},
|
||||
|
||||
},
|
||||
watch: {}
|
||||
}
|
||||
128
clientarea/hgcloud/components/coinActive/coinActive.css
Normal file
128
clientarea/hgcloud/components/coinActive/coinActive.css
Normal file
@@ -0,0 +1,128 @@
|
||||
.coin-active-popover {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.coin-active-btn {
|
||||
position: fixed;
|
||||
right: 3px;
|
||||
top: 35vh;
|
||||
z-index: 99;
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 5px;
|
||||
border-radius: 99px;
|
||||
color: #fff;
|
||||
background: var(--color-primary);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 8px rgba(26, 97, 214, 0.2);
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 16px rgba(26, 97, 214, 0.4);
|
||||
/* 由于@primary-color是CSS变量,less的lighten函数无法直接处理,改为使用filter实现亮色效果 */
|
||||
background: var(--color-primary);
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger:hover .trigger-icon {
|
||||
transform: rotate(5deg);
|
||||
background-color: #f8f9ff;
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger:hover .trigger-text {
|
||||
letter-spacing: 6px;
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger .trigger-icon {
|
||||
font-size: 0;
|
||||
padding: 7px;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger .trigger-icon .icon-svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.coin-active-btn .coin-active-trigger .trigger-text {
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
letter-spacing: 5px;
|
||||
font-size: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.coin-active-box .coin-title {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #2B2B2B;
|
||||
border-bottom: 1px solid #EAEAEA;
|
||||
}
|
||||
.coin-active-box .coin-active-tabs .el-tabs__nav-wrap {
|
||||
padding-left: 24px;
|
||||
}
|
||||
.coin-active-box .coin-list {
|
||||
padding: 0 24px;
|
||||
max-height: 5rem;
|
||||
overflow-y: auto;
|
||||
width: 5rem;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item {
|
||||
box-sizing: border-box;
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px dashed #EAEAEA;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item:nth-last-of-type(1) {
|
||||
border-bottom: none;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-icon {
|
||||
border-radius: 50%;
|
||||
background-color: #F3F3F3;
|
||||
padding: 11px;
|
||||
font-size: 0;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-icon .item-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content {
|
||||
flex: 1;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-content-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 0.3rem;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-content-top .coin-item-content-title-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #2B2B2B;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-content-top .coin-item-content-time {
|
||||
font-size: 12px;
|
||||
color: #A2A2A2;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-content-desc {
|
||||
text-align: right;
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-detail .coin-detail-active-limit,
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-detail .coin-detail-use-limit {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #2B2B2B;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.coin-active-box .coin-list .coin-list-item .coin-item-content .coin-item-detail .coin-detail-use-limit {
|
||||
margin-top: 10px;
|
||||
}
|
||||
467
clientarea/hgcloud/components/coinActive/coinActive.js
Normal file
467
clientarea/hgcloud/components/coinActive/coinActive.js
Normal file
@@ -0,0 +1,467 @@
|
||||
const coinActive = {
|
||||
template: /* html*/ `
|
||||
<el-popover placement="left-start" v-model="active_show" trigger="click" popper-class="coin-active-popover"
|
||||
@show="visbleShow" v-if="home_show_coin_activity == 1">
|
||||
<div class="coin-active-btn" slot="reference">
|
||||
<div class="coin-active-trigger" role="button" :aria-label="lang.coin_text71 + coin_name">
|
||||
<div class="trigger-icon" aria-hidden="true">
|
||||
<svg class="icon-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none"
|
||||
version="1.1" width="16" height="16" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<clipPath id="master_svg0_783_42616">
|
||||
<rect x="0" y="0" width="16" height="16" rx="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#master_svg0_783_42616)">
|
||||
<g>
|
||||
<path
|
||||
d="M13.6663418125,13.347250952929688L13.6663418125,6.6666717529296875L2.3330078125,6.6666717529296875L2.3330078125,13.347250952929688C2.3330078125,14.075946852929688,2.9237326425,14.666671752929688,3.6524287125,14.666671752929688L12.3469208125,14.666671752929688C13.0756168125,14.666671752929688,13.6663418125,14.075946852929688,13.6663418125,13.347250952929688"
|
||||
fill="var(--color-primary)" fill-opacity="1" style="mix-blend-mode:passthrough" />
|
||||
<path
|
||||
d="M2.4862143825,14.513465452929687Q2.9692757125,14.996526752929688,3.6524287125,14.996526752929688L12.3469208125,14.996526752929688Q13.0300728125,14.996526752929688,13.5131348125,14.513465452929687Q13.9961968125,14.030403652929689,13.9961968125,13.347250952929688L13.9961968125,6.6666717529296875Q13.9961968125,6.634183853929687,13.9898588125,6.602320201929688Q13.9835208125,6.570456549929688,13.9710878125,6.540441642929688Q13.9586548125,6.510426742929687,13.9406048125,6.483414042929687Q13.9225558125,6.456401352929688,13.8995838125,6.4334289129296875Q13.8766118125,6.410456512929687,13.8495988125,6.392407182929688Q13.8225858125,6.374357882929687,13.7925708125,6.361925302929688Q13.7625558125,6.349492732929687,13.7306918125,6.3431546429296874Q13.6988298125,6.336816552929688,13.6663418125,6.336816552929688L2.3330078125,6.336816552929688Q2.3005199135,6.336816552929688,2.2686562615,6.3431546429296874Q2.2367926095,6.349492732929687,2.2067777025,6.361925302929688Q2.1767628025,6.374357882929687,2.1497501025,6.392407182929688Q2.1227374125,6.410456512929687,2.0997649725,6.4334289129296875Q2.0767925725,6.456401352929688,2.0587432425,6.483414052929687Q2.0406939425,6.510426742929687,2.0282613625,6.540441642929688Q2.0158287925,6.570456549929688,2.0094907025,6.602320201929688Q2.0031526125,6.634183853929687,2.0031526125,6.6666717529296875L2.0031526125,13.347250952929688Q2.0031526125,14.030403652929689,2.4862143825,14.513465452929687ZM12.3469208125,14.336816752929687L3.6524287125,14.336816752929687Q3.2425374424999998,14.336816752929687,2.9527000825,14.046979452929687Q2.6628630125,13.757142552929688,2.6628630125,13.347250952929688L2.6628630125,6.996526952929687L13.3364868125,6.996526952929687L13.3364868125,13.347250952929688Q13.3364868125,13.757141552929689,13.0466488125,14.046979452929687Q12.7568108125,14.336816752929687,12.3469208125,14.336816752929687Z"
|
||||
fill-rule="evenodd" fill="var(--color-primary)" fill-opacity="1" style="mix-blend-mode:passthrough" />
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
d="M8.65971041,6.6666717529296875L8.660000029999999,6.6666717529296875L8.66000301,6.006668742929688L7.33999699,6.006668742929688L7.33999997,6.6666717529296875L7.34028959,6.6666717529296875L7.34028959,14.333338752929688L7.33999997,14.333338752929688L7.33999699,14.993341452929688L8.66000301,14.993341452929688L8.660000029999999,14.333338752929688L8.65971041,14.333338752929688L8.65971041,6.6666717529296875Z"
|
||||
fill-rule="evenodd" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough" />
|
||||
</g>
|
||||
<g>
|
||||
<rect x="1.3330078125" y="4" width="13.333333969116211" height="2.6666667461395264"
|
||||
rx="1.3194208145141602" fill="var(--color-primary)" fill-opacity="1"
|
||||
style="mix-blend-mode:passthrough" />
|
||||
<path
|
||||
d="M1.0031526125,5.3472459L1.0031526125,5.3194208Q1.0031526125,4.6362685,1.4862143825,4.15320657Q1.9692761325,3.6701448,2.6524286125,3.6701448L13.3469218125,3.6701448Q14.0300738125,3.6701448,14.5131358125,4.1532066499999996Q14.9961968125,4.6362685,14.9961968125,5.3194208L14.9961968125,5.3472459Q14.9961968125,6.0303984,14.5131358125,6.5134602Q14.0300738125,6.996521899999999,13.3469218125,6.996521899999999L2.6524286125,6.996521899999999Q1.9692763725,6.996521899999999,1.4862143825,6.5134602Q1.0031526125,6.0303984,1.0031526125,5.3472459ZM1.6628630125,5.3472459Q1.6628630725,5.7571373,1.9527000825,6.0469744Q2.2425371425,6.3368115,2.6524286125,6.3368115L13.3469218125,6.3368115Q13.7568118125,6.3368115,14.0466488125,6.0469744Q14.3364858125,5.7571373,14.3364858125,5.3472459L14.3364858125,5.3194208Q14.3364858125,4.90952921,14.0466488125,4.61969221Q13.7568118125,4.3298552,13.3469218125,4.3298552L2.6524286125,4.3298552Q2.2425370225,4.32985526,1.9527000825,4.61969227Q1.6628630125,4.90952933,1.6628630125,5.3194208L1.6628630125,5.3472459Z"
|
||||
fill="var(--color-primary)" fill-opacity="1" style="mix-blend-mode:passthrough" />
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
d="M4.8803459725,1.8136378270703126Q4.7811028325,1.7201073770703126,4.7270553125,1.5949034670703126Q4.6730077825,1.4696996070703126,4.6730077825,1.3333282470703125Q4.6730078425,1.2683239280703125,4.6856895725,1.2045686570703125Q4.6983712925,1.1408133670703124,4.7232474125,1.0807571970703125Q4.7481235225,1.0207010470703124,4.7842379225,0.9666519170703125Q4.8203523725,0.9126027870703125,4.8663173625,0.8666377970703125Q4.9122823525,0.8206728070703125,4.9663314825,0.7845583570703125Q5.0203806125,0.7484439570703125,5.0804367625,0.7235678470703125Q5.1404929325,0.6986917270703125,5.2042482225,0.6860100070703125Q5.2680034935,0.6733282770703125,5.3330078125,0.6733282170703125Q5.4693791725,0.6733282170703125,5.5945830325,0.7273757470703125Q5.7197869425,0.7814232670703125,5.8133173925,0.8806664070703125L7.9996745125,3.0670235470703124L10.1860304125,0.8806677470703125Q10.2795610125,0.7814239870703125,10.4047651125,0.7273761070703125Q10.5299692125,0.6733282170703125,10.6663413125,0.6733282170703125Q10.7313456125,0.6733282770703125,10.7951012125,0.6860100070703125Q10.858856212500001,0.6986917270703125,10.9189119125,0.7235678470703125Q10.978967712500001,0.7484439570703125,11.0330171125,0.7845583570703125Q11.0870657125,0.8206728070703125,11.1330309125,0.8666377970703125Q11.1789961125,0.9126027870703125,11.2151103125,0.9666519170703125Q11.2512250125,1.0207010470703124,11.276101112500001,1.0807571970703125Q11.300977212500001,1.1408133670703124,11.3136592125,1.2045686570703125Q11.3263407125,1.2683239280703125,11.3263411125,1.3333282470703125Q11.3263416125,1.4696971770703124,11.272295912499999,1.5948992370703126Q11.2182503125,1.7201012670703126,11.1190100125,1.8136314470703125L8.4661603125,4.466480747070312Q8.4202154125,4.512425447070313,8.3661899125,4.548523947070313Q8.3121643125,4.5846223470703125,8.2521345125,4.609487547070312Q8.1921048125,4.634352647070313,8.1283774125,4.6470289470703126Q8.0646500125,4.659705147070312,7.9996743125,4.659705147070312Q7.9346986125,4.659705147070312,7.8709710125,4.6470289470703126Q7.807243812499999,4.634352647070313,7.7472138125,4.609487547070312Q7.687184112500001,4.5846223470703125,7.6331589125,4.548523947070313Q7.5791335125,4.512425447070313,7.533188812500001,4.466480747070312L4.8803459725,1.8136378270703126Z"
|
||||
fill-rule="evenodd" fill="var(--color-primary)" fill-opacity="1" style="mix-blend-mode:passthrough" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="trigger-text">{{lang.coin_text71}}{{coin_name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="coin-active-box" v-loading="loading">
|
||||
<div class="coin-title">
|
||||
{{coin_name}}{{lang.coin_text72}}
|
||||
</div>
|
||||
<template v-if="product_id || host_id">
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick" class="coin-active-tabs">
|
||||
<el-tab-pane :label="lang.coin_text76" name="current">
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="lang.coin_text77" name="all">
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
<div class="coin-list">
|
||||
<template v-if="coinActiveList.length === 0 && !loading">
|
||||
<el-empty :description="lang.order_text15"></el-empty>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="coin-list-item" v-for="item in coinActiveList" :key="item.id">
|
||||
<div class="coin-item-icon">
|
||||
<svg class="item-icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
fill="none" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<clipPath id="master_svg0_783_43860">
|
||||
<rect x="0" y="0" width="24" height="24" rx="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#master_svg0_783_43860)">
|
||||
<g>
|
||||
<path
|
||||
d="M18.708139875,3.64892128671875C16.746531875000002,-0.54723961328125,13.474185875,0.72000699871875,12.082462875,1.87477598671875C11.011678675,4.83818338671875,8.189241875,9.15282158671875,6.912997675,10.94046338671875C9.057568575000001,10.38557438671875,10.998181375,13.12552738671875,11.700040775,14.56673738671875C11.914497375,13.85588038671875,16.461587875,6.99325228671875,18.708139875,3.64892128671875ZM18.132253875,5.46505788671875C18.618157875,6.10842898671875,20.269326875,7.25570008671875,22.995780875,6.69931168671875C20.890203875,8.653420486718751,16.440591875000003,12.96355938671875,15.489781875,14.56823938671875C14.762426875,14.65822038671875,13.100760875,14.78419538671875,12.274424875,14.56823938671875C13.549170875,12.33068538671875,16.509577874999998,7.37867598671875,18.132253875,5.46505788671875ZM4.994881375,16.10993138671875C4.4579884750000005,16.31688838671875,3.546170875,17.24520338671875,4.189542275,19.31178838671875C4.432493975,20.01964738671875,5.246830675,21.54184538671875,6.565067275,21.97375638671875C5.7852234750000004,22.15371938671875,3.999080375,21.87327738671875,3.079764475,19.31178838671875C3.040772275,19.27279838671875,2.236932905,15.64802238671875,4.994881375,16.10993138671875ZM4.802920074999999,13.40747038671875L5.990683075,11.44136338671875C7.151450675,11.05444038671875,9.804419075,11.17891638671875,11.121155775,14.75869938671875C12.485883875,15.16961838671875,15.930694875,15.53854338671875,18.780124875,13.71640938671875C18.499681875,14.07633538671875,17.860808875,14.85768038671875,17.554869875,15.10513038671875C18.001779875,15.16961838671875,19.002080875,15.33608438671875,19.429494875,15.49055438671875C18.601659875,16.06943838671875,16.245629875,17.21970938671875,13.457687875,17.18821538671875C14.083063875,17.54814338671875,15.501779875,18.26050038671875,16.176644875,18.22900538671875C15.882704875,18.28149638671875,15.203340875,18.38347638671875,14.835913875,18.38347638671875C15.000878875,18.70591138671875,15.432794875,19.40927138671875,15.831713875,19.65822238671875C14.222536875,19.46326038671875,10.746232075,18.33848538671875,9.703939875,15.37507838671875C9.270526875,14.34628438671875,7.682343975,12.51365138671875,4.802920074999999,13.40747038671875ZM12.115457875,18.77339738671875C11.748030675,18.68041638671875,11.094161975,18.06703738671875,10.813717875,17.77009738671875C10.629254375,18.14052438671875,10.072865475,19.80219038671875,9.817916875,20.58653438671875C9.297520675000001,22.03674538671875,8.553669975,22.81059038671875,8.247730775,23.01605038671875L9.511978175,23.13302638671875C9.601959274999999,22.63812438671875,11.286123275,20.02115038671875,12.115457875,18.77339738671875ZM9.092061475000001,15.06763738671875C7.469387075,12.87807538671875,5.072865675,13.58893538671875,4.075565575000001,14.21880838671875L2.469386425,16.34088338671875C2.008978501,17.20471038671875,1.971486052,18.24400338671875,2.008978501,18.65492038671875C2.592361685,22.20471238671875,5.290322574999999,23.19451338671875,6.566566975,23.24550438671875C8.129253875,23.18401538671875,9.107058075000001,21.39337338671875,9.401000475,20.50705138671875C9.553969875,19.88917338671875,10.153849575,18.19301438671875,10.434293775,17.42066738671875C9.699440975,16.77279638671875,9.234533775,15.58203438671875,9.093561675,15.06763638671875L9.092061475000001,15.06763738671875ZM8.019775875,19.58173538671875C7.215936675,16.367880386718753,5.422295775,15.60003138671875,4.255528975,15.61203038671875C3.8776046749999997,15.61503038671875,3.510177975,15.76200138671875,3.232733275,16.01694938671875C2.706338465,16.50585138671875,2.527874235,17.12222838671875,2.506878435,17.42066938671875C2.401899485,19.74220438671875,3.448690075,21.19691238671875,4.496980475,21.99625238671875C5.303818975,22.61263038671875,6.490082275,23.00105238671875,7.280423675,22.36067938671875C8.070765975,21.72031038671875,8.136752575,20.38407538671875,8.019775875,19.58173538671875Z"
|
||||
fill="var(--color-primary)" fill-opacity="1" style="mix-blend-mode:passthrough" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="coin-item-content">
|
||||
<div class="coin-item-content-top">
|
||||
<div class="coin-item-content-title-text">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="coin-item-content-time">
|
||||
<template v-if="item.begin_time == 0 ">
|
||||
{{lang.coin_text73}} - {{ item.end_time | formateTime }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ item.begin_time | formateTime }} - {{ item.end_time | formateTime }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="coin-item-content-desc">
|
||||
<span @click="item.show_desc = !item.show_desc">{{ lang.coin_text78 }}</span>
|
||||
<i class="el-icon-arrow-down" v-show="!item.show_desc" @click="item.show_desc = !item.show_desc"></i>
|
||||
<i class="el-icon-arrow-up" v-show="item.show_desc" @click="item.show_desc = !item.show_desc"></i>
|
||||
</div>
|
||||
<div class="coin-item-detail" v-if="item.show_desc">
|
||||
<div class="coin-detail-active-limit">
|
||||
{{lang.coin_text79}}
|
||||
</div>
|
||||
<div class="coin-active-detail">
|
||||
<template v-if="item.type === 'default'">
|
||||
<!-- 公开送 -->
|
||||
<p class="coin-detail-main-desc">
|
||||
{{coin_name}}{{lang.coin_text80}}
|
||||
</p>
|
||||
</template>
|
||||
<template v-if="item.type === 'property'">
|
||||
<!-- 属性送 -->
|
||||
<p class="coin-detail-main-desc">
|
||||
<p>{{lang.coin_text81}}:{{item.property_type === 'register' ? lang.coin_text82 : lang.coin_text83}}
|
||||
</p>
|
||||
<p>{{lang.coin_text84}}:<template v-if="item.property_strategy === 'signal'">
|
||||
{{lang.coin_text85}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{lang.coin_text86}}{{item.property_cycle_num}}{{item.property_cycle_unit === 'day' ? lang.coin_text87 : lang.coin_text88}},{{lang.coin_text89}}
|
||||
</template>
|
||||
</p>
|
||||
<p>{{lang.coin_text90}}{{coin_name}}{{lang.coin_text91}}:
|
||||
<template v-if="item.property_type === 'register'">
|
||||
{{item.property_amount}}{{coin_name}}
|
||||
</template>
|
||||
<template v-else>
|
||||
<p v-for="(property_item,index) in item.property_level" :key="index">
|
||||
{{property_item.level_id_arr.map(item => item.name).join('、')}},{{lang.coin_text92}}{{property_item.award}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
</p>
|
||||
</p>
|
||||
</template>
|
||||
<template v-if="item.type === 'recharge'">
|
||||
<!-- 充值送 -->
|
||||
<p>{{lang.coin_text93}}:{{lang.coin_text94}}</p>
|
||||
<p>{{lang.coin_text90}}{{coin_name}}{{lang.coin_text91}}:</p>
|
||||
<template v-if="item.recharge_type === 'gradient'">
|
||||
<p v-for="recharge_item in item.recharge_return" :key="recharge_item.amount">
|
||||
{{lang.coin_text94}}{{recharge_item.amount}},{{lang.coin_text92}}{{recharge_item.award}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>{{lang.coin_text94}}{{item.recharge_min}}{{lang.coin_text95}},{{lang.coin_text96}}
|
||||
{{item.recharge_proportion}}% {{lang.coin_text97}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="item.type === 'total_consume'">
|
||||
<!-- 累计消费送 -->
|
||||
<p>{{lang.coin_text81}}:{{lang.coin_text98}}</p>
|
||||
<p v-if="item.total_consume_type === 'total'">{{lang.coin_text99}}:{{lang.coin_text100}}</p>
|
||||
<p v-if="item.total_consume_type === 'stage'">{{lang.coin_text99}}:{{lang.coin_text101}}</p>
|
||||
<p>{{lang.coin_text102}}:{{lang.coin_text103}}</p>
|
||||
<p>{{lang.coin_text90}}{{coin_name}}{{lang.coin_text91}}:</p>
|
||||
<template v-if="item.total_consume_type === 'total'">
|
||||
<p v-for="total_consume_item in item.total_consume_total_return" :key="total_consume_item.amount">
|
||||
{{lang.coin_text104}}{{total_consume_item.amount}},{{lang.coin_text105}}{{total_consume_item.award}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p v-for="total_consume_item in item.total_consume_stage_return" :key="total_consume_item.amount">
|
||||
{{lang.coin_text106}}{{total_consume_item.amount}},{{lang.coin_text105}}{{total_consume_item.award}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="item.type === 'scene'">
|
||||
<!-- 场景送 -->
|
||||
<p v-for="(action,index) in calculateSceneRange(item.rules)" :key="index">{{action}}</p>
|
||||
<p>{{lang.coin_text102}}:
|
||||
<span v-if="item.gift_strategy === 'rule_once'">{{lang.coin_text145}}</span>
|
||||
<span v-if="item.gift_strategy === 'activity_once'">{{lang.coin_text146}}</span>
|
||||
<span v-if="item.gift_strategy === 'multiple'">{{lang.coin_text147}}</span>
|
||||
</p>
|
||||
</template>
|
||||
<template v-if="item.type === 'single_consume'">
|
||||
<!-- 单笔消费送 -->
|
||||
<p>{{lang.coin_text93}}:{{lang.coin_text98}}</p>
|
||||
{{lang.coin_text107}}:<template v-if="item.single_consume_able_product_ids_arr?.length > 0">
|
||||
<span v-for="(product_item,index) in item.single_consume_able_product_ids_arr"
|
||||
:key="product_item.id">
|
||||
<a :href="'/cart/goods.htm?id=' + product_item.id" target="_blank"
|
||||
style="color: var(--color-primary);">{{product_item.name}}
|
||||
<span v-if="index !== item.single_consume_able_product_ids_arr.length - 1">、</span>
|
||||
</a>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{lang.coin_text108}}
|
||||
</template>
|
||||
</p>
|
||||
<p>{{lang.coin_text99}}:{{lang.coin_text101}}</p>
|
||||
<p>{{lang.coin_text102}}:{{lang.coin_text103}}</p>
|
||||
<p>{{lang.coin_text90}}{{coin_name}}{{lang.coin_text91}}:</p>
|
||||
<p v-for="single_consume_item in item.single_consume_return" :key="single_consume_item.amount">
|
||||
{{lang.coin_text109}}{{single_consume_item.amount}},{{lang.coin_text105}}{{single_consume_item.award}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
<template v-if="item.type === 'order'">
|
||||
<!-- 订购送 -->
|
||||
<p>{{lang.coin_text81}}:{{lang.coin_text110}}</p>
|
||||
<p>{{lang.coin_text99}}:{{lang.coin_text111}}</p>
|
||||
<p v-if="item.order_same_once === 1">{{lang.coin_text102}}:{{lang.coin_text112}}</p>
|
||||
<p>{{lang.coin_text90}}{{coin_name}}{{lang.coin_text91}}:</p>
|
||||
<p v-for="(order_item,index) in item.order_return" :key="index">
|
||||
{{lang.coin_text110}}
|
||||
<template v-if="order_item.product_ids_arr?.length > 0">
|
||||
<span v-for="(product_item,indexs) in order_item.product_ids_arr" :key="product_item.id">
|
||||
<a :href="'/cart/goods.htm?id=' + product_item.id" target="_blank"
|
||||
style="color: var(--color-primary);">{{product_item.name}}</a>
|
||||
<span v-if="indexs !== order_item.product_ids_arr.length - 1">、</span>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{lang.coin_text108}}
|
||||
</template>
|
||||
,{{lang.coin_text105}}{{order_item.award}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
<template v-if="item.type === 'full_gift'">
|
||||
<!-- 每满送 -->
|
||||
<p>{{lang.coin_text93}}:
|
||||
<template v-if="item.full_gift_send_scene_order == 1">
|
||||
{{lang.coin_text110}}<template
|
||||
v-if="item.full_gift_send_scene_renew == 1 || item.full_gift_send_scene_upgrade == 1">、</template>
|
||||
</template>
|
||||
<template v-if="item.full_gift_send_scene_renew == 1">
|
||||
{{lang.coin_text113}}<template v-if="item.full_gift_send_scene_upgrade == 1">、</template>
|
||||
</template>
|
||||
<template v-if="item.full_gift_send_scene_upgrade == 1">
|
||||
{{lang.coin_text114}}
|
||||
</template>
|
||||
</p>
|
||||
<p>{{lang.coin_text115}}:
|
||||
<template v-if="item.full_gift_client_limit_open == 0">
|
||||
{{lang.coin_text116}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{item.full_gift_client_limit_type === 'client' ? lang.coin_text117 : lang.coin_text118}}
|
||||
</template>
|
||||
</p>
|
||||
<p>{{lang.coin_text107}}:<template v-if="item.full_gift_product_only_defence == 1">
|
||||
({{lang.coin_text119}})
|
||||
</template>
|
||||
<template v-if="item.full_gift_send_product_ids_arr?.length > 0">
|
||||
<span v-for="(product_item,index) in item.full_gift_send_product_ids_arr" :key="product_item.id">
|
||||
<a :href="'/cart/goods.htm?id=' + product_item.id" target="_blank"
|
||||
style="color: var(--color-primary);">{{product_item.name}}
|
||||
<span v-if="index !== item.full_gift_send_product_ids_arr.length - 1">、</span>
|
||||
</a>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{lang.coin_text108}}
|
||||
</template>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
{{lang.coin_text102}}:{{lang.coin_text120}}{{item.full_gift_payment_threshold>0?item.full_gift_payment_threshold:item.full_gift_threshold_amount}}
|
||||
<template v-if="item.full_gift_same_once == 1">,{{lang.coin_text121}}</template>
|
||||
</p>
|
||||
<p>{{lang.coin_text90}}{{coin_name}}{{lang.coin_text91}}:</p>
|
||||
<p>
|
||||
{{lang.coin_text122}}{{item.full_gift_threshold_amount}},{{lang.coin_text105}}{{item.full_gift_gift_amount}}{{coin_name}}
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
<div class="coin-detail-use-limit">{{coin_name}}{{lang.coin_text123}}</div>
|
||||
<p>{{lang.coin_text124}}:
|
||||
<template v-if="item.type == 'default'">
|
||||
{{item.effective_start_time | formateTime}}
|
||||
</template>
|
||||
<template v-else-if="item.immediately_effective == 1 || item.effective_time == 0">
|
||||
{{lang.coin_text125}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{lang.coin_text126}}{{item.effective_time}}{{item.effective_time_unit === 'day' ? lang.coin_text87 : lang.coin_text88}}{{lang.coin_text127}}
|
||||
</template>
|
||||
</p>
|
||||
<p>{{lang.coin_text128}}:
|
||||
<template v-if="item.type == 'default'">
|
||||
{{item.effective_end_time | formateTime}}
|
||||
</template>
|
||||
<template v-else-if="item.unlimit_efficient === 0">
|
||||
{{item.efficient_time }} {{item.efficient_time_unit === 'day' ? lang.coin_text87 : lang.coin_text88}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{lang.coin_text129}}
|
||||
</template>
|
||||
</p>
|
||||
<p v-if="item.certification_can_use === 1">{{lang.coin_text48}}</p>
|
||||
<p v-if="item.with_event_promotion_use === 0">{{lang.coin_text49}}</p>
|
||||
<p v-if="item.with_promo_code_use === 0">{{lang.coin_text50}}</p>
|
||||
<p v-if="item.with_client_level_use === 0">{{lang.coin_text51}}</p>
|
||||
<p v-if="item.with_voucher_use === 0">{{lang.coin_text52}}</p>
|
||||
<template
|
||||
v-if="item.order_use_limit == 'product' || item.single_consume_use_limit == 'product' || item.full_gift_use_limit == 'product' || item.type == 'default' || item.type == 'property' || item.type == 'recharge' || item.type == 'total_consume'">
|
||||
<p v-if="item.product_ids_arr?.length > 0">
|
||||
{{lang.coin_text47}}:
|
||||
<span v-for="(el,index) in item.product_ids_arr" :key="el.id">
|
||||
<a :href="'/cart/goods.htm?id=' + el.id" target="_blank"
|
||||
style="color: var(--color-primary);">{{el.name}}</a>
|
||||
<span v-if="index !== item.product_ids_arr.length - 1">、</span>
|
||||
</span>
|
||||
</p>
|
||||
<p v-else>
|
||||
{{lang.coin_text74}}
|
||||
</p>
|
||||
</template>
|
||||
<p
|
||||
v-if="item.order_use_limit == 'host' || item.single_consume_use_limit == 'host' || item.full_gift_use_limit == 'host'">
|
||||
{{lang.coin_text130}}{{coin_name}}{{lang.coin_text131}}
|
||||
</p>
|
||||
<p v-if="item.product_only_defence == 1">{{lang.coin_text65}}</p>
|
||||
<p
|
||||
v-if="item.order_available == 1 || item.upgrade_available == 1 || item.renew_available == 1 || item.demand_available == 1">
|
||||
{{lang.coin_text132}}:
|
||||
<template v-if="item.order_available == 1">
|
||||
{{lang.coin_text133}}<span
|
||||
v-if="item.upgrade_available == 1 || item.renew_available == 1 || item.demand_available == 1">、</span>
|
||||
</template>
|
||||
<template v-if="item.renew_available == 1">
|
||||
{{lang.coin_text134}}<span v-if="item.upgrade_available == 1 || item.demand_available == 1">、</span>
|
||||
</template>
|
||||
<template v-if="item.upgrade_available == 1">
|
||||
{{lang.coin_text135}}<span v-if="item.demand_available == 1">、</span>
|
||||
</template>
|
||||
<template v-if="item.demand_available == 1">
|
||||
{{lang.coin_text136}}
|
||||
</template>
|
||||
</p>
|
||||
<p v-if="item.cycle_limit === 1 ">
|
||||
{{lang.coin_text5}}:<span v-for="(cycle_item,index) in item.cycle"
|
||||
:key="cycle_item">{{lang[cycle_item]}}
|
||||
<span v-if="index !== item.cycle.length - 1">、</span></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
commonData: {},
|
||||
coin_name: "",
|
||||
coinClientInfo: {},
|
||||
coinActiveList: [],
|
||||
loading: false,
|
||||
home_show_coin_activity: 0,
|
||||
activeTab: "current",
|
||||
product_id: 0,
|
||||
host_id: 0,
|
||||
active_show: false,
|
||||
init: true,
|
||||
};
|
||||
},
|
||||
|
||||
filters: {
|
||||
formateTime(time) {
|
||||
if (time && time !== 0) {
|
||||
return formateDate(time * 1000, "YYYY-MM-DD HH:mm");
|
||||
} else {
|
||||
return lang.voucher_effective;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (!havePlugin("Coin")) {
|
||||
return;
|
||||
}
|
||||
// 加载css
|
||||
if (
|
||||
!document.querySelector(
|
||||
'link[href="' + url + 'components/coinActive/coinActive.css"]'
|
||||
)
|
||||
) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = `${url}components/coinActive/coinActive.css`;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
this.commonData =
|
||||
JSON.parse(localStorage.getItem("common_set_before")) || {};
|
||||
this.getCoinInfo();
|
||||
},
|
||||
methods: {
|
||||
visbleShow() {
|
||||
this.coinActiveList.forEach((item) => {
|
||||
item.show_desc = false;
|
||||
});
|
||||
this.getCoinActiveList();
|
||||
},
|
||||
handleTabClick() {
|
||||
this.getCoinActiveList();
|
||||
},
|
||||
// 计算场景送的活动范围
|
||||
calculateSceneRange(item) {
|
||||
const allActions = [];
|
||||
item.forEach(rule => {
|
||||
rule.notice_actions_arr.forEach(action => {
|
||||
if (action.name === 'host_renew') {
|
||||
allActions.push(`${rule.trigger_products[0] ? rule.trigger_products[0].name : lang.coin_text108}${action.name_lang}:${lang.coin_text105}${rule.amount}${this.coin_name}`);
|
||||
} else if (action.name === 'order_pay') {
|
||||
allActions.push(`${rule.trigger_products[0] ? rule.trigger_products[0].name : lang.coin_text108}${action.name_lang}:${lang.coin_text105}${rule.amount}${this.coin_name}`);
|
||||
} else {
|
||||
if (!allActions.includes(action)) {
|
||||
allActions.push(`${action.name_lang}:${lang.coin_text105}${rule.amount}${this.coin_name}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return allActions;
|
||||
},
|
||||
setProductId() {
|
||||
const nowUrl = location.href.split("/").pop();
|
||||
const pageRouter =
|
||||
nowUrl.indexOf("?") !== -1 ? nowUrl.split("?")[0] : nowUrl;
|
||||
if (pageRouter == "goods.htm") {
|
||||
this.product_id = getUrlParams().id;
|
||||
} else if (pageRouter == "productdetail.htm") {
|
||||
this.host_id = getUrlParams().id;
|
||||
}
|
||||
},
|
||||
async getCoinInfo() {
|
||||
try {
|
||||
const res = await apiCoinClientCoupon();
|
||||
this.coin_name = res.data.data.name;
|
||||
this.coinClientInfo = res.data.data;
|
||||
this.home_show_coin_activity = res.data.data.home_show_coin_activity;
|
||||
if (this.home_show_coin_activity == 1) {
|
||||
this.setProductId();
|
||||
await this.getCoinActiveList(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
async getCoinActiveList(isInit = false) {
|
||||
this.loading = true;
|
||||
const params = {};
|
||||
const isProduct = this.activeTab === "current" && this.product_id;
|
||||
const isHost = this.activeTab === "current" && this.host_id;
|
||||
params.product_id = isProduct ? this.product_id : undefined;
|
||||
params.host_id = isHost ? this.host_id : undefined;
|
||||
const isGoodPage = isProduct || isHost;
|
||||
await apiCoinActiveList(params)
|
||||
.then((res) => {
|
||||
this.coinActiveList = res.data.data.list.map((item) => {
|
||||
item.show_desc = false;
|
||||
return item;
|
||||
});
|
||||
if (isGoodPage && isInit === true) {
|
||||
this.active_show = this.coinActiveList.length > 0;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
190
clientarea/hgcloud/components/coinActive/coinActive.less
Normal file
190
clientarea/hgcloud/components/coinActive/coinActive.less
Normal file
@@ -0,0 +1,190 @@
|
||||
// 变量定义
|
||||
@primary-color: var(--color-primary);
|
||||
@text-primary: #2B2B2B;
|
||||
@text-secondary: #A2A2A2;
|
||||
@border-color: #EAEAEA;
|
||||
|
||||
|
||||
|
||||
|
||||
.coin-active-popover {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
// 主容器
|
||||
.coin-active-btn {
|
||||
position: fixed;
|
||||
right: 3px;
|
||||
top: 35vh;
|
||||
z-index: 99;
|
||||
|
||||
// 悬浮触发按钮
|
||||
.coin-active-trigger {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 5px;
|
||||
border-radius: 99px;
|
||||
color: #fff;
|
||||
background: @primary-color;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 8px rgba(26, 97, 214, 0.2);
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 16px rgba(26, 97, 214, 0.4);
|
||||
/* 由于@primary-color是CSS变量,less的lighten函数无法直接处理,改为使用filter实现亮色效果 */
|
||||
background: @primary-color;
|
||||
filter: brightness(1.08);
|
||||
|
||||
.trigger-icon {
|
||||
transform: rotate(5deg);
|
||||
background-color: #f8f9ff;
|
||||
}
|
||||
|
||||
.trigger-text {
|
||||
letter-spacing: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.trigger-icon {
|
||||
font-size: 0;
|
||||
padding: 7px;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.icon-svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.trigger-text {
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
letter-spacing: 5px;
|
||||
font-size: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.coin-active-box {
|
||||
|
||||
|
||||
.coin-title {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: @text-primary;
|
||||
border-bottom: 1px solid @border-color;
|
||||
}
|
||||
|
||||
.coin-active-tabs {
|
||||
.el-tabs__nav-wrap {
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.coin-list {
|
||||
padding: 0 24px;
|
||||
max-height: 5rem;
|
||||
overflow-y: auto;
|
||||
width: 5rem;
|
||||
|
||||
.coin-list-item {
|
||||
box-sizing: border-box;
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px dashed @border-color;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
|
||||
&:nth-last-of-type(1) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.coin-item-icon {
|
||||
border-radius: 50%;
|
||||
background-color: #F3F3F3;
|
||||
padding: 11px;
|
||||
font-size: 0;
|
||||
|
||||
.item-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.coin-item-content {
|
||||
flex: 1;
|
||||
|
||||
.coin-item-content-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: .3rem;
|
||||
|
||||
.coin-item-content-title-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: @text-primary;
|
||||
}
|
||||
|
||||
.coin-item-content-time {
|
||||
font-size: 12px;
|
||||
color: @text-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.coin-item-content-desc {
|
||||
text-align: right;
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
.coin-item-detail {
|
||||
|
||||
.coin-detail-active-limit,
|
||||
.coin-detail-use-limit {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: @text-primary;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.coin-detail-use-limit {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// &:hover {
|
||||
// cursor: pointer;
|
||||
|
||||
|
||||
|
||||
// .coin-item-content-top {
|
||||
// .coin-item-content-title-text {
|
||||
// color: @primary-color;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .coin-item-content {
|
||||
// background-color: #F3F3F3;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// 父组件执行该组件的countDown() 实现倒计时
|
||||
const countDownButton = {
|
||||
template: `
|
||||
<el-button :class="myClass" v-loading="loading" type="primary" :disabled="!flag">{{ flag? name : num + lang.second_try}}</el-button>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
num: 60,
|
||||
flag: true,
|
||||
timer: null,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
myClass: {
|
||||
type: String,
|
||||
default: "count-down-btn",
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: lang.send_code,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
countDown() {
|
||||
this.flag = false;
|
||||
this.num = --this.num;
|
||||
this.timer = setInterval(() => {
|
||||
if (this.num > 1) {
|
||||
this.flag = false;
|
||||
this.num = --this.num;
|
||||
} else {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.flag = true;
|
||||
this.num = 60;
|
||||
this.$emit("countend");
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
84
clientarea/hgcloud/components/creditNotice/creditNotice.js
Normal file
84
clientarea/hgcloud/components/creditNotice/creditNotice.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const creditNotice = {
|
||||
template: /*html*/ `
|
||||
<el-dialog width="7rem" :visible.sync="isShow" @close="diaClose" custom-class="credit-notice-dialog"
|
||||
:show-close="false">
|
||||
<div class="credit-content">
|
||||
<div class="credit-title">
|
||||
<span class="title-text">{{lang.coin_text67}}</span>
|
||||
<span class="close-btn" @click="diaClose">
|
||||
<i class="el-icon-close"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="credit-box">
|
||||
<div class="credit-open">
|
||||
{{lang.coin_text66}}:
|
||||
<el-switch v-model="credit_remind" :active-value="1" :inactive-value="0">
|
||||
</el-switch>
|
||||
</div>
|
||||
<div class="credit-input">
|
||||
{{lang.coin_text68}}
|
||||
<el-input-number v-model="credit_remind_amount" :min="0" :precision="2" :step="0.01" :controls="false"
|
||||
:placeholder="lang.coin_text70">
|
||||
</el-input-number>
|
||||
{{lang.coin_text69}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="credit-footer">
|
||||
<el-button class="cancel-btn" @click="diaClose">{{lang.referral_btn7}}</el-button>
|
||||
<el-button type="primary" @click="submitCredit" :loading="submitLoading">{{lang.referral_btn6}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
credit_remind_amount: undefined,
|
||||
submitLoading: false,
|
||||
credit_remind: 0,
|
||||
coinClientCoupon: {},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.isShow = true;
|
||||
accountDetail().then((res) => {
|
||||
const {credit_remind, credit_remind_amount} = res.data.data.account;
|
||||
this.credit_remind = credit_remind;
|
||||
this.credit_remind_amount = credit_remind_amount;
|
||||
});
|
||||
},
|
||||
diaClose() {
|
||||
this.amount = undefined;
|
||||
this.isShow = false;
|
||||
},
|
||||
submitCredit() {
|
||||
if (!this.credit_remind_amount) {
|
||||
return this.$message.error(lang.coin_text70);
|
||||
}
|
||||
this.submitLoading = true;
|
||||
apiCreateCreditRemind({
|
||||
credit_remind: this.credit_remind,
|
||||
credit_remind_amount: this.credit_remind_amount,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.$message.success(res.data.msg);
|
||||
this.diaClose();
|
||||
this.$emit("success", {
|
||||
credit_remind: this.credit_remind,
|
||||
credit_remind_amount: this.credit_remind_amount,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message.error(error.data.msg);
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
165
clientarea/hgcloud/components/customGoods/customGoods.js
Normal file
165
clientarea/hgcloud/components/customGoods/customGoods.js
Normal file
@@ -0,0 +1,165 @@
|
||||
const customGoods = {
|
||||
template: `
|
||||
<div class="custom-goods-box">
|
||||
<el-form :model="ruleForm" ref="ruleForm" :label-position="labelPosition" :label-width="labelWidth" :rules="rules" :hide-required-asterisk="hideRequiredAsterisk">
|
||||
<el-form-item :prop="item.id + ''" :label="item.field_name" v-for="item in customFieldList" :key="item.id">
|
||||
<el-select v-model="ruleForm[item.id]" :placeholder="item.description" v-if="item.field_type === 'dropdown'">
|
||||
<el-option :label="items" :value="items" v-for="(items,indexs) in calcFieldOption(item.field_option)" :key="indexs"></el-option>
|
||||
</el-select>
|
||||
<el-checkbox true-label="1" false-label="0" :label="item.field_name" v-model="ruleForm[item.id]"
|
||||
v-else-if="item.field_type === 'tickbox'" :disabled="item.is_required === 1">
|
||||
{{item.description}}
|
||||
</el-checkbox>
|
||||
<el-input type="textarea" v-model="ruleForm[item.id]" v-else-if="item.field_type === 'textarea'" :placeholder="item.description"></el-input>
|
||||
<span v-html="item.explain_content" v-else-if="item.field_type === 'explain'" class="custom-explain"></span>
|
||||
<el-input v-model="ruleForm[item.id]" :placeholder="item.description" v-else></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
ruleForm: {},
|
||||
rules: {},
|
||||
customFieldList: [],
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
id: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
},
|
||||
self_defined_field: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
is_show_custom: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
labelWidth: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "auto",
|
||||
},
|
||||
labelPosition: {
|
||||
// :value right/left/top
|
||||
type: String,
|
||||
required: false,
|
||||
default: "left",
|
||||
},
|
||||
hideRequiredAsterisk: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getCustomFields();
|
||||
},
|
||||
watch: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
getSelfDefinedField() {
|
||||
let isValid = false;
|
||||
this.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit("update:self_defined_field", this.ruleForm);
|
||||
isValid = true;
|
||||
} else {
|
||||
this.$message.error(lang.custom_goods_text3);
|
||||
}
|
||||
});
|
||||
return isValid;
|
||||
},
|
||||
getCustomFields() {
|
||||
customFieldsProduct(this.id).then((res) => {
|
||||
const obj = {};
|
||||
const rules = {};
|
||||
this.customFieldList = res.data.data.data.map((item) => {
|
||||
if (item.field_type === "dropdown" && item.is_required === 1) {
|
||||
obj[item.id + ""] = this.calcFieldOption(item.field_option)[0];
|
||||
} else {
|
||||
obj[item.id + ""] = item.field_type === "tickbox" ? 0 : "";
|
||||
if (item.field_type === "tickbox" && item.is_required === 1) {
|
||||
obj[item.id + ""] = "1";
|
||||
}
|
||||
}
|
||||
rules[item.id + ""] = this.calcRules(item);
|
||||
return item;
|
||||
});
|
||||
this.$set(this, "ruleForm", obj);
|
||||
if (Object.keys(this.self_defined_field).length > 0) {
|
||||
// 设置默认值
|
||||
for (let i = 0; i < this.customFieldList.length; i++) {
|
||||
const item = this.customFieldList[i];
|
||||
if (this.self_defined_field[item.id + ""] !== undefined) {
|
||||
this.ruleForm[item.id + ""] =
|
||||
this.self_defined_field[item.id + ""];
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$emit("update:is_show_custom", this.customFieldList.length > 0);
|
||||
this.$set(this, "rules", rules);
|
||||
});
|
||||
},
|
||||
calcValidator(item, value, callback, regexpr) {
|
||||
if (item.is_required === 1 && value === "") {
|
||||
callback(new Error(lang.custom_goods_text1));
|
||||
return;
|
||||
}
|
||||
if (
|
||||
value !== "" &&
|
||||
!new RegExp(regexpr.replace(/^\/|\/$/g, "")).test(value)
|
||||
) {
|
||||
callback(new Error(lang.custom_goods_text2));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
|
||||
calcRules(item) {
|
||||
const rules = [];
|
||||
if (item.is_required === 1) {
|
||||
rules.push({
|
||||
required: true,
|
||||
message: lang.custom_goods_text1,
|
||||
trigger: ["blur", "change"],
|
||||
});
|
||||
} else {
|
||||
rules.push({
|
||||
required: false,
|
||||
trigger: ["blur", "change"],
|
||||
});
|
||||
}
|
||||
|
||||
if (item.field_type === "link") {
|
||||
// 类型为链接时需要校验url格式 http://www.baidu.com
|
||||
const url =
|
||||
"/^(((ht|f)tps?)://)?([^!@#$%^&*?.s-]([^!@#$%^&*?.s]{0,63}[^!@#$%^&*?.s])?.)+[a-z]{2,6}/?/";
|
||||
rules.push({
|
||||
validator: (rule, value, callback) =>
|
||||
this.calcValidator(item, value, callback, url),
|
||||
trigger: ["blur", "change"],
|
||||
});
|
||||
}
|
||||
if (
|
||||
item.field_type !== "dropdown" &&
|
||||
item.field_type !== "tickbox" &&
|
||||
item.regexpr
|
||||
) {
|
||||
rules.push({
|
||||
validator: (rule, value, callback) =>
|
||||
this.calcValidator(item, value, callback, item.regexpr),
|
||||
trigger: ["blur", "change"],
|
||||
});
|
||||
}
|
||||
return rules;
|
||||
},
|
||||
calcFieldOption(item) {
|
||||
return item.split(",");
|
||||
},
|
||||
},
|
||||
};
|
||||
170
clientarea/hgcloud/components/discountCode/discountCode.js
Normal file
170
clientarea/hgcloud/components/discountCode/discountCode.js
Normal file
@@ -0,0 +1,170 @@
|
||||
const discountCode = {
|
||||
template: `
|
||||
<div>
|
||||
<el-popover placement="bottom" trigger="click" v-model="visibleShow" class="discount-popover" :visible-arrow="false">
|
||||
<div class="discount-content">
|
||||
<div class="close-btn-img" @click="closePopver">
|
||||
<img src="${url}/img/common/close_icon.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<el-input class="discount-input" clearable v-model="discountInputVal" :placeholder="lang.login_text10" maxlength="9"></el-input>
|
||||
<el-button class="discount-btn" :loading="isLoading" @click="handelApplyPromoCode">{{lang.shoppingCar_tip_text9}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="reference" class="discount-text">{{lang.shoppingCar_tip_text12}}</span>
|
||||
</el-popover>
|
||||
</div>
|
||||
`,
|
||||
data () {
|
||||
return {
|
||||
discountInputVal: "", // 输入框Value
|
||||
visibleShow: false, // 是否显示优惠弹窗
|
||||
isLoading: false, // 确认按钮loading
|
||||
discountMoney: 0, // 抵扣金额
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
scene: {
|
||||
type: String, // new新购,renew续费,upgrade升降级
|
||||
required: true,
|
||||
},
|
||||
isNeedPromo_code: {
|
||||
//优惠码
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
host_id: {
|
||||
// 产品ID
|
||||
type: String | Number,
|
||||
required: false,
|
||||
},
|
||||
product_id: {
|
||||
// 商品ID
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
qty: {
|
||||
// 数量 新购时必传
|
||||
type: String | Number,
|
||||
required: false,
|
||||
},
|
||||
amount: {
|
||||
//单价
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
billing_cycle_time: {
|
||||
// 周期时间
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
shopping_index: {
|
||||
// 购物车位置
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
multiple_product: {
|
||||
// 订购页面多商品同时使用优惠
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
created () { },
|
||||
mounted () { },
|
||||
methods: {
|
||||
closePopver () {
|
||||
this.visibleShow = false;
|
||||
this.discountInputVal = "";
|
||||
},
|
||||
handelApplyPromoCode () {
|
||||
if (this.isNeedPromo_code && this.discountInputVal.length === 0) {
|
||||
this.$message.warning(lang.shoppingCar_tip_text13);
|
||||
return;
|
||||
}
|
||||
this.isLoading = true;
|
||||
if (this.multiple_product.length === 0) {
|
||||
const params = {
|
||||
scene: this.scene,
|
||||
product_id: this.product_id,
|
||||
amount: this.amount,
|
||||
billing_cycle_time: this.billing_cycle_time,
|
||||
promo_code: this.discountInputVal,
|
||||
};
|
||||
if (this.qty) {
|
||||
params.qty = this.qty;
|
||||
}
|
||||
if (this.host_id) {
|
||||
params.host_id = this.host_id;
|
||||
}
|
||||
this.getCountMoney(params);
|
||||
} else {
|
||||
// 批量使用优惠码,目前只针对订购
|
||||
let discountArr = [];
|
||||
this.multiple_product.forEach(item => {
|
||||
const params = {
|
||||
scene: this.scene,
|
||||
product_id: item.product_id,
|
||||
amount: item.totalPrice,
|
||||
billing_cycle_time: this.billing_cycle_time,
|
||||
promo_code: this.discountInputVal,
|
||||
};
|
||||
if (item.qty) {
|
||||
params.qty = item.qty;
|
||||
}
|
||||
if (this.host_id) {
|
||||
params.host_id = this.host_id;
|
||||
}
|
||||
discountArr.push(applyPromoCode(params));
|
||||
});
|
||||
Promise.all(discountArr).then(res => {
|
||||
this.discountMoney = res.reduce((all, cur) => {
|
||||
all += Number(cur.data.data.discount);
|
||||
return all;
|
||||
}, 0);
|
||||
this.$emit(
|
||||
"get-discount",
|
||||
this.discountMoney,
|
||||
this.discountInputVal
|
||||
);
|
||||
this.$message.success(lang.shoppingCar_tip_text14);
|
||||
this.closePopver();
|
||||
}).catch(err => {
|
||||
this.$message.error(err.data.msg);
|
||||
}).finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
getCountMoney (params) {
|
||||
applyPromoCode(params)
|
||||
.then((res) => {
|
||||
this.discountMoney = Number(res.data.data.discount);
|
||||
if (this.shopping_index || this.shopping_index === 0) {
|
||||
this.$emit(
|
||||
"get-discount",
|
||||
this.discountMoney,
|
||||
this.discountInputVal,
|
||||
this.shopping_index
|
||||
);
|
||||
} else {
|
||||
this.$emit(
|
||||
"get-discount",
|
||||
this.discountMoney,
|
||||
this.discountInputVal
|
||||
);
|
||||
}
|
||||
this.$message.success(lang.shoppingCar_tip_text14);
|
||||
this.closePopver();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
171
clientarea/hgcloud/components/eventCode/eventCode.js
Normal file
171
clientarea/hgcloud/components/eventCode/eventCode.js
Normal file
@@ -0,0 +1,171 @@
|
||||
const eventCode = {
|
||||
template: `
|
||||
<div>
|
||||
<el-popover placement="bottom" trigger="click" v-model="visibleShow" :visible-arrow="false" v-if="!disabled && options.length !==0">
|
||||
<div class="event-content">
|
||||
<el-select class="event-select" @change="changePromotion" v-model="eventId"
|
||||
:placeholder="lang.goods_text5" >
|
||||
<el-option v-for="item in options" :key="item.id" :value="item.id" :label="calcLebal(item)">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<span slot="reference" class="event-text">{{showText}}<i class="el-icon-caret-bottom"></i></span>
|
||||
</el-popover>
|
||||
<span class="event-text" v-if="disabled && options.length > 0">{{showText}}</span>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
eventId: "", // 活动促销ID
|
||||
options: [],
|
||||
discount: 0,
|
||||
visibleShow: false,
|
||||
nowParams: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
showText() {
|
||||
return this.eventId
|
||||
? this.calcLebal(
|
||||
this.options.filter((item) => item.id === this.eventId)[0]
|
||||
)
|
||||
: lang.goods_text6;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
billing_cycle_time() {
|
||||
this.getEventList();
|
||||
},
|
||||
amount() {
|
||||
this.getEventList();
|
||||
},
|
||||
qty() {
|
||||
this.getEventList();
|
||||
},
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String | Number,
|
||||
},
|
||||
// 场景中的所有商品ID
|
||||
product_id: {
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
// 需要支付的原价格
|
||||
amount: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
},
|
||||
// 购买数量
|
||||
qty: {
|
||||
type: Number | String,
|
||||
default: 1,
|
||||
required: true,
|
||||
},
|
||||
//周期时间
|
||||
billing_cycle_time: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getEventList();
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
calcLebal(item) {
|
||||
if (!item) {
|
||||
return "";
|
||||
}
|
||||
return item.type === "percent"
|
||||
? lang.goods_text1 + " " + item.value + "%"
|
||||
: item.type === "reduce"
|
||||
? lang.goods_text2 + item.full + lang.goods_text3 + " " + item.value
|
||||
: lang.goods_text6;
|
||||
},
|
||||
getEventList() {
|
||||
const params = {
|
||||
id: this.product_id,
|
||||
billing_cycle_time: this.billing_cycle_time,
|
||||
qty: this.qty,
|
||||
amount: this.amount,
|
||||
billing_cycle_time: this.billing_cycle_time,
|
||||
};
|
||||
if (
|
||||
JSON.stringify(this.nowParams) == JSON.stringify(params) ||
|
||||
!this.billing_cycle_time
|
||||
) {
|
||||
// 没有变化 防止重复请求
|
||||
return;
|
||||
}
|
||||
this.nowParams = params;
|
||||
eventPromotion(params)
|
||||
.then((res) => {
|
||||
const event_list = res.data.list;
|
||||
const isTop =
|
||||
res.data.addon_event_promotion_does_not_participate === "top";
|
||||
if (event_list.length > 0) {
|
||||
const no_select = {
|
||||
id: 0,
|
||||
type: "no",
|
||||
value: 0,
|
||||
full: 0,
|
||||
};
|
||||
if (isTop) {
|
||||
event_list.unshift(no_select);
|
||||
} else {
|
||||
event_list.push(no_select);
|
||||
}
|
||||
this.options = event_list;
|
||||
// 默认选中处理
|
||||
if (
|
||||
this.id &&
|
||||
this.options.map((item) => item.id).includes(this.id)
|
||||
) {
|
||||
this.eventId = this.id;
|
||||
} else {
|
||||
this.eventId = this.options[0]?.id || "";
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
})
|
||||
.finally(() => {
|
||||
this.changePromotion();
|
||||
});
|
||||
},
|
||||
changePromotion() {
|
||||
this.$emit("change", {
|
||||
discount: this.eventId ? this.discount : 0,
|
||||
id: this.eventId ? this.eventId : "",
|
||||
});
|
||||
// applyEventPromotion({
|
||||
// event_promotion: this.eventId,
|
||||
// product_id: this.product_id,
|
||||
// qty: this.qty,
|
||||
// amount: this.amount,
|
||||
// billing_cycle_time: this.billing_cycle_time,
|
||||
// })
|
||||
// .then((res) => {
|
||||
// this.discount = res.data.data.discount;
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// this.discount = 0;
|
||||
// console.log(err.data);
|
||||
// })
|
||||
// .finally(() => {
|
||||
|
||||
// });
|
||||
},
|
||||
clearPromotion() {
|
||||
this.discount = 0;
|
||||
this.$emit("change", { discount: this.discount, id: this.eventId });
|
||||
},
|
||||
},
|
||||
};
|
||||
362
clientarea/hgcloud/components/flowPacket/flowPacket.js
Normal file
362
clientarea/hgcloud/components/flowPacket/flowPacket.js
Normal file
@@ -0,0 +1,362 @@
|
||||
const flowPacket = {
|
||||
template:
|
||||
`
|
||||
<div style="flex: 1">
|
||||
<el-dialog :visible.sync="showPackage && packageList.length > 0" custom-class="common-package-dialog" :loading="packageLoading">
|
||||
<i class="el-icon-close" @click="cancleDialog"></i>
|
||||
<div class="dialog-title">
|
||||
{{lang.buy_package}}
|
||||
</div>
|
||||
<!-- Radio 筛选:限时/不限时 -->
|
||||
<div class="filter-radio" v-if="hasLimitTime || hasUnlimitedTime">
|
||||
<el-radio-group v-model="filterType" @change="onFilterTypeChange">
|
||||
<el-radio :label="0" v-if="hasLimitTime">{{lang.limit_time_flow}}</el-radio>
|
||||
<el-radio :label="1" v-if="hasUnlimitedTime">{{lang.unlimited_traffic}}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="con">
|
||||
<div class="items">
|
||||
<div class="p-item" v-for="item in filteredPackageList" :key="item.id"
|
||||
:class="{active: item.id === curPackageId}" @click="choosePackage(item)">
|
||||
<p class="price">{{currencyPrefix}}{{getDisplayPrice(item) | filterMoney}}</p>
|
||||
<p class="tit">
|
||||
{{item.name}}
|
||||
<template v-if="item.billing_mode === 0">
|
||||
{{item.capacity}}G
|
||||
</template>
|
||||
<template v-else>{{item.min_capacity}}-{{item.max_capacity}}G</template>
|
||||
</p>
|
||||
<i class="el-icon-check"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slider-container" v-if="showSlider">
|
||||
<el-slider v-model="sliderValueComputed" :min="sliderMin" :max="sliderMax" :marks="sliderMarks"
|
||||
show-input>
|
||||
</el-slider>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<el-button class="btn-ok" @click="handlerPackage"
|
||||
:loading="submitLoading">{{lang.ticket_btn6}}</el-button>
|
||||
<el-button class="btn-no" @click="cancleDialog">{{lang.finance_btn7}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 弹窗模式下的触发按钮 -->
|
||||
<el-button v-if="showFlowPacketList && displayMode === 'dialog' && hasFlow && lineType === 'flow'"
|
||||
@click="openFlowListDialog" type="primary" size="small">
|
||||
{{lang.flow_packet_list}}
|
||||
</el-button>
|
||||
|
||||
<!-- 流量包列表 -->
|
||||
<component
|
||||
:is="listWrapper"
|
||||
v-bind="listWrapperProps"
|
||||
v-on="listWrapperEvents"
|
||||
v-if="showFlowPacketList && hasFlow && lineType === 'flow' && (displayMode === 'inline' || showFlowListDialog)">
|
||||
<div class="dialog-title" v-if="displayMode === 'dialog'">{{lang.flow_packet_list}}</div>
|
||||
<div class="dialog-main">
|
||||
<el-table :data="flowPacketList" v-loading="flowPacketLoading" style="width: 100%">
|
||||
<el-table-column prop="id" :label="lang.flow_packet_id" min-width="100"></el-table-column>
|
||||
<el-table-column prop="name" :label="lang.flow_packet_name" min-width="150"></el-table-column>
|
||||
<el-table-column :label="lang.flow_packet_create_time" min-width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.create_time | formateTime}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="lang.flow_packet_size" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.size}}GB
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="lang.flow_packet_used" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.used || 0}}GB
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="lang.flow_packet_expire_time" min-width="180">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.expire_time === 0">/</span>
|
||||
<span v-else>{{scope.row.expire_time | formateTime}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="lang.flow_packet_status" min-width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status === 1" type="success" size="small">{{lang.flow_packet_status_valid}}</el-tag>
|
||||
<el-tag v-else type="warning" size="small">{{lang.flow_packet_status_invalid}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<pagination :page-data="flowParams" v-if="flowParams.total > 0"
|
||||
@sizechange="handleFlowPageSizeChange" @currentchange="handleFlowPageChange">
|
||||
</pagination>
|
||||
</div>
|
||||
</component>
|
||||
</div>
|
||||
`,
|
||||
mixins: [mixin],
|
||||
components: {
|
||||
pagination
|
||||
},
|
||||
filters: {
|
||||
filterMoney (money) {
|
||||
if (isNaN(money)) {
|
||||
return '0.00';
|
||||
} else {
|
||||
const temp = `${money}`.split('.');
|
||||
return parseInt(temp[0]).toLocaleString() + '.' + (temp[1] || '00');
|
||||
}
|
||||
},
|
||||
formateTime (time) {
|
||||
if (time && time !== 0) {
|
||||
return formateDate(time * 1000);
|
||||
} else {
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
hasFlow: true,
|
||||
packageLoading: false,
|
||||
submitLoading: false,
|
||||
packageList: [],
|
||||
curPackageId: '',
|
||||
currencyPrefix: JSON.parse(localStorage.getItem("common_set_before")).currency_prefix,
|
||||
filterType: 0, // 1: 不限时, 0: 限时
|
||||
sliderValue: 10, // 滑动条的值
|
||||
showSlider: false, // 是否显示滑动条
|
||||
sliderMin: 0,
|
||||
sliderMax: 100,
|
||||
flowPacketList: [],
|
||||
flowPacketLoading: false,
|
||||
flowParams: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
pageSizes: [20, 50, 100],
|
||||
total: 0
|
||||
},
|
||||
showFlowListDialog: false, // 控制流量包列表弹窗
|
||||
};
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
},
|
||||
showPackage: {
|
||||
type: Boolean
|
||||
},
|
||||
module: {
|
||||
type: String,
|
||||
default: 'mf_cloud_mysql'
|
||||
},
|
||||
lineType: {
|
||||
type: String,
|
||||
default: 'bw'
|
||||
},
|
||||
displayMode: {
|
||||
type: String,
|
||||
default: 'inline' // inline | dialog (401使用dialog)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.hasFlow = this.addons_js_arr.includes('FlowPacket');
|
||||
if (this.hasFlow) {
|
||||
this.getPackageList();
|
||||
this.getFlowPacketList();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showFlowPacketList() {
|
||||
const hiddenModules = ['mf_dcim', 'remf_dcim'];
|
||||
return !hiddenModules.includes(this.module);
|
||||
},
|
||||
// 处理滑动条空值问题
|
||||
sliderValueComputed: {
|
||||
get () {
|
||||
return this.sliderValue === '' || this.sliderValue === null ? this.sliderMin : this.sliderValue;
|
||||
},
|
||||
set (val) {
|
||||
this.sliderValue = val;
|
||||
}
|
||||
},
|
||||
// 根据 filterType 筛选流量包
|
||||
filteredPackageList () {
|
||||
return this.packageList.filter(item => item.long_term_valid === this.filterType);
|
||||
},
|
||||
// 获取当前选中的流量包
|
||||
currentPackage () {
|
||||
return this.packageList.find(item => item.id === this.curPackageId);
|
||||
},
|
||||
// 滑动条标记
|
||||
sliderMarks () {
|
||||
return {
|
||||
[this.sliderMin]: this.sliderMin + 'GB',
|
||||
[this.sliderMax]: this.sliderMax + 'GB'
|
||||
};
|
||||
},
|
||||
// 是否有限时流量包
|
||||
hasLimitTime () {
|
||||
return this.packageList.some(item => item.long_term_valid === 0);
|
||||
},
|
||||
// 是否有不限时流量包
|
||||
hasUnlimitedTime () {
|
||||
return this.packageList.some(item => item.long_term_valid === 1);
|
||||
},
|
||||
// 动态容器组件
|
||||
listWrapper () {
|
||||
return this.displayMode === 'dialog' ? 'el-dialog' : 'div';
|
||||
},
|
||||
// 动态容器属性
|
||||
listWrapperProps () {
|
||||
if (this.displayMode === 'dialog') {
|
||||
return {
|
||||
width: "1200px",
|
||||
visible: this.showFlowListDialog,
|
||||
'custom-class': 'flow-list-dialog'
|
||||
};
|
||||
}
|
||||
return {
|
||||
class: 'flow-packet-list'
|
||||
};
|
||||
},
|
||||
// 动态容器事件
|
||||
listWrapperEvents () {
|
||||
if (this.displayMode === 'dialog') {
|
||||
return {
|
||||
'update:visible': (val) => { this.showFlowListDialog = val; }
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// 监听筛选类型变化,自动选中第一个
|
||||
filteredPackageList (newList) {
|
||||
if (newList.length > 0) {
|
||||
this.curPackageId = newList[0].id;
|
||||
this.choosePackage(newList[0]);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getPackageList () {
|
||||
try {
|
||||
this.packageLoading = true;
|
||||
const res = await getFlowPacket({
|
||||
id: this.id,
|
||||
page: 1,
|
||||
limit: 9999,
|
||||
});
|
||||
this.packageList = res.data.data.list;
|
||||
if (this.packageList.length === 0) {
|
||||
this.$emit('cancledialog', false);
|
||||
return;
|
||||
}
|
||||
// 根据数据设置默认 filterType 和选中流量包
|
||||
const limitTimeList = this.packageList.filter(item => item.long_term_valid === 0);
|
||||
const unlimitedTimeList = this.packageList.filter(item => item.long_term_valid === 1);
|
||||
|
||||
// 优先选限时,只有不限时时才选不限时
|
||||
if (limitTimeList.length > 0) {
|
||||
this.filterType = 0;
|
||||
this.curPackageId = limitTimeList[0].id;
|
||||
this.choosePackage(limitTimeList[0]);
|
||||
} else if (unlimitedTimeList.length > 0) {
|
||||
this.filterType = 1;
|
||||
this.curPackageId = unlimitedTimeList[0].id;
|
||||
this.choosePackage(unlimitedTimeList[0]);
|
||||
}
|
||||
this.packageLoading = false;
|
||||
} catch (error) {
|
||||
this.packageLoading = false;
|
||||
}
|
||||
},
|
||||
choosePackage (item) {
|
||||
this.curPackageId = item.id;
|
||||
// 如果 billing_mode = 1,显示滑动条
|
||||
if (item.billing_mode === 1) {
|
||||
this.showSlider = true;
|
||||
this.sliderMin = item.min_capacity;
|
||||
this.sliderMax = item.max_capacity;
|
||||
this.sliderValue = item.min_capacity;
|
||||
} else {
|
||||
this.showSlider = false;
|
||||
}
|
||||
},
|
||||
async handlerPackage () {
|
||||
try {
|
||||
this.submitLoading = true;
|
||||
const params = {
|
||||
id: this.id,
|
||||
flow_packet_id: this.curPackageId,
|
||||
};
|
||||
// 如果是范围流量包,传递滑动条的值
|
||||
if (this.currentPackage && this.currentPackage.billing_mode === 1) {
|
||||
params.selected_capacity = this.sliderValue;
|
||||
}
|
||||
const res = await buyFlowPacket(params);
|
||||
this.$emit('sendpackid', res.data.data.id);
|
||||
this.submitLoading = false;
|
||||
} catch (error) {
|
||||
this.submitLoading = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
cancleDialog () {
|
||||
this.$emit('cancledialog', false);
|
||||
},
|
||||
// 获取流量包列表
|
||||
async getFlowPacketList () {
|
||||
// mf_dcim 和 remf_dcim 不请求流量包列表
|
||||
if (!this.showFlowPacketList) return;
|
||||
try {
|
||||
this.flowPacketLoading = true;
|
||||
const res = await getFlowPacketByModule(this.module, {
|
||||
id: this.id,
|
||||
...this.flowParams
|
||||
});
|
||||
this.flowPacketList = res.data.data.list || [];
|
||||
this.flowParams.total = res.data.data.count || 0;
|
||||
this.flowPacketLoading = false;
|
||||
} catch (error) {
|
||||
this.flowPacketLoading = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
// 分页变化
|
||||
handleFlowPageChange (page) {
|
||||
this.flowParams.page = page;
|
||||
this.getFlowPacketList();
|
||||
},
|
||||
handleFlowPageSizeChange (e) {
|
||||
this.flowParams.limit = e;
|
||||
this.getFlowPacketList();
|
||||
},
|
||||
// 计算显示价格
|
||||
getDisplayPrice (item) {
|
||||
let price;
|
||||
if (item.billing_mode === 0) {
|
||||
price = item.price;
|
||||
} else {
|
||||
if (item.id === this.curPackageId) {
|
||||
price = this.sliderValue * item.price;
|
||||
} else {
|
||||
price = item.min_capacity * item.price;
|
||||
}
|
||||
}
|
||||
return Math.round(price * 100) / 100;
|
||||
},
|
||||
// 切换筛选类型时移除焦点
|
||||
onFilterTypeChange () {
|
||||
document.activeElement?.blur();
|
||||
},
|
||||
// 打开流量包列表弹窗
|
||||
openFlowListDialog () {
|
||||
this.showFlowListDialog = true;
|
||||
this.getFlowPacketList();
|
||||
}
|
||||
},
|
||||
};
|
||||
0
clientarea/hgcloud/components/forgetDialog/.gitkeep
Normal file
0
clientarea/hgcloud/components/forgetDialog/.gitkeep
Normal file
47
clientarea/hgcloud/components/hostStatus/hostStatus.js
Normal file
47
clientarea/hgcloud/components/hostStatus/hostStatus.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 处理产品转移中的状态 */
|
||||
const hostStatus = {
|
||||
template:
|
||||
`
|
||||
<div>
|
||||
<div class="host-is-transfer" v-if="isTransferring">{{lang.host_transferring}}</div>
|
||||
<slot v-else></slot>
|
||||
</div>
|
||||
`,
|
||||
data () {
|
||||
return {
|
||||
isTransferring: false,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: Number | String,
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getHostTransferStatus () {
|
||||
try {
|
||||
const res = await hostIsTransfer({ id: this.id * 1 });
|
||||
const transferring = res.data.data.status;
|
||||
// 状态为 Active 且 transferring === 1 的时候显示转移中
|
||||
this.isTransferring = transferring && this.status === 'Active';
|
||||
} catch (error) {
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const arr = JSON.parse(
|
||||
document.querySelector("#addons_js").getAttribute("addons_js")
|
||||
).map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
arr.includes("HostTransfer") && this.getHostTransferStatus();
|
||||
}
|
||||
};
|
||||
827
clientarea/hgcloud/components/ipDefase/ipDefase.js
Normal file
827
clientarea/hgcloud/components/ipDefase/ipDefase.js
Normal file
@@ -0,0 +1,827 @@
|
||||
const ipDefase = {
|
||||
template: /*html*/ `
|
||||
<div>
|
||||
|
||||
<div class="ip-defase-box">
|
||||
<div class="fire-list-search">
|
||||
<el-select v-model="params.status" clearable :placeholder="lang.ipDefase_text1">
|
||||
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input v-model="params.keywords" clearable @keyup.enter.native="search" :placeholder="lang.ipDefase_text2">
|
||||
</el-input>
|
||||
<el-button type="primary" @click="search">{{lang.ipDefase_text3}}</el-button>
|
||||
</div>
|
||||
<el-table v-loading="tabeLoading" :data="productList" @sort-change="sortChange"
|
||||
style="width: 100%; margin:0.2rem 0;">
|
||||
<el-table-column prop="id" label="ID">
|
||||
</el-table-column>
|
||||
<el-table-column prop="host_ip" :label="lang.ipDefase_text4" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="defense_peak" :label="lang.ipDefase_text14">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{row.defense_peak || '--'}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="due_time" :label="lang.index_text13">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{row.due_time | formateTime }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="lang.ipDefase_text5" width="200">
|
||||
<template slot-scope="{row}">
|
||||
<template v-if="row.statusLoading">
|
||||
<i class="primary-icon el-icon-loading"></i>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{getStatusLabel(row.status)}}
|
||||
<i @click="getProductStatus(row)" class="primary-icon el-icon-refresh"></i>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="op" :label="lang.ipDefase_text6" width="160" fixed="right">
|
||||
<template slot-scope="{row}">
|
||||
<div class="operation">
|
||||
<el-button type="text" @click="showRenew(row)" v-if="row.sub_host_id">{{lang.cloud_re_btn}}</el-button>
|
||||
<el-button type="text" @click="openUpgradeDialog(row)">{{lang.ipDefase_text7}}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination :page-data="params" @sizechange="sizeChange" @currentchange="currentChange"></pagination>
|
||||
</div>
|
||||
|
||||
<div class="upgrade-dialog" v-if="isShowUpgrade">
|
||||
<el-dialog width="9.5rem" :visible.sync="isShowUpgrade" :show-close="false" @close="upgradeDgClose">
|
||||
<div class="dialog-title">{{lang.ipDefase_text11}}</div>
|
||||
<div class="dialog-main">
|
||||
<div class="ipDefase-now-info">
|
||||
<div class="now-text">{{lang.ipDefase_text15}}:{{ipInfo.host_ip}}</div>
|
||||
<div class="now-text">{{lang.ipDefase_text16}}:{{getStatusLabel(ipInfo.status)}}</div>
|
||||
<div class="now-text">{{lang.ipDefase_text17}}:{{ipInfo.defense_peak || '--'}}</div>
|
||||
</div>
|
||||
<el-form ref="ipDefaseForm" label-position="left" label-width="100px" hide-required-asterisk>
|
||||
<!-- 防御 -->
|
||||
<el-form-item :label="lang.ipDefase_text12">
|
||||
<el-radio-group v-model="defenseName">
|
||||
<el-radio-button :label="c.desc" v-for="(c,cInd) in defenceList" :key="cInd" @click.native="chooseDefence($event,c)">
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="lang.cart_tip_text12" v-if="upDurationList.length > 0">
|
||||
<el-radio-group v-model="upParams.duration_id">
|
||||
<el-radio-button :label="c.id" v-for="c in upDurationList" :key="c.id" @click.native="changeDuration($event,c)">
|
||||
{{c.name_show}}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<div class="footer-top">
|
||||
<div class="money-text">{{lang.ipDefase_text13}}:</div>
|
||||
<div class="money" v-loading="upgradePriceLoading">
|
||||
<span class="money-num">{{commonData.currency_prefix }} {{ upParams.totalPrice | filterMoney}}</span>
|
||||
<el-popover placement="top-start" width="200" trigger="hover"
|
||||
v-if="isShowLevel || (isShowPromo && upParams.isUseDiscountCode)">
|
||||
<div class="show-config-list">
|
||||
<p v-if="isShowLevel">
|
||||
{{lang.shoppingCar_tip_text2}}:{{commonData.currency_prefix}}
|
||||
{{ upParams.clDiscount | filterMoney }}
|
||||
</p>
|
||||
<p v-if="isShowPromo && upParams.isUseDiscountCode">
|
||||
{{lang.shoppingCar_tip_text4}}:{{commonData.currency_prefix}}
|
||||
{{ upParams.code_discount | filterMoney}}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<i class="el-icon-warning-outline total-icon" slot="reference"></i>
|
||||
</el-popover>
|
||||
<p class="original-price" v-if="upParams.totalPrice != upParams.original_price">
|
||||
{{commonData.currency_prefix}} {{ upParams.original_price |
|
||||
filterMoney}}
|
||||
</p>
|
||||
<div class="code-box" v-if="false">
|
||||
<!-- 优惠码 -->
|
||||
<discount-code v-show="isShowPromo && !upParams.customfield.promo_code "
|
||||
@get-discount="getUpDiscount(arguments)" scene="upgrade" :product_id="product_id"
|
||||
:amount="upParams.original_price" :billing_cycle_time="billing_cycle_time">
|
||||
</discount-code>
|
||||
</div>
|
||||
<div class="code-number-text">
|
||||
<div class="discount-codeNumber" v-show="upParams.customfield.promo_code">
|
||||
{{ upParams.customfield.promo_code }}<i class="el-icon-circle-close remove-discountCode"
|
||||
@click="removeUpDiscountCode()"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<el-button class="btn-ok" @click="upgradeSub" :loading="loading4">
|
||||
{{lang.security_btn5}}
|
||||
</el-button>
|
||||
<div class="btn-no" @click="upgradeDgClose">
|
||||
{{lang.security_btn6}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 续费弹窗 -->
|
||||
<div class="renew-dialog">
|
||||
<el-dialog width="6.9rem" :visible.sync="isShowRenew" :show-close="false" @close="renewDgClose">
|
||||
<div class="dialog-title">{{lang.common_cloud_title10}}</div>
|
||||
<div class="dialog-main">
|
||||
<div class="renew-content">
|
||||
<div class="renew-item" :class="renewActiveId==item.id?'renew-active':''" v-for="item in renewPageData"
|
||||
:key="item.id" @click="renewItemChange(item)">
|
||||
<div class="item-top">{{item.customfield?.multi_language?.billing_cycle || item.billing_cycle}}</div>
|
||||
<div class="item-bottom" v-if="isShowPromo && renewParams.isUseDiscountCode">
|
||||
{{commonData.currency_prefix + item.base_price}}
|
||||
</div>
|
||||
<div class="item-bottom" v-else>
|
||||
{{commonData.currency_prefix + item.price}}
|
||||
</div>
|
||||
<div class="item-origin-price"
|
||||
v-if="item.price*1 < item.base_price*1 && !renewParams.isUseDiscountCode">
|
||||
{{commonData.currency_prefix + item.base_price}}
|
||||
</div>
|
||||
<i class="el-icon-check check" v-show="renewActiveId==item.id"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay-content">
|
||||
<div class="pay-price">
|
||||
<div class="money" v-loading="renewLoading">
|
||||
<span class="text">{{lang.common_cloud_label11}}:</span>
|
||||
<span>{{commonData.currency_prefix}}{{renewParams.totalPrice |
|
||||
filterMoney}}</span>
|
||||
<el-popover placement="top-start" width="200" trigger="hover"
|
||||
v-if="(isShowLevel && renewParams.clDiscount*1 > 0) || (isShowPromo && renewParams.isUseDiscountCode)">
|
||||
<div class="show-config-list">
|
||||
<p v-if="isShowLevel && renewParams.clDiscount*1 > 0">
|
||||
{{lang.shoppingCar_tip_text2}}:{{commonData.currency_prefix}}
|
||||
{{ renewParams.clDiscount | filterMoney}}
|
||||
</p>
|
||||
<p v-if="isShowPromo && renewParams.isUseDiscountCode">
|
||||
{{lang.shoppingCar_tip_text4}}:{{commonData.currency_prefix}}
|
||||
{{ renewParams.code_discount | filterMoney }}
|
||||
</p>
|
||||
</div>
|
||||
<i class="el-icon-warning-outline total-icon" slot="reference"></i>
|
||||
</el-popover>
|
||||
<p class="original-price"
|
||||
v-if="renewParams.customfield.promo_code && renewParams.totalPrice != renewParams.base_price">
|
||||
{{commonData.currency_prefix}} {{ renewParams.base_price |
|
||||
filterMoney}}
|
||||
</p>
|
||||
<p class="original-price"
|
||||
v-if="!renewParams.customfield.promo_code && renewParams.totalPrice != renewParams.original_price">
|
||||
{{commonData.currency_prefix}} {{ renewParams.original_price
|
||||
| filterMoney}}
|
||||
</p>
|
||||
<div class="code-box" v-if="false">
|
||||
<!-- 优惠码 -->
|
||||
<discount-code v-show="isShowPromo && !renewParams.customfield.promo_code"
|
||||
@get-discount="getRenewDiscount(arguments)" scene="renew" :product_id="product_id"
|
||||
:amount="renewParams.base_price" :billing_cycle_time="renewParams.duration">
|
||||
</discount-code>
|
||||
</div>
|
||||
<div class="code-number-text">
|
||||
<div class="discount-codeNumber" v-show="renewParams.customfield.promo_code">
|
||||
{{ renewParams.customfield.promo_code }}<i class="el-icon-circle-close remove-discountCode"
|
||||
@click="removeRenewDiscountCode()"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<el-button class="btn-ok" @click="subRenew" :loading="subRenewLoading">
|
||||
{{lang.common_cloud_btn30}}
|
||||
</el-button>
|
||||
<el-button class="btn-no" @click="renewDgClose">
|
||||
{{lang.common_cloud_btn29}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
|
||||
<pay-dialog ref="ipDefasePayDialog" @payok="paySuccess" @paycancel="payCancel"></pay-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
commonData: {},
|
||||
params: {
|
||||
keywords: "",
|
||||
status: "",
|
||||
page: 1,
|
||||
limit: 20,
|
||||
pageSizes: [20, 50, 100],
|
||||
total: 0,
|
||||
orderby: "id",
|
||||
sort: "desc",
|
||||
},
|
||||
tabeLoading: false,
|
||||
statusOptions: [
|
||||
{label: lang.ipDefase_text8, value: 0},
|
||||
{label: lang.ipDefase_text9, value: 1},
|
||||
{label: lang.ipDefase_text10, value: 2},
|
||||
],
|
||||
productList: [],
|
||||
isShowUpgrade: false,
|
||||
isShowLevel: false,
|
||||
isShowPromo: false,
|
||||
upParams: {
|
||||
customfield: {
|
||||
promo_code: "", // 优惠码
|
||||
},
|
||||
duration_id: "", // 周期
|
||||
isUseDiscountCode: false, // 是否使用优惠码
|
||||
clDiscount: 0, // 用户等级折扣价
|
||||
code_discount: 0, // 优惠码折扣价
|
||||
original_price: 0, // 原价
|
||||
totalPrice: 0, // 现价
|
||||
},
|
||||
upgradePriceLoading: false,
|
||||
loading4: false,
|
||||
|
||||
defenceList: [],
|
||||
peak_defence: "",
|
||||
defenseName: "",
|
||||
ipInfo: {},
|
||||
ip: "",
|
||||
isInit: true,
|
||||
isShowRenew: false, // 续费的总计loading
|
||||
renewBtnLoading: false, // 续费按钮的loading
|
||||
// 续费页面信息
|
||||
renewPageData: [],
|
||||
renewPriceList: [],
|
||||
renewActiveId: "",
|
||||
renewLoading: false, // 续费计算折扣loading
|
||||
// 续费参数
|
||||
renewParams: {
|
||||
id: 0, //默认选中的续费id
|
||||
isUseDiscountCode: false, // 是否使用优惠码
|
||||
customfield: {
|
||||
promo_code: "", // 优惠码
|
||||
},
|
||||
duration: "", // 周期
|
||||
billing_cycle: "", // 周期时间
|
||||
clDiscount: 0, // 用户等级折扣价
|
||||
code_discount: 0, // 优惠码折扣价
|
||||
original_price: 0, // 原价
|
||||
base_price: 0,
|
||||
totalPrice: 0, // 现价
|
||||
},
|
||||
sub_host_id: 0,
|
||||
subRenewLoading: false,
|
||||
upDurationList: [],
|
||||
};
|
||||
},
|
||||
components: {
|
||||
payDialog,
|
||||
pagination,
|
||||
discountCode,
|
||||
cashBack,
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
// 产品id
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
// 场景中的所有商品ID
|
||||
product_id: {
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
billing_cycle_time: {
|
||||
type: String | Number,
|
||||
required: true,
|
||||
},
|
||||
module: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
listmode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showip: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
renewParams: {
|
||||
handler() {
|
||||
let n = 0;
|
||||
// l:当前周期的续费价格
|
||||
if (this.isShowPromo && this.renewParams.customfield.promo_code) {
|
||||
// n: 算出来的价格
|
||||
n =
|
||||
(this.renewParams.base_price * 1000 -
|
||||
this.renewParams.clDiscount * 1000 -
|
||||
this.renewParams.code_discount * 1000) /
|
||||
1000 >
|
||||
0
|
||||
? (this.renewParams.base_price * 1000 -
|
||||
this.renewParams.clDiscount * 1000 -
|
||||
this.renewParams.code_discount * 1000) /
|
||||
1000
|
||||
: 0;
|
||||
} else {
|
||||
// n: 算出来的价格
|
||||
n =
|
||||
(this.renewParams.original_price * 1000 -
|
||||
this.renewParams.clDiscount * 1000 -
|
||||
this.renewParams.code_discount * 1000) /
|
||||
1000 >
|
||||
0
|
||||
? (this.renewParams.original_price * 1000 -
|
||||
this.renewParams.clDiscount * 1000 -
|
||||
this.renewParams.code_discount * 1000) /
|
||||
1000
|
||||
: 0;
|
||||
}
|
||||
let t = n;
|
||||
// 如果当前周期和选择的周期相同,则和当前周期对比价格
|
||||
// if (
|
||||
// this.hostData.billing_cycle_time === this.renewParams.duration ||
|
||||
// this.hostData.billing_cycle_name === this.renewParams.billing_cycle
|
||||
// ) {
|
||||
// // 谁大取谁
|
||||
// t = n;
|
||||
// }
|
||||
this.renewParams.totalPrice =
|
||||
t * 1000 > 0 ? ((t * 1000) / 1000).toFixed(2) : 0;
|
||||
},
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getProductList();
|
||||
this.getCommonData();
|
||||
},
|
||||
mounted() {
|
||||
this.isShowLevel = havePlugin("IdcsmartClientLevel");
|
||||
this.isShowPromo = havePlugin("PromoCode");
|
||||
},
|
||||
filters: {
|
||||
formateTime(time) {
|
||||
if (time && time !== 0) {
|
||||
return formateDate(time * 1000);
|
||||
} else {
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
// 返回剩余到期时间
|
||||
formateDueDay(time) {
|
||||
return Math.floor((time * 1000 - Date.now()) / (1000 * 60 * 60 * 24));
|
||||
},
|
||||
filterMoney(money) {
|
||||
if (isNaN(money) || money * 1 < 0) {
|
||||
return "0.00";
|
||||
} else {
|
||||
return formatNuberFiexd(money);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
paySuccess(e) {
|
||||
this.isShowUpgrade = false;
|
||||
this.$emit("success");
|
||||
setTimeout(() => {
|
||||
this.getProductList();
|
||||
}, 1000);
|
||||
},
|
||||
// 取消支付回调
|
||||
payCancel(e) {},
|
||||
openUpgradeDialog(row) {
|
||||
this.ipInfo = row;
|
||||
this.ip = row.host_ip;
|
||||
this.getUpConfig();
|
||||
},
|
||||
getUpConfig() {
|
||||
apiGetUpDefenceConfig(
|
||||
{
|
||||
id: this.id,
|
||||
ip: this.ip,
|
||||
},
|
||||
this.module
|
||||
)
|
||||
.then((res) => {
|
||||
this.defenceList = res.data.data?.defence || [];
|
||||
this.peak_defence = res.data.data?.current_defence
|
||||
? res.data.data?.current_defence
|
||||
: res.data.data?.defence[0]?.value || "";
|
||||
this.defenseName = this.defenceList.find(
|
||||
(item) => item.value === this.peak_defence
|
||||
)?.desc;
|
||||
this.isShowUpgrade = true;
|
||||
this.getCycleList();
|
||||
})
|
||||
.catch((err) => {
|
||||
err.data.msg && this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
chooseDefence(e, c) {
|
||||
this.defenseName = c.desc;
|
||||
this.peak_defence = c.value;
|
||||
this.getCycleList();
|
||||
e.preventDefault();
|
||||
},
|
||||
changeDuration(e, c) {
|
||||
this.upParams.duration_id = c.id;
|
||||
this.getCycleList();
|
||||
e.preventDefault();
|
||||
},
|
||||
// 关闭升降级弹窗
|
||||
upgradeDgClose() {
|
||||
this.isShowUpgrade = false;
|
||||
this.removeUpDiscountCode(false);
|
||||
},
|
||||
|
||||
// 升降级使用优惠码
|
||||
getUpDiscount(data) {
|
||||
this.upParams.customfield.promo_code = data[1];
|
||||
this.upParams.isUseDiscountCode = true;
|
||||
this.upParams.code_discount = Number(data[0]);
|
||||
this.getCycleList();
|
||||
},
|
||||
// 移除升降级优惠码
|
||||
removeUpDiscountCode(flag = true) {
|
||||
this.upParams.isUseDiscountCode = false;
|
||||
this.upParams.customfield.promo_code = "";
|
||||
this.upParams.code_discount = 0;
|
||||
if (flag) {
|
||||
this.getCycleList();
|
||||
}
|
||||
},
|
||||
|
||||
// 获取升降级价格
|
||||
getCycleList() {
|
||||
this.upgradePriceLoading = true;
|
||||
const params = {
|
||||
id: this.id,
|
||||
ip: this.ip,
|
||||
peak_defence: this.peak_defence,
|
||||
duration_id: this.upParams.duration_id,
|
||||
};
|
||||
apiCalculateUpDefencePrice(params, this.module)
|
||||
.then(async (res) => {
|
||||
if (res.data.status == 200) {
|
||||
this.upDurationList = res.data.data.durations;
|
||||
if (!this.upParams.duration_id) {
|
||||
this.upParams.duration_id =
|
||||
res.data.data.duration_id || this.upDurationList[0]?.id;
|
||||
}
|
||||
if (res.data.data.durations?.length === 0) {
|
||||
this.upParams.duration_id = "";
|
||||
}
|
||||
let price = res.data.data.price; // 当前产品的价格
|
||||
if (price < 0) {
|
||||
this.upParams.original_price = 0;
|
||||
this.upParams.totalPrice = 0;
|
||||
this.upgradePriceLoading = false;
|
||||
return;
|
||||
}
|
||||
this.upParams.original_price = price;
|
||||
this.upParams.totalPrice = price;
|
||||
// 开启了等级优惠
|
||||
if (this.isShowLevel) {
|
||||
await clientLevelAmount({id: this.product_id, amount: price})
|
||||
.then((ress) => {
|
||||
this.upParams.clDiscount = Number(ress.data.data.discount);
|
||||
})
|
||||
.catch(() => {
|
||||
this.upParams.clDiscount = 0;
|
||||
});
|
||||
}
|
||||
// 开启了优惠码插件
|
||||
if (this.isShowPromo) {
|
||||
// 更新优惠码
|
||||
await applyPromoCode({
|
||||
// 开启了优惠券
|
||||
scene: "upgrade",
|
||||
product_id: this.product_id,
|
||||
amount: price,
|
||||
billing_cycle_time: this.billing_cycle_time,
|
||||
promo_code: this.upParams.customfield.promo_code,
|
||||
host_id: this.id,
|
||||
})
|
||||
.then((resss) => {
|
||||
this.upParams.isUseDiscountCode = true;
|
||||
this.upParams.code_discount = Number(
|
||||
resss.data.data.discount
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
this.upParams.isUseDiscountCode = false;
|
||||
this.upParams.customfield.promo_code = "";
|
||||
this.upParams.code_discount = 0;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
}
|
||||
this.upParams.totalPrice =
|
||||
(price * 1000 -
|
||||
this.upParams.clDiscount * 1000 -
|
||||
this.upParams.code_discount * 1000) /
|
||||
1000 >
|
||||
0
|
||||
? (
|
||||
(price * 1000 -
|
||||
this.upParams.clDiscount * 1000 -
|
||||
this.upParams.code_discount * 1000) /
|
||||
1000
|
||||
).toFixed(2)
|
||||
: 0;
|
||||
this.upgradePriceLoading = false;
|
||||
} else {
|
||||
this.upParams.original_price = 0;
|
||||
this.upParams.clDiscount = 0;
|
||||
this.upParams.isUseDiscountCode = false;
|
||||
this.upParams.customfield.promo_code = "";
|
||||
this.upParams.code_discount = 0;
|
||||
this.upParams.totalPrice = 0;
|
||||
this.upgradePriceLoading = false;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.upDurationList = [];
|
||||
this.upParams.duration_id = "";
|
||||
this.upParams.original_price = 0;
|
||||
this.upParams.clDiscount = 0;
|
||||
this.upParams.isUseDiscountCode = false;
|
||||
this.upParams.customfield.promo_code = "";
|
||||
this.upParams.code_discount = 0;
|
||||
this.upParams.totalPrice = 0;
|
||||
this.upgradePriceLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
// 升降级提交
|
||||
upgradeSub() {
|
||||
const params = {
|
||||
id: this.id,
|
||||
ip: this.ip,
|
||||
peak_defence: this.peak_defence,
|
||||
duration_id: this.upParams.duration_id,
|
||||
customfield: this.upParams.customfield,
|
||||
};
|
||||
this.loading4 = true;
|
||||
apiGenerateUpDefenceOrder(params, this.module)
|
||||
.then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.$message.success(lang.common_cloud_text56);
|
||||
const orderId = res.data.data.id;
|
||||
// 调支付弹窗
|
||||
this.$refs.ipDefasePayDialog.showPayDialog(orderId, 0);
|
||||
} else {
|
||||
this.$message.error(err.data.msg);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading4 = false;
|
||||
});
|
||||
},
|
||||
|
||||
goProductDetail(row) {
|
||||
window.open(`/productdetail.htm?id=${row.host_id}&showUp=1`);
|
||||
},
|
||||
getStatusLabel(status) {
|
||||
return (
|
||||
this.statusOptions.find((item) => item.value === status)?.label || "--"
|
||||
);
|
||||
},
|
||||
search() {
|
||||
this.params.page = 1;
|
||||
this.getProductList();
|
||||
},
|
||||
// 每页展示数改变
|
||||
sizeChange(e) {
|
||||
this.params.limit = e;
|
||||
this.params.page = 1;
|
||||
// 获取列表
|
||||
this.getProductList();
|
||||
},
|
||||
// 当前页改变
|
||||
currentChange(e) {
|
||||
this.params.page = e;
|
||||
this.getProductList();
|
||||
},
|
||||
sortChange({prop, order}) {
|
||||
this.params.orderby = order ? prop : "id";
|
||||
this.params.sort = order === "ascending" ? "asc" : "desc";
|
||||
this.getProductList();
|
||||
},
|
||||
// 获取产品状态
|
||||
getProductStatus(item, isInit = false) {
|
||||
!isInit && (item.statusLoading = true);
|
||||
apiProductRefreshHostIpStatus({id: item.id}, this.listmode)
|
||||
.then((res) => {
|
||||
item.status = res.data.data.status;
|
||||
if (item.statusLoading) {
|
||||
this.$message.success(res.data.msg);
|
||||
}
|
||||
item.statusLoading = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
item.statusLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
getProductList() {
|
||||
this.tabeLoading = true;
|
||||
apiProductGetHostIp({...this.params, host_id: this.id}, this.listmode)
|
||||
.then(async (res) => {
|
||||
this.tabeLoading = false;
|
||||
this.productList = res.data.data.list.map((item) => {
|
||||
item.statusLoading = false;
|
||||
this.getProductStatus(item, true);
|
||||
return item;
|
||||
});
|
||||
this.params.total = res.data.data.count;
|
||||
if (this.showip && this.isInit) {
|
||||
this.isInit = false;
|
||||
const ipInfo = this.productList.find(
|
||||
(item) => item.host_ip == this.showip
|
||||
);
|
||||
if (ipInfo) {
|
||||
this.openUpgradeDialog(ipInfo);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.tabeLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
getCommonData() {
|
||||
this.commonData = JSON.parse(localStorage.getItem("common_set_before"));
|
||||
},
|
||||
|
||||
// 续费使用优惠码
|
||||
async getRenewDiscount(data) {
|
||||
this.renewParams.customfield.promo_code = data[1];
|
||||
this.renewParams.isUseDiscountCode = true;
|
||||
this.renewParams.code_discount = Number(data[0]);
|
||||
const price = this.renewParams.base_price;
|
||||
const discountParams = {id: this.product_id, amount: price};
|
||||
// 开启了等级折扣插件
|
||||
if (this.isShowLevel) {
|
||||
// 获取等级抵扣价格
|
||||
await clientLevelAmount(discountParams)
|
||||
.then((res2) => {
|
||||
if (res2.data.status === 200) {
|
||||
this.renewParams.clDiscount = Number(res2.data.data.discount); // 客户等级优惠金额
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.renewParams.clDiscount = 0;
|
||||
});
|
||||
}
|
||||
},
|
||||
// 移除续费的优惠码
|
||||
removeRenewDiscountCode() {
|
||||
this.renewParams.isUseDiscountCode = false;
|
||||
this.renewParams.customfield.promo_code = "";
|
||||
this.renewParams.code_discount = 0;
|
||||
this.renewParams.clDiscount = 0;
|
||||
const price = this.renewParams.original_price;
|
||||
},
|
||||
|
||||
// 显示续费弹窗
|
||||
showRenew(row) {
|
||||
this.sub_host_id = row.sub_host_id;
|
||||
if (this.renewBtnLoading) return;
|
||||
this.renewBtnLoading = true;
|
||||
// 获取续费页面信息
|
||||
const params = {
|
||||
id: this.sub_host_id,
|
||||
};
|
||||
this.isShowRenew = true;
|
||||
this.renewLoading = true;
|
||||
renewPage(params)
|
||||
.then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.renewBtnLoading = false;
|
||||
this.renewPageData = res.data.data.host;
|
||||
this.renewActiveId = this.renewPageData[0].id;
|
||||
this.renewParams.billing_cycle =
|
||||
this.renewPageData[0].billing_cycle;
|
||||
this.renewParams.duration = this.renewPageData[0].duration;
|
||||
this.renewParams.original_price = this.renewPageData[0].price;
|
||||
this.renewParams.base_price = this.renewPageData[0].base_price;
|
||||
}
|
||||
this.renewLoading = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.renewBtnLoading = false;
|
||||
this.renewLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
getRenewPrice() {
|
||||
renewPage({id: this.id})
|
||||
.then(async (res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.renewPriceList = res.data.data.host;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.renewPriceList = [];
|
||||
});
|
||||
},
|
||||
// 续费弹窗关闭
|
||||
renewDgClose() {
|
||||
this.isShowRenew = false;
|
||||
this.removeRenewDiscountCode();
|
||||
},
|
||||
// 续费提交
|
||||
subRenew() {
|
||||
this.subRenewLoading = true;
|
||||
const params = {
|
||||
id: this.sub_host_id,
|
||||
billing_cycle: this.renewParams.billing_cycle,
|
||||
customfield: this.renewParams.customfield,
|
||||
};
|
||||
|
||||
renew(params)
|
||||
.then((res) => {
|
||||
this.subRenewLoading = false;
|
||||
if (res.data.status === 200) {
|
||||
this.$message.success(res.data.msg);
|
||||
this.isShowRenew = false;
|
||||
if (res.data.code == "Paid") {
|
||||
this.getProductList();
|
||||
} else {
|
||||
this.$refs.ipDefasePayDialog.showPayDialog(res.data.data.id);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.subRenewLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
// 续费周期点击
|
||||
async renewItemChange(item) {
|
||||
this.renewLoading = true;
|
||||
this.renewActiveId = item.id;
|
||||
this.renewParams.duration = item.duration;
|
||||
this.renewParams.billing_cycle = item.billing_cycle;
|
||||
this.renewParams.original_price = item.price;
|
||||
this.renewParams.base_price = item.base_price;
|
||||
|
||||
// 开启了优惠码插件
|
||||
if (this.isShowPromo && this.renewParams.isUseDiscountCode) {
|
||||
const discountParams = {id: this.product_id, amount: item.base_price};
|
||||
// 开启了等级折扣插件
|
||||
if (this.isShowLevel) {
|
||||
// 获取等级抵扣价格
|
||||
await clientLevelAmount(discountParams)
|
||||
.then((res2) => {
|
||||
if (res2.data.status === 200) {
|
||||
this.renewParams.clDiscount = Number(res2.data.data.discount); // 客户等级优惠金额
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.renewParams.clDiscount = 0;
|
||||
});
|
||||
}
|
||||
|
||||
// 更新优惠码
|
||||
await applyPromoCode({
|
||||
scene: "renew",
|
||||
product_id: this.product_id,
|
||||
amount: item.base_price,
|
||||
billing_cycle_time: this.renewParams.duration,
|
||||
promo_code: this.renewParams.customfield.promo_code,
|
||||
})
|
||||
.then((resss) => {
|
||||
price = item.base_price;
|
||||
this.renewParams.isUseDiscountCode = true;
|
||||
this.renewParams.code_discount = Number(resss.data.data.discount);
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
this.removeRenewDiscountCode();
|
||||
});
|
||||
}
|
||||
this.renewLoading = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
452
clientarea/hgcloud/components/loginDialog/loginDialog.js
Normal file
452
clientarea/hgcloud/components/loginDialog/loginDialog.js
Normal file
@@ -0,0 +1,452 @@
|
||||
// 验证码通过
|
||||
function captchaCheckSuccsss(bol, captcha, token) {
|
||||
if (bol) {
|
||||
// 验证码验证通过
|
||||
getData(captcha, token)
|
||||
}
|
||||
};
|
||||
// 取消验证码验证
|
||||
function captchaCheckCancel() {
|
||||
captchaCancel()
|
||||
};
|
||||
const loginDialog = {
|
||||
template:
|
||||
`
|
||||
<div>
|
||||
<!-- 验证码 -->
|
||||
<captcha-dialog :is-show-captcha="isShowCaptcha" ref="captcha"></captcha-dialog>
|
||||
<el-dialog width="16.95rem" custom-class='login-dialog' :visible.sync="visible" :show-close=true>
|
||||
<div class="login-left">
|
||||
<div class="login-text">
|
||||
<div class="login-text-title">{{lang.login}}</div>
|
||||
<div class="login-text-regist" v-if="commonData.register_email == 1 || commonData.register_phone == 1">
|
||||
{{lang.login_no_account}}<a @click="toRegist">{{lang.login_regist_text}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<div class="login-top">
|
||||
<div v-show="isPassOrCode" class="login-email" :class="isEmailOrPhone? 'active':null" @click="isEmailOrPhone = true">{{lang.login_email}}
|
||||
</div>
|
||||
<div class="login-phone" :class="!isEmailOrPhone? 'active':null" @click="isEmailOrPhone = false">{{lang.login_phone}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-main">
|
||||
<div class="form-item">
|
||||
<el-input v-if="isEmailOrPhone" v-model="formData.email" :placeholder="lang.login_placeholder_pre + lang.login_email"></el-input>
|
||||
<el-input v-else class="input-with-select select-input" v-model="formData.phone" :placeholder="lang.login_placeholder_pre + lang.login_phone">
|
||||
<el-select filterable slot="prepend" v-model="formData.countryCode">
|
||||
<el-option v-for="item in countryList" :key="item.name" :value="item.phone_code" :label="item.name_zh + '+' + item.phone_code"></el-option>
|
||||
</el-select>
|
||||
</el-input>
|
||||
</div>
|
||||
<div v-if="isPassOrCode" class="form-item">
|
||||
<el-input :placeholder="lang.login_pass" v-model="formData.password" type="password">
|
||||
</el-input>
|
||||
</div>
|
||||
<div v-else class="form-item code-item">
|
||||
<!-- 邮箱验证码 -->
|
||||
<el-input v-if="isEmailOrPhone" v-model="formData.emailCode" :placeholder="lang.email_code">
|
||||
</el-input>
|
||||
<count-down-button ref="emailCodebtn" @click.native="sendEmailCode" v-if="isEmailOrPhone" my-class="code-btn"></count-down-button>
|
||||
<!-- <el-button v-if="isEmailOrPhone" class="code-btn" type="primary">获取验证码</el-button> -->
|
||||
|
||||
<!-- 手机验证码 -->
|
||||
<el-input v-if="!isEmailOrPhone" v-model="formData.phoneCode" :placeholder="lang.login_phone_code">
|
||||
</el-input>
|
||||
<count-down-button ref="phoneCodebtn" @click.native="sendPhoneCode" v-if="!isEmailOrPhone" my-class="code-btn"></count-down-button>
|
||||
<!-- <el-button v-if="!isEmailOrPhone" class="code-btn" type="primary">获取验证码</el-button> -->
|
||||
</div>
|
||||
<div class="form-item rember-item">
|
||||
<el-checkbox v-model="formData.isRemember">{{lang.login_remember}}</el-checkbox>
|
||||
<a @click="toForget">{{lang.login_forget}}</a>
|
||||
</div>
|
||||
<div class="read-item" v-if="errorText.length !== 0">
|
||||
<el-alert :title="errorText" type="error" show-icon :closable="false">
|
||||
</el-alert>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<el-button type="primary" class="login-btn" @click="doLogin">{{lang.login}}</el-button>
|
||||
</div>
|
||||
<div class="form-item read-item">
|
||||
<el-checkbox v-model="checked">
|
||||
{{lang.login_read}}<a @click="toService">{{lang.read_service}}</a>{{lang.read_and}}<a @click="toPrivacy">{{lang.read_privacy}}</a>
|
||||
</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-item line-item" v-if="commonData.login_phone_verify == 1">
|
||||
<el-divider><span class="text">or</span></el-divider>
|
||||
</div>
|
||||
<div class="form-item" v-if="commonData.login_phone_verify == 1">
|
||||
<el-button v-if="isPassOrCode" :disabled="commonData.login_phone_verify == 0" @click="isPassOrCode = false;isEmailOrPhone = false" class="type-btn">{{lang.login_code_login}}
|
||||
</el-button>
|
||||
<el-button v-else @click="isPassOrCode = true" class="type-btn">
|
||||
{{lang.login_pass_login}}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-right">
|
||||
<img src="${url}/img/common/login_back.png" class="login-back-img">
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
visible: true,
|
||||
// 登录是否需要验证
|
||||
isCaptcha: false,
|
||||
isShowCaptcha: false, //登录是否显示验证码弹窗
|
||||
checked: getCookie("checked") == "1" ? true : false,
|
||||
isEmailOrPhone: getCookie("isEmailOrPhone") == "1" ? true : false, // true:电子邮件 false:手机号
|
||||
isPassOrCode: getCookie("isPassOrCode") == "1" ? true : false, // true:密码登录 false:验证码登录
|
||||
errorText: "",
|
||||
formData: {
|
||||
email: getCookie("email") ? getCookie("email") : null,
|
||||
phone: getCookie("phone") ? getCookie("phone") : null,
|
||||
password: getCookie("password") ? getCookie("password") : null,
|
||||
phoneCode: "",
|
||||
emailCode: "",
|
||||
isRemember: getCookie("isRemember") == "1" ? true : false,
|
||||
countryCode: 86
|
||||
},
|
||||
token: "",
|
||||
captcha: '',
|
||||
countryList: [],
|
||||
commonData: {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
countDownButton,
|
||||
captchaDialog
|
||||
},
|
||||
props: {
|
||||
isShowLogin: {
|
||||
default: false,
|
||||
type: Boolean,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCommonData()
|
||||
this.getCountryList()
|
||||
},
|
||||
mounted() {
|
||||
window.captchaCancel = this.captchaCancel
|
||||
window.getData = this.getData
|
||||
window.showLoginDialog = this.showLoginDialog
|
||||
},
|
||||
methods: {
|
||||
// 获取通用配置
|
||||
getCommonData() {
|
||||
this.commonData = JSON.parse(localStorage.getItem('common_set_before'))
|
||||
if (this.commonData.login_phone_verify == 0) {
|
||||
this.isPassOrCode = true
|
||||
}
|
||||
if (this.commonData.captcha_client_login == 1) {
|
||||
this.isCaptcha = true
|
||||
}
|
||||
},
|
||||
showLoginDialog() {
|
||||
this.visible = true
|
||||
},
|
||||
toRegist() {
|
||||
// location.href = 'regist.html'
|
||||
console.log("显示注册弹窗");
|
||||
},
|
||||
toForget() {
|
||||
// location.href = 'forget.html'
|
||||
console.log("显示忘记密码弹窗");
|
||||
},
|
||||
|
||||
|
||||
// 验证码验证成功后的回调
|
||||
getData(captchaCode, token) {
|
||||
this.isCaptcha = false
|
||||
this.token = token
|
||||
this.captcha = captchaCode
|
||||
this.isShowCaptcha = false
|
||||
// 判断是否密码登录 是执行登录
|
||||
// 否则判断发送手机验证码还是邮箱验证码
|
||||
if (this.isPassOrCode) {
|
||||
this.doLogin()
|
||||
} else {
|
||||
if (this.isEmailOrPhone) {
|
||||
// 发送邮箱验证码
|
||||
this.sendEmailCode()
|
||||
} else {
|
||||
// 发送手机验证码
|
||||
this.sendPhoneCode()
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
// 登录
|
||||
doLogin() {
|
||||
let isPass = true;
|
||||
const form = { ...this.formData };
|
||||
console.log(form);
|
||||
// 邮件登录验证
|
||||
if (this.isEmailOrPhone) {
|
||||
if (!form.email) {
|
||||
isPass = false
|
||||
this.errorText = "请输入邮箱"
|
||||
} else if (
|
||||
form.email.search(
|
||||
/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
|
||||
) === -1
|
||||
) {
|
||||
isPass = false
|
||||
this.errorText = "邮箱格式不正确"
|
||||
}
|
||||
|
||||
// 邮件 密码登录 验证
|
||||
if (this.isPassOrCode) { // 密码登录
|
||||
if (!form.password) {
|
||||
isPass = false
|
||||
this.errorText = "请输入密码"
|
||||
}
|
||||
} else {
|
||||
// 邮件 验证码登录 验证
|
||||
if (!form.emailCode) {
|
||||
isPass = false
|
||||
this.errorText = "请输入邮箱验证码"
|
||||
} else {
|
||||
if (form.emailCode.length !== 6) {
|
||||
isPass = false
|
||||
this.errorText = "邮箱验证码应为6位"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 手机号码登录 验证
|
||||
if (!this.isEmailOrPhone) {
|
||||
if (!form.phone) {
|
||||
isPass = false
|
||||
this.errorText = "请输入手机号码"
|
||||
} else {
|
||||
// 设置正则表达式的手机号码格式 规则 ^起点 $终点 1第一位数是必为1 [3-9]第二位数可取3-9的数字 \d{9} 匹配9位数字
|
||||
const reg = /^1[3-9]\d{9}$/;
|
||||
if (!reg.test(form.phone)) {
|
||||
isPass = false
|
||||
this.errorText = "请输入正确的手机号"
|
||||
}
|
||||
}
|
||||
|
||||
// 手机号 密码登录 验证
|
||||
if (this.isPassOrCode) { // 密码登录
|
||||
if (!form.password) {
|
||||
isPass = false
|
||||
this.errorText = "请输入密码"
|
||||
}
|
||||
} else {
|
||||
// 手机 验证码登录 验证
|
||||
if (!form.phoneCode) {
|
||||
isPass = false
|
||||
this.errorText = "请输入手机验证码"
|
||||
} else {
|
||||
if (form.phoneCode.length !== 6) {
|
||||
isPass = false
|
||||
this.errorText = "手机验证码应为6位"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 勾选协议
|
||||
if (!this.checked) {
|
||||
isPass = false
|
||||
this.errorText = "请勾选服务协议书!"
|
||||
}
|
||||
|
||||
if (isPass && this.isCaptcha) {
|
||||
this.isShowCaptcha = true
|
||||
this.$refs.captcha.doGetCaptcha()
|
||||
return
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
if (isPass) {
|
||||
this.errorText = ""
|
||||
let code = "";
|
||||
if (!this.isPassOrCode) {
|
||||
if (this.isEmailOrPhone) {
|
||||
code = form.emailCode
|
||||
} else {
|
||||
code = form.phoneCode
|
||||
}
|
||||
}
|
||||
const params = {
|
||||
type: this.isPassOrCode ? "password" : "code",
|
||||
account: this.isEmailOrPhone ? form.email : form.phone,
|
||||
phone_code: form.countryCode.toString(),
|
||||
code,
|
||||
password: this.isPassOrCode ? this.encrypt(form.password) : "",
|
||||
remember_password: form.isRemember ? "1" : "0",
|
||||
captcha: this.captcha,
|
||||
token: this.token
|
||||
}
|
||||
|
||||
//调用登录接口
|
||||
logIn(params).then(res => {
|
||||
if (res.data.status === 200) {
|
||||
this.$message.success(res.data.msg);
|
||||
// 存入 jwt
|
||||
localStorage.setItem("jwt", res.data.data.jwt);
|
||||
if (form.isRemember) {// 记住密码
|
||||
console.log(form);
|
||||
if (this.isEmailOrPhone) {
|
||||
console.log("email");
|
||||
setCookie("email", form.email, 30)
|
||||
} else {
|
||||
console.log("phone");
|
||||
setCookie("phone", form.phone, 30)
|
||||
}
|
||||
setCookie("password", form.password, 30)
|
||||
setCookie("isRemember", form.isRemember ? "1" : "0")
|
||||
setCookie("checked", this.checked ? "1" : "0")
|
||||
|
||||
// 保存登录方式
|
||||
setCookie("isEmailOrPhone", this.isEmailOrPhone ? "1" : "0")
|
||||
setCookie("isPassOrCode", this.isPassOrCode ? "1" : "0")
|
||||
|
||||
} else {
|
||||
// 未勾选记住密码
|
||||
delCookie("email")
|
||||
delCookie("phone")
|
||||
delCookie("password")
|
||||
delCookie("isRemember")
|
||||
delCookie("checked")
|
||||
}
|
||||
|
||||
location.reload();
|
||||
}
|
||||
}).catch(err => {
|
||||
if (err.data.msg === "请输入图形验证码" || err.data.msg === "图形验证码错误") {
|
||||
this.isShowCaptcha = true
|
||||
this.$refs.captcha.doGetCaptcha()
|
||||
} else {
|
||||
this.errorText = err.data.msg
|
||||
// this.$message.error(err.data.msg);
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
},
|
||||
// 获取国家列表
|
||||
getCountryList() {
|
||||
getCountry({}).then(res => {
|
||||
console.log(res);
|
||||
if (res.data.status === 200) {
|
||||
this.countryList = res.data.data.list
|
||||
}
|
||||
})
|
||||
},
|
||||
// 加密方法
|
||||
encrypt(str) {
|
||||
const key = CryptoJS.enc.Utf8.parse("idcsmart.finance");
|
||||
const iv = CryptoJS.enc.Utf8.parse("9311019310287172");
|
||||
var encrypted = CryptoJS.AES.encrypt(str, key, {
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
iv: iv,
|
||||
}).toString();
|
||||
return encrypted;
|
||||
},
|
||||
// 发送邮箱验证码
|
||||
sendEmailCode() {
|
||||
let isPass = true
|
||||
const form = this.formData
|
||||
if (!form.email) {
|
||||
isPass = false
|
||||
this.errorText = "请输入邮箱"
|
||||
} else if (
|
||||
form.email.search(
|
||||
/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
|
||||
) === -1
|
||||
) {
|
||||
isPass = false
|
||||
this.errorText = "邮箱格式不正确"
|
||||
}
|
||||
if (isPass) {
|
||||
this.errorText = ""
|
||||
const params = {
|
||||
action: "login",
|
||||
email: form.email,
|
||||
token: this.token,
|
||||
captcha: this.captcha
|
||||
}
|
||||
emailCode(params).then(res => {
|
||||
if (res.data.status === 200) {
|
||||
// 执行倒计时
|
||||
this.$refs.emailCodebtn.countDown()
|
||||
}
|
||||
}).catch(err => {
|
||||
if (err.data.msg === "请输入图形验证码" || err.data.msg === "图形验证码错误") {
|
||||
this.isShowCaptcha = true
|
||||
this.$refs.captcha.doGetCaptcha()
|
||||
} else {
|
||||
this.errorText = err.data.msg
|
||||
// this.$message.error(err.data.msg);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 发送手机短信
|
||||
sendPhoneCode() {
|
||||
let isPass = true
|
||||
const form = this.formData
|
||||
if (!form.phone) {
|
||||
isPass = false
|
||||
this.errorText = "请输入手机号码"
|
||||
} else {
|
||||
// 设置正则表达式的手机号码格式 规则 ^起点 $终点 1第一位数是必为1 [3-9]第二位数可取3-9的数字 \d{9} 匹配9位数字
|
||||
const reg = /^1[3-9]\d{9}$/;
|
||||
if (!reg.test(form.phone)) {
|
||||
isPass = false
|
||||
this.errorText = "请输入正确的手机号"
|
||||
}
|
||||
}
|
||||
|
||||
if (isPass) {
|
||||
this.errorText = ""
|
||||
const params = {
|
||||
action: "login",
|
||||
phone_code: form.countryCode,
|
||||
phone: form.phone,
|
||||
token: this.token,
|
||||
captcha: this.captcha
|
||||
}
|
||||
phoneCode(params).then(res => {
|
||||
if (res.data.status === 200) {
|
||||
// 执行倒计时
|
||||
this.$refs.phoneCodebtn.countDown()
|
||||
}
|
||||
}).catch(err => {
|
||||
if (err.data.msg == "请输入图形验证码" || err.data.msg == "图形验证码错误") {
|
||||
this.isShowCaptcha = true
|
||||
this.$refs.captcha.doGetCaptcha()
|
||||
} else {
|
||||
this.errorText = err.data.msg
|
||||
// this.$message.error(err.data.msg);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
toService() {
|
||||
const url = this.commonData.terms_service_url
|
||||
window.open(url);
|
||||
},
|
||||
toPrivacy() {
|
||||
const url = this.commonData.terms_privacy_url
|
||||
window.open(url);
|
||||
},
|
||||
// 验证码 关闭
|
||||
captchaCancel() {
|
||||
this.isShowCaptcha = false
|
||||
}
|
||||
},
|
||||
}
|
||||
79
clientarea/hgcloud/components/pagination/pagination.js
Normal file
79
clientarea/hgcloud/components/pagination/pagination.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// css 样式依赖common.css
|
||||
const pagination = {
|
||||
inheritAttrs: false,
|
||||
template: `
|
||||
<div class="myPage custom-pagination">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pageData.page"
|
||||
:page-sizes="pageData.pageSizes" :page-size="pageData.limit"
|
||||
:layout="layoutToUse"
|
||||
:total="pageData.total"
|
||||
:pager-count=5
|
||||
v-bind="$attrs"
|
||||
:disabled="pageData.page <= 1 && isNextPageDisabled && showCustomButtons"
|
||||
>
|
||||
<span class="page-total">{{lang.total}} {{pageData.total}} {{lang.pieces}}</span>
|
||||
</el-pagination>
|
||||
<div class="manual-btn" v-if="showCustomButtons">
|
||||
<el-button type="primary" size="small" :disabled="pageData.page <= 1" @click="handleChange(0)">{{lang.prev_page}}</el-button>
|
||||
<el-button type="primary" size="small" :disabled="isNextPageDisabled" @click="handleChange(1)">{{lang.next_page}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data () {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
layoutToUse () {
|
||||
return this.$attrs.layout || "slot, sizes, prev, pager,jumper, next";
|
||||
},
|
||||
isNextPageDisabled () {
|
||||
return this.curPageLength < this.pageData.limit;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
pageData: {
|
||||
default: function () {
|
||||
return {
|
||||
page: 1,
|
||||
pageSizes: [20, 50, 100],
|
||||
limit: 20,
|
||||
total: 400,
|
||||
};
|
||||
},
|
||||
},
|
||||
showCustomButtons: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
curPageLength: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange (direction) {
|
||||
if (direction === 0) {
|
||||
if (this.pageData.page > 1) {
|
||||
this.pageData.page -= 1;
|
||||
this.$emit('currentchange', this.pageData.page);
|
||||
}
|
||||
} else if (direction === 1) {
|
||||
if (!this.isNextPageDisabled) {
|
||||
this.pageData.page += 1;
|
||||
this.$emit('currentchange', this.pageData.page);
|
||||
}
|
||||
}
|
||||
},
|
||||
handleSizeChange (e) {
|
||||
this.pageData.limit = e;
|
||||
this.$emit("sizechange", e);
|
||||
},
|
||||
handleCurrentChange (e) {
|
||||
this.pageData.page = e;
|
||||
this.$emit("currentchange", e);
|
||||
},
|
||||
},
|
||||
};
|
||||
1404
clientarea/hgcloud/components/payDialog/payDialog.js
Normal file
1404
clientarea/hgcloud/components/payDialog/payDialog.js
Normal file
File diff suppressed because it is too large
Load Diff
98
clientarea/hgcloud/components/productFilter/productFilter.js
Normal file
98
clientarea/hgcloud/components/productFilter/productFilter.js
Normal file
@@ -0,0 +1,98 @@
|
||||
const productFilter = {
|
||||
template: /*html */ `
|
||||
<div class="product-tab-list">
|
||||
<el-tabs v-model="select_tab" @tab-click="handelTab" v-if="isInit">
|
||||
<el-tab-pane v-for="(item,index) in tabList" :key="item.tab" :name="item.tab">
|
||||
<template #label>
|
||||
<span>{{item.name}}</span>
|
||||
<span v-if="count[item.countName] > 0">({{count[item.countName]}})</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
select_tab: "all",
|
||||
isInit: false,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
tabList: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => {
|
||||
return [
|
||||
{
|
||||
name: lang.product_list_status1,
|
||||
tab: "using",
|
||||
countName: "using_count",
|
||||
},
|
||||
{
|
||||
name: lang.product_list_status2,
|
||||
tab: "expiring",
|
||||
countName: "expiring_count",
|
||||
},
|
||||
{
|
||||
name: lang.product_list_status3,
|
||||
tab: "overdue",
|
||||
countName: "overdue_count",
|
||||
},
|
||||
{
|
||||
name: lang.product_list_status4,
|
||||
tab: "deleted",
|
||||
countName: "deleted_count",
|
||||
},
|
||||
{
|
||||
name: lang.finance_btn5,
|
||||
tab: "all",
|
||||
countName: "all_count",
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
count: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {
|
||||
all_count: 0, // 全部产品数量
|
||||
deleted_count: 0, // 已删除产品数量
|
||||
expiring_count: 0, // 即将到期产品数量
|
||||
overdue_count: 0, // 已逾期产品数量
|
||||
using_count: 0, // 正常使用产品数量
|
||||
},
|
||||
},
|
||||
},
|
||||
// 监听count 数据变化了代表有数据 只执行一次 初始化不执行
|
||||
watch: {
|
||||
count: {
|
||||
handler(newVal) {
|
||||
if (newVal.list) {
|
||||
this.isInit = true;
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.tab) {
|
||||
this.select_tab = this.tab;
|
||||
}
|
||||
if (this.tab == "") {
|
||||
this.select_tab = "all";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handelTab({name}) {
|
||||
const tab = name === "all" ? "" : name;
|
||||
this.$emit("update:tab", tab);
|
||||
this.$emit("change");
|
||||
},
|
||||
},
|
||||
};
|
||||
358
clientarea/hgcloud/components/proofDialog/proofDialog.js
Normal file
358
clientarea/hgcloud/components/proofDialog/proofDialog.js
Normal file
@@ -0,0 +1,358 @@
|
||||
const proofDialog = {
|
||||
template: `
|
||||
<!-- 上传凭证 -->
|
||||
<div>
|
||||
<el-dialog custom-class='pay-dialog proof-dailog' :class='{look: isLook}' :visible.sync="proofDialog" :show-close="false"
|
||||
@close="proofClose">
|
||||
<div class="pc-pay">
|
||||
<div class="dia-title">
|
||||
<div class="title-text" v-if="isLook">{{lang.finance_custom19}}</div>
|
||||
<div class="title-text" v-else>{{lang.finance_custom6}}:{{zfData.orderId}}</div>
|
||||
<div class="title-text" v-show="!isLook">{{lang.pay_text2}}
|
||||
<span class="pay-money">{{ commonData.currency_prefix }}
|
||||
<span class="font-26">{{ Number(zfData.amount).toFixed(2)}}</span>
|
||||
</span>
|
||||
<i class="el-icon-circle-close close" @click="proofDialog = false"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dia-content">
|
||||
<div class="item" v-show="!isLook">
|
||||
<div class="pay-top">
|
||||
<div class="pay-type" ref="payListRef">
|
||||
<div class="type-item active">
|
||||
<img :src="bankImg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qr-money">
|
||||
<span>{{lang.finance_custom11}}:</span>
|
||||
<span class="pay-money">{{ commonData.currency_prefix}}
|
||||
<span class="font-26">
|
||||
{{orderInfo.amount_unpaid}}{{commonData.currency_code}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<p class="des">
|
||||
({{lang.finance_custom12}}:{{commonData.currency_prefix}}{{orderInfo.credit}}{{commonData.currency_code}})
|
||||
</p>
|
||||
<div class="custom-text">
|
||||
<div class="qr-content" v-loading="payLoading" v-html="payHtml" id="payBox"></div>
|
||||
<i class="el-icon-document-copy" v-if="payHtml" @click="copyText(payHtml)"></i>
|
||||
</div>
|
||||
<el-steps :space="200" :active="stepNum" finish-status="success" :align-center="true"
|
||||
class="custom-step">
|
||||
<el-step :title="lang.finance_custom7"></el-step>
|
||||
<el-step :title="lang.finance_custom4"></el-step>
|
||||
<el-step>
|
||||
<template slot="title">
|
||||
<span class="txt" :class="{ fail: orderStatus === 'ReviewFail'}">{{orderStatus === 'ReviewFail'
|
||||
? lang.finance_custom9 : lang.finance_custom8}}</span>
|
||||
<el-popover placement="top-start" trigger="hover" :title="review_fail_reason">
|
||||
<span class="help" slot="reference" v-if="orderStatus === 'ReviewFail'">?</span>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step :title="lang.finance_custom10"></el-step>
|
||||
</el-steps>
|
||||
</div>
|
||||
<div class="item">
|
||||
<p v-show="!isLook">{{lang.finance_custom4}}</p>
|
||||
<el-upload class="upload-demo" ref="fileupload" drag
|
||||
action="/console/v1/upload" :headers="{Authorization: jwt}"
|
||||
:before-remove="beforeRemove" multiple :file-list="fileList" :on-success="handleSuccess"
|
||||
:on-preview="clickFile"
|
||||
:limit="10"
|
||||
accept="image/*, .pdf, .PDF" v-if="!isLook">
|
||||
<div class="el-upload__text">
|
||||
<p>{{lang.finance_custom16}}<em>{{lang.finance_custom17}}</em></p>
|
||||
<p>{{lang.finance_custom18}}</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div v-else class="view-box">
|
||||
<p class="item" v-for="(item, index) in fileList" :key="index" @click="clickFile(item)">
|
||||
{{item.name}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="dia-fotter" v-if="!isLook">
|
||||
<el-button class="cancel-btn" @click="changeWay">{{lang.finance_custom14}}</el-button>
|
||||
<el-button @click="submitProof" :disabled="formData.voucher.length === 0" class="submit-btn" :loading="submitLoading">
|
||||
{{orderStatus === 'WaitUpload' ? lang.finance_custom4 : lang.finance_custom5}}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="dia-fotter" v-else>
|
||||
<el-button class="cancel-btn" @click="proofClose">{{lang.finance_text58}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 图片预览 -->
|
||||
<div style="height: 0;">
|
||||
<img id="proofViewer" :src="preImg" alt="">
|
||||
</div>
|
||||
<!-- 变更支付方式 -->
|
||||
<div class="delete-dialog">
|
||||
<el-dialog width="4.35rem" :visible.sync="showChangeWay" :show-close=false @close="showChangeWay=false">
|
||||
<div class="delete-box">
|
||||
<div class="delete-content">{{lang.finance_custom15}}</div>
|
||||
<div class="delete-btn">
|
||||
<el-button class="confirm-btn btn" @click="handelChangeWay" :loading="changeLoading">{{lang.finance_btn8}}</el-button>
|
||||
<el-button class="cancel-btn btn" @click="showChangeWay=false">{{lang.finance_btn7}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`,
|
||||
created() {},
|
||||
mounted() {
|
||||
// 引入 jquery
|
||||
// const script = document.createElement("script");
|
||||
// script.src = `${url}js/common/jquery.mini.js`;
|
||||
// document.body.appendChild(script);
|
||||
// this.initViewer();
|
||||
},
|
||||
// components: {
|
||||
// payDialog
|
||||
// },
|
||||
computed: {
|
||||
srcList() {
|
||||
return this.formData.voucher;
|
||||
},
|
||||
},
|
||||
destroyed() {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
proofDialog: false,
|
||||
zfData: {
|
||||
orderId: 0,
|
||||
amount: 0,
|
||||
},
|
||||
commonData: {
|
||||
currency_prefix: "¥",
|
||||
},
|
||||
orderInfo: {},
|
||||
stepNum: 0,
|
||||
orderStatus: "",
|
||||
review_fail_reason: "",
|
||||
payLoading: false,
|
||||
payHtml: "",
|
||||
fileList: [],
|
||||
jwt: `Bearer ${localStorage.jwt}`,
|
||||
formData: {
|
||||
id: "",
|
||||
voucher: [],
|
||||
},
|
||||
submitLoading: false,
|
||||
showChangeWay: false,
|
||||
changeLoading: false,
|
||||
viewer: null,
|
||||
preImg: "",
|
||||
isLook: false,
|
||||
bankImg: `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGoAAAAcCAYAAACJWipLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
|
||||
bWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdp
|
||||
bj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6
|
||||
eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2
|
||||
MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJo
|
||||
dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlw
|
||||
dGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAv
|
||||
IiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RS
|
||||
ZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpD
|
||||
cmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0
|
||||
YW5jZUlEPSJ4bXAuaWlkOkRDQ0EyQzUzQTNFOTExRUE5OENBOTNGMERBMUM4MkM0IiB4bXBNTTpE
|
||||
b2N1bWVudElEPSJ4bXAuZGlkOkRDQ0EyQzU0QTNFOTExRUE5OENBOTNGMERBMUM4MkM0Ij4gPHht
|
||||
cE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RENDQTJDNTFBM0U5MTFF
|
||||
QTk4Q0E5M0YwREExQzgyQzQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RENDQTJDNTJBM0U5
|
||||
MTFFQTk4Q0E5M0YwREExQzgyQzQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94
|
||||
OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz48YXx4AAAEzUlEQVR42uxaO2/TUBR2SiqxoKYS
|
||||
MMDQAGKuO9IONQsSYmiQGBBCqvsLcOcMSQWZm1asqC4TEgNhYGGJI9GygOqOFUW4bEyEAYFQUDhH
|
||||
fJee3th5tUpi4SMdXz+u7+N85+kkZSjKNy7Q8SbxGWM49Jt4xyil3/BFs9k0EjqkNEC6R8cnxKeH
|
||||
vqJ84xUd7xD/TOA5pDESzBVq3ZEA6S/dIi4m0OhAGcZd4vERW9f9BJpWoM6N4LouJtC0ApVQAlRC
|
||||
J5n1PSauxHHx1tycyW1te9vvd4z52VmLmoDGCHp8L0ONzYkYvVvXnvG66t2MKcsQ2g+vxfe2tuqt
|
||||
QJXS+9TujxwKj7qqoxxiE8wCKqvzsL46oBA2K6lH5w4EH0WuJngW6iq/y8LV+nrIXMshANtyHgLH
|
||||
ADg8f5X4Ot5XwOX4WTquroA2kaVmkXgNVlEXIHla9wJxJgQkTwCegfCjqIL3eF7mHPE3fk/MnwFP
|
||||
CGs1YF0KTPW+KwA3I7xFRa0xtkCJWusBuKZAIqEUNVAKESBNswYLS7G6mNcG8IqqaHn+eXF/VZzX
|
||||
tLEDzJ9Fa4WA5KGfHVugsBG2piUSsisA4M3ZQpMj3RhAWmJtpv58beqxJoxYCag/a/oO8TKsRa6B
|
||||
z7N0r9MaLLBu/TmAw3M4Kl6ljXyjDI0cNUp10WeDBLOB8xXh9lytXzXEjZWhsT6uGbBOIHnCqg7g
|
||||
5liwLmJPFsIP6LrYIcZFEc9RJ4CKetYXO6JN+GRVl+D+TMSYQAlJCFRpuS5wV1igilFfe1AeG3PL
|
||||
uGdi/imxlpYY18ZLqOzpBa6le12JbYwisALaTAA34wlACnpMikivXcSUGlxeKiRtryKGedr9CYCV
|
||||
QTKhMj8es9iF2wuj65hvGWP7wjMEcY1RlnRnJKimSCY2kYGxO7+Nc2V5ngBpEVlbr+RDqMqyTIxf
|
||||
V+m4sNR/7xB4TgfF81SqrhINvhf3LxNKWAzKLs4dkVGVNXc0j1hiiBR5KaT+6UhsfWxhsLIAABmw
|
||||
LgfzFMG+lgkamqv028SpBZQgsY5RLBwPlqW7PhYmB/NNpNFsNct0ryyEbYnis58vGaruMuEGq0gu
|
||||
KsKysrC4Tc2aXPRjXmCFof1Y2v4qtLcDjJMbtEW9Jp5sw2+P8RnIQcoshVmHtdVDUuDjUBYgqbjE
|
||||
c0wSGFlYmCPcFyc2tmaRgUg6XjIY6lOYcO1FAMpW5QzaoqaMUjq6Tsk39uh4rccxTbgW5jURMwqI
|
||||
WTY2vAMLK7f7LoivDraoZ8Jcn6uCPFJwS9VfbLVQGJWo+Fxcy/qMrnMohtfgHj14B0fLDi0oxSq7
|
||||
wEFa1GUC41Sb5x/6GDMDjZ6Bm5hQ8YvdG0CxUGPl9M9IEVQAT2PsnuIYWwxc6woSFiek2N5ldwgA
|
||||
LdzLiPhkcglCbANQb5AWNQ4N+RjxfK+PMXMqwENbZ3SLwbOiEf7zvhPillI9zO9G1Uf4ghFW5Joi
|
||||
AVHx1oHLCzg+afFq4K6P6WoboHr+gh/yc0CvWZx/zP0EfTwP2uwnsigeGwJQxkkB9T8RW9SXAc63
|
||||
TnFqvYt+nxNoWi3qGfGvEVvX0wQaHahS+hO1/AfM7yOypufEDxNojlJK1DFn6XiD+PyQ1vKD+B0p
|
||||
znu+SP7SfJT+CDAAdKMBqP61EkMAAAAASUVORK5CYII=
|
||||
`,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
proofClose() {
|
||||
this.proofDialog = false;
|
||||
this.viewer && this.viewer.destroy();
|
||||
},
|
||||
changeWay() {
|
||||
this.showChangeWay = true;
|
||||
},
|
||||
initViewer() {
|
||||
this.viewer = new Viewer(document.getElementById("proofViewer"), {
|
||||
button: true,
|
||||
inline: false,
|
||||
zoomable: true,
|
||||
title: true,
|
||||
tooltip: true,
|
||||
minZoomRatio: 0.5,
|
||||
maxZoomRatio: 100,
|
||||
movable: true,
|
||||
interval: 2000,
|
||||
navbar: true,
|
||||
loading: true,
|
||||
});
|
||||
},
|
||||
// 附件下载
|
||||
clickFile(item) {
|
||||
const name = item.name;
|
||||
const imgUrl = item.url || item.response.data.image_url;
|
||||
const type = name.substring(name.lastIndexOf(".") + 1);
|
||||
if (
|
||||
[
|
||||
"png",
|
||||
"jpg",
|
||||
"jepg",
|
||||
"bmp",
|
||||
"webp",
|
||||
"PNG",
|
||||
"JPG",
|
||||
"JEPG",
|
||||
"BMP",
|
||||
"WEBP",
|
||||
].includes(type)
|
||||
) {
|
||||
this.preImg = imgUrl;
|
||||
if (!this.viewer) {
|
||||
this.initViewer();
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.viewer.show();
|
||||
$("#proofViewer").attr("src", imgUrl);
|
||||
}, 10);
|
||||
} else {
|
||||
const downloadElement = document.createElement("a");
|
||||
downloadElement.href = url;
|
||||
downloadElement.download = item.name; // 下载后文件名
|
||||
document.body.appendChild(downloadElement);
|
||||
downloadElement.click(); // 点击下载
|
||||
}
|
||||
},
|
||||
emitRefresh(isChange = false) {
|
||||
this.$emit("refresh", isChange, this.orderInfo.id);
|
||||
},
|
||||
async handelChangeWay() {
|
||||
try {
|
||||
this.changeLoading = true;
|
||||
const res = await changePayType(this.orderInfo.id);
|
||||
this.$message.success(res.data.msg);
|
||||
this.showChangeWay = false;
|
||||
this.proofDialog = false;
|
||||
this.changeLoading = false;
|
||||
this.emitRefresh(true);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
this.changeLoading = false;
|
||||
this.showChangeWay = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
onProgress(event) {
|
||||
console.log(event);
|
||||
},
|
||||
async submitProof() {
|
||||
try {
|
||||
if (this.formData.voucher.length === 0) {
|
||||
return this.$message.warning(lang.finance_custom13);
|
||||
}
|
||||
this.submitLoading = true;
|
||||
const params = {
|
||||
id: this.zfData.orderId,
|
||||
voucher: this.formData.voucher,
|
||||
};
|
||||
const res = await uploadProof(params);
|
||||
this.submitLoading = false;
|
||||
this.$message.success(res.data.msg);
|
||||
this.proofDialog = false;
|
||||
this.emitRefresh();
|
||||
} catch (error) {
|
||||
this.submitLoading = false;
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
beforeRemove(file, fileList) {
|
||||
// 获取到删除的 save_name
|
||||
let save_name = file.save_name || file.response.data.save_name;
|
||||
this.formData.voucher = this.formData.voucher.filter((item) => {
|
||||
return item != save_name;
|
||||
});
|
||||
},
|
||||
// 上传文件相关
|
||||
handleSuccess(response, file, fileList) {
|
||||
if (response.status != 200) {
|
||||
this.$message.error(response.msg);
|
||||
// 清空上传框
|
||||
let uploadFiles = this.$refs["fileupload"].uploadFiles;
|
||||
let length = uploadFiles.length;
|
||||
uploadFiles.splice(length - 1, length);
|
||||
} else {
|
||||
this.formData.voucher = [];
|
||||
this.formData.voucher = fileList.map(
|
||||
(item) => item.response?.data?.save_name || item.save_name
|
||||
);
|
||||
}
|
||||
},
|
||||
async getOrderDetails(orderId) {
|
||||
try {
|
||||
const res = await orderDetails(orderId);
|
||||
this.orderInfo = res.data.data.order;
|
||||
|
||||
const {id, amount, status, review_fail_reason} = res.data.data.order;
|
||||
this.zfData.orderId = Number(id);
|
||||
this.zfData.amount = amount;
|
||||
this.proofDialog = true;
|
||||
this.orderStatus = status;
|
||||
this.review_fail_reason = review_fail_reason;
|
||||
this.isLook = status === "Paid" && this.orderInfo.voucher.length > 0;
|
||||
if (status === "WaitUpload") {
|
||||
this.stepNum = 2;
|
||||
} else {
|
||||
this.stepNum = 3;
|
||||
}
|
||||
// 获取转账信息
|
||||
this.payLoading = true;
|
||||
let result = "";
|
||||
if (!this.isLook) {
|
||||
result = await pay({
|
||||
id,
|
||||
gateway: "UserCustom",
|
||||
});
|
||||
this.payLoading = false;
|
||||
this.payHtml = result.data.data.html;
|
||||
$("#payBox").html(res.data.data.html);
|
||||
}
|
||||
|
||||
this.fileList = this.orderInfo.voucher;
|
||||
this.formData.voucher = this.orderInfo.voucher.map(
|
||||
(item) => item.save_name
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
this.$message.error(error.data.msg);
|
||||
this.payLoading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
255
clientarea/hgcloud/components/rechargeDialog/rechargeDialog.js
Normal file
255
clientarea/hgcloud/components/rechargeDialog/rechargeDialog.js
Normal file
@@ -0,0 +1,255 @@
|
||||
const rechargeDialog = {
|
||||
template: /*html*/ `
|
||||
<div>
|
||||
<el-dialog width="7.5rem" :visible.sync="isShowCz" @close="czClose" custom-class="recharge-dialog"
|
||||
:show-close="false">
|
||||
<div class="recharge-content">
|
||||
<div class="recharge-title">
|
||||
<span class="title-text">{{lang.finance_title4}}</span>
|
||||
<span class="close-btn" @click="czClose">
|
||||
<i class="el-icon-close"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="recharge-box">
|
||||
<div class="recharge-input">
|
||||
<el-input-number v-model="amount" :min="0" :precision="2" :step="0.01" :controls="false"
|
||||
:placeholder="lang.finance_text130">
|
||||
</el-input-number>
|
||||
<el-button @click="handleSubmit" type="primary" :loading="submitLoading">{{lang.finance_btn6}}
|
||||
</el-button>
|
||||
</div>
|
||||
<template v-if="rechargeActive.length > 0">
|
||||
<div class="recharge-tip">
|
||||
<template v-for="(item, index) in rechargeTip">
|
||||
<span>{{item}}</span>
|
||||
<template v-if="index !== rechargeTip.length - 1">
|
||||
<br />
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<div class="recharge-active">
|
||||
<div class="active-title">{{lang.coin_text12}}<el-tooltip effect="dark" placement="top"
|
||||
v-if="coinClientCoupon.coin_description_open == 1">
|
||||
<div slot="content" v-html="coinClientCoupon.coin_description"></div>
|
||||
<svg t="1745803081479" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="14138" width="16" height="16"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path
|
||||
d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m45.32419 487.619047v73.142857h-68.510476l-0.024381-73.142857h68.534857z m-4.047238-362.008381c44.251429 8.923429 96.889905 51.126857 96.889905 112.518096 0 61.415619-50.151619 84.650667-68.120381 96.134095-17.993143 11.50781-24.722286 24.771048-24.722286 38.863238V609.52381h-68.534857v-90.672762c0-21.504 6.89981-36.571429 26.087619-49.883429l4.315429-2.852571 38.497524-25.6c24.551619-16.530286 24.210286-49.712762 9.020952-64.365715a68.998095 68.998095 0 0 0-60.391619-15.481904c-42.715429 8.387048-47.640381 38.521905-47.932952 67.779047v16.554667H390.095238c0-56.953905 6.534095-82.773333 36.912762-115.395048 34.03581-36.449524 81.993143-42.300952 126.268952-33.328762z"
|
||||
p-id="14139" fill="currentColor"></path>
|
||||
</svg>
|
||||
</el-tooltip></div>
|
||||
<div class="active-main">
|
||||
<div class="active-list">
|
||||
<div class="active-item" v-for="item in rechargeActive" :key="item.id">
|
||||
<div class="active-name">
|
||||
<span>{{item.name}}</span>
|
||||
<span class="active-time">
|
||||
<template v-if="item.begin_time == 0">
|
||||
{{item.begin_time | formateTime}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{item.begin_time | formateTime}} - {{item.end_time | formateTime}}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="gradient-content" v-if="item.type === 'gradient'">
|
||||
<div class="gradient-item"
|
||||
:class="{active: amount *1 >= items.amount * 1 && (index == item.return.length - 1 || amount * 1 < item.return[index + 1].amount * 1)}"
|
||||
v-for="(items, index) in item.return" :key="items.id"
|
||||
@click="amount = items.amount">
|
||||
<div class="gradient-money">
|
||||
<span class="s-12">{{currency_prefix}}</span>{{items.amount}}
|
||||
</div>
|
||||
<div class="gradient-award ">
|
||||
{{lang.coin_text13}}{{items.amount}}{{lang.coin_text14}}{{items.award}}{{coinClientCoupon.name}}
|
||||
<i class="el-icon-check active-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gradient-content" v-if="item.type === 'proportion'">
|
||||
<div class="gradient-item" :class="{active:amount * 1 >= item.recharge_min * 1}"
|
||||
@click="amount = item.recharge_min">
|
||||
<div class="gradient-money">
|
||||
<span class="s-12">{{currency_prefix}}</span>{{item.recharge_min}}
|
||||
</div>
|
||||
<div class="gradient-award ">
|
||||
{{lang.coin_text15}}{{item.recharge_min}}<br>{{lang.coin_text16}}{{Number(item.recharge_proportion)}}%{{coinClientCoupon.name}}
|
||||
<i class="el-icon-check active-icon"></i>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="commonData.recharge_money_notice_content" v-html="commonData.recharge_money_notice_content"
|
||||
class="cz-notice">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<pay-dialog ref="payDialog" @payok="paySuccess"></pay-dialog>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
isShowCz: false,
|
||||
currency_prefix: "",
|
||||
currency_suffix: "",
|
||||
commonData: {},
|
||||
amount: undefined,
|
||||
submitLoading: false,
|
||||
rechargeActive: [],
|
||||
coinClientCoupon: {},
|
||||
};
|
||||
},
|
||||
components: {
|
||||
payDialog,
|
||||
},
|
||||
created() {
|
||||
this.getCommon();
|
||||
},
|
||||
filters: {
|
||||
formateTime(time) {
|
||||
if (time && time !== 0) {
|
||||
return formateDate(time * 1000);
|
||||
} else if (time === 0) {
|
||||
return lang.coin_text17;
|
||||
} else {
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
rechargeTip() {
|
||||
if (this.rechargeActive.length === 0 || !this.amount) {
|
||||
return [];
|
||||
}
|
||||
const rechargeTipList = [];
|
||||
const maxCoinAward = Number(
|
||||
this.coinClientCoupon.per_recharge_get_coin_max
|
||||
);
|
||||
this.rechargeActive.forEach((item) => {
|
||||
if (item.type === "proportion") {
|
||||
if (this.amount * 1 >= item.recharge_min * 1) {
|
||||
const award = Number(item.recharge_proportion * 0.01 * this.amount);
|
||||
const tip = `${item.name}:${lang.coin_text18}${Number(
|
||||
award > maxCoinAward ? maxCoinAward : award
|
||||
).toFixed(2)}${this.coinClientCoupon.name}`;
|
||||
rechargeTipList.push(tip);
|
||||
} else {
|
||||
const tip = `${item.name}:${lang.coin_text19}${Number(
|
||||
item.recharge_min - this.amount
|
||||
).toFixed(2)}${this.currency_suffix}${lang.coin_text20}${Number(
|
||||
item.recharge_proportion * 0.01 * item.recharge_min
|
||||
).toFixed(2)}${this.coinClientCoupon.name}`;
|
||||
rechargeTipList.push(tip);
|
||||
}
|
||||
}
|
||||
if (item.type === "gradient") {
|
||||
// 找出最大的阶梯金额
|
||||
const maxAmount = Math.max(
|
||||
...item.return.map((items) => items.amount)
|
||||
);
|
||||
if (this.amount * 1 >= maxAmount * 1) {
|
||||
const maxAward = item.return.find(
|
||||
(items) => items.amount === maxAmount
|
||||
)?.award;
|
||||
const tip = `${item.name}:${lang.coin_text18}${Number(
|
||||
maxAward > maxCoinAward ? maxCoinAward : maxAward
|
||||
).toFixed(2)}${this.coinClientCoupon.name}`;
|
||||
rechargeTipList.push(tip);
|
||||
} else {
|
||||
// 找出当前充值金额对应的阶梯 和 下一个阶梯
|
||||
const currentIndex = item.return.findIndex((items, index) => {
|
||||
return (
|
||||
this.amount * 1 >= items.amount * 1 &&
|
||||
this.amount * 1 < item.return[index + 1]?.amount * 1
|
||||
);
|
||||
});
|
||||
const currentAmount = item.return[currentIndex];
|
||||
const nextAmount = item.return[currentIndex + 1];
|
||||
if (currentAmount && nextAmount) {
|
||||
const currentAward =
|
||||
currentAmount.award > maxCoinAward
|
||||
? maxCoinAward
|
||||
: currentAmount.award;
|
||||
const nextAward =
|
||||
nextAmount.award > maxCoinAward
|
||||
? maxCoinAward
|
||||
: nextAmount.award;
|
||||
const tip = `${item.name}:${lang.coin_text21}${Number(
|
||||
currentAward
|
||||
).toFixed(2)}${this.coinClientCoupon.name},${
|
||||
lang.coin_text22
|
||||
}${Number(nextAmount.amount - this.amount).toFixed(2)}${
|
||||
this.currency_suffix
|
||||
}${lang.coin_text20}${Number(nextAward).toFixed(2)}${
|
||||
this.coinClientCoupon.name
|
||||
}`;
|
||||
rechargeTipList.push(tip);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return rechargeTipList;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getCoinClientCoupon() {
|
||||
apiCoinClientCoupon().then((res) => {
|
||||
this.coinClientCoupon = res.data.data;
|
||||
});
|
||||
},
|
||||
getRechargeDetail() {
|
||||
apiCoinRechargeDetail().then((res) => {
|
||||
this.rechargeActive = res.data.data.coins;
|
||||
});
|
||||
},
|
||||
open() {
|
||||
if (havePlugin("Coin")) {
|
||||
this.getRechargeDetail();
|
||||
this.getCoinClientCoupon();
|
||||
}
|
||||
this.isShowCz = true;
|
||||
},
|
||||
czClose() {
|
||||
this.amount = undefined;
|
||||
this.isShowCz = false;
|
||||
},
|
||||
handleSubmit() {
|
||||
if (!this.amount) {
|
||||
return this.$message.error(lang.finance_text130);
|
||||
}
|
||||
this.submitLoading = true;
|
||||
apiRecharge({amount: this.amount})
|
||||
.then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.isShowCz = false;
|
||||
const orderId = res.data.data.id;
|
||||
this.$refs.payDialog.czPay(orderId);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message.error(error.data.msg);
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitLoading = false;
|
||||
});
|
||||
},
|
||||
paySuccess() {
|
||||
this.$emit("success");
|
||||
},
|
||||
|
||||
getCommon() {
|
||||
this.commonData = JSON.parse(localStorage.getItem("common_set_before"));
|
||||
this.currency_prefix = this.commonData.currency_prefix;
|
||||
this.currency_suffix = this.commonData.currency_suffix;
|
||||
},
|
||||
},
|
||||
};
|
||||
10
clientarea/hgcloud/components/refundDialog/refundDialog.js
Normal file
10
clientarea/hgcloud/components/refundDialog/refundDialog.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const refundDialog = {
|
||||
template: `
|
||||
<div>这是退款弹窗</div>
|
||||
`,
|
||||
created() {},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {},
|
||||
};
|
||||
0
clientarea/hgcloud/components/registDialog/.gitkeep
Normal file
0
clientarea/hgcloud/components/registDialog/.gitkeep
Normal file
96
clientarea/hgcloud/components/renewDialog/renewDialog.css
Normal file
96
clientarea/hgcloud/components/renewDialog/renewDialog.css
Normal file
@@ -0,0 +1,96 @@
|
||||
.common-renew-dialog .dialog-main .renew-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
width: 105%;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item {
|
||||
width: 1.6rem;
|
||||
min-height: 0.83rem;
|
||||
border: 1px solid #E6E7EB;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-right: 0.2rem;
|
||||
margin-bottom: 0.2rem;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item:nth-child(3) {
|
||||
margin-right: 0;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item:nth-child(6) {
|
||||
margin-right: 0;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item .item-top {
|
||||
font-size: 0.15rem;
|
||||
color: #1E2736;
|
||||
margin-top: 0.08rem;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item .item-bottom {
|
||||
font-size: 0.15rem;
|
||||
color: var(--color-primary);
|
||||
margin-top: 0.04rem;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item .check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
color: #FFF;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-item .item-origin-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 0.15rem;
|
||||
color: #8692B0;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-active {
|
||||
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.common-renew-dialog .dialog-main .renew-content .renew-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 0.24rem solid var(--color-primary);
|
||||
border-left: 0.24rem solid transparent;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .pay-content {
|
||||
border: 1px solid #E6E7EB;
|
||||
border-radius: 3px;
|
||||
padding: 0.2rem 0;
|
||||
padding-right: 0.3rem;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .pay-content .pay-price {
|
||||
display: flex;
|
||||
text-align: right;
|
||||
flex-direction: row;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .pay-content .pay-price .text {
|
||||
font-size: 0.14rem;
|
||||
margin-top: 0.1rem;
|
||||
color: #1E2736;
|
||||
margin-right: 1.43rem;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .pay-content .pay-price .money {
|
||||
width: 100%;
|
||||
font-size: 0.28rem;
|
||||
font-weight: bold;
|
||||
color: var(--color-price-text);
|
||||
text-align: right;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .pay-content .pay-price .total-icon {
|
||||
font-size: 0.16rem;
|
||||
color: #1E2736;
|
||||
}
|
||||
.common-renew-dialog .dialog-main .pay-content .pay-price .original-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 0.2rem;
|
||||
font-weight: 500;
|
||||
color: #999999;
|
||||
}
|
||||
325
clientarea/hgcloud/components/renewDialog/renewDialog.js
Normal file
325
clientarea/hgcloud/components/renewDialog/renewDialog.js
Normal file
@@ -0,0 +1,325 @@
|
||||
const renewDialog = {
|
||||
template: /*html*/ `
|
||||
<div>
|
||||
<el-dialog width="6.9rem" :visible.sync="isShowRenew" :show-close="false" @close="renewDgClose" class="common-renew-dialog">
|
||||
<div class="dialog-title">{{demand ? '转包年包月' : '续费'}}</div>
|
||||
<div class="dialog-main">
|
||||
<div class="renew-content">
|
||||
<div class="renew-item" :class="selected_id==item.id?'renew-active':''" v-for="item in renewList"
|
||||
:key="item.id" @click="renewItemChange(item)">
|
||||
<div class="item-top">{{item.customfield?.multi_language?.billing_cycle || item.billing_cycle}}</div>
|
||||
<div class="item-bottom" v-if="hasShowPromo && useDiscount">
|
||||
{{commonData.currency_prefix + item.base_price}}
|
||||
</div>
|
||||
<div class="item-bottom" v-else>{{commonData.currency_prefix + item.price}}</div>
|
||||
<div class="item-origin-price"
|
||||
v-if="item.price*1 < item.base_price*1 && !useDiscount">
|
||||
{{commonData.currency_prefix + item.base_price}}
|
||||
</div>
|
||||
<i class="el-icon-check check" v-show="selected_id==item.id"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay-content">
|
||||
<div class="pay-price">
|
||||
<div class="money" v-loading="renewLoading">
|
||||
<span class="text">{{lang.common_cloud_label11}}:</span>
|
||||
<span>{{commonData.currency_prefix}}{{totalPrice | filterMoney}}</span>
|
||||
<el-popover placement="top-start" width="200" trigger="hover" v-if="level_discount_amount * 1 || code_discount_amount * 1">
|
||||
<div class="show-config-list">
|
||||
<p v-if="level_discount_amount*1 > 0">
|
||||
{{lang.shoppingCar_tip_text2}}:{{commonData.currency_prefix}}
|
||||
{{ level_discount_amount | filterMoney}}
|
||||
</p>
|
||||
<p v-if="code_discount_amount * 1 > 0">
|
||||
{{lang.shoppingCar_tip_text4}}:{{commonData.currency_prefix}}
|
||||
{{ code_discount_amount | filterMoney }}
|
||||
</p>
|
||||
</div>
|
||||
<i class="el-icon-warning-outline total-icon" slot="reference"></i>
|
||||
</el-popover>
|
||||
<p class="original-price"
|
||||
v-if="customfield.promo_code && totalPrice != base_price">
|
||||
{{commonData.currency_prefix}} {{ base_price | filterMoney}}
|
||||
</p>
|
||||
<p class="original-price"
|
||||
v-if="!customfield.promo_code && totalPrice != original_price">
|
||||
{{commonData.currency_prefix}} {{ original_price | filterMoney}}
|
||||
</p>
|
||||
<div class="code-box">
|
||||
<!-- 优惠码 -->
|
||||
<discount-code v-show="hasShowPromo && !customfield.promo_code"
|
||||
@get-discount="getRenewDiscount(arguments)"
|
||||
:scene="demand ? 'change_billing_cycle' : 'renew'" :product_id="product_id"
|
||||
:amount="base_price" :billing_cycle_time="duration"></discount-code>
|
||||
</div>
|
||||
<div class="code-number-text">
|
||||
<div class="discount-codeNumber" v-show="customfield.promo_code">
|
||||
{{ customfield.promo_code }}<i class="el-icon-circle-close remove-discountCode"
|
||||
@click="removeRenewDiscountCode"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="submitLoading" type="primary" class="btn-ok" @click="subRenew">
|
||||
{{demand ? lang.mf_demand_tip9 : lang.common_cloud_btn30}}
|
||||
</el-button>
|
||||
<div class="btn-no" @click="renewDgClose">{{lang.common_cloud_btn29}}</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
isShowRenew: false,
|
||||
currency_prefix: "",
|
||||
currency_suffix: "",
|
||||
commonData: {},
|
||||
submitLoading: false,
|
||||
renewList: [],
|
||||
hasClientLevel: false,
|
||||
hasShowPromo: false,
|
||||
hasShowCash: false,
|
||||
useDiscount: false,
|
||||
level_discount_amount: 0, // 用户等级优惠金额
|
||||
code_discount_amount: 0, // 优惠码优惠金额
|
||||
duration: 0, // 续费周期
|
||||
customfield: {
|
||||
promo_code: "",
|
||||
voucher_get_id: "",
|
||||
},
|
||||
billing_cycle: "",
|
||||
selected_id: 0,
|
||||
original_price: 0,
|
||||
base_price: 0,
|
||||
renewLoading: false,
|
||||
};
|
||||
},
|
||||
|
||||
props: {
|
||||
demand: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
required: true,
|
||||
},
|
||||
product_id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
required: true,
|
||||
},
|
||||
renew_amount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
billing_cycle_time: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
billing_cycle_name: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
// 加载css
|
||||
if (
|
||||
!document.querySelector(
|
||||
'link[href="' + url + 'components/renewDialog/renewDialog.css"]'
|
||||
)
|
||||
) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = `${url}components/renewDialog/renewDialog.css`;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
this.hasClientLevel = havePlugin("IdcsmartClientLevel");
|
||||
this.hasShowPromo = havePlugin("PromoCode");
|
||||
this.hasShowCash = havePlugin("IdcsmartVoucher");
|
||||
this.getCommon();
|
||||
},
|
||||
computed: {
|
||||
totalPrice() {
|
||||
const goodsPrice =
|
||||
this.hasShowPromo && this.customfield.promo_code
|
||||
? this.base_price
|
||||
: this.original_price;
|
||||
const discountPrice =
|
||||
this.level_discount_amount + this.code_discount_amount;
|
||||
const totalPrice = goodsPrice - discountPrice;
|
||||
const nowPrice = totalPrice > 0 ? totalPrice.toFixed(2) : 0;
|
||||
const showPirce = Number(nowPrice);
|
||||
return showPirce > 0 ? showPirce.toFixed(2) : 0;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 显示续费弹窗
|
||||
showRenew() {
|
||||
if (this.isShowRenew) return;
|
||||
// 获取续费页面信息
|
||||
const params = {
|
||||
id: this.id,
|
||||
};
|
||||
this.renewLoading = true;
|
||||
this.submitLoading = true;
|
||||
this.isShowRenew = true;
|
||||
const getRenewApi = this.demand
|
||||
? apiGetDemandToPrepaymentPrice
|
||||
: renewPage;
|
||||
getRenewApi(params)
|
||||
.then(async (res) => {
|
||||
this.submitLoading = false;
|
||||
this.renewLoading = false;
|
||||
if (res.data.status === 200) {
|
||||
this.renewList = res.data.data.host || res.data.data.duration || [];
|
||||
this.selected_id = this.renewList[0].id;
|
||||
this.billing_cycle = this.renewList[0].billing_cycle;
|
||||
this.duration = this.renewList[0].duration;
|
||||
this.original_price = this.renewList[0].price;
|
||||
this.base_price = this.renewList[0].base_price;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.submitLoading = false;
|
||||
this.renewLoading = false;
|
||||
this.isShowRenew = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
|
||||
// 续费使用优惠码
|
||||
async getRenewDiscount(data) {
|
||||
this.customfield.promo_code = data[1];
|
||||
this.useDiscount = true;
|
||||
this.code_discount_amount = Number(data[0]);
|
||||
this.level_discount_amount = await this.getClientLevelAmount(
|
||||
this.base_price
|
||||
);
|
||||
},
|
||||
|
||||
// 移除续费的优惠码
|
||||
removeRenewDiscountCode() {
|
||||
this.useDiscount = false;
|
||||
this.customfield.promo_code = "";
|
||||
this.code_discount_amount = 0;
|
||||
this.level_discount_amount = 0;
|
||||
},
|
||||
|
||||
// 续费弹窗关闭
|
||||
renewDgClose() {
|
||||
this.isShowRenew = false;
|
||||
this.selected_id = 0;
|
||||
this.duration = 0;
|
||||
this.billing_cycle = "";
|
||||
this.original_price = 0;
|
||||
this.base_price = 0;
|
||||
this.renewList = [];
|
||||
this.customfield = {
|
||||
promo_code: "",
|
||||
voucher_get_id: "",
|
||||
};
|
||||
this.code_discount_amount = 0;
|
||||
this.level_discount_amount = 0;
|
||||
this.removeRenewDiscountCode();
|
||||
},
|
||||
|
||||
async getClientLevelAmount(amount) {
|
||||
try {
|
||||
if (!this.hasClientLevel) {
|
||||
return 0;
|
||||
}
|
||||
const params = {id: this.product_id, amount: amount};
|
||||
const res = await apiClientLevelAmount(params);
|
||||
return Number(res.data.data.discount);
|
||||
} catch (error) {
|
||||
this.$message.error(error.data.msg);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
async getPromoDiscount(amount) {
|
||||
try {
|
||||
if (!this.hasShowPromo || !this.useDiscount) {
|
||||
return 0;
|
||||
}
|
||||
const params = {
|
||||
scene: this.demand ? "change_billing_cycle" : "renew",
|
||||
product_id: this.product_id,
|
||||
amount: amount,
|
||||
billing_cycle_time: this.duration,
|
||||
promo_code: this.customfield.promo_code,
|
||||
};
|
||||
|
||||
// 更新优惠码
|
||||
const res = await applyPromoCode(params);
|
||||
return Number(res.data.data.discount);
|
||||
} catch (error) {
|
||||
this.useDiscount = false;
|
||||
this.customfield.promo_code = "";
|
||||
this.level_discount_amount = 0;
|
||||
this.$message.error(error.data.msg);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
// 续费周期点击
|
||||
async renewItemChange(item) {
|
||||
this.submitLoading = true;
|
||||
this.selected_id = item.id;
|
||||
this.duration = item.duration;
|
||||
this.billing_cycle = item.billing_cycle;
|
||||
this.original_price = item.price;
|
||||
this.base_price = item.base_price;
|
||||
// 开启了优惠码插件
|
||||
this.level_discount_amount = await this.getClientLevelAmount(
|
||||
item.base_price
|
||||
);
|
||||
this.code_discount_amount = await this.getPromoDiscount(item.base_price);
|
||||
this.submitLoading = false;
|
||||
},
|
||||
|
||||
// 续费提交
|
||||
subRenew() {
|
||||
this.submitLoading = true;
|
||||
const params = {
|
||||
id: this.id,
|
||||
billing_cycle: this.billing_cycle,
|
||||
customfield: this.customfield,
|
||||
duration_id: this.selected_id,
|
||||
};
|
||||
const subApi = this.demand ? apiDemandToPrepayment : apiRenew;
|
||||
subApi(params)
|
||||
.then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.data.status === 200) {
|
||||
if (res.data.code == "Paid") {
|
||||
this.isShowRenew = false;
|
||||
this.$message.success(res.data.msg);
|
||||
this.$emit("success");
|
||||
} else {
|
||||
this.isShowRenew = false;
|
||||
this.$emit("pay", res.data.data.id);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.submitLoading = false;
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
|
||||
getCommon() {
|
||||
this.commonData = JSON.parse(localStorage.getItem("common_set_before"));
|
||||
this.currency_prefix = this.commonData.currency_prefix;
|
||||
this.currency_suffix = this.commonData.currency_suffix;
|
||||
},
|
||||
},
|
||||
};
|
||||
122
clientarea/hgcloud/components/renewDialog/renewDialog.less
Normal file
122
clientarea/hgcloud/components/renewDialog/renewDialog.less
Normal file
@@ -0,0 +1,122 @@
|
||||
.common-renew-dialog {
|
||||
|
||||
|
||||
|
||||
.dialog-main {
|
||||
.renew-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
width: 105%;
|
||||
|
||||
.renew-item {
|
||||
width: 1.6rem;
|
||||
min-height: .83rem;
|
||||
border: 1px solid #E6E7EB;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-right: .2rem;
|
||||
margin-bottom: .2rem;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:nth-child(3) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:nth-child(6) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.item-top {
|
||||
font-size: .15rem;
|
||||
color: #1E2736;
|
||||
margin-top: .08rem;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
font-size: .15rem;
|
||||
color: var(--color-primary);
|
||||
margin-top: .04rem;
|
||||
}
|
||||
|
||||
.check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.item-origin-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 0.15rem;
|
||||
color: #8692B0;
|
||||
}
|
||||
}
|
||||
|
||||
.renew-active {
|
||||
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 0.24rem solid var(--color-primary);
|
||||
border-left: 0.24rem solid transparent;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pay-content {
|
||||
border: 1px solid #E6E7EB;
|
||||
border-radius: 3px;
|
||||
padding: 0.2rem 0;
|
||||
padding-right: 0.3rem;
|
||||
|
||||
.pay-price {
|
||||
display: flex;
|
||||
text-align: right;
|
||||
flex-direction: row;
|
||||
|
||||
.text {
|
||||
font-size: 0.14rem;
|
||||
margin-top: .1rem;
|
||||
color: #1E2736;
|
||||
margin-right: 1.43rem;
|
||||
}
|
||||
|
||||
.money {
|
||||
width: 100%;
|
||||
font-size: .28rem;
|
||||
font-weight: bold;
|
||||
color: var(--color-price-text);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.total-icon {
|
||||
font-size: 0.16rem;
|
||||
color: #1E2736;
|
||||
}
|
||||
|
||||
.original-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 0.2rem;
|
||||
font-weight: 500;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
171
clientarea/hgcloud/components/resetAuth/resetAuth.css
Normal file
171
clientarea/hgcloud/components/resetAuth/resetAuth.css
Normal file
@@ -0,0 +1,171 @@
|
||||
.qrcode-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
.qrcode-status.loading {
|
||||
color: #999;
|
||||
}
|
||||
.qrcode-status.error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.common-auth-info .top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.common-auth-info .top .tit {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
.common-auth-info .top .reset-auth {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
.common-auth-info .top .reset-auth:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.common-auth-info .bot-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.common-auth-info .bot-info .label {
|
||||
color: #606266;
|
||||
}
|
||||
.common-auth-info .bot-info .status.reject {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.common-auth-info .bot-info .status.pending {
|
||||
color: #e6a23c;
|
||||
}
|
||||
.common-auth-info .bot-info .status.pending .cancel-auth {
|
||||
margin-left: 10px;
|
||||
color: var(--color-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
.common-auth-info .bot-info .status.pending .cancel-auth:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.common-auth-info .bot-info .status.approved {
|
||||
color: #67c23a;
|
||||
}
|
||||
.common-auth-dialog .dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
.common-auth-dialog .tip {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.common-auth-dialog .tip.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .base-info {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .base-info .item .s-tit {
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .base-info .item .info-row {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .base-info .item .info-row .label {
|
||||
color: #909399;
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .base-info .item .info-row .value {
|
||||
color: #303133;
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .base-info .item .info-row .value.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.common-auth-dialog .auth-info-display .domain-tip {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.common-auth-dialog .reason-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.common-auth-dialog .method-selection {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.common-auth-dialog .method-selection .method-card {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.common-auth-dialog .method-selection .method-card:hover {
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 2px 12px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
.common-auth-dialog .method-selection .method-card h4 {
|
||||
margin: 0 0 10px;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
.common-auth-dialog .method-selection .method-card p {
|
||||
color: #909399;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.common-auth-dialog .verify-content .user-info {
|
||||
background: #f5f7fa;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.common-auth-dialog .verify-content .user-info .info-row {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.common-auth-dialog .verify-content .user-info .info-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.common-auth-dialog .verify-content .user-info .info-row .label {
|
||||
color: #909399;
|
||||
}
|
||||
.common-auth-dialog .verify-content .user-info .info-row .value {
|
||||
color: #303133;
|
||||
}
|
||||
.common-auth-dialog .verify-content .user-info .info-row .value.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.common-auth-dialog .verify-content .qr-section {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.common-auth-dialog .verify-content .qr-section > p {
|
||||
color: #606266;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.common-auth-dialog .verify-content .qr-section .qr-code {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.common-auth-dialog .verify-content .qr-section .qr-code #qrcode-container {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.common-auth-dialog .verify-content .qr-section .verify-status {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.common-auth-dialog .dialog-footer {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
567
clientarea/hgcloud/components/resetAuth/resetAuth.js
Normal file
567
clientarea/hgcloud/components/resetAuth/resetAuth.js
Normal file
@@ -0,0 +1,567 @@
|
||||
// 加载组件样式
|
||||
(function () {
|
||||
if (!document.querySelector('link[href*="resetAuth.css"]')) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = `${url}components/resetAuth/resetAuth.css`;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
})();
|
||||
|
||||
const resetAuth = {
|
||||
template: `
|
||||
<div>
|
||||
<!-- 授权 -->
|
||||
<div class="common-auth-info">
|
||||
<div class="top">
|
||||
<p class="tit">{{lang.reset_auth_detail_title}}</p>
|
||||
<span class="reset-auth" @click="handleResetAuth" v-if="hasRestAuth && authDialog.status !== 'pending'">{{lang.reset_auth_reset_button}}</span>
|
||||
</div>
|
||||
<div class="bot-info" v-if="hasRestAuth">
|
||||
<span class="label">{{lang.reset_auth_status_label}}:</span>
|
||||
<div class="status">
|
||||
<div class="status reject" v-if="authDialog.status === 'rejected'">{{lang.reset_auth_status_failed}}({{authDialog.reject_reason}})
|
||||
</div>
|
||||
<div class="status pending" v-if="authDialog.status === 'pending'">{{lang.reset_auth_status_pending}}<span class="cancel-auth"
|
||||
@click="handleCancelAuth">{{lang.reset_auth_cancel_reset}}</span></div>
|
||||
<div class="status approved" v-if="authDialog.status === 'approved'">{{lang.reset_auth_status_normal}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 授权重置弹窗 -->
|
||||
<el-dialog :visible.sync="authDialog.visible" width="800px"
|
||||
:close-on-click-modal="false" custom-class="common-auth-dialog " @close="closeAuthDialog">
|
||||
<div class="dialog-title">
|
||||
{{authDialogTitle}}
|
||||
</div>
|
||||
<div v-if="authDialog.currentStep === 'confirm'">
|
||||
<p class="tip">{{lang.reset_auth_modify_tip}}</p>
|
||||
</div>
|
||||
<el-form :model="authDialog" status-icon :rules="rules" ref="ruleForm" label-width="100px"
|
||||
label-position="top" class="demo-ruleForm">
|
||||
<template v-if="authDialog.currentStep !== 'autoVerify'">
|
||||
<div class="auth-info-display">
|
||||
<div class="base-info">
|
||||
<div class="item">
|
||||
<p class="s-tit">{{lang.reset_auth_current_info}}:</p>
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_ip_label}}:</span>
|
||||
<span class="value">{{authDialog.original_ip || '--'}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_domain_label}}:</span>
|
||||
<span class="value">{{authDialog.original_domain || '--'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"
|
||||
v-if="authDialog.currentStep === 'selectMethod' || authDialog.currentStep === 'manualReview'">
|
||||
<p class="s-tit">{{lang.reset_auth_new_info}}:</p>
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_ip_label}}:</span>
|
||||
<span class="value">{{authDialog.new_ip || '--'}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_domain_label}}:</span>
|
||||
<span class="value">{{authDialog.new_domain || '--'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="authDialog.currentStep === 'confirm'">
|
||||
<el-form-item :label="lang.reset_auth_new_ip" prop="new_ip">
|
||||
<el-input v-model="authDialog.new_ip" :placeholder="lang.reset_auth_ip_placeholder"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="lang.reset_auth_new_domain" prop="new_domain">
|
||||
<el-input v-model="authDialog.new_domain" :placeholder="lang.reset_auth_domain_placeholder"></el-input>
|
||||
</el-form-item>
|
||||
<p class="domain-tip">{{lang.reset_auth_domain_tip}}</p>
|
||||
<p class="domain-tip">{{lang.reset_auth_domain_example}}</p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 申请理由 -->
|
||||
<div class="reason-section" v-if="authDialog.currentStep !== 'confirm' && authDialog.currentStep !== 'autoVerify'">
|
||||
<el-form-item :label="lang.reset_auth_apply_reason" prop="reset_reason">
|
||||
<el-input type="textarea" v-model="authDialog.reset_reason" :rows="4" :maxlength="300"
|
||||
show-word-limit :placeholder="lang.reset_auth_reason_placeholder">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 方式选择 -->
|
||||
<div v-if="authDialog.currentStep === 'selectMethod'">
|
||||
<p class="tip">{{lang.reset_auth_select_verify_tip}}</p>
|
||||
<div class="method-selection">
|
||||
<div class="method-card" @click="selectVerifyMethod('manual')">
|
||||
<h4>{{lang.reset_auth_manual_review}}</h4>
|
||||
<p>{{lang.reset_auth_manual_review_desc}}</p>
|
||||
<el-button>{{lang.reset_auth_submit_manual}}</el-button>
|
||||
</div>
|
||||
<div class="method-card" @click="selectVerifyMethod('auto')">
|
||||
<h4>{{lang.reset_auth_auto_reset}}</h4>
|
||||
<p>{{lang.reset_auth_auto_reset_desc}}</p>
|
||||
<el-button>{{lang.reset_auth_start_auto}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自动扫码认证 -->
|
||||
<div class="verify-content" v-if="authDialog.currentStep === 'autoVerify'">
|
||||
<p class="tip">{{lang.reset_auth_verify_tip}}</p>
|
||||
<p class="tip primary-color">{{lang.reset_auth_current_verify_info}}</p>
|
||||
<div class="user-info">
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_current_user}}:</span>
|
||||
<span class="value primary-color">{{authDialog.userInfo.username}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_real_name}}:</span>
|
||||
<span class="value primary-color">{{authDialog.userInfo.card_name}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">{{lang.reset_auth_id_card}}:</span>
|
||||
<span class="value primary-color">{{authDialog.userInfo.card_number}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qr-section">
|
||||
<p>{{lang.reset_auth_scan_tip}}</p>
|
||||
<div class="qr-code">
|
||||
<div id="qrcode-container">
|
||||
<!-- 二维码将在这里生成 -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="verify-status">
|
||||
<el-link :loading="verifying" type="primary" :underline="false" v-if="realnameStatus === 2">
|
||||
<i class="el-icon-loading"></i>
|
||||
{{lang.reset_auth_waiting_verify}}
|
||||
</el-link>
|
||||
<el-link type="success" :underline="false" v-if="realnameStatus === 1">{{lang.reset_auth_verify_success}}</el-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 动态底部按钮 -->
|
||||
<div class="dialog-footer">
|
||||
<template v-if="authDialog.currentStep === 'confirm'">
|
||||
<el-button type="primary" @click="confirmAuthChange" :loading="submitLoading">{{lang.reset_auth_confirm_modify}}</el-button>
|
||||
<el-button @click="closeAuthDialog">{{lang.reset_auth_cancel}}</el-button>
|
||||
</template>
|
||||
|
||||
<template v-if="authDialog.currentStep === 'selectMethod'">
|
||||
<el-button @click="goBackStep">{{lang.reset_auth_back}}</el-button>
|
||||
<el-button @click="closeAuthDialog">{{lang.reset_auth_cancel}}</el-button>
|
||||
</template>
|
||||
<div v-show="authDialog.currentStep === 'autoVerify'">
|
||||
<el-button type="primary" @click="handleSure" :disabled="realnameStatus === 2" :loading="submitLoading">{{lang.reset_auth_confirm_apply}}</el-button>
|
||||
<el-button @click="closeAuthDialog">{{lang.reset_auth_cancel}}</el-button>
|
||||
</div>
|
||||
<!-- 人工审核提交转移到选择方式的时候直接提交
|
||||
<template v-if="authDialog.currentStep === 'manualReview'">
|
||||
<el-button type="primary" @click="submitReset" :loading="submitLoading">{{lang.reset_auth_submit_apply}}</el-button>
|
||||
<el-button @click="closeAuthDialog">{{lang.reset_auth_cancel}}</el-button>
|
||||
</template>
|
||||
-->
|
||||
</div>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
hasRestAuth: false,
|
||||
authDialog: {
|
||||
visible: false,
|
||||
currentStep: "confirm", // confirm -> selectMethod -> autoVerify/manualReview
|
||||
host_id: "",
|
||||
original_ip: "",
|
||||
original_domain: "",
|
||||
status: "",
|
||||
application_id: "",
|
||||
new_ip: "",
|
||||
new_domain: "",
|
||||
userInfo: {
|
||||
username: "",
|
||||
card_name: "",
|
||||
card_number: "",
|
||||
url: "",
|
||||
certify_id: "",
|
||||
},
|
||||
reset_reason: "",
|
||||
verifying: false,
|
||||
},
|
||||
// 实名状态
|
||||
realnameStatus: 2, // 1通过 2未通过
|
||||
verifying: true,
|
||||
rules: {
|
||||
new_ip: [
|
||||
{
|
||||
required: false,
|
||||
pattern:
|
||||
/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
|
||||
message: this.lang.reset_auth_ip_format_error,
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
new_domain: [
|
||||
{
|
||||
required: false,
|
||||
pattern:
|
||||
/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/,
|
||||
message: this.lang.reset_auth_domain_format_error,
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
reset_reason: [
|
||||
{
|
||||
required: true,
|
||||
message: this.lang.reset_auth_reason_required,
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
},
|
||||
submitLoading: false,
|
||||
pollingTimer: null, // 轮询定时器
|
||||
pollingTimeout: null, // 轮询超时定时器
|
||||
qrCodeLibLoaded: false, // QRCode库是否已加载
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
info: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => {
|
||||
return {
|
||||
reject_reason: "", // 授权信息里面回显的拒绝理由
|
||||
host_id: "",
|
||||
original_ip: "",
|
||||
original_domain: "",
|
||||
status: "",
|
||||
reset_reason: "", // 申请重置的理由
|
||||
application_id: "",
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.info && Object.keys(this.info).length > 0) {
|
||||
Object.assign(this.authDialog, this.info);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
info: {
|
||||
handler(newVal) {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
Object.assign(this.authDialog, newVal);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
authDialogTitle() {
|
||||
const titleMap = {
|
||||
confirm: this.lang.reset_auth_modify_title,
|
||||
selectMethod: this.lang.reset_auth_modify_title,
|
||||
autoVerify: this.lang.reset_auth_auto_reset,
|
||||
manualReview: this.lang.reset_auth_manual_review,
|
||||
};
|
||||
return (
|
||||
titleMap[this.authDialog.currentStep] ||
|
||||
this.lang.reset_auth_modify_title
|
||||
);
|
||||
},
|
||||
// 检查是否有授权信息变更
|
||||
hasAuthChanges() {
|
||||
const hasIPChange =
|
||||
this.authDialog.new_ip.trim() !== "" &&
|
||||
this.authDialog.new_ip !== this.authDialog.original_ip;
|
||||
const hasDomainChange =
|
||||
this.authDialog.new_domain.trim() !== "" &&
|
||||
this.authDialog.new_domain !== this.authDialog.original_domain;
|
||||
return hasIPChange || hasDomainChange;
|
||||
},
|
||||
},
|
||||
mixins: [mixin],
|
||||
mounted() {
|
||||
this.hasRestAuth = this.addons_js_arr.includes("IdcsmartAuthreset");
|
||||
},
|
||||
methods: {
|
||||
/* 授权相关方法 */
|
||||
// 打开授权重置弹窗
|
||||
handleResetAuth() {
|
||||
this.authDialog.visible = true;
|
||||
this.authDialog.currentStep = "confirm";
|
||||
// 重置表单数据
|
||||
this.authDialog.new_ip = this.authDialog.original_ip;
|
||||
this.authDialog.new_domain = this.authDialog.original_domain;
|
||||
this.authDialog.reset_reason = "";
|
||||
this.authDialog.verifying = false;
|
||||
},
|
||||
|
||||
/* 撤销重置 */
|
||||
handleCancelAuth() {
|
||||
this.$confirm(this.lang.reset_auth_cancel_confirm)
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await apiCancelRest({
|
||||
application_id: this.authDialog.application_id,
|
||||
});
|
||||
this.$message.success(res.data.msg);
|
||||
this.$emit("cancel-auth");
|
||||
} catch (error) {
|
||||
this.$message.error(error.data?.msg);
|
||||
}
|
||||
})
|
||||
.catch((_) => {});
|
||||
},
|
||||
// 确认授权修改
|
||||
confirmAuthChange() {
|
||||
if (!this.hasAuthChanges) {
|
||||
this.submitReset();
|
||||
} else {
|
||||
this.$refs.ruleForm.validate((valid) => {
|
||||
if (!valid) {
|
||||
this.$message.error("请检查输入信息格式");
|
||||
return;
|
||||
}
|
||||
this.authDialog.currentStep = "selectMethod";
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 选择验证方式
|
||||
selectVerifyMethod(method) {
|
||||
this.authDialog.reset_method = method;
|
||||
this.submitReset();
|
||||
},
|
||||
|
||||
// 开始自动验证
|
||||
async startAutoVerify() {
|
||||
try {
|
||||
// application_id 提交申请过后返回的 application_id
|
||||
const params = {
|
||||
application_id: this.authDialog.application_id,
|
||||
};
|
||||
const res = await apiGetRealName(params);
|
||||
this.authDialog.userInfo = res.data.data;
|
||||
|
||||
if (!this.authDialog.userInfo.url) {
|
||||
this.realnameStatus = 2;
|
||||
return this.$message.error("获取认证链接失败");
|
||||
}
|
||||
// 1. 根据 this.authDialog.userInfo.url生成二维码
|
||||
this.generateQRCode(this.authDialog.userInfo.url);
|
||||
|
||||
// 2. 开始轮询状态
|
||||
this.startPolling();
|
||||
} catch (error) {
|
||||
this.$message.error(error.data?.msg);
|
||||
}
|
||||
},
|
||||
|
||||
// 加载QRCode库
|
||||
loadQRCodeLib() {
|
||||
return new Promise((resolve) => {
|
||||
if (typeof QRCode !== "undefined") {
|
||||
this.qrCodeLibLoaded = true;
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
// 检查是否已有加载中的脚本
|
||||
if (document.querySelector('script[src*="qrcode.min.js"]')) {
|
||||
const checkLoaded = setInterval(() => {
|
||||
if (typeof QRCode !== "undefined") {
|
||||
clearInterval(checkLoaded);
|
||||
this.qrCodeLibLoaded = true;
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
const script = document.createElement("script");
|
||||
script.src = `${url}js/common/qrcode.min.js`;
|
||||
script.onload = () => {
|
||||
this.qrCodeLibLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
},
|
||||
|
||||
// 生成二维码
|
||||
async generateQRCode(qrUrl) {
|
||||
if (!qrUrl) return;
|
||||
|
||||
const container = document.getElementById("qrcode-container");
|
||||
if (!container) return;
|
||||
|
||||
// 显示加载状态
|
||||
container.innerHTML = '<div class="qrcode-status loading">生成中...</div>';
|
||||
|
||||
try {
|
||||
// 确保QRCode库已加载
|
||||
if (!this.qrCodeLibLoaded) {
|
||||
await this.loadQRCodeLib();
|
||||
}
|
||||
|
||||
if (typeof QRCode !== "undefined") {
|
||||
container.innerHTML = "";
|
||||
new QRCode(container, {
|
||||
text: qrUrl,
|
||||
width: 150,
|
||||
height: 150,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.M,
|
||||
});
|
||||
} else {
|
||||
container.innerHTML = '<div class="qrcode-status error">二维码库加载失败</div>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("二维码生成错误:", error);
|
||||
container.innerHTML = '<div class="qrcode-status error">二维码生成失败</div>';
|
||||
}
|
||||
},
|
||||
|
||||
// 开始轮询认证状态
|
||||
startPolling() {
|
||||
this.verifying = true;
|
||||
this.realnameStatus = 2; // 重置为未通过状态
|
||||
// 清除之前的轮询
|
||||
if (this.pollingTimer) {
|
||||
clearInterval(this.pollingTimer);
|
||||
}
|
||||
// 开始轮询,每3秒检查一次
|
||||
this.pollingTimer = setInterval(async () => {
|
||||
try {
|
||||
const result = await apiGetRealNameStatus({
|
||||
application_id: this.authDialog.application_id,
|
||||
certify_id: this.authDialog.userInfo.certify_id,
|
||||
});
|
||||
|
||||
if (result.data && result.data.code === 1) {
|
||||
// 认证成功
|
||||
this.realnameStatus = 1;
|
||||
this.verifying = false;
|
||||
this.stopPolling();
|
||||
}
|
||||
} 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 = 2;
|
||||
this.$message.warning("认证超时,请重试");
|
||||
}
|
||||
}, 300000);
|
||||
},
|
||||
|
||||
// 停止轮询
|
||||
stopPolling() {
|
||||
if (this.pollingTimer) {
|
||||
clearInterval(this.pollingTimer);
|
||||
this.pollingTimer = null;
|
||||
}
|
||||
if (this.pollingTimeout) {
|
||||
clearTimeout(this.pollingTimeout);
|
||||
this.pollingTimeout = null;
|
||||
}
|
||||
},
|
||||
async handleSure() {
|
||||
try {
|
||||
this.submitLoading = true;
|
||||
const res = await apiAutoResetSure({
|
||||
application_id: this.authDialog.application_id,
|
||||
});
|
||||
this.$message.success(res.data.msg);
|
||||
this.submitLoading = false;
|
||||
this.closeAuthDialog();
|
||||
} catch (error) {
|
||||
this.submitLoading = false;
|
||||
this.$message.error(error.data?.msg);
|
||||
}
|
||||
},
|
||||
// 提交审核申请
|
||||
submitReset() {
|
||||
this.$refs.ruleForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
let params = {};
|
||||
if (this.authDialog.currentStep !== "confirm") {
|
||||
params = {
|
||||
new_ip: this.authDialog.new_ip,
|
||||
new_domain: this.authDialog.new_domain,
|
||||
reset_reason: this.authDialog.reset_reason,
|
||||
reset_method: this.authDialog.reset_method,
|
||||
};
|
||||
}
|
||||
this.submitLoading = true;
|
||||
params.host_id = this.authDialog.host_id;
|
||||
const res = await apiRestAuth(params);
|
||||
this.$message.success(res.data.msg);
|
||||
|
||||
const {application_id} = res.data.data;
|
||||
this.authDialog.application_id = application_id;
|
||||
this.submitLoading = false;
|
||||
if (params.reset_method === "auto") {
|
||||
this.authDialog.currentStep = "autoVerify";
|
||||
this.startAutoVerify();
|
||||
} else {
|
||||
this.closeAuthDialog();
|
||||
}
|
||||
} catch (error) {
|
||||
this.submitLoading = false;
|
||||
this.$message.error(error.data?.msg);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 返回上一步
|
||||
goBackStep() {
|
||||
const stepFlow = {
|
||||
selectMethod: "confirm",
|
||||
autoVerify: "selectMethod",
|
||||
manualReview: "selectMethod",
|
||||
};
|
||||
this.authDialog.currentStep =
|
||||
stepFlow[this.authDialog.currentStep] || "confirm";
|
||||
},
|
||||
|
||||
// 关闭弹窗
|
||||
closeAuthDialog() {
|
||||
// 避免重复触发
|
||||
if (!this.authDialog.visible) return;
|
||||
// 停止轮询
|
||||
this.stopPolling();
|
||||
// 重置状态
|
||||
this.verifying = false;
|
||||
this.realnameStatus = 2;
|
||||
// 清空二维码
|
||||
const container = document.getElementById("qrcode-container");
|
||||
if (container) {
|
||||
container.innerHTML = "";
|
||||
}
|
||||
// 关闭弹窗
|
||||
this.authDialog.visible = false;
|
||||
this.authDialog.currentStep = "confirm";
|
||||
// 重新拉取授权信息
|
||||
this.$emit("cancel-auth");
|
||||
},
|
||||
/* 授权相关方法 end */
|
||||
},
|
||||
|
||||
// 组件销毁时清理定时器
|
||||
beforeDestroy() {
|
||||
this.stopPolling();
|
||||
},
|
||||
};
|
||||
230
clientarea/hgcloud/components/resetAuth/resetAuth.less
Normal file
230
clientarea/hgcloud/components/resetAuth/resetAuth.less
Normal file
@@ -0,0 +1,230 @@
|
||||
// 授权重置组件样式
|
||||
|
||||
// 二维码状态样式
|
||||
.qrcode-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
&.loading {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
.common-auth-info {
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.tit {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.reset-auth {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bot-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.status {
|
||||
&.reject {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
&.pending {
|
||||
color: #e6a23c;
|
||||
|
||||
.cancel-auth {
|
||||
margin-left: 10px;
|
||||
color: var(--color-primary);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.approved {
|
||||
color: #67c23a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 授权重置弹窗
|
||||
.common-auth-dialog {
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.tip {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
&.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.auth-info-display {
|
||||
.base-info {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.item {
|
||||
.s-tit {
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
margin-bottom: 8px;
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
|
||||
&.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.domain-tip {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.reason-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
// 方式选择
|
||||
.method-selection {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
|
||||
.method-card {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 2px 12px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #909399;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自动验证
|
||||
.verify-content {
|
||||
.user-info {
|
||||
background: #f5f7fa;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin: 15px 0;
|
||||
|
||||
.info-row {
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
|
||||
&.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qr-section {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
|
||||
> p {
|
||||
color: #606266;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.qr-code {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
#qrcode-container {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.verify-status {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
100
clientarea/hgcloud/components/safeConfirm/safeConfirm.js
Normal file
100
clientarea/hgcloud/components/safeConfirm/safeConfirm.js
Normal file
@@ -0,0 +1,100 @@
|
||||
const safeConfirm = {
|
||||
template: `
|
||||
<div>
|
||||
<el-dialog width="6.8rem" :visible.sync="visible" :show-close=false @close="closeDialog" custom-class="withdraw-dialog">
|
||||
<div class="dialog-title">
|
||||
{{lang.account_tips_text3}}
|
||||
</div>
|
||||
<div class="dialog-main">
|
||||
<el-form label-width="80px" ref="ruleForm" :rules="rules" :model="dataForm" label-position="top" @submit.native.prevent>
|
||||
<el-form-item :label="lang.account_tips_text3" prop="password">
|
||||
<el-input class="input-select" type="password" v-model="dataForm.password" autocomplete="off" :placeholder="lang.account_tips_text2"></el-input>
|
||||
<el-checkbox v-model="remember" style="margin-top: 5px;color: #999;}">{{lang.account_tips_text13}}</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button class="btn-ok" type="primary" @click="save" v-loading="submitLoading">{{lang.cart_tip_text9}}</el-button>
|
||||
<el-button class="btn-no" @click="closeDialog">{{lang.cart_tip_text10}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
submitLoading: false,
|
||||
passData: "",
|
||||
callbackFun: "",
|
||||
home_enforce_safe_method: [],
|
||||
dataForm: {
|
||||
password: "",
|
||||
},
|
||||
rules: {
|
||||
password: [
|
||||
{required: true, message: lang.account_tips_text2, trigger: "blur"},
|
||||
],
|
||||
},
|
||||
remember: false,
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
props: {
|
||||
password: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
isLogin: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
this.home_enforce_safe_method =
|
||||
JSON.parse(localStorage.getItem("common_set_before"))
|
||||
?.home_enforce_safe_method || [];
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @param {String} callbackFun 回调函数名称
|
||||
*/
|
||||
openDialog(callbackFun) {
|
||||
this.callbackFun = callbackFun;
|
||||
this.dataForm.password = "";
|
||||
this.$emit("update:password", this.dataForm.password);
|
||||
|
||||
// if (
|
||||
// !this.home_enforce_safe_method.includes("operate_password") &&
|
||||
// !this.isLogin
|
||||
// ) {
|
||||
// this.$emit("update:password", "noNeed");
|
||||
// // 执行父级方法
|
||||
// this.$emit("confirm", this.callbackFun);
|
||||
// } else {
|
||||
// this.visible = true;
|
||||
// setTimeout(() => {
|
||||
// this.$refs.ruleForm.resetFields();
|
||||
// }, 0);
|
||||
// }
|
||||
this.visible = true;
|
||||
setTimeout(() => {
|
||||
this.$refs.ruleForm.resetFields();
|
||||
}, 0);
|
||||
},
|
||||
closeDialog() {
|
||||
this.visible = false;
|
||||
},
|
||||
save() {
|
||||
this.$refs.ruleForm.validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
this.$emit("update:password", this.dataForm.password);
|
||||
// 执行父级方法
|
||||
this.$emit("confirm", this.callbackFun, this.remember ? 1 : 0);
|
||||
this.closeDialog();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
93
clientarea/hgcloud/components/scrollText/scrollText.js
Normal file
93
clientarea/hgcloud/components/scrollText/scrollText.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const scrollText = {
|
||||
template: /* html*/ `
|
||||
<div class="scroll-container" ref="container">
|
||||
<div
|
||||
class="scroll-text"
|
||||
ref="text"
|
||||
:class="{ 'centered': !isOverflow }"
|
||||
:style="textStyle"
|
||||
@mouseenter="pause"
|
||||
@mouseleave="resume"
|
||||
>
|
||||
<slot></slot>
|
||||
<!-- loop 模式下复制一份实现无缝 -->
|
||||
<span v-if="mode === 'loop' && isOverflow" class="clone">
|
||||
<slot></slot>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
duration: 0,
|
||||
isOverflow: false,
|
||||
paused: false,
|
||||
containerWidth: 0,
|
||||
textWidth: 0,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
speed: {type: Number, default: 50}, // 像素/秒
|
||||
pauseTime: {type: Number, default: 2}, // once 模式停顿时间(秒)
|
||||
mode: {
|
||||
type: String,
|
||||
default: "loop", // 可选: loop, once, pause
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
textStyle() {
|
||||
// 不超出:静止居中
|
||||
if (!this.isOverflow) {
|
||||
return {transform: "translateX(0)"};
|
||||
}
|
||||
|
||||
let animation = "";
|
||||
if (this.mode === "loop") {
|
||||
animation = `scroll-loop ${this.duration}s linear infinite`;
|
||||
} else if (this.mode === "once") {
|
||||
// 每次滚动结束,停 pauseTime 秒
|
||||
const totalTime = this.duration + this.pauseTime;
|
||||
animation = `scroll-once ${totalTime}s linear infinite`;
|
||||
} else if (this.mode === "pause") {
|
||||
animation = `scroll-pause ${this.duration}s linear forwards`;
|
||||
}
|
||||
|
||||
return {
|
||||
animation,
|
||||
"animation-play-state": this.paused ? "paused" : "running",
|
||||
};
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.checkOverflow();
|
||||
window.addEventListener("resize", this.checkOverflow);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("resize", this.checkOverflow);
|
||||
},
|
||||
methods: {
|
||||
checkOverflow() {
|
||||
this.$nextTick(() => {
|
||||
const container = this.$refs.container;
|
||||
const text = this.$refs.text;
|
||||
if (!container || !text) return;
|
||||
|
||||
this.containerWidth = container.clientWidth;
|
||||
this.textWidth = text.scrollWidth;
|
||||
|
||||
this.isOverflow = this.textWidth > this.containerWidth;
|
||||
|
||||
if (this.isOverflow) {
|
||||
this.duration = this.textWidth / this.speed;
|
||||
}
|
||||
});
|
||||
},
|
||||
pause() {
|
||||
this.paused = true;
|
||||
},
|
||||
resume() {
|
||||
this.paused = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -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();
|
||||
},
|
||||
};
|
||||
39
clientarea/hgcloud/components/shadowContent/shadowContent.js
Normal file
39
clientarea/hgcloud/components/shadowContent/shadowContent.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const shadowContent = {
|
||||
template: /* html*/ `
|
||||
<div ref="shadow"></div>
|
||||
`,
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
shadowRoot: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.shadowRoot = this.$refs.shadow.attachShadow({mode: "open"});
|
||||
this.renderShadow();
|
||||
},
|
||||
// 内容变动时更新 Shadow DOM
|
||||
watch: {
|
||||
content() {
|
||||
this.renderShadow();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
renderShadow() {
|
||||
this.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
${this.content}
|
||||
`;
|
||||
},
|
||||
},
|
||||
};
|
||||
616
clientarea/hgcloud/components/topMenu/topMenu.js
Normal file
616
clientarea/hgcloud/components/topMenu/topMenu.js
Normal file
@@ -0,0 +1,616 @@
|
||||
// css 样式依赖common.css
|
||||
ELEMENT.Dialog.props.closeOnClickModal.default = false;
|
||||
const topMenu = {
|
||||
template: /*html*/ `
|
||||
<div>
|
||||
<el-drawer :visible.sync="isShowMenu" direction="ltr" :before-close="handleClose" :with-header="false" size="3.8rem"
|
||||
custom-class="drawer-menu">
|
||||
<div class="drawer-menu-top">
|
||||
<a :href="commonData.clientarea_logo_url || '/home.htm'" onclick="return false" class="menu-alink">
|
||||
<img class="drawer-menu-logo" @click="goHome" :src="logo"></img>
|
||||
</a>
|
||||
</div>
|
||||
<div class="drawer-menu-list-top">
|
||||
<el-menu class="menu-top" :default-active="menuActiveId" @select="handleSelect" background-color="transparent"
|
||||
text-color="var(--color-menu-text)" active-text-color="var(--color-menu-text-active)">
|
||||
<template v-for="item in menu1">
|
||||
<!-- 只有一级菜单 -->
|
||||
<el-menu-item v-if="!item.child || item.child?.length === 0" :key="item.id"
|
||||
:index="item.id ? item.id + '' : item.url" :id="item.url">
|
||||
<a :href="getMenuUrl(item.id || item.url)" onclick="return false" class="menu-alink">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</a>
|
||||
</el-menu-item>
|
||||
<!-- 有二级菜单 -->
|
||||
<el-submenu v-else :key="item.id" :index="item.id ? item.id + '' : item.url" :id="item.url">
|
||||
<template slot="title">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</template>
|
||||
<template v-for="child in item.child">
|
||||
<el-menu-item :index="child.id ? child.id + '' : child.url" :key="child.id">
|
||||
<a :href="getMenuUrl(child.id || child.url)" onclick="return false" class="menu-alink">
|
||||
{{child.name}}
|
||||
</a>
|
||||
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-submenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
|
||||
<div class="line" v-if="hasSeparate"></div>
|
||||
|
||||
<el-menu class="menu-top" :default-active="menuActiveId " @select="handleSelect" background-color="transparent"
|
||||
text-color="var(--color-menu-text)" active-text-color="var(--color-menu-text-active)">
|
||||
<template v-for="item in menu2">
|
||||
<!-- 只有一级菜单 -->
|
||||
<el-menu-item v-if="!item.child || item.child?.length === 0" :key="item.id"
|
||||
:index="item.id ? item.id + '' : item.url" :id="item.url">
|
||||
<a :href="getMenuUrl(item.id || item.url)" onclick="return false" class="menu-alink">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</a>
|
||||
</el-menu-item>
|
||||
<!-- 有二级菜单 -->
|
||||
<el-submenu v-else :key="item.id" :index="item.id ? item.id + '' : item.url" :id="item.url">
|
||||
<template slot="title">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<span class="aside-menu-text" slot="title">{{item.name}}</span>
|
||||
</template>
|
||||
<template v-for="child in item.child">
|
||||
<el-menu-item :index="child.id ? child.id + '' : child.url" :key="child.id">
|
||||
<a :href="getMenuUrl(child.id || child.url)" onclick="return false" class="menu-alink">
|
||||
{{child.name}}
|
||||
</a>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-submenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<el-header>
|
||||
<div class="header-left">
|
||||
<img src="${url}/img/common/menu.png" class="menu-img" @click="showMenu">
|
||||
<img v-if="isShowMore" src="${url}/img/common/search.png" class="left-img">
|
||||
<el-autocomplete v-if="isShowMore" v-model="topInput" :fetch-suggestions="querySearchAsync" placeholder="请输入内容"
|
||||
@select="handleSelect">
|
||||
<template slot-scope="{ item }">
|
||||
<div class="search-value">{{ item.value }}</div>
|
||||
<div class="search-name">{{ item.name }}</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="header-right-item car-item">
|
||||
<div v-if="isShowCart" class="right-item" @click="goShoppingCar">
|
||||
<el-badge :value="shoppingCarNum" class="item" :max="999" :hidden="shoppingCarNum === 0 ? true : false">
|
||||
<img src="${url}/img/common/cart.svg">
|
||||
</el-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right-item car-item" v-plugin="'ClientCare'">
|
||||
<el-popover placement="bottom-start" trigger="hover" :visible-arrow="false">
|
||||
<div class="top-msg-box">
|
||||
<div class="msg-top">
|
||||
<span class="msg-top-left">{{lang.subaccount_text56}}</span>
|
||||
<span class="msg-top-right" @click="goAccount">{{lang.subaccount_text57}}</span>
|
||||
</div>
|
||||
<div class="msg-list" v-if="msgList.length !== 0">
|
||||
<div class="msg-item" v-for="item in msgList" :key="item.id" @click="goMsgDetail(item.id)">
|
||||
<div class="msg-item-left" :style="{color: item.read === 1 ? '#8692b0' : 'var(--color-primary)' }">
|
||||
<svg t="1750123872473" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12811" width="16" height="16">
|
||||
<path d="M440.35072 623.04768 46.04416 373.1456l0 393.62048c0 64.63488 52.53632 117.39136 117.31968 117.39136l706.71872 0c64.70656 0 117.31456-52.57728 117.31456-117.39136l0-387.1232-368.99328 242.10944C568.1408 654.72 491.07968 655.19104 440.35072 623.04768L440.35072 623.04768 440.35072 623.04768z" fill="currentColor" p-id="12812"></path>
|
||||
<path d="M870.08256 158.51008 163.35872 158.51008c-64.70656 0-117.31968 52.57728-117.31968 117.39136l0 0.90112 443.30496 280.96c20.83328 13.2096 58.27584 12.95872 78.93504-0.57856l419.1488-275.00032 0-6.28224C987.39712 211.3024 934.8608 158.51008 870.08256 158.51008L870.08256 158.51008 870.08256 158.51008z" fill="currentColor" p-id="12813"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="msg-item-right">
|
||||
<div class="msg-item-right-top">{{item.title}}</div>
|
||||
<div class="msg-item-right-bottom">
|
||||
<span>{{msgType[item.type]}}</span>
|
||||
<span>{{item.create_time | formateTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else :description="lang.subaccount_text55"></el-empty>
|
||||
</div>
|
||||
<div class="right-item" slot="reference">
|
||||
<el-badge :value="msgCount" class="item" :max="999" :hidden="msgCount === 0 ? true : false">
|
||||
<img src="${url}/img/common/msg.svg">
|
||||
</el-badge>
|
||||
</div>
|
||||
</el-popover>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="header-right-item hg-24">
|
||||
<el-dropdown @command="changeLang" trigger="click" :disabled="commonData.lang_home_open * 1 ? false : true">
|
||||
<div class="el-dropdown-country">
|
||||
<img :src="curSrc" alt="">
|
||||
<i class="right-icon el-icon-arrow-down el-icon--right"></i>
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-for="item in commonData.lang_list" :key="item.display_lang"
|
||||
:command="item.display_lang">{{item.display_name}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="header-right-item cloum-line-item" v-if="isGetData">
|
||||
<div class="cloum-line"></div>
|
||||
</div>
|
||||
|
||||
<div class="header-right-item" v-show="unLogin && isGetData">
|
||||
<div class="un-login" @click="goLogin">
|
||||
<img src="${url}/img/common/login_icon.png">{{lang.topMenu_text1}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-right-item" v-show="!unLogin && isGetData">
|
||||
<el-dropdown @command="handleCommand" trigger="click">
|
||||
<div class="el-dropdown-header">
|
||||
<div class="right-item head-box" ref="headBoxRef" v-show="firstName">{{firstName}}</div>
|
||||
<i class="right-icon el-icon-arrow-down el-icon--right"></i>
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="account">{{lang.topMenu_text2}}</el-dropdown-item>
|
||||
<el-dropdown-item command="quit">{{lang.topMenu_text3}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<coin-active ref="coinActive" v-plugin="'Coin'"></coin-active>
|
||||
</div>
|
||||
</el-header>
|
||||
</div>
|
||||
`,
|
||||
directives: {
|
||||
plugin: {
|
||||
inserted: function (el, binding) {
|
||||
const addonsDom = document.querySelector("#addons_js");
|
||||
let addonsArr = [];
|
||||
let arr = [];
|
||||
if (addonsDom) {
|
||||
addonsArr = JSON.parse(addonsDom.getAttribute("addons_js")) || []; // 插件列表
|
||||
// 判断是否安装了某插件
|
||||
arr = addonsArr.filter((item) => item.name === binding.value);
|
||||
if (arr.length === 0) {
|
||||
// 未安装 移除该元素的dom
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
} else {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
coinActive,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
topInput: "",
|
||||
// curSrc: url+'/img/common/'+lang_obj.countryImg+'.png' ,
|
||||
curSrc: `/upload/common/country/${lang_obj.countryImg}.png`,
|
||||
isShowMenu: false,
|
||||
logo: `/upload/logo.png`,
|
||||
menu1: [],
|
||||
menu2: [],
|
||||
menuActiveId: "",
|
||||
firstName: "",
|
||||
hasSeparate: false,
|
||||
originMenu: [],
|
||||
produclData: [],
|
||||
selectValue: "",
|
||||
shoppingCarNum: 0,
|
||||
headBgcList: [
|
||||
"#3699FF",
|
||||
"#57C3EA",
|
||||
"#5CC2D7",
|
||||
"#EF8BA2",
|
||||
"#C1DB81",
|
||||
"#F1978C",
|
||||
"#F08968",
|
||||
],
|
||||
commonData: {
|
||||
lang_list: [],
|
||||
},
|
||||
unLogin: true,
|
||||
isGetData: false,
|
||||
msgList: [],
|
||||
msgCount: 0,
|
||||
accountData: {},
|
||||
msgType: {
|
||||
official: lang.subaccount_text54,
|
||||
host: lang.finance_info,
|
||||
finance: lang.finance_text123,
|
||||
},
|
||||
predefineColors: [
|
||||
"#ff4500",
|
||||
"#ff8c00",
|
||||
"#ffd700",
|
||||
"#90ee90",
|
||||
"#00ced1",
|
||||
"#1e90ff",
|
||||
"#c71585",
|
||||
"rgba(255, 69, 0, 0.68)",
|
||||
"rgb(255, 120, 0)",
|
||||
"hsv(51, 100, 98)",
|
||||
"hsva(120, 40, 94, 0.5)",
|
||||
"hsl(181, 100%, 37%)",
|
||||
"hsla(209, 100%, 56%, 0.73)",
|
||||
"#c7158577",
|
||||
],
|
||||
};
|
||||
},
|
||||
props: {
|
||||
isShowMore: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isShowCart: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
num: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
num (val) {
|
||||
if (val) {
|
||||
this.shoppingCarNum = val;
|
||||
}
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
formateTime (time) {
|
||||
if (time && time !== 0) {
|
||||
const date = new Date(time * 1000);
|
||||
Y = date.getFullYear() + "-";
|
||||
M =
|
||||
(date.getMonth() + 1 < 10
|
||||
? "0" + (date.getMonth() + 1)
|
||||
: date.getMonth() + 1) + "-";
|
||||
D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";
|
||||
h =
|
||||
(date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) +
|
||||
":";
|
||||
m =
|
||||
date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
|
||||
return Y + M + D + h + m;
|
||||
} else {
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.GetIndexData();
|
||||
this.doGetMenu();
|
||||
this.getCartList();
|
||||
this.getCommonSetting();
|
||||
},
|
||||
mounted () {
|
||||
// 不生效
|
||||
this.color1 = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--color-primary")
|
||||
.trim();
|
||||
|
||||
if (this.getPluginId("ClientCare")) {
|
||||
this.getMessageList();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getPluginId (pluginName) {
|
||||
const addonsDom = document.querySelector("#addons_js");
|
||||
if (addonsDom) {
|
||||
const addonsArr = JSON.parse(addonsDom.getAttribute("addons_js")); // 插件列表
|
||||
for (let index = 0; index < addonsArr.length; index++) {
|
||||
const element = addonsArr[index];
|
||||
if (pluginName === element.name) {
|
||||
return element.id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("请检查页面是否有插件dom");
|
||||
}
|
||||
},
|
||||
goAccount () {
|
||||
location.href = "/account.htm?type=3";
|
||||
},
|
||||
getMessageList () {
|
||||
messageInfo().then((res) => {
|
||||
this.msgList = res.data.data.credit_limit.list;
|
||||
this.msgCount = res.data.data.credit_limit.count;
|
||||
this.msgType = res.data.data.credit_limit.type.reduce((all, cur) => {
|
||||
all[cur.name] = cur.name_lang;
|
||||
return all;
|
||||
}, {});
|
||||
});
|
||||
},
|
||||
goMsgDetail (id) {
|
||||
location.href = `/plugin/${getPluginId(
|
||||
"ClientCare"
|
||||
)}/msgDetail.htm?id=${id}`;
|
||||
},
|
||||
// 退出登录
|
||||
logOut () {
|
||||
this.$confirm(lang.topMenu_text4, lang.topMenu_text5, {
|
||||
confirmButtonText: lang.topMenu_text6,
|
||||
cancelButtonText: lang.topMenu_text7,
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
//const res = await Axios.post('/logout')
|
||||
Axios.post("/logout").then((res) => {
|
||||
localStorage.removeItem("jwt");
|
||||
setTimeout(() => {
|
||||
location.href = "/login.htm";
|
||||
}, 300);
|
||||
});
|
||||
})
|
||||
.catch(() => { });
|
||||
},
|
||||
goLogin () {
|
||||
location.href = "/login.htm";
|
||||
},
|
||||
goHome () {
|
||||
localStorage.frontMenusActiveId = "";
|
||||
const openUrl = this.commonData.clientarea_logo_url || "/home.htm";
|
||||
if (this.commonData.clientarea_logo_url_blank == 1) {
|
||||
window.open(openUrl);
|
||||
} else {
|
||||
location.href = openUrl;
|
||||
}
|
||||
},
|
||||
|
||||
// 获取购物车数量
|
||||
getCartList () {
|
||||
cartList()
|
||||
.then((res) => {
|
||||
this.shoppingCarNum = res.data.data.list.filter(
|
||||
(item) => item.customfield?.is_domain !== 1
|
||||
).length;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$message.error(err.data.msg);
|
||||
});
|
||||
},
|
||||
GetIndexData () {
|
||||
accountDetail()
|
||||
.then((res) => {
|
||||
if (res.data.status == 200) {
|
||||
this.accountData = res.data.data.account;
|
||||
localStorage.lang = res.data.data.account.language || "zh-cn";
|
||||
this.firstName = res.data.data.account.username
|
||||
.substring(0, 1)
|
||||
.toUpperCase();
|
||||
this.unLogin = false;
|
||||
if (sessionStorage.headBgc) {
|
||||
this.$refs.headBoxRef.style.background = sessionStorage.headBgc;
|
||||
} else {
|
||||
const index = Math.round(
|
||||
Math.random() * (this.headBgcList.length - 1)
|
||||
);
|
||||
this.$refs.headBoxRef.style.background = this.headBgcList[index];
|
||||
sessionStorage.headBgc = this.headBgcList[index];
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isGetData = true;
|
||||
});
|
||||
},
|
||||
goShoppingCar () {
|
||||
localStorage.frontMenusActiveId = "";
|
||||
location.href = "/cart/shoppingCar.htm";
|
||||
},
|
||||
goAccountpage () {
|
||||
location.href = "/account.htm";
|
||||
},
|
||||
// 语言切换
|
||||
changeLang (e) {
|
||||
if (localStorage.getItem("lang") !== e || !localStorage.getItem("lang")) {
|
||||
localStorage.setItem("lang", e);
|
||||
sessionStorage.setItem("brow_lang", e);
|
||||
let jwt = localStorage.getItem("jwt") || "";
|
||||
if (jwt) {
|
||||
this.accountData.language = e;
|
||||
this.saveAccount();
|
||||
} else {
|
||||
this.changeLangHandle(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
async changeLangHandle (e) {
|
||||
try {
|
||||
const res = await changeLanguage({
|
||||
language: e,
|
||||
});
|
||||
this.$message.success(res.data.msg);
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
this.$message.error(error.data.msg);
|
||||
}
|
||||
},
|
||||
// 编辑基础资料
|
||||
saveAccount () {
|
||||
const params = {
|
||||
...this.accountData,
|
||||
};
|
||||
updateAccount(params)
|
||||
.then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
this.$message.success(res.data.msg);
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message.error(error.data.msg);
|
||||
});
|
||||
},
|
||||
handleCommand (e) {
|
||||
if (e == "account") {
|
||||
this.goAccountpage();
|
||||
}
|
||||
if (e == "quit") {
|
||||
this.logOut();
|
||||
}
|
||||
console.log(e);
|
||||
},
|
||||
// 全局搜索
|
||||
querySearchAsync (queryString, cb) {
|
||||
if (queryString.length == 0) {
|
||||
return false;
|
||||
}
|
||||
const params = {
|
||||
keywords: queryString,
|
||||
};
|
||||
globalSearch(params).then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
const data = res.data.data.hosts;
|
||||
const result = [];
|
||||
data.map((item) => {
|
||||
let value = item.product_name + "#/" + item.id;
|
||||
result.push({
|
||||
id: item.id,
|
||||
value,
|
||||
name: item.name,
|
||||
});
|
||||
});
|
||||
cb(result);
|
||||
}
|
||||
});
|
||||
},
|
||||
/*
|
||||
* 获取菜单url
|
||||
* @param {Number} id 菜单id 或者url
|
||||
* @return {String} url 菜单url
|
||||
*/
|
||||
getMenuUrl (id) {
|
||||
const temp =
|
||||
this.originMenu.find((item) => item.id == id || item.url == id) || {};
|
||||
const reg =
|
||||
/^(((ht|f)tps?):\/\/)([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/;
|
||||
let url = "/" + temp.url;
|
||||
if (reg.test(temp.url)) {
|
||||
if (temp?.second_reminder === 1) {
|
||||
url = `/transfer.htm?target=${encodeURIComponent(temp.url)}`;
|
||||
} else {
|
||||
url = temp.url;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
},
|
||||
handleSelect (id) {
|
||||
localStorage.setItem("frontMenusActiveId", id);
|
||||
const temp =
|
||||
this.originMenu.find((item) => item.id == id || item.url == id) || {};
|
||||
const reg =
|
||||
/^(((ht|f)tps?):\/\/)([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/;
|
||||
if (reg.test(temp.url)) {
|
||||
if (temp?.second_reminder === 1) {
|
||||
return window.open(
|
||||
`/transfer.htm?target=${encodeURIComponent(temp.url)}`
|
||||
);
|
||||
} else {
|
||||
return window.open(temp.url);
|
||||
}
|
||||
}
|
||||
location.href = "/" + temp.url;
|
||||
},
|
||||
showMenu () {
|
||||
this.isShowMenu = true;
|
||||
},
|
||||
handleClose () {
|
||||
this.isShowMenu = false;
|
||||
},
|
||||
// 获取前台导航
|
||||
doGetMenu () {
|
||||
getMenu().then((res) => {
|
||||
if (res.data.status === 200) {
|
||||
res.data.data.menu.forEach((item) => {
|
||||
if (item.child && item.child.length > 0) {
|
||||
this.originMenu.push(...item.child);
|
||||
} else {
|
||||
this.originMenu.push(item);
|
||||
}
|
||||
});
|
||||
const menu = res.data.data.menu;
|
||||
localStorage.setItem("frontMenus", JSON.stringify(menu));
|
||||
let index = menu.findIndex((item) => item.name == "分隔符");
|
||||
if (index != -1) {
|
||||
this.hasSeparate = true;
|
||||
this.menu1 = menu.slice(0, index);
|
||||
this.menu2 = menu.slice(index + 1);
|
||||
} else {
|
||||
this.hasSeparate = false;
|
||||
this.menu1 = menu;
|
||||
}
|
||||
|
||||
this.setActiveMenu();
|
||||
}
|
||||
});
|
||||
},
|
||||
// 判断当前菜单激活
|
||||
setActiveMenu () {
|
||||
const originUrl = location.pathname.slice(1);
|
||||
const allUrl = originUrl + location.search;
|
||||
let flag = false;
|
||||
this.originMenu.forEach((item) => {
|
||||
// 当前url下存在和导航菜单对应的路径
|
||||
if (!item.child && item.url) {
|
||||
const url = String(item.url).split("?");
|
||||
if (
|
||||
(url.length > 1 && item.url == allUrl) ||
|
||||
(url.length == 1 && item.url == originUrl)
|
||||
) {
|
||||
this.menuActiveId = item.id + "";
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
// 当前url下存在二级菜单
|
||||
if (item.child && item.child.length > 0) {
|
||||
item.child.forEach((child) => {
|
||||
const url = String(child.url).split("?");
|
||||
if (
|
||||
(url.length > 1 && child.url == allUrl) ||
|
||||
(url.length == 1 && child.url == originUrl)
|
||||
) {
|
||||
this.menuActiveId = child.id + "";
|
||||
flag = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!flag) {
|
||||
this.menuActiveId = localStorage.getItem("frontMenusActiveId") || "";
|
||||
}
|
||||
},
|
||||
// 页面跳转
|
||||
toPage (e) {
|
||||
location.href = "/" + e.url;
|
||||
},
|
||||
|
||||
// 获取通用配置
|
||||
async getCommonSetting () {
|
||||
try {
|
||||
if (!localStorage.getItem("common_set_before")) {
|
||||
const res = await getCommon();
|
||||
this.commonData = res.data.data;
|
||||
localStorage.setItem(
|
||||
"common_set_before",
|
||||
JSON.stringify(res.data.data)
|
||||
);
|
||||
}
|
||||
this.commonData = JSON.parse(localStorage.getItem("common_set_before"));
|
||||
this.logo = this.commonData.system_logo;
|
||||
} catch (error) { }
|
||||
},
|
||||
},
|
||||
};
|
||||
108
clientarea/hgcloud/components/trafficWarning/trafficWarning.js
Normal file
108
clientarea/hgcloud/components/trafficWarning/trafficWarning.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 流量预警 */
|
||||
const trafficWarning = {
|
||||
template: `
|
||||
<div class="traffic-warning">
|
||||
<div class="search-btn" @click="handleConfig">{{lang.flow_warn_text3}}</div>
|
||||
<span v-if="tempValue" class="tip">{{lang.flow_warn_text1}}{{tempValue}}%{{lang.flow_warn_text2}}</span>
|
||||
<el-dialog width="6.8rem" :visible.sync="visible" :show-close="false" @close="closeDialog" custom-class="withdraw-dialog">
|
||||
<div class="dialog-title">{{lang.flow_warn_text3}}</div>
|
||||
<div class="dialog-main">
|
||||
<el-form label-width="120px" ref="ruleForm" :rules="rules" :model="warningForm" label-position="right">
|
||||
<el-form-item :label="lang.flow_warn_text4" prop="warning_switch">
|
||||
<el-switch v-model="warningForm.warning_switch" active-color="var(--color-primary)"
|
||||
:active-value="1" :inactive-value="0">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item :label="lang.flow_warn_text1" prop="leave_percent" v-if="warningForm.warning_switch">
|
||||
<el-select v-model="warningForm.leave_percent" :placeholder="lang.placeholder_pre2">
|
||||
<el-option :value="5" label="5%"></el-option>
|
||||
<el-option :value="10" label="10%"></el-option>
|
||||
<el-option :value="15" label="15%"></el-option>
|
||||
<el-option :value="20" label="20%"></el-option>
|
||||
</el-select>
|
||||
<span class="warning-text">{{lang.flow_warn_text5}}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button class="btn-ok" type="primary" @click="submit" :loading="submitLoading">{{lang.cart_tip_text9}}</el-button>
|
||||
<el-button class="btn-no" @click="closeDialog">{{lang.cart_tip_text10}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
submitLoading: false,
|
||||
rules: {
|
||||
leave_percent: [
|
||||
{required: true, message: lang.placeholder_pre2, trigger: "change"},
|
||||
],
|
||||
},
|
||||
warningForm: {
|
||||
module: "",
|
||||
warning_switch: 1,
|
||||
leave_percent: "",
|
||||
},
|
||||
tempValue: 0,
|
||||
tempData: {},
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
props: {
|
||||
module: {
|
||||
type: String,
|
||||
default: "mf_cloud", // 目前支持 mf_cloud mf_dcim
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
this.getWarningConfig();
|
||||
},
|
||||
methods: {
|
||||
async getWarningConfig() {
|
||||
try {
|
||||
const res = await getTrafficWarning({
|
||||
module: this.module,
|
||||
});
|
||||
const temp = res.data.data;
|
||||
this.tempValue = temp.leave_percent;
|
||||
temp.leave_percent = temp.leave_percent || "";
|
||||
this.warningForm = temp;
|
||||
this.tempData = JSON.parse(JSON.stringify(temp));
|
||||
} catch (error) {
|
||||
this.$message.error(error.message);
|
||||
}
|
||||
},
|
||||
handleConfig() {
|
||||
this.visible = true;
|
||||
Object.assign(this.warningForm, this.tempData);
|
||||
},
|
||||
closeDialog() {
|
||||
this.visible = false;
|
||||
},
|
||||
submit() {
|
||||
this.$refs.ruleForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const params = {
|
||||
module: this.module,
|
||||
warning_switch: this.warningForm.warning_switch,
|
||||
leave_percent: this.warningForm.leave_percent,
|
||||
};
|
||||
if (params.warning_switch === 0) {
|
||||
params.leave_percent = 0;
|
||||
}
|
||||
this.submitLoading = true;
|
||||
const res = await saveTrafficWarning(params);
|
||||
this.submitLoading = false;
|
||||
this.visible = false;
|
||||
this.$message.success(res.data.msg);
|
||||
this.getWarningConfig();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
238
clientarea/hgcloud/components/withdrawDialog/withdrawDialog.js
Normal file
238
clientarea/hgcloud/components/withdrawDialog/withdrawDialog.js
Normal file
@@ -0,0 +1,238 @@
|
||||
const withdrawDialog = {
|
||||
template: /*html */ `
|
||||
<el-dialog width="6.8rem" :visible.sync="withdrawVisible" :show-close=false @close="withdrawCancel" custom-class="withdraw-dialog">
|
||||
<div class="dialog-title">
|
||||
{{lang.withdraw_title}}
|
||||
</div>
|
||||
<div class="dialog-main">
|
||||
<el-form label-width="80px" :model="withdrawForm" label-position="top">
|
||||
<el-form-item :label="lang.withdraw_label1" >
|
||||
<el-select class="input-select" v-model="withdrawForm.method_id" @change="methodChange" :placeholder="lang.withdraw_placeholder1">
|
||||
<el-option v-for="item in ruler.method" :key="item.id" :value="item.id" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<template v-if="withdrawForm.method_id != 0">
|
||||
<el-form-item :label="lang.withdraw_label2" v-if="isBank">
|
||||
<el-input class="input-select" v-model="withdrawForm.card_number"
|
||||
:placeholder="lang.withdraw_placeholder3"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="lang.withdraw_label3" v-else>
|
||||
<el-input class="input-select" v-model="withdrawForm.account"
|
||||
:placeholder="lang.withdraw_placeholder2"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="lang.withdraw_label4">
|
||||
<el-input class="input-select" v-model="withdrawForm.name" :placeholder="lang.withdraw_placeholder4"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item :label="lang.withdraw_label5" >
|
||||
<el-input @keyup.native="withdrawForm.amount=oninput(withdrawForm.amount)" class="input-select amount-input" v-model="withdrawForm.amount" :placeholder="lang.withdraw_placeholder5 + currency_prefix + ruler.withdrawable_amount">
|
||||
<el-button class="all-btn" type="text" slot="suffix" @click="withdrawForm.amount=ruler.withdrawable_amount">{{lang.withdraw_btn3}}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="errText">
|
||||
<el-alert :title="errText" type="error" :closable="false" show-icon>
|
||||
</el-alert>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="withdraw-rule">
|
||||
<div class="label">{{lang.withdraw_title2}}</div>
|
||||
<div class="rules">
|
||||
<div class="rules-item" v-if="ruler.withdraw_min || ruler.withdraw_max">
|
||||
{{lang.withdraw_text1}}
|
||||
<span v-if="ruler.withdraw_min">{{lang.withdraw_text2}}{{currency_prefix}}{{ruler.withdraw_min}}</span>
|
||||
<span v-if="ruler.withdraw_min && ruler.withdraw_max">,</span>
|
||||
<span v-if="ruler.withdraw_max">{{lang.withdraw_text3}}{{currency_prefix}}{{ruler.withdraw_max}}</span>
|
||||
</div>
|
||||
<div class="rules-item" v-if="ruler.withdraw_handling_fee || ruler.percent_min">
|
||||
{{lang.withdraw_text4}}
|
||||
<span v-if="ruler.withdraw_handling_fee">{{ruler.withdraw_handling_fee}}</span>
|
||||
<!-- 最低手续费 -->
|
||||
<span v-if="ruler.percent_min">{{lang.withdraw_text5}}{{currency_prefix}}{{ruler.percent_min}}</span>
|
||||
<span>{{lang.withdraw_text6}}</span>
|
||||
</div>
|
||||
<div class="rules-item">
|
||||
{{lang.withdraw_text7}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button class="btn-ok" type="primary" @click="doApplyWithdraw()" v-loading="withdrawLoading">{{lang.withdraw_btn1}}</el-button>
|
||||
<el-button class="btn-no" @click="withdrawCancel">{{lang.withdraw_btn2}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
// 提现弹窗开始
|
||||
// 是否显示提现弹窗
|
||||
currency_prefix: "¥",
|
||||
withdrawVisible: false,
|
||||
withdrawForm: {
|
||||
source: "",
|
||||
method_id: "",
|
||||
amount: "",
|
||||
card_number: "",
|
||||
name: "",
|
||||
account: "",
|
||||
notes: "",
|
||||
},
|
||||
isBank: false,
|
||||
withdrawLoading: false,
|
||||
errText: "",
|
||||
ruler: {
|
||||
// 提现来源
|
||||
source: "",
|
||||
// 提现方式
|
||||
method: [],
|
||||
// 第一个提现方式
|
||||
method_id: "",
|
||||
// 可提现金额
|
||||
withdrawable_amount: "",
|
||||
// 单次提现最提金额
|
||||
withdraw_min: "",
|
||||
// 单次提现最高金额
|
||||
withdraw_max: "",
|
||||
// 提现手续费 百分比的带上“%” 固定金额 保留两位数
|
||||
withdraw_handling_fee: "",
|
||||
// 最低提现手续费
|
||||
percent_min: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.currency_prefix = JSON.parse(
|
||||
localStorage.getItem("common_set_before")
|
||||
).currency_prefix;
|
||||
},
|
||||
methods: {
|
||||
// 提现弹窗开始
|
||||
// 提现方式变化
|
||||
methodChange(e) {
|
||||
const method = this.ruler.method;
|
||||
this.isBank = false;
|
||||
method.forEach((item) => {
|
||||
if (item.id == e && item.name == "银行卡") {
|
||||
this.isBank = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 显示提现弹窗
|
||||
shwoWithdrawal(ruler) {
|
||||
this.withdrawForm = {
|
||||
source: ruler.source,
|
||||
method_id: ruler.method_id,
|
||||
amount: "",
|
||||
card_number: "",
|
||||
name: "",
|
||||
account: "",
|
||||
notes: "",
|
||||
};
|
||||
// 默认选择第一个
|
||||
// this.withdrawForm.method_id = ruler.method[0].id
|
||||
this.methodChange(this.withdrawForm.method_id);
|
||||
this.ruler = ruler;
|
||||
|
||||
this.withdrawVisible = true;
|
||||
this.errText = "";
|
||||
},
|
||||
|
||||
// 申请提现
|
||||
doApplyWithdraw() {
|
||||
let isPass = true;
|
||||
this.errText = "";
|
||||
const params = {
|
||||
...this.withdrawForm,
|
||||
};
|
||||
if (this.isBank && !params.card_number) {
|
||||
this.errText = lang.withdraw_placeholder3;
|
||||
isPass = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.method_id && params.method_id != 0) {
|
||||
this.errText = lang.withdraw_placeholder1;
|
||||
isPass = false;
|
||||
return;
|
||||
}
|
||||
if (!params.amount) {
|
||||
this.errText = lang.withdraw_placeholder6;
|
||||
isPass = false;
|
||||
return;
|
||||
} else {
|
||||
// 提现金额小于最小金额
|
||||
if (
|
||||
this.ruler.withdraw_min &&
|
||||
Number(this.ruler.withdraw_min) > Number(params.amount)
|
||||
) {
|
||||
this.errText =
|
||||
lang.withdraw_tips1 +
|
||||
this.currency_prefix +
|
||||
this.ruler.withdraw_min;
|
||||
isPass = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Number(params.amount) > Number(this.ruler.withdrawable_amount)) {
|
||||
this.errText = lang.withdraw_tips2;
|
||||
isPass = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.ruler.withdraw_max &&
|
||||
Number(this.ruler.withdraw_max) < Number(params.amount)
|
||||
) {
|
||||
this.errText =
|
||||
lang.withdraw_tips3 +
|
||||
this.currency_prefix +
|
||||
this.ruler.withdraw_max;
|
||||
isPass = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isPass) {
|
||||
this.withdrawLoading = true;
|
||||
this.errText = "";
|
||||
this.$emit("dowithdraw", params);
|
||||
}
|
||||
},
|
||||
|
||||
oninput(value) {
|
||||
let str = value;
|
||||
let len1 = str.substr(0, 1);
|
||||
let len2 = str.substr(1, 1);
|
||||
//如果第一位是0,第二位不是点,就用数字把点替换掉
|
||||
if (str.length > 1 && len1 == 0 && len2 != ".") {
|
||||
str = str.substr(1, 1);
|
||||
}
|
||||
//第一位不能是.
|
||||
if (len1 == ".") {
|
||||
str = "";
|
||||
}
|
||||
if (len1 == "+") {
|
||||
str = "";
|
||||
}
|
||||
if (len1 == "-") {
|
||||
str = "";
|
||||
}
|
||||
//限制只能输入一个小数点
|
||||
if (str.indexOf(".") != -1) {
|
||||
let str_ = str.substr(str.indexOf(".") + 1);
|
||||
if (str_.indexOf(".") != -1) {
|
||||
str = str.substr(0, str.indexOf(".") + str_.indexOf(".") + 1);
|
||||
}
|
||||
}
|
||||
//正则替换
|
||||
str = str.replace(/[^\d^\.]+/g, ""); // 保留数字和小数点
|
||||
str = str.replace(/^\D*([0-9]\d*\.?\d{0,2})?.*$/, "$1"); // 小数点后只能输 2 位
|
||||
return str;
|
||||
},
|
||||
withdrawCancel() {
|
||||
this.withdrawVisible = false;
|
||||
this.withdrawLoading = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user