main #2

Merged
jingrow merged 250 commits from main into v1 2026-01-13 22:45:50 +08:00
2 changed files with 472 additions and 76 deletions
Showing only changes of commit ce05b26800 - Show all commits

View File

@ -28,14 +28,6 @@
</TextInput>
</div>
<div class="flex gap-2">
<select
v-model="selectedType"
class="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
>
<option value="">全部类型</option>
<option value="I">个人</option>
<option value="E">企业/组织</option>
</select>
<select
v-model="selectedStatus"
class="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
@ -51,9 +43,8 @@
<div class="rounded-lg border border-gray-200 bg-white">
<!-- 表头 -->
<div class="grid grid-cols-12 gap-4 border-b border-gray-200 bg-gray-50 px-6 py-3 text-sm font-medium text-gray-700">
<div class="col-span-3">名称</div>
<div class="col-span-2">类型</div>
<div class="col-span-2">实名状态</div>
<div class="col-span-4">名称</div>
<div class="col-span-3">实名状态</div>
<div class="col-span-3">联系信息</div>
<div class="col-span-2">操作</div>
</div>
@ -86,29 +77,21 @@
@click="viewOwner(owner)"
>
<!-- 名称列 -->
<div class="col-span-3">
<div class="col-span-4">
<div class="font-medium text-gray-900">{{ getDisplayName(owner) }}</div>
<div class="text-sm text-gray-500">{{ owner.title || owner.name }}</div>
</div>
<!-- 类型列 -->
<div class="col-span-2 flex items-center">
<Badge :variant="owner.c_regtype === 'I' ? 'blue' : 'purple'">
{{ owner.c_regtype === 'I' ? '个人' : '企业/组织' }}
</Badge>
</div>
<!-- 实名状态列 -->
<div class="col-span-2 flex items-center">
<Badge :variant="getRealNameStatusVariant(owner.r_status)">
{{ getRealNameStatusText(owner.r_status) }}
</Badge>
<div class="col-span-3 flex items-center">
<span class="text-sm">{{ getRealNameStatusText(owner.r_status) }}</span>
</div>
<!-- 联系信息列 -->
<div class="col-span-3">
<div class="text-sm text-gray-900">{{ owner.c_em || '-' }}</div>
<div class="text-sm text-gray-500">{{ owner.c_ph || '-' }}</div>
<div class="text-sm text-gray-400">{{ getAddressInfo(owner) }}</div>
</div>
<!-- 操作列 -->
@ -198,19 +181,11 @@
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">所有者类型</label>
<p class="mt-1 text-sm text-gray-900">
<Badge :variant="selectedOwner.c_regtype === 'I' ? 'blue' : 'purple'">
{{ selectedOwner.c_regtype === 'I' ? '个人' : '企业/组织' }}
</Badge>
</p>
<p class="mt-1 text-sm text-gray-900">{{ getOwnerTypeText(selectedOwner.c_regtype) }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">实名认证状态</label>
<p class="mt-1 text-sm text-gray-900">
<Badge :variant="getRealNameStatusVariant(selectedOwner.r_status)">
{{ getRealNameStatusText(selectedOwner.r_status) }}
</Badge>
</p>
<p class="mt-1 text-sm text-gray-900">{{ getRealNameStatusText(selectedOwner.r_status) }}</p>
</div>
<div v-if="selectedOwner.c_regtype === 'E'">
<label class="block text-sm font-medium text-gray-700">单位名称</label>
@ -290,6 +265,174 @@
</div>
</div>
</div>
<!-- 编辑域名所有者弹窗 -->
<div v-if="showEditDialog" 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="closeEditDialog"
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" v-if="selectedOwner">
<form @submit.prevent="handleEditSubmit" 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="editFormData.c_regtype"
value="I"
class="mr-2"
>
<span class="text-sm">个人</span>
</label>
<label class="flex items-center">
<input
type="radio"
v-model="editFormData.c_regtype"
value="E"
class="mr-2"
>
<span class="text-sm">企业/组织</span>
</label>
</div>
</div>
<!-- 中文信息 -->
<div class="space-y-4">
<!-- 单位名称企业时显示 -->
<div v-if="editFormData.c_regtype === 'E'" class="w-full">
<label class="block text-sm font-medium text-gray-700 mb-2">所有者单位名称</label>
<input
v-model="editFormData.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="editFormData.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="editFormData.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-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">电子邮箱</label>
<input
v-model="editFormData.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>
<label class="block text-sm font-medium text-gray-700 mb-2">手机号码</label>
<input
v-model="editFormData.c_ph"
type="tel"
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-3 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">省份</label>
<input
v-model="editFormData.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>
<label class="block text-sm font-medium text-gray-700 mb-2">城市</label>
<input
v-model="editFormData.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>
<label class="block text-sm font-medium text-gray-700 mb-2">邮编</label>
<input
v-model="editFormData.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>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">通讯地址</label>
<input
v-model="editFormData.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>
</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
@click="closeEditDialog"
variant="outline"
>
取消
</Button>
<Button
@click="handleEditSubmit"
:loading="editLoading"
variant="solid"
>
保存
</Button>
</div>
</div>
</div>
</div>
</div>
</template>
@ -326,7 +469,6 @@ export default {
isLoading: false,
error: null,
searchQuery: '',
selectedType: '',
selectedStatus: '',
pagination: {
pageno: 1,
@ -337,7 +479,21 @@ export default {
showCreateDialog: false,
createLoading: false,
showDetailDialog: false,
selectedOwner: null
selectedOwner: null,
showEditDialog: false,
editLoading: false,
editFormData: { //
c_regtype: 'I', //
c_org_m: '',
c_ln_m: '',
c_fn_m: '',
c_em: '',
c_ph: '',
c_st_m: '',
c_ct_m: '',
c_adr_m: '',
c_pc: ''
}
};
},
computed: {
@ -355,14 +511,15 @@ export default {
});
}
//
if (this.selectedType) {
filtered = filtered.filter(owner => owner.c_regtype === this.selectedType);
}
//
if (this.selectedStatus) {
filtered = filtered.filter(owner => String(owner.r_status) === this.selectedStatus);
filtered = filtered.filter(owner => {
// r_status
// 0: , 1: , 2: , 3: , 4: , 5:
const rStatus = owner.r_status;
const isVerified = rStatus === '1'; // '1'
return String(isVerified ? '1' : '0') === this.selectedStatus;
});
}
return filtered;
@ -388,28 +545,67 @@ export default {
//
getRealNameStatusText(status) {
if (!status || status === '') {
return '未实名认证';
}
// r_status
// 0: , 1: , 2: , 3: , 4: , 5:
const statusMap = {
'1': '已认证',
'0': '未认证',
'2': '认证中',
'3': '认证失败',
'4': '认证过期',
'0': '未实名认证',
'1': '已实名认证',
'2': '实名认证中',
'3': '实名认证失败',
'4': '实名认证过期',
'5': '待审核'
};
return statusMap[String(status)] || '未知';
return statusMap[status] || '未实名认证';
},
//
getRealNameStatusVariant(status) {
const variantMap = {
'1': 'success', // - 绿
'0': 'warning', // -
'2': 'blue', // -
'3': 'danger', // -
'4': 'danger', // -
'5': 'blue' // -
//
getOwnerTypeText(type) {
if (!type || type === '') return '未知';
const typeMap = {
'I': '个人',
'E': '企业/组织'
};
return variantMap[String(status)] || 'default';
return typeMap[type] || '未知';
},
//
getAddressInfo(owner) {
const addressParts = [];
if (owner.c_st_m) addressParts.push(owner.c_st_m);
if (owner.c_ct_m) addressParts.push(owner.c_ct_m);
if (owner.c_adr_m) addressParts.push(owner.c_adr_m);
if (owner.c_pc) addressParts.push(owner.c_pc);
return addressParts.join(' ');
},
//
getCertificateTypeName(type) {
const typeMap = {
//
'SFZ': '身份证',
'HZ': '护照',
'GAJMTX': '港澳居民来往内地通行证',
'TWJMTX': '台湾居民来往大陆通行证',
'WJLSFZ': '外国人永久居留身份证',
'GAJZZ': '港澳台居民居住证',
'ORG': '组织机构代码证',
'YYZZ': '工商营业执照',
'TYDM': '统一社会信用代码',
//
'1': '身份证',
'5': '护照',
'6': '港澳居民来往内地通行证',
'11': '台湾居民来往大陆通行证',
'12': '外国人永久居留身份证',
'30': '港澳台居民居住证',
'2': '组织机构代码证',
'3': '工商营业执照',
'4': '统一社会信用代码'
};
return typeMap[type] || type || '-';
},
//
@ -499,27 +695,95 @@ export default {
//
editOwner(owner) {
// TODO:
console.log('编辑所有者:', owner);
//
if (this.showDetailDialog) {
this.closeDetailDialog();
this.selectedOwner = owner;
this.editFormData = { //
c_regtype: owner.c_regtype,
c_org_m: owner.c_org_m || '',
c_ln_m: owner.c_ln_m || '',
c_fn_m: owner.c_fn_m || '',
c_em: owner.c_em || '',
c_ph: owner.c_ph || '',
c_st_m: owner.c_st_m || '',
c_ct_m: owner.c_ct_m || '',
c_adr_m: owner.c_adr_m || '',
c_pc: owner.c_pc || ''
};
this.showDetailDialog = false; //
this.showEditDialog = true; //
},
//
closeEditDialog() {
this.showEditDialog = false;
this.selectedOwner = null;
this.editFormData = { //
c_regtype: 'I',
c_org_m: '',
c_ln_m: '',
c_fn_m: '',
c_em: '',
c_ph: '',
c_st_m: '',
c_ct_m: '',
c_adr_m: '',
c_pc: ''
};
},
//
async handleEditSubmit() {
this.editLoading = true;
try {
//
const requestParams = {
name: this.selectedOwner.name,
...this.editFormData
};
const editRequest = createResource({
url: 'jcloud.api.domain_west.update_domain_owner',
params: requestParams,
onSuccess: (response) => {
if (response.status === 'Success') {
toast.success('域名所有者模板更新成功!');
this.fetchOwners(); //
this.closeEditDialog(); //
} else {
console.error('更新失败 - response:', response);
toast.error(response.message || '更新失败');
this.editLoading = false;
}
},
onError: (error) => {
console.error('=== onError 回调 ===');
console.error('error:', error);
console.error('error.message:', error.message);
console.error('error.response:', error.response);
const errorMessage = getToastErrorMessage(error);
console.error('errorMessage:', errorMessage);
toast.error(errorMessage);
this.editLoading = false;
}
});
editRequest.submit();
} catch (error) {
console.error('=== catch 错误 ===');
console.error('catch error:', error);
console.error('catch error.message:', error.message);
console.error('catch error.stack:', error.stack);
toast.error('更新失败,请稍后重试');
this.editLoading = false;
}
},
//
getCertificateTypeName(type) {
const typeMap = {
'SFZ': '身份证',
'HZ': '护照',
'YYZZ': '营业执照',
'ORG': '组织机构代码证'
};
return typeMap[type] || type || '-';
},
//
previousPage() {
if (this.pagination.pageno > 1) {

View File

@ -1803,7 +1803,9 @@ def get_domain_owners():
domain_owners = jingrow.get_all(
"Domain Owner",
{"team": team},
["name", "title", "fullname", "c_regtype", "c_org_m", "c_ln_m", "c_fn_m"]
["name", "title", "fullname", "c_regtype", "c_org_m", "c_ln_m", "c_fn_m",
"c_em", "c_ph", "c_st_m", "c_ct_m", "c_adr_m", "c_pc", "r_status",
"c_idtype_gswl", "c_idnum_gswl", "c_sysid"]
)
return {
@ -3205,3 +3207,133 @@ def modify_west_contact_template(**data):
return {"status": "error", "message": f"修改实名模板资料失败: {str(e)}"}
@jingrow.whitelist()
def update_domain_owner(name, **data):
"""更新域名所有者信息"""
try:
jingrow.log_error("update_domain_owner", f"开始更新域名所有者 - name: {name}, data: {data}")
if not name:
jingrow.log_error("update_domain_owner", "域名所有者名称不能为空")
return {"status": "Error", "message": "域名所有者名称不能为空"}
# 获取指定的域名所有者
jingrow.log_error("update_domain_owner", f"正在获取域名所有者: {name}")
domain_owner = jingrow.get_pg("Domain Owner", name)
if not domain_owner:
jingrow.log_error("update_domain_owner", f"未找到指定的域名所有者: {name}")
return {"status": "Error", "message": "未找到指定的域名所有者"}
jingrow.log_error("update_domain_owner", f"找到域名所有者: {domain_owner.name}, team: {getattr(domain_owner, 'team', 'None')}")
# 检查权限(只能更新当前团队的所有者)
jingrow.log_error("update_domain_owner", "正在检查权限...")
team = get_current_team()
jingrow.log_error("update_domain_owner", f"当前团队: {team}")
if not team:
jingrow.log_error("update_domain_owner", "未找到当前团队")
return {"status": "Error", "message": "未找到当前团队"}
if domain_owner.team != team:
jingrow.log_error("update_domain_owner", f"权限检查失败 - 所有者团队: {domain_owner.team}, 当前团队: {team}")
return {"status": "Error", "message": "无权更新该域名所有者信息"}
jingrow.log_error("update_domain_owner", "权限检查通过,开始更新西部数码模板...")
# 检查是否有 c_sysid西部数码模板标识
c_sysid = getattr(domain_owner, 'c_sysid', None)
if not c_sysid:
jingrow.log_error("update_domain_owner", "域名所有者没有 c_sysid无法更新西部数码模板")
return {"status": "Error", "message": "域名所有者没有模板标识,无法更新"}
# 构建西部数码模板更新数据
template_data = {
'c_sysid': c_sysid
}
# 添加需要更新的字段
field_mapping = {
'c_regtype': 'c_regtype',
'c_org_m': 'c_org_m',
'c_ln_m': 'c_ln_m',
'c_fn_m': 'c_fn_m',
'c_em': 'c_em',
'c_ph': 'c_ph',
'c_st_m': 'c_st_m',
'c_ct_m': 'c_ct_m',
'c_adr_m': 'c_adr_m',
'c_pc': 'c_pc',
'c_ph_type': 'c_ph_type',
'c_ph_code': 'c_ph_code',
'c_ph_num': 'c_ph_num',
'c_ph_fj': 'c_ph_fj',
'reg_contact_type': 'reg_contact_type',
'c_idtype_gswl': 'c_idtype_gswl',
'c_idnum_gswl': 'c_idnum_gswl'
}
for local_field, template_field in field_mapping.items():
if local_field in data:
template_data[template_field] = data[local_field]
# 添加现有字段(如果新数据中没有提供)
for local_field, template_field in field_mapping.items():
if template_field not in template_data and hasattr(domain_owner, local_field):
current_value = getattr(domain_owner, local_field, None)
if current_value:
template_data[template_field] = current_value
jingrow.log_error("update_domain_owner", f"准备调用 modify_west_contact_template参数: {template_data}")
# 调用西部数码模板更新接口
try:
west_result = modify_west_contact_template(**template_data)
jingrow.log_error("update_domain_owner", f"西部数码模板更新结果: {west_result}")
if west_result.get('status') != 'success':
error_msg = west_result.get('message', '西部数码模板更新失败')
jingrow.log_error("update_domain_owner", f"西部数码模板更新失败: {error_msg}")
return {"status": "Error", "message": f"西部数码模板更新失败: {error_msg}"}
jingrow.log_error("update_domain_owner", "西部数码模板更新成功,开始更新本地记录...")
except Exception as e:
jingrow.log_error("update_domain_owner", f"调用 modify_west_contact_template 失败: {str(e)}")
return {"status": "Error", "message": f"西部数码模板更新失败: {str(e)}"}
# 西部数码模板更新成功后,更新本地记录
updated_fields = []
for key, value in data.items():
if hasattr(domain_owner, key):
old_value = getattr(domain_owner, key, None)
setattr(domain_owner, key, value)
updated_fields.append(f"{key}: {old_value} -> {value}")
jingrow.log_error("update_domain_owner", f"更新字段 {key}: {old_value} -> {value}")
else:
jingrow.log_error("update_domain_owner", f"字段 {key} 不存在于 Domain Owner 中")
jingrow.log_error("update_domain_owner", f"更新的字段: {updated_fields}")
# 保存更新
jingrow.log_error("update_domain_owner", "正在保存本地更新...")
domain_owner.save()
jingrow.log_error("update_domain_owner", "本地记录保存成功")
return {
"status": "Success",
"message": "域名所有者信息更新成功",
"data": {
"name": domain_owner.name,
"title": domain_owner.title
}
}
except Exception as e:
jingrow.log_error("update_domain_owner", f"更新域名所有者信息失败: {str(e)}")
jingrow.log_error("update_domain_owner", f"异常详情: {type(e).__name__}: {str(e)}")
import traceback
jingrow.log_error("update_domain_owner", f"堆栈跟踪: {traceback.format_exc()}")
return {"status": "Error", "message": f"更新域名所有者信息失败: {str(e)}"}