Files
mp-vue/src/views/shop/shopMerchantApply/components/applyReview.vue
赵忠林 a485faa0e4 feat(shop): 添加商户入驻申请功能
- 在API模型中新增证件类型字段(idType)
- 修改API请求路径,移除SERVER_API_URL前缀
- 新增根据入驻申请创建商户的接口方法
- 在菜单配置中添加商城管理和商户入驻申请菜单项
- 新增商家入驻申请和申请成功页面路由
- 创建商家入驻申请表单页面,包含三步流程:基本信息、资质信息、确认提交
- 实现图片上传和预览功能,支持营业执照、身份证等资质文件上传
- 添加表单验证规则,确保必填信息完整
- 创建申请提交成功页面,提供返回首页和查看申请按钮
- 优化CMS网站搜索组件代码结构和格式
2025-12-05 23:48:16 +08:00

351 lines
10 KiB
Vue

<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
title="审核商户入驻申请"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="submitReview"
>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="申请信息">
<a-descriptions bordered :column="{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }">
<a-descriptions-item label="商户名称">{{ data?.merchantName }}</a-descriptions-item>
<a-descriptions-item label="证件号码">{{ data?.merchantCode }}</a-descriptions-item>
<a-descriptions-item label="联系人手机号">{{ data?.phone }}</a-descriptions-item>
<a-descriptions-item label="联系人姓名">{{ data?.realName }}</a-descriptions-item>
<a-descriptions-item label="身份证号码">{{ data?.idCard }}</a-descriptions-item>
<a-descriptions-item label="店铺类型">{{ data?.shopType }}</a-descriptions-item>
<a-descriptions-item label="商户分类">{{ data?.category }}</a-descriptions-item>
<a-descriptions-item label="手续费">{{ data?.commission }}%</a-descriptions-item>
<a-descriptions-item label="创建时间">{{ data?.createTime }}</a-descriptions-item>
</a-descriptions>
</a-tab-pane>
<a-tab-pane key="2" tab="资质文件">
<a-row :gutter="24">
<a-col :span="8">
<div class="file-preview">
<h4>营业执照</h4>
<a-image
v-if="data?.yyzz"
:src="data?.yyzz"
:width="150"
:height="150"
/>
<a-empty v-else description="未上传" />
</div>
</a-col>
<a-col :span="8">
<div class="file-preview">
<h4>身份证正面</h4>
<a-image
v-if="data?.sfz1"
:src="data?.sfz1"
:width="150"
:height="150"
/>
<a-empty v-else description="未上传" />
</div>
</a-col>
<a-col :span="8">
<div class="file-preview">
<h4>身份证反面</h4>
<a-image
v-if="data?.sfz2"
:src="data?.sfz2"
:width="150"
:height="150"
/>
<a-empty v-else description="未上传" />
</div>
</a-col>
<a-col :span="24" style="margin-top: 20px;">
<div class="file-preview">
<h4>其他资质文件</h4>
<div v-if="otherFiles.length > 0" class="files-grid">
<a-image
v-for="(file, index) in otherFiles"
:key="index"
:src="file"
:width="100"
:height="100"
style="margin-right: 10px; margin-bottom: 10px;"
/>
</div>
<a-empty v-else description="未上传其他资质文件" />
</div>
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane key="3" tab="审核处理">
<a-form
ref="formRef"
:model="reviewForm"
:rules="reviewRules"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
>
<a-form-item label="审核结果" name="status" required>
<a-radio-group v-model:value="reviewForm.status">
<a-radio :value="1">通过</a-radio>
<a-radio :value="2">驳回</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
v-if="reviewForm.status === 2"
label="驳回原因"
name="reason"
required
>
<a-textarea
v-model:value="reviewForm.reason"
:rows="4"
:maxlength="200"
placeholder="请输入驳回原因"
/>
</a-form-item>
<a-form-item
v-if="reviewForm.status === 1"
label="手续费(%)"
name="commission"
>
<a-input-number
v-model:value="reviewForm.commission"
:step="0.1"
:max="100"
:min="0"
:precision="2"
placeholder="请输入手续费"
/>
</a-form-item>
<a-form-item
v-if="reviewForm.status === 1"
label="是否自营"
name="ownStore"
>
<a-switch
checked-children=""
un-checked-children=""
:checked="reviewForm.ownStore === 1"
@update:checked="val => reviewForm.ownStore = val ? 1 : 0"
/>
</a-form-item>
<a-form-item
v-if="reviewForm.status === 1"
label="是否推荐"
name="recommend"
>
<a-switch
checked-children=""
un-checked-children=""
:checked="reviewForm.recommend === 1"
@update:checked="val => reviewForm.recommend = val ? 1 : 0"
/>
</a-form-item>
<a-form-item
v-if="reviewForm.status === 1"
label="是否需要审核"
name="goodsReview"
>
<a-switch
checked-children=""
un-checked-children=""
:checked="reviewForm.goodsReview === 1"
@update:checked="val => reviewForm.goodsReview = val ? 1 : 0"
/>
</a-form-item>
<a-form-item
v-if="reviewForm.status === 1"
label="创建商户"
name="createMerchant"
>
<a-switch
checked-children=""
un-checked-children=""
:checked="reviewForm.createMerchant"
@update:checked="val => reviewForm.createMerchant = val"
/>
<div class="tips">审核通过后是否立即创建商户</div>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
v-model:value="reviewForm.comments"
:rows="4"
:maxlength="200"
placeholder="请输入备注信息"
/>
</a-form-item>
</a-form>
</a-tab-pane>
</a-tabs>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { checkShopMerchantApply, createMerchantFromApply } from '@/api/shop/shopMerchantApply';
import { ShopMerchantApply } from '@/api/shop/shopMerchantApply/model';
const useForm = Form.useForm;
const props = defineProps<{
visible: boolean;
data?: ShopMerchantApply | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表单引用
const formRef = ref<any>(null);
// 当前标签页
const activeKey = ref('1');
// 其他资质文件
const otherFiles = ref<string[]>([]);
// 审核表单
const reviewForm = reactive({
status: 1, // 默认通过
reason: '',
commission: 0,
ownStore: 0,
recommend: 0,
goodsReview: 1,
createMerchant: true, // 默认创建商户
comments: ''
});
// 审核表单验证规则
const reviewRules = reactive({
status: [
{ required: true, message: '请选择审核结果', trigger: 'change' }
],
reason: [
{ required: true, message: '请输入驳回原因', trigger: 'blur' }
]
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 提交审核
const submitReview = () => {
if (!formRef.value) return;
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
applyId: props.data?.applyId,
status: reviewForm.status,
reason: reviewForm.reason,
commission: reviewForm.commission,
ownStore: reviewForm.ownStore,
recommend: reviewForm.recommend,
goodsReview: reviewForm.goodsReview,
comments: reviewForm.comments
};
checkShopMerchantApply(formData)
.then(async (msg) => {
message.success(msg);
// 如果审核通过且需要创建商户
if (reviewForm.status === 1 && reviewForm.createMerchant && props.data?.applyId) {
try {
await createMerchantFromApply(props.data.applyId);
message.success('商户创建成功');
} catch (e) {
message.error('商户创建失败: ' + (e as Error).message);
}
}
loading.value = false;
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
const { resetFields } = useForm(reviewForm, reviewRules);
watch(
() => props.visible,
(visible) => {
if (visible) {
resetFields();
reviewForm.status = 1;
reviewForm.createMerchant = true;
// 解析其他资质文件
otherFiles.value = [];
if (props.data?.files) {
try {
const files = JSON.parse(props.data.files);
if (Array.isArray(files)) {
otherFiles.value = files;
} else {
otherFiles.value = [props.data.files];
}
} catch {
otherFiles.value = [props.data.files];
}
}
}
},
{ immediate: true }
);
</script>
<style lang="less" scoped>
.file-preview {
text-align: center;
h4 {
margin-bottom: 10px;
font-weight: normal;
}
}
.files-grid {
display: flex;
flex-wrap: wrap;
}
.tips {
font-size: 12px;
color: #999;
margin-top: 5px;
}
</style>