397 lines
14 KiB
Vue
397 lines
14 KiB
Vue
<template>
|
||
<Dialog v-bind="$attrs" :options="{ title: '实名资料上传', size: 'lg' }" v-model="show">
|
||
<template #body-content>
|
||
<div class="p-4 sm:p-6">
|
||
<div class="space-y-4">
|
||
<!-- 域名显示 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">域名:</label>
|
||
<div class="text-base text-black font-semibold">{{ domainDoc?.domain || domain }}</div>
|
||
</div>
|
||
<!-- 资料状态 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">资料状态</label>
|
||
<div class="flex space-x-2">
|
||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||
未传图片
|
||
</span>
|
||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||
未实名
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 域名所有者 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">域名所有者</label>
|
||
<div class="text-sm text-gray-900">
|
||
{{ ownerType ? `(${ownerType === 'I' ? '个人' : '企业'})` : '' }} {{ domainDoc?.owner_name || '未知' }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 所有者证件号码 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">所有者证件号码</label>
|
||
<div class="flex space-x-3">
|
||
<select
|
||
v-model="formData.idType"
|
||
class="px-3 py-1.5 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white text-sm"
|
||
>
|
||
<option
|
||
v-for="option in idTypeOptions"
|
||
:key="option.value"
|
||
:value="option.value"
|
||
>
|
||
{{ option.label }}
|
||
</option>
|
||
</select>
|
||
<input
|
||
type="text"
|
||
v-model="formData.idNumber"
|
||
class="flex-1 px-3 py-1.5 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm"
|
||
placeholder="请输入证件号码"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 所有者证件材料 -->
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">所有者证件材料</label>
|
||
<div class="flex space-x-4">
|
||
<!-- 上传区域 -->
|
||
<div class="flex-1">
|
||
<div
|
||
@click="triggerFileInput"
|
||
@dragover.prevent
|
||
@drop.prevent="handleDrop"
|
||
class="border-2 border-dashed border-gray-300 rounded-md p-6 text-center cursor-pointer hover:border-blue-400 hover:bg-blue-50 transition-colors duration-200"
|
||
>
|
||
<div class="text-green-500 mb-2">
|
||
<svg class="w-8 h-8 mx-auto" fill="currentColor" viewBox="0 0 20 20">
|
||
<path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM6.293 6.707a1 1 0 010-1.414l3-3a1 1 0 011.414 0l3 3a1 1 0 01-1.414 1.414L11 5.414V13a1 1 0 11-2 0V5.414L7.707 6.707a1 1 0 01-1.414 0z" clip-rule="evenodd" />
|
||
</svg>
|
||
</div>
|
||
<p class="text-sm text-gray-600 font-medium">点击上传</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 说明文字 -->
|
||
<div class="flex-1">
|
||
<div class="text-xs text-gray-600 leading-relaxed mb-3">
|
||
请保证图片中证件四角完整、证件上文字信息完整清晰,请使用原件拍摄或彩色扫描件,不要用复印件,否则无法通过审核。
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 已上传文件列表 -->
|
||
<div v-if="uploadedFiles.length > 0" class="space-y-2">
|
||
<div
|
||
v-for="(file, index) in uploadedFiles"
|
||
:key="index"
|
||
class="flex items-center justify-between bg-gray-50 rounded-md p-2"
|
||
>
|
||
<div class="flex items-center">
|
||
<svg class="w-4 h-4 text-blue-600 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||
<path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clip-rule="evenodd" />
|
||
</svg>
|
||
<div>
|
||
<div class="text-xs font-medium text-gray-900">{{ file.name }}</div>
|
||
<div class="text-xs text-gray-500">{{ formatFileSize(file.size) }}</div>
|
||
</div>
|
||
</div>
|
||
<button
|
||
@click="removeFile(index)"
|
||
class="text-gray-400 hover:text-red-500 transition-colors"
|
||
>
|
||
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 隐藏的文件输入框 -->
|
||
<input
|
||
ref="fileInput"
|
||
type="file"
|
||
accept="image/*,.pdf"
|
||
multiple
|
||
class="hidden"
|
||
@change="handleFileSelect"
|
||
/>
|
||
</template>
|
||
|
||
<template #actions>
|
||
<div class="w-full flex justify-end space-x-3">
|
||
<button
|
||
type="button"
|
||
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none"
|
||
@click="show = false"
|
||
>
|
||
重置
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="px-4 py-2 bg-black border border-transparent rounded-md text-sm font-medium text-white hover:bg-gray-800 focus:outline-none disabled:bg-gray-300 disabled:cursor-not-allowed"
|
||
@click="submitUpload"
|
||
:disabled="loading || !isValid"
|
||
>
|
||
{{ loading ? '提交中...' : '提交' }}
|
||
</button>
|
||
</div>
|
||
</template>
|
||
</Dialog>
|
||
</template>
|
||
|
||
<script>
|
||
import { Dialog, createResource } from 'jingrow-ui';
|
||
import { toast } from 'vue-sonner';
|
||
|
||
export default {
|
||
name: 'JsiteDomainUploadRealNameDialog',
|
||
components: {
|
||
Dialog
|
||
},
|
||
props: {
|
||
domain: String,
|
||
domainDoc: Object,
|
||
onSuccess: Function
|
||
},
|
||
emits: ['success', 'close'],
|
||
data() {
|
||
return {
|
||
show: true,
|
||
loading: false,
|
||
ownerType: null, // 初始为空,等待从所有者信息获取
|
||
formData: {
|
||
idType: '',
|
||
idNumber: ''
|
||
},
|
||
uploadedFiles: []
|
||
};
|
||
},
|
||
computed: {
|
||
isValid() {
|
||
return this.formData.idNumber.trim() && this.formData.idType && this.uploadedFiles.length > 0;
|
||
},
|
||
idTypeOptions() {
|
||
if (!this.ownerType) {
|
||
// 如果还没有获取到所有者类型,返回空数组
|
||
return [];
|
||
}
|
||
|
||
if (this.ownerType === 'I') {
|
||
// 个人证件类型
|
||
return [
|
||
{ value: 'SFZ', label: '身份证' },
|
||
{ value: 'HZ', label: '护照' },
|
||
{ value: 'GAJMTX', label: '港澳居民来往内地通行证' },
|
||
{ value: 'TWJMTX', label: '台湾居民来往大陆通行证' },
|
||
{ value: 'WJLSFZ', label: '外国人永久居留身份证' },
|
||
{ value: 'GAJZZ', label: '港澳台居民居住证' }
|
||
];
|
||
} else {
|
||
// 企业证件类型
|
||
return [
|
||
{ value: 'ORG', label: '组织机构代码证' },
|
||
{ value: 'YYZZ', label: '工商营业执照' },
|
||
{ value: 'TYDM', label: '统一社会信用代码证书' }
|
||
];
|
||
}
|
||
}
|
||
},
|
||
resources: {
|
||
getOwnerInfo() {
|
||
return {
|
||
url: 'jcloud.api.domain_west.get_domain_owner',
|
||
params: {
|
||
name: this.domainDoc?.domain_owner
|
||
},
|
||
onSuccess: (response) => {
|
||
return response;
|
||
},
|
||
onError: (error) => {
|
||
console.error('获取所有者信息失败:', error);
|
||
}
|
||
};
|
||
}
|
||
},
|
||
mounted() {
|
||
this.loadOwnerInfo();
|
||
},
|
||
methods: {
|
||
triggerFileInput() {
|
||
this.$refs.fileInput.click();
|
||
},
|
||
handleFileSelect(event) {
|
||
const files = Array.from(event.target.files);
|
||
this.addFiles(files);
|
||
},
|
||
handleDrop(event) {
|
||
const files = Array.from(event.dataTransfer.files);
|
||
this.addFiles(files);
|
||
},
|
||
addFiles(newFiles) {
|
||
const validFiles = newFiles.filter(file => {
|
||
// 检查文件大小 (5MB限制)
|
||
if (file.size > 5 * 1024 * 1024) {
|
||
alert(`文件 ${file.name} 超过 5MB 限制`);
|
||
return false;
|
||
}
|
||
return true;
|
||
});
|
||
|
||
this.uploadedFiles = [...this.uploadedFiles, ...validFiles];
|
||
},
|
||
removeFile(index) {
|
||
this.uploadedFiles.splice(index, 1);
|
||
},
|
||
formatFileSize(bytes) {
|
||
if (bytes === 0) return '0 Bytes';
|
||
const k = 1024;
|
||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||
},
|
||
async submitUpload() {
|
||
if (!this.validateForm()) {
|
||
return;
|
||
}
|
||
|
||
this.loading = true;
|
||
|
||
try {
|
||
// 创建FormData对象
|
||
const formData = new FormData();
|
||
|
||
// 获取域名
|
||
const domain = this.domainDoc?.domain || this.domain;
|
||
|
||
// 验证域名是否有效
|
||
if (!domain || domain === '36h8on65rd') {
|
||
console.error('域名信息无效:', domain);
|
||
alert('域名信息无效,请重试');
|
||
return;
|
||
}
|
||
|
||
// 确保域名格式正确
|
||
if (!domain.includes('.')) {
|
||
console.error('域名格式无效:', domain);
|
||
alert('域名格式无效,请重试');
|
||
return;
|
||
}
|
||
|
||
formData.append('domain', domain);
|
||
formData.append('idType', this.formData.idType);
|
||
formData.append('idNumber', this.formData.idNumber);
|
||
|
||
// 添加文件
|
||
this.uploadedFiles.forEach((file, index) => {
|
||
formData.append(`files_${index}`, file);
|
||
});
|
||
|
||
// 调用后端上传API
|
||
const xhr = new XMLHttpRequest();
|
||
|
||
xhr.onreadystatechange = () => {
|
||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||
this.loading = false;
|
||
|
||
if (xhr.status === 200) {
|
||
try {
|
||
const response = JSON.parse(xhr.responseText);
|
||
|
||
// Jingrow 响应格式:{message: {...}}
|
||
if (response && response.message && response.message.status === "success") {
|
||
// 调用父组件的成功回调
|
||
if (this.onSuccess) {
|
||
this.onSuccess();
|
||
}
|
||
// 关闭弹窗
|
||
this.show = false;
|
||
} else {
|
||
const errorMessage = response?.message?.message || response?.message || '上传失败,请重试';
|
||
console.error('上传失败:', errorMessage);
|
||
alert(errorMessage);
|
||
}
|
||
} catch (error) {
|
||
console.error('解析响应失败:', error);
|
||
alert('上传失败,请重试');
|
||
}
|
||
} else {
|
||
console.error('上传失败:', xhr.status, xhr.statusText);
|
||
alert('上传失败,请重试');
|
||
}
|
||
}
|
||
};
|
||
|
||
xhr.open('POST', '/api/action/jcloud.api.domain_west.upload_domain_real_name_files', true);
|
||
xhr.setRequestHeader('Accept', 'application/json');
|
||
|
||
// 添加CSRF token
|
||
if (window.csrf_token && window.csrf_token !== '{{ csrf_token }}') {
|
||
xhr.setRequestHeader('X-Jingrow-CSRF-Token', window.csrf_token);
|
||
}
|
||
|
||
xhr.send(formData);
|
||
|
||
} catch (error) {
|
||
console.error('上传实名资料失败:', error);
|
||
alert('上传失败,请重试');
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
validateForm() {
|
||
if (!this.formData.idNumber.trim()) {
|
||
alert('请填写证件号码');
|
||
return false;
|
||
}
|
||
|
||
if (!this.formData.idType) {
|
||
alert('请选择证件类型');
|
||
return false;
|
||
}
|
||
|
||
if (this.uploadedFiles.length === 0) {
|
||
alert('请上传证件材料');
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
async loadOwnerInfo() {
|
||
try {
|
||
if (this.domainDoc && this.domainDoc.domain_owner) {
|
||
// 获取域名所有者信息
|
||
const response = await this.$resources.getOwnerInfo.submit();
|
||
|
||
if (response && response.status === 'Success' && response.data) {
|
||
const owner = response.data;
|
||
|
||
// 优先从所有者信息获取类型
|
||
this.ownerType = owner.c_regtype;
|
||
|
||
// 填充身份证号码
|
||
if (owner.c_idnum_gswl) {
|
||
this.formData.idNumber = owner.c_idnum_gswl;
|
||
}
|
||
// 填充证件类型
|
||
if (owner.c_idtype_gswl) {
|
||
this.formData.idType = owner.c_idtype_gswl;
|
||
} else if (this.ownerType) {
|
||
// 根据所有者类型设置默认证件类型
|
||
this.formData.idType = this.ownerType === 'I' ? 'SFZ' : 'ORG';
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('获取所有者信息失败:', error);
|
||
}
|
||
},
|
||
}
|
||
};
|
||
</script> |