461 lines
14 KiB
Vue
461 lines
14 KiB
Vue
<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="manageDNS"
|
||
: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 manageDNS() {
|
||
if (!this.$domain.pg.domain) {
|
||
toast.error('域名信息不存在');
|
||
return;
|
||
}
|
||
|
||
// 这里可以打开DNS管理对话框
|
||
toast.info('DNS管理功能开发中...');
|
||
},
|
||
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();
|
||
},
|
||
// 显示实名认证信息
|
||
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> |