fix: 修复商户中心页面lint并完善商户设置
This commit is contained in:
@@ -28,4 +28,3 @@ pnpm dev:ele
|
||||
|
||||
- 配置文件:`TakeoutSaaS.TenantUI/apps/web-ele/vite.config.mts`
|
||||
- 后端需暴露形如:`/api/admin/v1/...` 的接口
|
||||
|
||||
|
||||
@@ -162,3 +162,10 @@ export interface CurrentMerchantCenterDto {
|
||||
export async function getMerchantInfoApi() {
|
||||
return requestClient.get<CurrentMerchantCenterDto>('/merchant/info');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新商户信息
|
||||
*/
|
||||
export async function updateMerchantInfoApi(data: any) {
|
||||
return requestClient.post('/merchant/update', data);
|
||||
}
|
||||
|
||||
@@ -1,199 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type {
|
||||
CurrentMerchantCenterDto,
|
||||
MerchantAuditLogDto,
|
||||
MerchantChangeLogDto,
|
||||
MerchantContractDto,
|
||||
MerchantDocumentDto,
|
||||
} from '#/api/merchant';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Profile } from '@vben/common-ui';
|
||||
import { useUserStore } from '@vben/stores';
|
||||
|
||||
import { getMerchantInfoApi } from '#/api/merchant';
|
||||
import MerchantSetting from './merchant-setting.vue';
|
||||
|
||||
// 1. 定义页面状态
|
||||
const userStore = useUserStore();
|
||||
const merchantCenterInfo = ref<CurrentMerchantCenterDto | null>(null);
|
||||
const loading = ref(false);
|
||||
const tabsValue = ref('basic');
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
label: '基本信息',
|
||||
value: 'basic',
|
||||
},
|
||||
{
|
||||
label: '资质合同',
|
||||
value: 'qualification',
|
||||
},
|
||||
{
|
||||
label: '门店信息',
|
||||
value: 'stores',
|
||||
},
|
||||
{
|
||||
label: '员工信息',
|
||||
value: 'staffs',
|
||||
},
|
||||
{
|
||||
label: '日志记录',
|
||||
value: 'logs',
|
||||
},
|
||||
{ label: '基本信息', value: 'basic' },
|
||||
{ label: '资质合同', value: 'qualification' },
|
||||
{ label: '门店信息', value: 'stores' },
|
||||
{ label: '员工信息', value: 'staffs' },
|
||||
{ label: '日志记录', value: 'logs' },
|
||||
];
|
||||
|
||||
// 2. 请求商户中心聚合信息
|
||||
async function fetchMerchantInfo() {
|
||||
loading.value = true;
|
||||
try {
|
||||
merchantCenterInfo.value = await getMerchantInfoApi();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchMerchantInfo();
|
||||
});
|
||||
|
||||
// 3. 计算视图展示数据
|
||||
const merchantInfo = computed(() => merchantCenterInfo.value?.merchant ?? null);
|
||||
const stores = computed(() => merchantInfo.value?.stores ?? []);
|
||||
const staffs = computed(() => merchantCenterInfo.value?.staffs ?? []);
|
||||
const documents = computed(() => merchantCenterInfo.value?.documents ?? []);
|
||||
const contracts = computed(() => merchantCenterInfo.value?.contracts ?? []);
|
||||
const auditLogs = computed(() => merchantCenterInfo.value?.auditLogs ?? []);
|
||||
const changeLogs = computed(() => merchantCenterInfo.value?.changeLogs ?? []);
|
||||
|
||||
const basicInfo = computed(() => [
|
||||
{ label: '商户ID', value: merchantInfo.value?.id },
|
||||
{ label: '租户ID', value: merchantInfo.value?.tenantId },
|
||||
{ label: '租户名称', value: merchantInfo.value?.tenantName },
|
||||
{ label: '商户名称', value: merchantInfo.value?.name },
|
||||
{ label: '经营模式', value: merchantInfo.value?.operatingMode },
|
||||
{ label: '商户状态', value: merchantInfo.value?.status },
|
||||
{ label: '营业执照号', value: merchantInfo.value?.licenseNumber },
|
||||
{ label: '法人/负责人', value: merchantInfo.value?.legalRepresentative },
|
||||
{ label: '注册地址', value: merchantInfo.value?.registeredAddress },
|
||||
{ label: '联系电话', value: merchantInfo.value?.contactPhone },
|
||||
{ label: '联系邮箱', value: merchantInfo.value?.contactEmail },
|
||||
{ label: '是否冻结', value: merchantInfo.value?.isFrozen ? '是' : '否' },
|
||||
{ label: '冻结原因', value: merchantInfo.value?.frozenReason },
|
||||
{ label: '冻结时间', value: merchantInfo.value?.frozenAt },
|
||||
{ label: '审核通过人', value: merchantInfo.value?.approvedBy },
|
||||
{ label: '审核通过时间', value: merchantInfo.value?.approvedAt },
|
||||
{ label: '创建时间', value: merchantInfo.value?.createdAt },
|
||||
{ label: '更新时间', value: merchantInfo.value?.updatedAt },
|
||||
]);
|
||||
|
||||
const documentColumns = [
|
||||
{ dataIndex: 'id', key: 'id', title: '证照ID' },
|
||||
{ dataIndex: 'documentType', key: 'documentType', title: '证照类型' },
|
||||
{ dataIndex: 'status', key: 'status', title: '审核状态' },
|
||||
{ dataIndex: 'documentNumber', key: 'documentNumber', title: '证照编号' },
|
||||
{ dataIndex: 'issuedAt', key: 'issuedAt', title: '签发时间' },
|
||||
{ dataIndex: 'expiresAt', key: 'expiresAt', title: '到期时间' },
|
||||
{ dataIndex: 'fileUrl', key: 'fileUrl', title: '文件地址' },
|
||||
{ dataIndex: 'remarks', key: 'remarks', title: '备注' },
|
||||
];
|
||||
|
||||
const contractColumns = [
|
||||
{ dataIndex: 'id', key: 'id', title: '合同ID' },
|
||||
{ dataIndex: 'contractNumber', key: 'contractNumber', title: '合同编号' },
|
||||
{ dataIndex: 'status', key: 'status', title: '合同状态' },
|
||||
{ dataIndex: 'startDate', key: 'startDate', title: '开始时间' },
|
||||
{ dataIndex: 'endDate', key: 'endDate', title: '结束时间' },
|
||||
{ dataIndex: 'signedAt', key: 'signedAt', title: '签署时间' },
|
||||
{ dataIndex: 'terminatedAt', key: 'terminatedAt', title: '终止时间' },
|
||||
{
|
||||
dataIndex: 'terminationReason',
|
||||
key: 'terminationReason',
|
||||
title: '终止原因',
|
||||
},
|
||||
{ dataIndex: 'fileUrl', key: 'fileUrl', title: '文件地址' },
|
||||
];
|
||||
|
||||
const storeColumns = [
|
||||
{ dataIndex: 'id', key: 'id', title: '门店ID' },
|
||||
{ dataIndex: 'name', key: 'name', title: '门店名称' },
|
||||
{ dataIndex: 'licenseNumber', key: 'licenseNumber', title: '营业执照号' },
|
||||
{ dataIndex: 'contactPhone', key: 'contactPhone', title: '联系电话' },
|
||||
{ dataIndex: 'address', key: 'address', title: '门店地址' },
|
||||
{ dataIndex: 'status', key: 'status', title: '状态' },
|
||||
];
|
||||
|
||||
const staffColumns = [
|
||||
{ dataIndex: 'id', key: 'id', title: '员工ID' },
|
||||
{ dataIndex: 'name', key: 'name', title: '姓名' },
|
||||
{ dataIndex: 'phone', key: 'phone', title: '手机号' },
|
||||
{ dataIndex: 'email', key: 'email', title: '邮箱' },
|
||||
{ dataIndex: 'roleType', key: 'roleType', title: '角色类型' },
|
||||
{ dataIndex: 'status', key: 'status', title: '状态' },
|
||||
{ dataIndex: 'storeId', key: 'storeId', title: '门店ID' },
|
||||
];
|
||||
|
||||
const auditColumns = [
|
||||
{ dataIndex: 'id', key: 'id', title: '日志ID' },
|
||||
{ dataIndex: 'action', key: 'action', title: '操作类型' },
|
||||
{ dataIndex: 'title', key: 'title', title: '标题' },
|
||||
{ dataIndex: 'description', key: 'description', title: '描述' },
|
||||
{ dataIndex: 'operatorName', key: 'operatorName', title: '操作人' },
|
||||
{ dataIndex: 'ipAddress', key: 'ipAddress', title: 'IP地址' },
|
||||
{ dataIndex: 'createdAt', key: 'createdAt', title: '创建时间' },
|
||||
];
|
||||
|
||||
const changeColumns = [
|
||||
{ dataIndex: 'id', key: 'id', title: '日志ID' },
|
||||
{ dataIndex: 'fieldName', key: 'fieldName', title: '变更字段' },
|
||||
{ dataIndex: 'oldValue', key: 'oldValue', title: '旧值' },
|
||||
{ dataIndex: 'newValue', key: 'newValue', title: '新值' },
|
||||
{ dataIndex: 'changedByName', key: 'changedByName', title: '变更人' },
|
||||
{ dataIndex: 'changeReason', key: 'changeReason', title: '变更原因' },
|
||||
{ dataIndex: 'changedAt', key: 'changedAt', title: '变更时间' },
|
||||
];
|
||||
|
||||
function buildDocumentRows(items: MerchantDocumentDto[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
expiresAt: item.expiresAt ?? '-',
|
||||
issuedAt: item.issuedAt ?? '-',
|
||||
remarks: item.remarks ?? '-',
|
||||
}));
|
||||
}
|
||||
|
||||
function buildContractRows(items: MerchantContractDto[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
signedAt: item.signedAt ?? '-',
|
||||
terminatedAt: item.terminatedAt ?? '-',
|
||||
terminationReason: item.terminationReason ?? '-',
|
||||
}));
|
||||
}
|
||||
|
||||
function buildAuditRows(items: MerchantAuditLogDto[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
description: item.description ?? '-',
|
||||
ipAddress: item.ipAddress ?? '-',
|
||||
operatorName: item.operatorName ?? '-',
|
||||
}));
|
||||
}
|
||||
|
||||
function buildChangeRows(items: MerchantChangeLogDto[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
oldValue: item.oldValue ?? '-',
|
||||
newValue: item.newValue ?? '-',
|
||||
changedByName: item.changedByName ?? '-',
|
||||
changeReason: item.changeReason ?? '-',
|
||||
}));
|
||||
}
|
||||
|
||||
const documentRows = computed(() => buildDocumentRows(documents.value));
|
||||
const contractRows = computed(() => buildContractRows(contracts.value));
|
||||
const auditRows = computed(() => buildAuditRows(auditLogs.value));
|
||||
const changeRows = computed(() => buildChangeRows(changeLogs.value));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -202,96 +24,19 @@ const changeRows = computed(() => buildChangeRows(changeLogs.value));
|
||||
v-model:model-value="tabsValue"
|
||||
:title="$t('page.merchant.center')"
|
||||
:user-info="{
|
||||
realName: merchantInfo?.name || '加载中...',
|
||||
realName: userStore.userInfo?.realName || '',
|
||||
avatar: userStore.userInfo?.avatar || '',
|
||||
userId: userStore.userInfo?.userId || '',
|
||||
username:
|
||||
merchantInfo?.contactPhone || userStore.userInfo?.username || '',
|
||||
username: userStore.userInfo?.username || '',
|
||||
}"
|
||||
:tabs="tabs"
|
||||
>
|
||||
<template #content>
|
||||
<div v-loading="loading" class="rounded-lg bg-card p-6">
|
||||
<div v-if="tabsValue === 'basic'">
|
||||
<h3 class="mb-4 text-lg font-medium">基本信息</h3>
|
||||
<a-descriptions :column="1" bordered>
|
||||
<a-descriptions-item
|
||||
v-for="item in basicInfo"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
>
|
||||
{{ item.value || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
<div class="rounded-lg bg-card">
|
||||
<!-- 基本信息:使用表单形式,支持展示和修改 -->
|
||||
<MerchantSetting v-if="tabsValue === 'basic'" />
|
||||
|
||||
<div v-else-if="tabsValue === 'qualification'" class="space-y-6">
|
||||
<div>
|
||||
<h3 class="mb-4 text-lg font-medium">商户资质</h3>
|
||||
<a-table
|
||||
:columns="documentColumns"
|
||||
:data-source="documentRows"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="mb-4 text-lg font-medium">商户合同</h3>
|
||||
<a-table
|
||||
:columns="contractColumns"
|
||||
:data-source="contractRows"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tabsValue === 'stores'">
|
||||
<h3 class="mb-4 text-lg font-medium">关联门店</h3>
|
||||
<a-table
|
||||
:columns="storeColumns"
|
||||
:data-source="stores"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tabsValue === 'staffs'">
|
||||
<h3 class="mb-4 text-lg font-medium">商户员工</h3>
|
||||
<a-table
|
||||
:columns="staffColumns"
|
||||
:data-source="staffs"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tabsValue === 'logs'" class="space-y-6">
|
||||
<div>
|
||||
<h3 class="mb-4 text-lg font-medium">审核日志</h3>
|
||||
<a-table
|
||||
:columns="auditColumns"
|
||||
:data-source="auditRows"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="mb-4 text-lg font-medium">变更日志</h3>
|
||||
<a-table
|
||||
:columns="changeColumns"
|
||||
:data-source="changeRows"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 其他 Tab 暂时保留或后续根据需要优化 -->
|
||||
<div v-else class="p-6 text-center text-gray-400">正在开发中...</div>
|
||||
</div>
|
||||
</template>
|
||||
</Profile>
|
||||
|
||||
85
apps/web-antd/src/views/merchant/center/merchant-setting.vue
Normal file
85
apps/web-antd/src/views/merchant/center/merchant-setting.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<script setup lang="ts">
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { ProfileBaseSetting } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { getMerchantInfoApi, updateMerchantInfoApi } from '#/api/merchant';
|
||||
|
||||
const profileBaseSettingRef = ref();
|
||||
|
||||
const formSchema = computed((): VbenFormSchema[] => {
|
||||
return [
|
||||
{
|
||||
fieldName: 'name',
|
||||
component: 'Input',
|
||||
label: '商户名称',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'operatingMode',
|
||||
component: 'Select',
|
||||
label: '经营模式',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '直营', value: 1 },
|
||||
{ label: '加盟', value: 2 },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'licenseNumber',
|
||||
component: 'Input',
|
||||
label: '营业执照号',
|
||||
},
|
||||
{
|
||||
fieldName: 'legalRepresentative',
|
||||
component: 'Input',
|
||||
label: '法人/负责人',
|
||||
},
|
||||
{
|
||||
fieldName: 'contactPhone',
|
||||
component: 'Input',
|
||||
label: '联系电话',
|
||||
},
|
||||
{
|
||||
fieldName: 'contactEmail',
|
||||
component: 'Input',
|
||||
label: '联系邮箱',
|
||||
},
|
||||
{
|
||||
fieldName: 'registeredAddress',
|
||||
component: 'Textarea',
|
||||
label: '注册地址',
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
async function handleSubmit(values: Record<string, unknown>) {
|
||||
try {
|
||||
await updateMerchantInfoApi(values);
|
||||
message.success('商户信息更新成功');
|
||||
} catch {
|
||||
message.error('更新失败');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const data = await getMerchantInfoApi();
|
||||
// 假设接口返回的是 CurrentMerchantCenterDto,我们需要取其中的 merchant 对象
|
||||
if (data && data.merchant) {
|
||||
profileBaseSettingRef.value.getFormApi().setValues(data.merchant);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProfileBaseSetting
|
||||
ref="profileBaseSettingRef"
|
||||
:form-schema="formSchema"
|
||||
@submit="handleSubmit"
|
||||
/>
|
||||
</template>
|
||||
Reference in New Issue
Block a user