Files
BlackFruit-UI/clientarea/hgcloud/components/batchRenewpage/batchRenewpage.js
yiqiu 3b41cffbc9
All checks were successful
continuous-integration/drone/push Build is passing
feat: 会员中心 hgcloud 主题初始化 + drone 部署步骤
- 解压官方默认主题 default_yfMBA.tar.gz 到 clientarea/hgcloud/
- .gitignore 排除压缩包和临时解压目录
- drone 新增步骤: 同步 hgcloud 到 /clientarea/template/pc/
2026-03-19 17:56:44 +08:00

652 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
});
},
},
};