This commit is contained in:
2026-08-18 09:09:34 +08:00
parent dcbca0bf85
commit 8046f9b9ee
27 changed files with 230 additions and 83 deletions
@@ -34,6 +34,7 @@ import {
type PlatformTenantStatus,
} from '@/modules/iam'
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
import OperationErrorToast from '@/shared/components/OperationErrorToast.vue'
import CopyButton from '@/shared/components/CopyButton.vue'
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
@@ -1018,6 +1019,7 @@ onMounted(() => { void loadCustomers() })
<template>
<AdminPage as="div" class="customers-page">
<OperationErrorToast :details="passwordError || impersonationError || archiveError" />
<ListPageLayout aria-label="客户管理">
<template #toolbar><QueryToolbar v-model="filters" class="surface-panel" ariaLabel="客户筛选" :fields="queryFields" preference-key="customers-query" @search="applyFilters" /></template>
<template v-if="loadError" #state>
@@ -1158,7 +1160,6 @@ onMounted(() => { void loadCustomers() })
<el-dialog v-model="passwordDialogOpen" title="重置客户密码" width="min(520px, calc(100vw - 28px))" class="customer-password-dialog" :close-on-click-modal="false" :close-on-press-escape="!passwordSubmitting" :show-close="!passwordSubmitting">
<div v-if="passwordTenant" class="decision-summary"><div><strong>正在重置企业管理员登录密码</strong><span>{{ passwordTenant.tenantName }}</span></div><span>客户编号:{{ passwordTenant.tenantCode }}</span></div>
<el-alert v-if="passwordError" type="error" :closable="false" show-icon role="alert"><template #title><div class="api-error-alert-title"><span>{{ passwordError.message }}</span><ApiErrorMeta :details="passwordError" /></div></template></el-alert>
<el-form ref="passwordFormRef" :model="passwordForm" :rules="passwordRules" label-position="top">
<el-form-item label="新密码" prop="newPassword" required><div class="password-input-row"><el-input v-model="passwordForm.newPassword" type="password" show-password autocomplete="new-password" placeholder="请输入 8-20 位新密码" /><el-button @click="randomPassword">随机生成</el-button></div></el-form-item>
<el-form-item label="确认新密码" prop="confirmPassword" required><el-input v-model="passwordForm.confirmPassword" type="password" show-password autocomplete="new-password" placeholder="请再次输入新密码" /></el-form-item>
@@ -1171,7 +1172,6 @@ onMounted(() => { void loadCustomers() })
<el-dialog v-model="impersonationDialogOpen" title="跳转登录客户工作台" width="min(560px, calc(100vw - 28px))" :close-on-click-modal="false" :close-on-press-escape="!impersonationSubmitting" :show-close="!impersonationSubmitting">
<div v-if="impersonationTenant" class="decision-summary"><div><strong>{{ impersonationTenant.tenantName }}</strong><span>将以企业管理员身份打开客户工作台</span></div><span>客户编号:{{ impersonationTenant.tenantCode }}</span></div>
<el-alert type="warning" :closable="false" show-icon>本操作会生成一次性、短时有效的客户会话,并记录代登录原因;不会替换当前 Admin 会话。</el-alert>
<el-alert v-if="impersonationError" type="error" :closable="false" show-icon role="alert"><template #title><div class="api-error-alert-title"><span>{{ impersonationError.message }}</span><ApiErrorMeta :details="impersonationError" /></div></template></el-alert>
<el-form ref="impersonationFormRef" :model="impersonationForm" :rules="impersonationRules" label-position="top"><el-form-item label="代登录原因" prop="reason" required><el-input v-model="impersonationForm.reason" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="请填写 5-500 字的业务原因" /></el-form-item></el-form>
<template #footer><div class="drawer-footer"><el-button :disabled="impersonationSubmitting" @click="impersonationDialogOpen = false">取消</el-button><el-button type="primary" :loading="impersonationSubmitting" @click="submitImpersonation">确认跳转</el-button></div></template>
</el-dialog>
@@ -1179,7 +1179,6 @@ onMounted(() => { void loadCustomers() })
<el-dialog v-model="archiveDialogOpen" title="删除客户" width="min(560px, calc(100vw - 28px))" :close-on-click-modal="false" :close-on-press-escape="!archiveSubmitting" :show-close="!archiveSubmitting">
<el-alert type="warning" :closable="false" show-icon>删除是逻辑归档:历史业务数据会保留,客户账号会被停用。是否允许归档由服务端最终判断。</el-alert>
<div v-if="archiveTenant" class="archive-confirm"><strong>{{ archiveTenant.tenantName }}</strong><span>请输入客户编号 {{ archiveTenant.tenantCode }} 以确认。</span><el-input v-model="archiveConfirmCode" :disabled="archiveSubmitting" :placeholder="archiveTenant.tenantCode" autocomplete="off" /></div>
<el-alert v-if="archiveError" type="error" :closable="false" show-icon role="alert"><template #title><div class="api-error-alert-title"><span>{{ archiveError.message }}</span><ApiErrorMeta :details="archiveError" /></div></template></el-alert>
<template #footer><div class="drawer-footer"><el-button :disabled="archiveSubmitting" @click="archiveDialogOpen = false">取消</el-button><el-button type="danger" :loading="archiveSubmitting" :disabled="!archiveTenant || archiveConfirmCode.trim() !== archiveTenant.tenantCode" @click="submitArchive">确认删除</el-button></div></template>
</el-dialog>
</AdminPage>