jcloud/dashboard/src2/components/DomainOwnerDialog.vue

558 lines
21 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="visible" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white rounded-lg shadow-2xl max-w-4xl w-full mx-4 max-h-[90vh] flex flex-col overflow-hidden">
<!-- 固定标题栏 -->
<div class="p-4 border-b border-gray-200 bg-white rounded-t-lg flex-shrink-0">
<div class="flex items-center justify-between">
<h3 class="text-lg font-medium text-gray-900">新建域名所有者</h3>
<button
@click="closeDialog"
class="text-gray-400 hover:text-gray-600 transition-colors duration-200"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
</div>
<!-- 可滚动内容区域 -->
<div class="p-6 overflow-y-auto flex-1">
<!-- 重要提醒 -->
<div class="mb-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
<div class="flex">
<svg class="w-5 h-5 text-yellow-400 mt-0.5" 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 class="ml-3">
<p class="text-sm text-yellow-800">
域名所有者名称代表域名的所有权请按照证件上的企业名称或个人姓名准确填写如果域名需要备案请确保域名所有者名称与备案主体名称一致并完成域名实名认证实名认证后所有者不可修改
</p>
</div>
</div>
</div>
<form @submit.prevent="handleSubmit" class="space-y-6">
<!-- 所有者类型 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">所有者类型 *</label>
<div class="flex gap-4">
<label class="flex items-center">
<input
type="radio"
v-model="formData.c_regtype"
value="I"
@change="onRegTypeChange"
class="mr-2"
>
<span class="text-sm">个人</span>
</label>
<label class="flex items-center">
<input
type="radio"
v-model="formData.c_regtype"
value="E"
@change="onRegTypeChange"
class="mr-2"
>
<span class="text-sm">企业/组织</span>
</label>
</div>
</div>
<!-- 中文信息 -->
<div class="space-y-4">
<!-- 单位名称企业时显示- 单独一行 -->
<div v-if="formData.c_regtype === 'E'" class="w-full">
<label class="block text-sm font-medium text-gray-700 mb-2">所有者单位名称 *</label>
<input
v-model="formData.c_org_m"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入单位名称"
>
</div>
<!-- 姓名部分 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2"> *</label>
<input
v-model="formData.c_ln_m"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入姓"
>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2"> *</label>
<input
v-model="formData.c_fn_m"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入名"
>
</div>
</div>
<!-- 区域选择 -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<!-- 国家/地区选择 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">国家/地区 *</label>
<select
v-model="selectedCountry"
@change="onCountryChange"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="">请选择国家/地区</option>
<option v-for="country in countryList" :key="country.code" :value="country.code">
{{ country.name }}
</option>
</select>
</div>
<!-- 所属区域 - 仅中国显示 -->
<div v-if="selectedCountry === 'CN'">
<label class="block text-sm font-medium text-gray-700 mb-2">所属省份 *</label>
<select
v-model="selectedProvince"
@change="onProvinceChange"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="">请选择省份</option>
<option v-for="province in chinaRegions" :key="province.code" :value="province.name">
{{ province.name }}
</option>
</select>
</div>
<div v-if="selectedCountry === 'CN'">
<label class="block text-sm font-medium text-gray-700 mb-2">所属城市 *</label>
<select
v-model="selectedCity"
@change="onCityChange"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
:disabled="!selectedProvince"
>
<option value="">请选择城市</option>
<option v-for="city in getCurrentCities()" :key="city.code" :value="city.name">
{{ city.name }}
</option>
</select>
</div>
<div v-if="selectedCountry === 'CN'">
<label class="block text-sm font-medium text-gray-700 mb-2">所属区县</label>
<select
v-model="selectedDistrict"
@change="onDistrictChange"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
:disabled="!selectedCity"
>
<option value="">请选择区县</option>
<option v-for="district in getCurrentDistricts()" :key="district.code" :value="district.name">
{{ district.name }}
</option>
</select>
</div>
<!-- 非中国地区的省份/州输入框 -->
<div v-if="selectedCountry && selectedCountry !== 'CN'">
<label class="block text-sm font-medium text-gray-700 mb-2">省份/ *</label>
<input
v-model="formData.c_st_m"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入省份/州"
>
</div>
<!-- 非中国地区的城市输入框 -->
<div v-if="selectedCountry && selectedCountry !== 'CN'">
<label class="block text-sm font-medium text-gray-700 mb-2">城市 *</label>
<input
v-model="formData.c_ct_m"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入城市"
>
</div>
</div>
<!-- 通讯地址 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">通讯地址 *</label>
<input
v-model="formData.c_adr_m"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入详细地址"
>
</div>
<!-- 联系信息 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 邮编 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">邮编 *</label>
<input
v-model="formData.c_pc"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入邮编"
>
</div>
<!-- 手机号码 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">手机号码 *</label>
<div class="flex">
<span class="inline-flex items-center px-3 py-2 border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm rounded-l-lg">
+86
</span>
<input
v-model="formData.c_ph"
type="text"
class="flex-1 border rounded-r-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入手机号码"
>
</div>
</div>
</div>
<!-- 电子邮箱 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">电子邮箱 *</label>
<input
v-model="formData.c_em"
type="email"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入邮箱地址"
>
</div>
<!-- 证件信息 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 证件类型 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">证件类型 *</label>
<select
v-model="formData.c_idtype_gswl"
@change="onCertificateTypeChange"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="">请选择证件类型</option>
<option v-for="option in getCertificateTypeOptions()" :key="option.value" :value="option.value">
{{ option.label }}
</option>
</select>
</div>
<!-- 证件号码 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">证件号码 *</label>
<input
v-model="formData.c_idnum_gswl"
type="text"
class="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
:placeholder="getCertificatePlaceholder()"
@input="validateIdNumber"
>
<div v-if="idNumberError" class="text-red-500 text-xs mt-1">
{{ idNumberError }}
</div>
</div>
</div>
</div>
<!-- 红色警告 -->
<div class="p-4 bg-red-50 border border-red-200 rounded-lg">
<p class="text-sm text-red-800">
根据互联网域名管理办法请提供真实准确完整的身份信息域名信息模板中的电话号码必须与域名所有者一致否则可能被认定为虚假注册导致域名被注销严禁代理持有联系电话在修改后90天内不可变更
</p>
</div>
</form>
</div>
<!-- 固定底部栏 -->
<div class="p-4 border-t border-gray-200 bg-white rounded-b-lg flex-shrink-0">
<div class="flex justify-end gap-3">
<button
type="button"
@click="closeDialog"
class="px-4 py-2 text-sm border border-gray-300 bg-white text-gray-700 rounded-lg hover:bg-gray-50 transition-colors duration-200"
>
取消
</button>
<button
type="submit"
:disabled="isLoading"
class="px-4 py-2 text-sm bg-gray-900 text-white rounded-lg hover:bg-gray-800 disabled:bg-gray-300 transition-colors duration-200"
@click="handleSubmit"
>
{{ isLoading ? '创建中...' : '立即保存' }}
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { getCountryList, getChinaRegions, getCitiesByProvince, getDistrictsByCity } from '../utils/regions';
export default {
name: 'DomainOwnerDialog',
props: {
visible: {
type: Boolean,
default: false
},
isLoading: {
type: Boolean,
default: false
}
},
emits: ['close', 'submit'],
data() {
return {
formData: {
c_regtype: 'I', // I: 个人, E: 企业
c_org_m: '', // 中文单位名称
c_ln_m: '', // 中文姓
c_fn_m: '', // 中文名
c_st_m: '', // 中文省份
c_ct_m: '', // 中文城市
c_dt_m: '', // 中文区县
c_adr_m: '', // 中文地址
c_pc: '', // 邮编
c_ph_type: '0', // 电话类型0-手机(固定值)
c_ph: '', // 手机号码
c_em: '', // 邮箱
c_idtype_gswl: 'SFZ', // 证件类型,个人默认身份证
c_idnum_gswl: '' // 证件号码
},
selectedCountry: 'CN',
selectedProvince: '',
selectedCity: '',
selectedDistrict: '',
countryList: getCountryList(),
chinaRegions: getChinaRegions(),
idNumberError: ''
};
},
methods: {
closeDialog() {
this.resetForm();
this.$emit('close');
},
async handleSubmit() {
// 验证表单
const errors = this.validateForm();
if (errors.length > 0) {
alert(errors[0]); // 可以改为更友好的提示方式
return;
}
try {
const submitData = { ...this.formData };
submitData.c_co = this.selectedCountry;
submitData.cocode = this.selectedCountry === 'CN' ? '+86' : '';
const response = await this.$resources.createDomainOwner.submit(submitData);
if (response.status === 'Success') {
alert('域名所有者创建成功!');
this.$emit('submit', response.data);
this.closeDialog();
} else {
alert(`创建失败: ${response.message}`);
}
} catch (error) {
alert('创建失败,请检查网络连接或联系管理员');
}
},
validateForm() {
const errors = [];
if (!this.formData.c_regtype) {
errors.push('请选择所有者类型');
}
if (!this.formData.c_ln_m || !this.formData.c_fn_m) {
errors.push('请输入姓名');
}
if (!this.selectedCountry) {
errors.push('请选择国家/地区');
}
if (this.selectedCountry === 'CN' && (!this.formData.c_st_m || !this.formData.c_ct_m)) {
errors.push('请选择所属区域');
}
if (this.selectedCountry !== 'CN' && (!this.formData.c_st_m || !this.formData.c_ct_m)) {
errors.push('请输入省份/州和城市');
}
if (!this.formData.c_adr_m) {
errors.push('请输入通讯地址');
}
if (!this.formData.c_pc) {
errors.push('请输入邮编');
}
// 验证手机号码
if (!this.formData.c_ph) {
errors.push('请输入手机号码');
}
// 企业类型验证
if (this.formData.c_regtype === 'E' && !this.formData.c_org_m) {
errors.push('企业类型必须填写单位名称');
}
if (!this.formData.c_em) {
errors.push('请输入电子邮箱');
}
if (!this.formData.c_idtype_gswl) {
errors.push('请选择证件类型');
}
if (!this.formData.c_idnum_gswl) {
errors.push('请输入证件号码');
} else if (this.formData.c_idtype_gswl === 'SFZ') {
const idNum = this.formData.c_idnum_gswl;
if (idNum.length !== 18) {
errors.push('身份证号码必须是18位');
} else if (!(idNum.slice(0, 17).match(/^\d+$/) && (idNum[17].match(/^\d$/) || idNum[17].toUpperCase() === 'X'))) {
errors.push('身份证号码格式不正确');
}
}
return errors;
},
resetForm() {
this.formData = {
c_regtype: 'I',
c_org_m: '',
c_ln_m: '',
c_fn_m: '',
c_st_m: '',
c_ct_m: '',
c_dt_m: '',
c_adr_m: '',
c_pc: '',
c_ph_type: '0',
c_ph: '',
c_em: '',
c_idtype_gswl: 'SFZ', // 个人默认证件类型
c_idnum_gswl: ''
};
this.selectedCountry = 'CN';
this.selectedProvince = '';
this.selectedCity = '';
this.selectedDistrict = '';
this.idNumberError = '';
},
onCountryChange() {
// 重置省市区选择
this.selectedProvince = '';
this.selectedCity = '';
this.selectedDistrict = '';
this.formData.c_st_m = '';
this.formData.c_ct_m = '';
this.formData.c_dt_m = '';
},
onProvinceChange() {
this.selectedCity = '';
this.selectedDistrict = '';
this.formData.c_st_m = this.selectedProvince;
this.formData.c_ct_m = '';
this.formData.c_dt_m = '';
},
onCityChange() {
this.selectedDistrict = '';
this.formData.c_ct_m = this.selectedCity;
this.formData.c_dt_m = '';
},
onDistrictChange() {
this.formData.c_dt_m = this.selectedDistrict;
},
onCertificateTypeChange() {
// 清空证件号码和错误信息
this.formData.c_idnum_gswl = '';
this.idNumberError = '';
},
onRegTypeChange() {
// 根据所有者类型设置默认证件类型
if (this.formData.c_regtype === 'I') {
this.formData.c_idtype_gswl = 'SFZ'; // 个人默认身份证
} else {
this.formData.c_idtype_gswl = 'YYZZ'; // 企业默认营业执照
}
// 清空证件号码和错误信息
this.formData.c_idnum_gswl = '';
this.idNumberError = '';
},
getCurrentCities() {
if (!this.selectedProvince) return [];
return getCitiesByProvince(this.selectedProvince);
},
getCurrentDistricts() {
if (!this.selectedCity || !this.selectedProvince) return [];
return getDistrictsByCity(this.selectedProvince, this.selectedCity);
},
getCertificateTypeOptions() {
return this.formData.c_regtype === 'I'
? [
{ value: 'SFZ', label: '身份证' },
{ value: 'HZ', label: '护照' }
]
: [
{ value: 'YYZZ', label: '营业执照' },
{ value: 'ORG', label: '组织机构代码证' }
];
},
getCertificatePlaceholder() {
if (this.formData.c_idtype_gswl === 'SFZ') {
return '请输入18位身份证号码';
} else if (this.formData.c_idtype_gswl === 'HZ') {
return '请输入护照号码';
} else if (this.formData.c_idtype_gswl === 'YYZZ') {
return '请输入营业执照号码';
} else if (this.formData.c_idtype_gswl === 'ORG') {
return '请输入组织机构代码证号码';
}
return '请输入证件号码';
},
validateIdNumber() {
this.idNumberError = '';
if (!this.formData.c_idnum_gswl) {
return;
}
if (this.formData.c_idtype_gswl === 'SFZ') {
const idNum = this.formData.c_idnum_gswl;
if (idNum.length !== 18) {
this.idNumberError = `身份证号码必须是18位当前为${idNum.length}`;
return;
}
// 验证格式前17位为数字最后一位可能是数字或X
if (!(idNum.slice(0, 17).match(/^\d+$/) && (idNum[17].match(/^\d$/) || idNum[17].toUpperCase() === 'X'))) {
this.idNumberError = '身份证号码格式不正确';
return;
}
}
},
},
resources: {
createDomainOwner() {
return {
url: 'jcloud.api.domain_west.create_domain_owner_with_template',
onSuccess(response) {
return response;
},
onError(error) {
throw error;
}
};
}
}
};
</script>