jcloud/dashboard/src2/components/JsiteDomainOverview.vue

470 lines
15 KiB
Vue
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.

<template>
<div
v-if="$domain?.pg"
class="grid grid-cols-1 items-start gap-5 lg:grid-cols-2"
>
<!-- 左侧区块基本信息 -->
<div class="col-span-1 space-y-5">
<!-- 当前套餐卡片 -->
<div class="rounded-md border">
<div class="p-5">
<div class="flex h-full flex-col sm:flex-row sm:items-center sm:justify-between">
<div class="mb-4 sm:mb-0">
<!-- 实名认证状态 -->
<div class="mb-4 p-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<div v-if="realNameStatus === 'verified'" class="flex items-center space-x-3">
<div class="inline-flex items-center rounded-full bg-gradient-to-r from-green-50 to-emerald-50 px-4 py-2 text-sm font-semibold text-green-800 border border-green-200 shadow-sm">
<svg class="mr-2 h-4 w-4 text-green-600" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
</svg>
实名认证
</div>
<button
@click="showRealNameInfo"
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-blue-700 bg-blue-100 hover:bg-blue-200 rounded-lg transition-colors duration-200 border border-blue-300"
>
<svg class="mr-1.5 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
查看认证信息
</button>
</div>
<div v-else class="flex items-center space-x-3">
<div class="inline-flex items-center rounded-full bg-gradient-to-r from-amber-50 to-orange-50 px-4 py-2 text-sm font-semibold text-amber-800 border border-amber-200 shadow-sm">
<svg class="mr-2 h-4 w-4 text-amber-600" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path>
</svg>
待实名认证
</div>
<button
@click="showUploadRealName"
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-white bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 rounded-lg transition-all duration-200 shadow-sm hover:shadow-md"
>
<svg class="mr-1.5 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
</svg>
上传实名资料
</button>
</div>
</div>
</div>
</div>
<div v-if="$domain.pg.end_date" class="mt-2 inline-flex items-center rounded-full bg-amber-50 px-4 py-2 text-sm font-medium text-amber-800">
<ClockIcon class="mr-1.5 h-4 w-4 text-amber-500" />
到期时间{{ $format.date($domain.pg.end_date) }}
</div>
</div>
<div class="flex gap-2">
<Button
@click="renewDomain"
:loading="$domain.renew?.loading"
class="px-5 !bg-[#1fc76f] !hover:bg-[#1bb85f] !text-white"
>
续费
</Button>
</div>
</div>
</div>
</div>
<!-- 域名信息 -->
<div class="rounded-md border">
<div class="h-12 border-b px-5 py-4">
<h2 class="text-lg font-medium text-gray-900">域名信息</h2>
</div>
<div>
<div
v-for="info in domainInformation"
:key="info.label"
class="flex items-center px-5 py-3 last:pb-5 even:bg-gray-50/70"
>
<div class="w-1/3 text-base text-gray-600">{{ info.label }}</div>
<div
class="flex w-2/3 items-center space-x-2 text-base text-gray-900"
>
<div v-if="info.prefix">
<component :is="info.prefix" />
</div>
<span>
{{ info.value }}
</span>
<div v-if="info.suffix">
<component :is="info.suffix" />
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧区块DNS信息和操作 -->
<div class="col-span-1 space-y-5">
<!-- 操作 -->
<div class="rounded-md border">
<div class="h-12 border-b px-5 py-4">
<h2 class="text-lg font-medium text-gray-900">操作</h2>
</div>
<div class="p-5">
<div class="flex flex-wrap gap-2">
<Button
@click="modifyDNSServer"
:loading="dnsLoading"
variant="outline"
class="bg-gray-100 text-gray-700 hover:bg-gray-200"
>
修改DNS服务器
</Button>
<!-- <Button
@click="toggleAutoRenew"
:loading="autoRenewLoading"
variant="outline"
class="bg-gray-100 text-gray-700 hover:bg-gray-200"
>
{{ $domain.pg.auto_renew ? '关闭自动续费' : '开启自动续费' }}
</Button> -->
<Button
@click="toggleWhoisProtection"
:loading="whoisProtectionLoading"
variant="outline"
class="bg-gray-100 text-gray-700 hover:bg-gray-200"
>
{{ $domain.pg.whois_protection ? '关闭隐私保护' : '开启隐私保护' }}
</Button>
</div>
</div>
</div>
<!-- DNS服务器信息 -->
<div class="rounded-md border">
<div class="h-12 border-b px-5 py-4">
<h2 class="text-lg font-medium text-gray-900">DNS服务器</h2>
</div>
<div class="p-5">
<div class="space-y-3">
<div class="flex justify-between">
<span class="text-gray-600">主DNS:</span>
<span class="font-mono text-gray-900">{{ $domain.pg.dns_host1 }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">辅DNS:</span>
<span class="font-mono text-gray-900">{{ $domain.pg.dns_host2 }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">DNS3:</span>
<span class="font-mono text-gray-900">{{ $domain.pg.dns_host3 }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">DNS4:</span>
<span class="font-mono text-gray-900">{{ $domain.pg.dns_host4 }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">DNS5:</span>
<span class="font-mono text-gray-900">{{ $domain.pg.dns_host5 }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">DNS6:</span>
<span class="font-mono text-gray-900">{{ $domain.pg.dns_host6 }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { getCachedDocumentResource, Badge, Tooltip, Button, createResource } from 'jingrow-ui';
import { h, defineAsyncComponent } from 'vue';
import { toast } from 'vue-sonner';
import { getToastErrorMessage } from '../utils/toast';
import { renderDialog, confirmDialog } from '../utils/components';
import ClockIcon from '~icons/lucide/clock';
import InfoIcon from '~icons/lucide/info';
export default {
name: 'JsiteDomainOverview',
props: ['domain'],
components: {
Badge,
Button,
ClockIcon,
InfoIcon,
},
data() {
return {
renewLoading: false,
dnsLoading: false,
autoRenewLoading: false,
whoisProtectionLoading: false,
domainOwner: null,
realNameStatus: 'unverified', // 实名认证状态verified, unverified
};
},
methods: {
getStatusText(status) {
const statusMap = {
'Active': '正常',
'Expired': '已过期'
};
return statusMap[status] || status;
},
getStatusVariant(status) {
const variantMap = {
'Active': 'success',
'Expired': 'danger'
};
return variantMap[status] || 'default';
},
// 获取域名所有者显示名称
getOwnerDisplayName() {
if (!this.domainOwner) {
return null;
}
// 如果是个人优先显示fullname没有的话显示title
if (this.domainOwner.c_regtype === 'I') {
return this.domainOwner.fullname || this.domainOwner.title;
}
// 如果是公司优先显示c_org_m没有的话显示title
else if (this.domainOwner.c_regtype === 'E') {
return this.domainOwner.c_org_m || this.domainOwner.title;
}
// 默认显示title
return this.domainOwner.title;
},
// 获取域名所有者信息
async getDomainOwner() {
if (!this.$domain.pg?.domain_owner) {
this.domainOwner = null;
this.realNameStatus = 'unverified';
return;
}
try {
const getOwnerRequest = createResource({
url: 'jcloud.api.domain_west.get_domain_owner',
params: {
name: this.$domain.pg.domain_owner
},
onSuccess: (response) => {
if (response && response.status === "Success" && response.data) {
this.domainOwner = response.data;
// 根据域名所有者记录的r_status字段设置实名认证状态
// r_status是check字段类型1表示已认证0表示未认证
const rStatus = response.data.r_status;
// 对于check字段将值转换为布尔值进行判断
const isVerified = Boolean(rStatus && (rStatus === 1 || rStatus === '1' || rStatus === true));
if (isVerified) {
this.realNameStatus = 'verified';
} else {
this.realNameStatus = 'unverified';
}
} else {
this.realNameStatus = 'unverified';
}
},
onError: (error) => {
console.error('获取域名所有者信息失败:', error);
this.domainOwner = null;
this.realNameStatus = 'unverified';
}
});
getOwnerRequest.submit();
} catch (error) {
console.error('获取域名所有者信息失败:', error);
this.domainOwner = null;
this.realNameStatus = 'unverified';
}
},
renewDomain() {
const JsiteDomainRenewalDialog = defineAsyncComponent(() => import('./JsiteDomainRenewalDialog.vue'));
renderDialog(h(JsiteDomainRenewalDialog, {
domain: this.domain,
domainDoc: this.$domain.pg,
onSuccess: this.onRenewalSuccess
}));
},
async modifyDNSServer() {
if (!this.$domain.pg.domain) {
toast.error('域名信息不存在');
return;
}
const JsiteDomainModifyDNSServerDialog = defineAsyncComponent(() => import('./JsiteDomainModifyDNSServerDialog.vue'));
renderDialog(h(JsiteDomainModifyDNSServerDialog, {
domain: this.domain,
domainDoc: this.$domain.pg,
onSuccess: this.onModifyDNSSuccess
}));
},
async toggleAutoRenew() {
if (!this.$domain.pg.name) {
toast.error('域名记录不存在');
return;
}
const newValue = !this.$domain.pg.auto_renew;
const actionText = newValue ? '开启' : '关闭';
confirmDialog({
title: `${actionText}自动续费`,
message: `确定要${actionText}域名 "${this.$domain.pg.domain}" 的自动续费吗?`,
primaryAction: {
label: '确定',
onClick: ({ hide }) => {
toast.success(`${actionText}自动续费已开通`);
hide();
this.autoRenewLoading = true;
const toggleRequest = createResource({
url: 'jcloud.api.domain_west.toggle_domain_auto_renew',
params: {
pagetype: 'Jsite Domain',
name: this.$domain.pg.name,
auto_renew: newValue
},
onSuccess: () => {
this.autoRenewLoading = false;
this.$domain.reload();
},
onError: (error) => {
toast.error(getToastErrorMessage(error));
this.autoRenewLoading = false;
}
});
toggleRequest.submit();
}
}
});
},
async toggleWhoisProtection() {
if (!this.$domain.pg.name) {
toast.error('域名记录不存在');
return;
}
const newValue = !this.$domain.pg.whois_protection;
const actionText = newValue ? '开启' : '关闭';
confirmDialog({
title: `${actionText}隐私保护`,
message: `确定要${actionText}域名 "${this.$domain.pg.domain}" 的隐私保护吗?`,
primaryAction: {
label: '确定',
onClick: ({ hide }) => {
toast.success(`${actionText}隐私保护已开启`);
hide();
this.whoisProtectionLoading = true;
const toggleRequest = createResource({
url: 'jcloud.api.domain_west.toggle_domain_whois_protection',
params: {
pagetype: 'Jsite Domain',
name: this.$domain.pg.name,
whois_protection: newValue
},
onSuccess: () => {
this.whoisProtectionLoading = false;
this.$domain.reload();
},
onError: (error) => {
toast.error(getToastErrorMessage(error));
this.whoisProtectionLoading = false;
}
});
toggleRequest.submit();
}
}
});
},
onRenewalSuccess(data) {
toast.success('域名续费成功!');
this.$domain.reload();
},
onModifyDNSSuccess(data) {
toast.success('DNS服务器修改成功');
this.$domain.reload();
},
// 显示实名认证信息
showRealNameInfo() {
const JsiteDomainRealNameInfoDialog = defineAsyncComponent(() => import('./JsiteDomainRealNameInfoDialog.vue'));
renderDialog(h(JsiteDomainRealNameInfoDialog, {
domain: this.domain,
domainDoc: this.$domain.pg
}));
},
// 显示上传实名资料
showUploadRealName() {
const JsiteDomainUploadRealNameDialog = defineAsyncComponent(() => import('./JsiteDomainUploadRealNameDialog.vue'));
renderDialog(h(JsiteDomainUploadRealNameDialog, {
domain: this.domain,
domainDoc: this.$domain.pg,
onSuccess: this.onUploadSuccess
}));
},
// 上传成功回调
onUploadSuccess() {
toast.success('实名资料上传成功!');
this.getDomainOwner(); // 重新获取域名所有者信息(包含实名认证状态)
},
},
watch: {
// 监听域名数据变化,重新获取所有者信息
'$domain.pg.domain_owner': {
handler(newVal) {
if (newVal) {
this.getDomainOwner();
} else {
this.domainOwner = null;
this.realNameStatus = 'unverified';
}
},
immediate: true
}
},
computed: {
domainInformation() {
return [
{
label: '状态',
value: this.getStatusText(this.$domain.pg?.status),
},
{
label: '域名',
value: this.$domain.pg?.domain,
},
{
label: '注册时间',
value: this.$domain.pg?.registration_date,
},
{
label: '所有者',
value: this.getOwnerDisplayName(),
},
];
},
$domain() {
return getCachedDocumentResource('Jsite Domain', this.domain);
},
},
mounted() {
// 初始化时获取域名所有者信息
if (this.$domain.pg?.domain_owner) {
this.getDomainOwner();
} else {
this.realNameStatus = 'unverified';
}
},
};
</script>