feat: 新增门店列表页面并修复全局类型错误
1. 新增门店列表页(筛选/统计/表格/抽屉编辑),使用 mockjs 提供接口数据 2. 新增门店相关枚举、API 定义、路由配置 3. 修复 auth.ts loginApi 参数类型不匹配 4. 修复 merchant-center stores 属性路径错误及 merchant prop 类型不兼容 5. 修复 merchant-setting showSubmitButton 不存在于 VbenFormProps
This commit is contained in:
@@ -1,404 +1,475 @@
|
||||
<script setup lang="ts">
|
||||
import type {
|
||||
CurrentMerchantCenterDto,
|
||||
MerchantAuditLogDto,
|
||||
MerchantChangeLogDto,
|
||||
MerchantContractDto,
|
||||
MerchantDocumentDto,
|
||||
MerchantStaffDto,
|
||||
MerchantStoreDto,
|
||||
} from '#/api/merchant';
|
||||
import type { CurrentMerchantCenterDto } from '#/api/merchant';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { Profile } from '@vben/common-ui';
|
||||
import { useUserStore } from '@vben/stores';
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Alert, Empty, List, message, Spin, Tag } from 'ant-design-vue';
|
||||
import {
|
||||
Alert,
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
Descriptions,
|
||||
Empty,
|
||||
Image,
|
||||
Modal,
|
||||
Spin,
|
||||
Table,
|
||||
TabPane,
|
||||
Tabs,
|
||||
Tag,
|
||||
Timeline,
|
||||
} from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { getMerchantInfoApi } from '#/api/merchant';
|
||||
import {
|
||||
ContractStatus,
|
||||
MerchantAuditAction,
|
||||
MerchantDocumentStatus,
|
||||
MerchantDocumentType,
|
||||
MerchantStatus,
|
||||
OperatingMode,
|
||||
StaffRoleType,
|
||||
StaffStatus,
|
||||
StoreStatus,
|
||||
} from '#/enums/merchantEnum';
|
||||
|
||||
import MerchantSetting from './merchant-setting.vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const tabsValue = ref('basic');
|
||||
const loading = ref(false);
|
||||
const merchantCenter = ref<CurrentMerchantCenterDto | null>(null);
|
||||
const activeTab = ref('documents');
|
||||
const isEditModalVisible = ref(false);
|
||||
|
||||
const tabs = [
|
||||
{ label: '基本信息', value: 'basic' },
|
||||
{ label: '资质合同', value: 'qualification' },
|
||||
{ label: '门店信息', value: 'stores' },
|
||||
{ label: '员工信息', value: 'staffs' },
|
||||
{ label: '日志记录', value: 'logs' },
|
||||
];
|
||||
const merchant = computed(() => merchantCenter.value?.merchant);
|
||||
const documents = computed(() => merchantCenter.value?.documents ?? []);
|
||||
const contracts = computed(() => merchantCenter.value?.contracts ?? []);
|
||||
const stores = computed(() => merchantCenter.value?.merchant?.stores ?? []);
|
||||
const staffs = computed(() => merchantCenter.value?.staffs ?? []);
|
||||
const auditLogs = computed(() => merchantCenter.value?.auditLogs ?? []);
|
||||
const changeLogs = computed(() => merchantCenter.value?.changeLogs ?? []);
|
||||
|
||||
const merchantStores = computed<MerchantStoreDto[]>(() => {
|
||||
return merchantCenter.value?.merchant.stores ?? [];
|
||||
});
|
||||
|
||||
const merchantDocuments = computed<MerchantDocumentDto[]>(() => {
|
||||
return merchantCenter.value?.documents ?? [];
|
||||
});
|
||||
|
||||
const merchantContracts = computed<MerchantContractDto[]>(() => {
|
||||
return merchantCenter.value?.contracts ?? [];
|
||||
});
|
||||
|
||||
const merchantStaffs = computed<MerchantStaffDto[]>(() => {
|
||||
return merchantCenter.value?.staffs ?? [];
|
||||
});
|
||||
|
||||
const merchantAuditLogs = computed<MerchantAuditLogDto[]>(() => {
|
||||
return merchantCenter.value?.auditLogs ?? [];
|
||||
});
|
||||
|
||||
const merchantChangeLogs = computed<MerchantChangeLogDto[]>(() => {
|
||||
return merchantCenter.value?.changeLogs ?? [];
|
||||
});
|
||||
|
||||
function formatDateTime(value?: null | string) {
|
||||
if (!value) {
|
||||
return '--';
|
||||
}
|
||||
|
||||
return new Date(value).toLocaleString('zh-CN', { hour12: false });
|
||||
}
|
||||
|
||||
function resolveStoreStatus(status: number) {
|
||||
if (status === 1) {
|
||||
return '营业中';
|
||||
}
|
||||
|
||||
if (status === 2) {
|
||||
return '停业中';
|
||||
}
|
||||
|
||||
return `状态${status}`;
|
||||
}
|
||||
|
||||
function resolveContractStatus(status: number) {
|
||||
if (status === 1) {
|
||||
return '生效中';
|
||||
}
|
||||
|
||||
if (status === 2) {
|
||||
return '已终止';
|
||||
}
|
||||
|
||||
if (status === 3) {
|
||||
return '已过期';
|
||||
}
|
||||
|
||||
return `状态${status}`;
|
||||
}
|
||||
|
||||
function resolveDocumentType(documentType: number) {
|
||||
if (documentType === 1) {
|
||||
return '营业执照';
|
||||
}
|
||||
|
||||
if (documentType === 2) {
|
||||
return '食品经营许可证';
|
||||
}
|
||||
|
||||
if (documentType === 3) {
|
||||
return '法人身份证';
|
||||
}
|
||||
|
||||
if (documentType === 4) {
|
||||
return '门头照';
|
||||
}
|
||||
|
||||
return `类型${documentType}`;
|
||||
}
|
||||
|
||||
function resolveDocumentStatus(status: number) {
|
||||
if (status === 1) {
|
||||
return '待审核';
|
||||
}
|
||||
|
||||
if (status === 2) {
|
||||
return '已通过';
|
||||
}
|
||||
|
||||
if (status === 3) {
|
||||
return '已驳回';
|
||||
}
|
||||
|
||||
return `状态${status}`;
|
||||
}
|
||||
|
||||
function resolveStaffRole(roleType: number) {
|
||||
if (roleType === 1) {
|
||||
return '店长';
|
||||
}
|
||||
|
||||
if (roleType === 2) {
|
||||
return '店员';
|
||||
}
|
||||
|
||||
if (roleType === 3) {
|
||||
return '财务';
|
||||
}
|
||||
|
||||
return `角色${roleType}`;
|
||||
}
|
||||
|
||||
function resolveStaffStatus(status: number) {
|
||||
if (status === 1) {
|
||||
return '在职';
|
||||
}
|
||||
|
||||
if (status === 2) {
|
||||
return '离职';
|
||||
}
|
||||
|
||||
return `状态${status}`;
|
||||
}
|
||||
|
||||
async function loadMerchantCenter() {
|
||||
async function loadData() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
merchantCenter.value = await getMerchantInfoApi();
|
||||
} catch {
|
||||
message.error('商户中心信息加载失败');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadMerchantCenter();
|
||||
});
|
||||
function handleEditSuccess() {
|
||||
isEditModalVisible.value = false;
|
||||
loadData();
|
||||
}
|
||||
|
||||
function formatDateTime(dateStr?: null | string) {
|
||||
if (!dateStr) return '--';
|
||||
return dayjs(dateStr).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
function formatDate(dateStr?: null | string) {
|
||||
if (!dateStr) return '--';
|
||||
return dayjs(dateStr).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
// Enum Resolvers
|
||||
function resolveOperatingMode(mode?: OperatingMode) {
|
||||
const map: Record<number, string> = {
|
||||
[OperatingMode.Direct]: '直营',
|
||||
[OperatingMode.Franchise]: '加盟',
|
||||
};
|
||||
return mode ? (map[mode] ?? mode) : '--';
|
||||
}
|
||||
|
||||
function resolveMerchantStatus(status?: MerchantStatus) {
|
||||
const map: Record<number, { color: string; text: string }> = {
|
||||
[MerchantStatus.Pending]: { color: 'orange', text: '待审核' },
|
||||
[MerchantStatus.Active]: { color: 'green', text: '营业中' },
|
||||
[MerchantStatus.Suspended]: { color: 'red', text: '已暂停' },
|
||||
[MerchantStatus.Closed]: { color: 'default', text: '已关闭' },
|
||||
};
|
||||
if (status === undefined) {
|
||||
return { color: 'default', text: '--' };
|
||||
}
|
||||
return map[status] ?? { color: 'default', text: `未知(${status})` };
|
||||
}
|
||||
|
||||
function resolveDocumentType(type: MerchantDocumentType) {
|
||||
const map: Record<number, string> = {
|
||||
[MerchantDocumentType.BusinessLicense]: '营业执照',
|
||||
[MerchantDocumentType.Permit]: '许可证',
|
||||
[MerchantDocumentType.Other]: '其他',
|
||||
};
|
||||
return map[type] ?? `类型${type}`;
|
||||
}
|
||||
|
||||
function resolveDocumentStatus(status: MerchantDocumentStatus) {
|
||||
const map: Record<
|
||||
number,
|
||||
{
|
||||
status: 'default' | 'error' | 'processing' | 'success' | 'warning';
|
||||
text: string;
|
||||
}
|
||||
> = {
|
||||
[MerchantDocumentStatus.Pending]: { status: 'processing', text: '审核中' },
|
||||
[MerchantDocumentStatus.Approved]: { status: 'success', text: '有效' },
|
||||
[MerchantDocumentStatus.Rejected]: { status: 'error', text: '已驳回' },
|
||||
[MerchantDocumentStatus.Expired]: { status: 'warning', text: '已过期' },
|
||||
};
|
||||
return map[status] ?? { status: 'default', text: `状态${status}` };
|
||||
}
|
||||
|
||||
function resolveContractStatus(status: ContractStatus) {
|
||||
const map: Record<number, { color: string; text: string }> = {
|
||||
[ContractStatus.Draft]: { color: 'default', text: '草稿' },
|
||||
[ContractStatus.Active]: { color: 'green', text: '生效中' },
|
||||
[ContractStatus.Expired]: { color: 'orange', text: '已过期' },
|
||||
[ContractStatus.Terminated]: { color: 'red', text: '已终止' },
|
||||
};
|
||||
return map[status] ?? { color: 'default', text: `状态${status}` };
|
||||
}
|
||||
|
||||
function resolveStoreStatus(status: StoreStatus) {
|
||||
const map: Record<number, { color: string; text: string }> = {
|
||||
[StoreStatus.Operating]: { color: 'green', text: '营业中' },
|
||||
[StoreStatus.Closed]: { color: 'red', text: '已关店' },
|
||||
[StoreStatus.Renovating]: { color: 'orange', text: '装修中' },
|
||||
};
|
||||
return map[status] ?? { color: 'default', text: `状态${status}` };
|
||||
}
|
||||
|
||||
function resolveStaffRole(role: StaffRoleType) {
|
||||
const map: Record<number, string> = {
|
||||
[StaffRoleType.StoreManager]: '店长',
|
||||
[StaffRoleType.Financial]: '财务',
|
||||
[StaffRoleType.Operator]: '操作员',
|
||||
};
|
||||
return map[role] ?? `角色${role}`;
|
||||
}
|
||||
|
||||
function resolveStaffStatus(status: StaffStatus) {
|
||||
const map: Record<number, { color: string; text: string }> = {
|
||||
[StaffStatus.Active]: { color: 'green', text: '在职' },
|
||||
[StaffStatus.Resigned]: { color: 'default', text: '离职' },
|
||||
};
|
||||
return map[status] ?? { color: 'default', text: `状态${status}` };
|
||||
}
|
||||
|
||||
function resolveAuditAction(action: MerchantAuditAction) {
|
||||
const map: Record<number, string> = {
|
||||
[MerchantAuditAction.Unknown]: '未知',
|
||||
[MerchantAuditAction.Create]: '创建',
|
||||
[MerchantAuditAction.Update]: '更新',
|
||||
[MerchantAuditAction.Delete]: '删除',
|
||||
[MerchantAuditAction.Audit]: '审核通过',
|
||||
[MerchantAuditAction.Reject]: '审核驳回',
|
||||
[MerchantAuditAction.Freeze]: '冻结',
|
||||
[MerchantAuditAction.Unfreeze]: '解冻',
|
||||
[MerchantAuditAction.Close]: '关闭',
|
||||
[MerchantAuditAction.Reopen]: '重开',
|
||||
};
|
||||
return map[action] ?? `动作${action}`;
|
||||
}
|
||||
|
||||
// Table Columns
|
||||
const storeColumns = [
|
||||
{ title: '门店名称', dataIndex: 'name', key: 'name' },
|
||||
{ title: '营业执照号', dataIndex: 'licenseNumber', key: 'licenseNumber' },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', key: 'contactPhone' },
|
||||
{ title: '地址', dataIndex: 'address', key: 'address' },
|
||||
{ title: '状态', key: 'status' },
|
||||
];
|
||||
|
||||
const staffColumns = [
|
||||
{ title: '姓名', dataIndex: 'name', key: 'name' },
|
||||
{ title: '角色', key: 'roleType' },
|
||||
{ title: '电话', dataIndex: 'phone', key: 'phone' },
|
||||
{ title: '邮箱', dataIndex: 'email', key: 'email' },
|
||||
{ title: '状态', key: 'status' },
|
||||
];
|
||||
|
||||
const contractColumns = [
|
||||
{ title: '合同编号', dataIndex: 'contractNumber', key: 'contractNumber' },
|
||||
{ title: '状态', key: 'status' },
|
||||
{ title: '开始日期', key: 'startDate' },
|
||||
{ title: '结束日期', key: 'endDate' },
|
||||
{ title: '签署时间', key: 'signedAt' },
|
||||
{ title: '操作', key: 'action' },
|
||||
];
|
||||
|
||||
onMounted(loadData);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-5">
|
||||
<Profile
|
||||
v-model:model-value="tabsValue"
|
||||
:title="$t('page.merchant.center')"
|
||||
:user-info="{
|
||||
realName: userStore.userInfo?.realName || '',
|
||||
avatar: userStore.userInfo?.avatar || '',
|
||||
username: userStore.userInfo?.username || '',
|
||||
}"
|
||||
:tabs="tabs"
|
||||
>
|
||||
<template #content>
|
||||
<div class="rounded-lg bg-card p-4">
|
||||
<Spin :spinning="loading">
|
||||
<MerchantSetting v-if="tabsValue === 'basic'" />
|
||||
<Page title="商户中心">
|
||||
<template #extra>
|
||||
<Button type="primary" @click="isEditModalVisible = true">
|
||||
编辑基本信息
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tabsValue === 'qualification'">
|
||||
<div class="mb-3 text-base font-medium">资质证照</div>
|
||||
<Empty
|
||||
v-if="merchantDocuments.length === 0"
|
||||
description="暂无资质证照"
|
||||
/>
|
||||
<List
|
||||
v-else
|
||||
:data-source="merchantDocuments"
|
||||
item-layout="vertical"
|
||||
<div v-if="loading" class="p-10 text-center">
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="!merchant" class="p-10 text-center">
|
||||
<Empty description="暂无商户数据" />
|
||||
</div>
|
||||
|
||||
<div v-else class="space-y-4">
|
||||
<!-- 基本信息卡片 -->
|
||||
<Card :bordered="false" title="基本信息">
|
||||
<Descriptions
|
||||
:column="{ xxl: 3, xl: 3, lg: 2, md: 2, sm: 1, xs: 1 }"
|
||||
bordered
|
||||
>
|
||||
<Descriptions.Item label="商户名称">
|
||||
<span class="text-lg font-bold">{{ merchant.name }}</span>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="状态">
|
||||
<Tag :color="resolveMerchantStatus(merchant.status).color">
|
||||
{{ resolveMerchantStatus(merchant.status).text }}
|
||||
</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="经营模式">
|
||||
<Tag color="blue">
|
||||
{{ resolveOperatingMode(merchant.operatingMode) }}
|
||||
</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="营业执照号">
|
||||
{{ merchant.licenseNumber || '--' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="法人/负责人">
|
||||
{{ merchant.legalRepresentative || '--' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="联系电话">
|
||||
{{ merchant.contactPhone || '--' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="联系邮箱">
|
||||
{{ merchant.contactEmail || '--' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="创建时间">
|
||||
{{ formatDateTime(merchant.createdAt) }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="注册地址" :span="3">
|
||||
{{ merchant.registeredAddress || '--' }}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
<!-- 详细信息 Tabs -->
|
||||
<Card :bordered="false">
|
||||
<Tabs v-model:active-key="activeTab">
|
||||
<!-- 资质证照 -->
|
||||
<TabPane key="documents" tab="资质证照">
|
||||
<Empty v-if="documents.length === 0" description="暂无资质证照" />
|
||||
<div
|
||||
v-else
|
||||
class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4"
|
||||
>
|
||||
<Card
|
||||
v-for="doc in documents"
|
||||
:key="doc.id"
|
||||
hoverable
|
||||
class="overflow-hidden"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<List.Item>
|
||||
<div class="mb-2 flex flex-wrap items-center gap-2">
|
||||
<Tag color="blue">
|
||||
{{ resolveDocumentType(item.documentType) }}
|
||||
</Tag>
|
||||
<Tag>{{ resolveDocumentStatus(item.status) }}</Tag>
|
||||
<span class="text-gray-500">
|
||||
编号:{{ item.documentNumber || '--' }}
|
||||
<template #cover>
|
||||
<div class="flex h-48 items-center justify-center bg-gray-50">
|
||||
<Image
|
||||
v-if="doc.fileUrl"
|
||||
:src="doc.fileUrl"
|
||||
alt="证照预览"
|
||||
class="max-h-full max-w-full object-contain"
|
||||
height="100%"
|
||||
/>
|
||||
<div v-else class="text-gray-400">无预览图</div>
|
||||
</div>
|
||||
</template>
|
||||
<Card.Meta :title="resolveDocumentType(doc.documentType)">
|
||||
<template #description>
|
||||
<div class="space-y-1 text-xs">
|
||||
<div class="flex justify-between">
|
||||
<span>状态:</span>
|
||||
<Badge
|
||||
:status="resolveDocumentStatus(doc.status).status"
|
||||
:text="resolveDocumentStatus(doc.status).text"
|
||||
/>
|
||||
</div>
|
||||
<div>证号: {{ doc.documentNumber || '--' }}</div>
|
||||
<div>有效期: {{ formatDate(doc.expiresAt) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
</div>
|
||||
</TabPane>
|
||||
|
||||
<!-- 门店信息 -->
|
||||
<TabPane key="stores" tab="门店信息">
|
||||
<Table
|
||||
:columns="storeColumns"
|
||||
:data-source="stores"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
<Tag :color="resolveStoreStatus(record.status).color">
|
||||
{{ resolveStoreStatus(record.status).text }}
|
||||
</Tag>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
</TabPane>
|
||||
|
||||
<!-- 员工信息 -->
|
||||
<TabPane key="staffs" tab="员工信息">
|
||||
<Table
|
||||
:columns="staffColumns"
|
||||
:data-source="staffs"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'roleType'">
|
||||
<Tag>{{ resolveStaffRole(record.roleType) }}</Tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'status'">
|
||||
<Tag :color="resolveStaffStatus(record.status).color">
|
||||
{{ resolveStaffStatus(record.status).text }}
|
||||
</Tag>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
</TabPane>
|
||||
|
||||
<!-- 合同信息 -->
|
||||
<TabPane key="contracts" tab="合同信息">
|
||||
<Table
|
||||
:columns="contractColumns"
|
||||
:data-source="contracts"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
<Tag :color="resolveContractStatus(record.status).color">
|
||||
{{ resolveContractStatus(record.status).text }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'startDate'">
|
||||
{{ formatDate(record.startDate) }}
|
||||
</template>
|
||||
<template v-if="column.key === 'endDate'">
|
||||
{{ formatDate(record.endDate) }}
|
||||
</template>
|
||||
<template v-if="column.key === 'signedAt'">
|
||||
{{ formatDateTime(record.signedAt) }}
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<Button
|
||||
v-if="record.fileUrl"
|
||||
type="link"
|
||||
:href="record.fileUrl"
|
||||
target="_blank"
|
||||
>
|
||||
下载
|
||||
</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
</TabPane>
|
||||
|
||||
<!-- 操作日志 -->
|
||||
<TabPane key="logs" tab="操作日志">
|
||||
<div class="flex gap-8">
|
||||
<div class="flex-1">
|
||||
<Alert class="mb-4" message="审核日志" type="info" />
|
||||
<Empty
|
||||
v-if="auditLogs.length === 0"
|
||||
description="暂无审核日志"
|
||||
/>
|
||||
<Timeline v-else>
|
||||
<Timeline.Item
|
||||
v-for="log in auditLogs"
|
||||
:key="log.id"
|
||||
color="blue"
|
||||
>
|
||||
<div class="font-medium">
|
||||
<span class="mr-2">
|
||||
[{{ resolveAuditAction(log.action) }}]
|
||||
</span>
|
||||
{{ log.title }}
|
||||
<span class="ml-2 text-xs text-gray-400">
|
||||
{{ formatDateTime(log.createdAt) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
签发时间:{{ formatDateTime(item.issuedAt) }}
|
||||
<div class="text-sm text-gray-600">
|
||||
{{ log.description || '无描述' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
到期时间:{{ formatDateTime(item.expiresAt) }}
|
||||
<div class="text-xs text-gray-500">
|
||||
操作人: {{ log.operatorName || '--' }} (IP:
|
||||
{{ log.ipAddress || '--' }})
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
文件地址:
|
||||
<a
|
||||
:href="item.fileUrl"
|
||||
class="text-blue-500"
|
||||
target="_blank"
|
||||
>
|
||||
{{ item.fileUrl }}
|
||||
</a>
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<Alert class="mb-4" message="变更日志" type="info" />
|
||||
<Empty
|
||||
v-if="changeLogs.length === 0"
|
||||
description="暂无变更日志"
|
||||
/>
|
||||
<Timeline v-else>
|
||||
<Timeline.Item
|
||||
v-for="log in changeLogs"
|
||||
:key="log.id"
|
||||
color="orange"
|
||||
>
|
||||
<div class="font-medium">
|
||||
变更字段: {{ log.fieldName }}
|
||||
<span class="ml-2 text-xs text-gray-400">
|
||||
{{ formatDateTime(log.changedAt) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
备注:{{ item.remarks || '--' }}
|
||||
<div class="text-sm">
|
||||
<span class="text-red-500 line-through">
|
||||
{{ log.oldValue || '(空)' }}
|
||||
</span>
|
||||
<span class="mx-2">-></span>
|
||||
<span class="text-green-500">
|
||||
{{ log.newValue || '(空)' }}
|
||||
</span>
|
||||
</div>
|
||||
</List.Item>
|
||||
</template>
|
||||
</List>
|
||||
<div class="text-xs text-gray-500">
|
||||
操作人: {{ log.changedByName || '--' }}
|
||||
</div>
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
</div>
|
||||
</div>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mt-6 text-base font-medium">合同信息</div>
|
||||
<Empty
|
||||
v-if="merchantContracts.length === 0"
|
||||
description="暂无合同"
|
||||
/>
|
||||
<List
|
||||
v-else
|
||||
:data-source="merchantContracts"
|
||||
item-layout="vertical"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<List.Item>
|
||||
<div class="mb-2 flex flex-wrap items-center gap-2">
|
||||
<Tag color="purple">
|
||||
合同号:{{ item.contractNumber }}
|
||||
</Tag>
|
||||
<Tag>{{ resolveContractStatus(item.status) }}</Tag>
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
生效日期:{{ formatDateTime(item.startDate) }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
截止日期:{{ formatDateTime(item.endDate) }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
签署时间:{{ formatDateTime(item.signedAt) }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
终止时间:{{ formatDateTime(item.terminatedAt) }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
终止原因:{{ item.terminationReason || '--' }}
|
||||
</div>
|
||||
</List.Item>
|
||||
</template>
|
||||
</List>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tabsValue === 'stores'">
|
||||
<Empty
|
||||
v-if="merchantStores.length === 0"
|
||||
description="暂无门店信息"
|
||||
/>
|
||||
<List v-else :data-source="merchantStores" item-layout="vertical">
|
||||
<template #renderItem="{ item }">
|
||||
<List.Item>
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<Tag color="green">{{ item.name }}</Tag>
|
||||
<Tag>{{ resolveStoreStatus(item.status) }}</Tag>
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
门店地址:{{ item.address }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
联系电话:{{ item.contactPhone || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
营业执照号:{{ item.licenseNumber || '--' }}
|
||||
</div>
|
||||
</List.Item>
|
||||
</template>
|
||||
</List>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tabsValue === 'staffs'">
|
||||
<Empty
|
||||
v-if="merchantStaffs.length === 0"
|
||||
description="暂无员工信息"
|
||||
/>
|
||||
<List v-else :data-source="merchantStaffs" item-layout="vertical">
|
||||
<template #renderItem="{ item }">
|
||||
<List.Item>
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<Tag color="cyan">{{ item.name }}</Tag>
|
||||
<Tag>{{ resolveStaffRole(item.roleType) }}</Tag>
|
||||
<Tag>{{ resolveStaffStatus(item.status) }}</Tag>
|
||||
</div>
|
||||
<div class="text-gray-600">联系电话:{{ item.phone }}</div>
|
||||
<div class="text-gray-600">
|
||||
联系邮箱:{{ item.email || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
所属门店ID:{{ item.storeId || '--' }}
|
||||
</div>
|
||||
</List.Item>
|
||||
</template>
|
||||
</List>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tabsValue === 'logs'">
|
||||
<Alert class="mb-4" message="审核日志" type="info" />
|
||||
<Empty
|
||||
v-if="merchantAuditLogs.length === 0"
|
||||
description="暂无审核日志"
|
||||
/>
|
||||
<List
|
||||
v-else
|
||||
:data-source="merchantAuditLogs"
|
||||
item-layout="vertical"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<List.Item>
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<Tag color="orange">{{ item.title }}</Tag>
|
||||
<Tag>动作{{ item.action }}</Tag>
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
操作人:{{ item.operatorName || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
操作描述:{{ item.description || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
操作IP:{{ item.ipAddress || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
操作时间:{{ formatDateTime(item.createdAt) }}
|
||||
</div>
|
||||
</List.Item>
|
||||
</template>
|
||||
</List>
|
||||
|
||||
<Alert class="mb-4 mt-6" message="变更日志" type="info" />
|
||||
<Empty
|
||||
v-if="merchantChangeLogs.length === 0"
|
||||
description="暂无变更日志"
|
||||
/>
|
||||
<List
|
||||
v-else
|
||||
:data-source="merchantChangeLogs"
|
||||
item-layout="vertical"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<List.Item>
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<Tag color="gold">{{ item.fieldName }}</Tag>
|
||||
<Tag>{{ item.changedByName || '--' }}</Tag>
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
旧值:{{ item.oldValue || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
新值:{{ item.newValue || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
变更原因:{{ item.changeReason || '--' }}
|
||||
</div>
|
||||
<div class="text-gray-600">
|
||||
变更时间:{{ formatDateTime(item.changedAt) }}
|
||||
</div>
|
||||
</List.Item>
|
||||
</template>
|
||||
</List>
|
||||
</template>
|
||||
</Spin>
|
||||
</div>
|
||||
</template>
|
||||
</Profile>
|
||||
</div>
|
||||
<!-- Edit Modal -->
|
||||
<Modal
|
||||
v-model:open="isEditModalVisible"
|
||||
title="编辑商户信息"
|
||||
:footer="null"
|
||||
width="800px"
|
||||
destroy-on-close
|
||||
>
|
||||
<MerchantSetting
|
||||
:merchant="merchant ?? null"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
</Modal>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bg-card {
|
||||
background-color: var(--el-bg-color-overlay);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user