jcloud/dashboard/src2/components/DomainOwner.vue

899 lines
27 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 class="space-y-4">
<div>
<div class="flex flex-col sm:flex-row gap-4 items-center">
<div class="w-full sm:w-1/2">
<div class="flex gap-2">
<TextInput
v-model="searchQuery"
placeholder="搜索所有者姓名、单位名称..."
class="flex-1"
>
<template #prefix>
<SearchIcon class="h-4 w-4 text-gray-400" />
</template>
</TextInput>
<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"
>
<option value="">全部状态</option>
<option value="1">已实名认证</option>
<option value="0">未实名认证</option>
</select>
</div>
</div>
<div class="w-full sm:w-1/2 flex justify-end">
<Button
@click="createDomainOwner"
variant="solid"
iconLeft="plus"
label="新建所有者模板"
/>
</div>
</div>
<!-- 列表内容 -->
<div class="rounded-lg border border-gray-200 bg-white my-4">
<!-- 表头 -->
<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-4">所有者名称</div>
<div class="col-span-3">实名状态</div>
<div class="col-span-3">联系信息</div>
<div class="col-span-2">操作</div>
</div>
<!-- 加载状态 -->
<div v-if="isLoading" class="flex items-center justify-center py-12">
<Loader2Icon class="h-6 w-6 animate-spin text-gray-400" />
<span class="ml-2 text-gray-600">加载中...</span>
</div>
<!-- 错误状态 -->
<div v-else-if="error" class="flex items-center justify-center py-12">
<AlertCircleIcon class="h-6 w-6 text-red-500" />
<span class="ml-2 text-red-600">{{ error }}</span>
</div>
<!-- 空状态 -->
<div v-else-if="filteredOwners.length === 0" class="flex flex-col items-center justify-center py-12 text-gray-500">
<UsersIcon class="mb-4 h-12 w-12 text-gray-300" />
<p class="text-lg font-medium">暂无域名所有者模板</p>
<p class="text-sm">点击上方按钮创建第一个模板</p>
</div>
<!-- 数据列表 -->
<div v-else class="divide-y divide-gray-200">
<div
v-for="owner in filteredOwners"
:key="owner.name"
class="grid grid-cols-12 gap-4 px-6 py-4 hover:bg-gray-50 transition-colors cursor-pointer"
@click="viewOwner(owner)"
>
<!-- 名称列 -->
<div class="col-span-4 flex items-center">
<div class="text-sm text-gray-900">{{ getDisplayName(owner) }}</div>
</div>
<!-- 实名状态列 -->
<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_ph || '-' }}</div>
<div class="text-sm text-gray-500">{{ owner.c_em || '-' }}</div>
</div>
<!-- 操作列 -->
<div class="col-span-2 flex items-center gap-2" @click.stop>
<Button
@click="viewOwner(owner)"
variant="ghost"
size="sm"
class="text-blue-600 hover:text-blue-700"
title="查看详情"
>
<EyeIcon class="h-4 w-4" />
</Button>
<Button
@click="editOwner(owner)"
variant="ghost"
size="sm"
class="text-gray-600 hover:text-gray-700"
title="编辑"
>
<EditIcon class="h-4 w-4" />
</Button>
<Button
@click="deleteOwner(owner)"
variant="ghost"
size="sm"
class="text-red-600 hover:text-red-700"
title="删除"
>
<Trash2Icon class="h-4 w-4" />
</Button>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div v-if="pagination.total > pagination.limit" class="flex flex-col items-center space-y-4">
<div class="text-sm text-gray-700">
显示第 {{ (pagination.pageno - 1) * pagination.limit + 1 }} -
{{ Math.min(pagination.pageno * pagination.limit, pagination.total) }}
{{ pagination.total }} 条记录
</div>
<div class="flex items-center space-x-2">
<Button
@click="previousPage"
:disabled="pagination.pageno <= 1"
variant="outline"
size="sm"
class="px-3"
>
</Button>
<div class="flex items-center space-x-1">
<Button
v-for="page in getVisiblePages()"
:key="page"
@click="changePage(page)"
:class="[
'px-3 py-1 text-sm rounded',
page === pagination.pageno
? '!bg-[#1fc76f] text-white'
: 'bg-white text-gray-700 border border-gray-300 hover:bg-gray-50'
]"
:disabled="page === pagination.pageno"
>
{{ page }}
</Button>
</div>
<Button
@click="nextPage"
:disabled="pagination.pageno >= pagination.pagecount"
variant="outline"
size="sm"
class="px-3"
>
</Button>
</div>
</div>
</div>
<!-- 创建域名所有者弹窗 -->
<DomainOwnerDialog
:visible="showCreateDialog"
:isLoading="createLoading"
@close="handleCloseDialog"
@submit="handleCreateSubmit"
/>
<!-- 详情查看弹窗 -->
<div v-if="showDetailDialog" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @click="closeDetailDialog">
<div class="bg-white rounded-lg shadow-2xl max-w-2xl w-full mx-4 max-h-[90vh] flex flex-col overflow-hidden" @click.stop>
<!-- 标题栏 -->
<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="closeDetailDialog"
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">
<div class="space-y-6">
<!-- 基本信息 -->
<div>
<h4 class="text-base font-medium text-gray-900 mb-4">基本信息</h4>
<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">{{ 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">{{ getRealNameStatusText(selectedOwner.r_status) }}</p>
</div>
<div v-if="selectedOwner.c_regtype === 'E'">
<label class="block text-sm font-medium text-gray-700">单位名称</label>
<p class="mt-1 text-sm text-gray-900">{{ selectedOwner.c_org_m || '-' }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">姓名</label>
<p class="mt-1 text-sm text-gray-900">{{ getDisplayName(selectedOwner) }}</p>
</div>
</div>
</div>
<!-- 联系信息 -->
<div>
<h4 class="text-base font-medium text-gray-900 mb-4">联系信息</h4>
<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">{{ selectedOwner.c_em || '-' }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">手机号码</label>
<p class="mt-1 text-sm text-gray-900">{{ selectedOwner.c_ph || '-' }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">省份</label>
<p class="mt-1 text-sm text-gray-900">{{ selectedOwner.c_st_m || '-' }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">城市</label>
<p class="mt-1 text-sm text-gray-900">{{ selectedOwner.c_ct_m || '-' }}</p>
</div>
<div class="col-span-2">
<label class="block text-sm font-medium text-gray-700">通讯地址</label>
<p class="mt-1 text-sm text-gray-900">{{ selectedOwner.c_adr_m || '-' }}</p>
</div>
</div>
</div>
<!-- 证件信息 -->
<div>
<h4 class="text-base font-medium text-gray-900 mb-4">证件信息</h4>
<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">{{ getCertificateTypeName(selectedOwner.c_idtype_gswl) }}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">证件号码</label>
<p class="mt-1 text-sm text-gray-900">{{ selectedOwner.c_idnum_gswl || '-' }}</p>
</div>
</div>
</div>
</div>
</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="closeDetailDialog"
variant="outline"
>
关闭
</Button>
<Button
@click="editOwner(selectedOwner)"
variant="solid"
>
编辑
</Button>
</div>
</div>
</div>
</div>
<!-- 编辑域名所有者弹窗 -->
<div v-if="showEditDialog" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @click="closeEditDialog">
<div class="bg-white rounded-lg shadow-2xl max-w-4xl w-full mx-4 max-h-[90vh] flex flex-col overflow-hidden" @click.stop>
<!-- 标题栏 -->
<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>
<script>
import { Badge, Button, TextInput, createResource } from 'jingrow-ui';
import { toast } from 'vue-sonner';
import { getToastErrorMessage } from '../utils/toast';
import { confirmDialog } from '../utils/components';
import DomainOwnerDialog from './DomainOwnerDialog.vue';
import SearchIcon from '~icons/lucide/search';
import EyeIcon from '~icons/lucide/eye';
import EditIcon from '~icons/lucide/edit';
import Trash2Icon from '~icons/lucide/trash-2';
import Loader2Icon from '~icons/lucide/loader-2';
import AlertCircleIcon from '~icons/lucide/alert-circle';
import UsersIcon from '~icons/lucide/users';
export default {
name: 'DomainOwner',
components: {
Badge,
Button,
TextInput,
SearchIcon,
EyeIcon,
EditIcon,
Trash2Icon,
Loader2Icon,
AlertCircleIcon,
UsersIcon,
DomainOwnerDialog,
},
data() {
return {
owners: [],
isLoading: false,
error: null,
searchQuery: '',
selectedStatus: '',
pagination: {
pageno: 1,
limit: 10,
total: 0,
pagecount: 0
},
showCreateDialog: false,
createLoading: false,
showDetailDialog: false,
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: {
filteredOwners() {
// 由于搜索和过滤现在在服务器端处理,直接返回当前页的数据
return this.owners;
}
},
watch: {
// 监听搜索条件变化
searchQuery() {
this.pagination.pageno = 1; // 重置到第一页
this.fetchOwners();
},
// 监听状态过滤变化
selectedStatus() {
this.pagination.pageno = 1; // 重置到第一页
this.fetchOwners();
}
},
methods: {
// 获取显示名称
getDisplayName(owner) {
if (owner.c_regtype === 'I') {
// 个人:优先显示 fullname没有的话显示 姓+名
if (owner.fullname) {
return owner.fullname;
}
const lastName = owner.c_ln_m || '';
const firstName = owner.c_fn_m || '';
return `${lastName}${firstName}`.trim() || owner.title || owner.name;
} else if (owner.c_regtype === 'E') {
// 企业:优先显示 c_org_m没有的话显示 title
return owner.c_org_m || owner.title || owner.name;
}
return owner.title || owner.name;
},
// 获取实名认证状态文本
getRealNameStatusText(status) {
if (!status || status === '') {
return '未实名认证';
}
// 根据r_status字段判断实名认证状态
// 0: 未实名, 1: 实名成功, 2: 实名中, 3: 实名失败, 4: 认证过期, 5: 待审核
const statusMap = {
'0': '未实名认证',
'1': '已实名认证',
'2': '实名认证中',
'3': '实名认证失败',
'4': '实名认证过期',
'5': '待审核'
};
return statusMap[status] || '未实名认证';
},
// 获取所有者类型文本
getOwnerTypeText(type) {
if (!type || type === '') return '未知';
const typeMap = {
'I': '个人',
'E': '企业/组织'
};
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);
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 || '-';
},
// 获取域名所有者列表
async fetchOwners() {
this.isLoading = true;
this.error = null;
try {
const ownersRequest = createResource({
url: 'jcloud.api.domain_west.get_domain_owners',
params: {
limit: this.pagination.limit,
pageno: this.pagination.pageno,
searchQuery: this.searchQuery,
selectedStatus: this.selectedStatus
},
onSuccess: (response) => {
if (response.status === 'Success') {
this.owners = response.data.items || [];
this.pagination = {
pageno: response.data.pageno || 1,
limit: response.data.limit || 20,
total: response.data.total || 0,
pagecount: response.data.pagecount || 0
};
} else {
this.error = response.message || '获取域名所有者列表失败';
}
this.isLoading = false;
},
onError: (error) => {
this.error = getToastErrorMessage(error);
this.isLoading = false;
}
});
ownersRequest.submit();
} catch (error) {
this.error = '获取域名所有者列表失败';
this.isLoading = false;
}
},
// 创建新的域名所有者
createDomainOwner() {
this.showCreateDialog = true;
},
// 处理弹窗关闭
handleCloseDialog() {
this.showCreateDialog = false;
this.createLoading = false;
},
// 处理创建提交
async handleCreateSubmit(data) {
this.createLoading = true;
try {
const createRequest = createResource({
url: 'jcloud.api.domain_west.create_domain_owner',
params: data,
onSuccess: (response) => {
if (response.status === 'Success') {
toast.success('域名所有者模板创建成功!');
this.fetchOwners(); // 刷新列表
this.handleCloseDialog(); // 关闭弹窗
} else {
toast.error(response.message || '创建失败');
this.createLoading = false;
}
},
onError: (error) => {
toast.error(getToastErrorMessage(error));
this.createLoading = false;
}
});
createRequest.submit();
} catch (error) {
toast.error('创建失败,请稍后重试');
this.createLoading = false;
}
},
// 查看域名所有者详情
viewOwner(owner) {
this.selectedOwner = owner;
this.showDetailDialog = true;
},
// 关闭详情弹窗
closeDetailDialog() {
this.showDetailDialog = false;
this.selectedOwner = null;
},
// 编辑域名所有者
editOwner(owner) {
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 || '更新失败');
}
// 确保在所有情况下都重置 loading 状态
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;
}
},
// 删除域名所有者
async deleteOwner(owner) {
confirmDialog({
title: '确认删除',
message: `确定要删除域名所有者模板 "<strong>${this.getDisplayName(owner)}</strong>" 吗?<br><br>此操作将同时删除西部数码平台和本地的模板记录,且不可逆。`,
primaryAction: {
label: '删除',
variant: 'solid',
onClick: async ({ hide }) => {
try {
const deleteRequest = createResource({
url: 'jcloud.api.domain_west.delete_domain_owner',
params: { name: owner.name },
onSuccess: (response) => {
if (response.status === 'Success') {
toast.success('域名所有者模板删除成功!');
this.fetchOwners(); // 刷新列表
hide();
} else {
throw new Error(response.message || '删除失败');
}
},
onError: (error) => {
throw new Error(getToastErrorMessage(error));
}
});
await deleteRequest.submit();
} catch (error) {
toast.error(error.message || '删除失败,请稍后重试');
throw error;
}
}
}
});
},
// 上一页
previousPage() {
if (this.pagination.pageno > 1) {
this.pagination.pageno--;
this.fetchOwners();
}
},
// 下一页
nextPage() {
if (this.pagination.pageno < this.pagination.pagecount) {
this.pagination.pageno++;
this.fetchOwners();
}
},
// 刷新列表
refresh() {
this.fetchOwners();
},
// 获取可见的页码
getVisiblePages() {
const current = this.pagination.pageno;
const total = this.pagination.pagecount;
const pages = [];
// 如果总页数小于等于5显示所有页码
if (total <= 5) {
for (let i = 1; i <= total; i++) {
pages.push(i);
}
} else {
// 显示当前页附近的页码
const start = Math.max(1, current - 2);
const end = Math.min(total, current + 2);
for (let i = start; i <= end; i++) {
pages.push(i);
}
}
return pages;
},
// 切换页码
changePage(page) {
if (page >= 1 && page <= this.pagination.pagecount) {
this.pagination.pageno = page;
this.fetchOwners();
}
}
},
mounted() {
// 组件挂载时获取数据
this.fetchOwners();
}
};
</script>