- 新增经销商申请页面,支持申请列表展示和分页查询 - 添加搜索组件,支持按客户名称、联系电话、审核状态等条件筛选 - 实现申请状态管理,包括跟进中、已签约、已取消三种状态 - 开发编辑弹窗功能,支持新增和修改申请信息 - 添加审核功能,支持批量通过和单个驳回操作 - 集成跟进记录管理,可查看历史记录并添加新的跟进内容 - 完善表单验证,包含必填字段校验和格式验证 - 优化模型定义,在相关实体中增加头像、昵称、真实姓名等字段 - 调整商品模型,将isShow字段从数字类型改为布尔类型 - 新增分销佣金相关字段,支持固定金额和百分比两种分佣类型
698 lines
18 KiB
Vue
698 lines
18 KiB
Vue
<!-- 编辑弹窗 -->
|
|
<template>
|
|
<ele-modal
|
|
:width="1000"
|
|
:visible="visible"
|
|
:maskClosable="false"
|
|
:maxable="maxable"
|
|
:title="isUpdate ? '编辑提现申请' : '新增提现申请'"
|
|
:body-style="{ paddingBottom: '28px' }"
|
|
@update:visible="updateVisible"
|
|
@ok="save"
|
|
>
|
|
<a-form
|
|
ref="formRef"
|
|
:model="form"
|
|
:rules="rules"
|
|
:label-col="{ span: 6 }"
|
|
:wrapper-col="{ span: 18 }"
|
|
>
|
|
<!-- 基本信息 -->
|
|
<a-divider orientation="left">
|
|
<span style="color: #1890ff; font-weight: 600">基本信息</span>
|
|
</a-divider>
|
|
<a-row :gutter="16">
|
|
<a-col :span="12">
|
|
<a-form-item label="备注" name="comments">
|
|
<div class="text-red-500">{{ form.comments }}</div>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
|
|
<!-- 收款信息 -->
|
|
<a-divider orientation="left">
|
|
<span style="color: #1890ff; font-weight: 600">收款信息</span>
|
|
</a-divider>
|
|
|
|
<!-- 微信收款信息 -->
|
|
<div v-if="form.payType === 10" class="payment-info wechat-info">
|
|
<a-alert
|
|
message="微信收款信息"
|
|
description="请确保微信账号信息准确,以免影响到账"
|
|
type="success"
|
|
show-icon
|
|
style="margin-bottom: 16px"
|
|
/>
|
|
<a-form-item label="微信号" name="wechatAccount">
|
|
<a-input
|
|
placeholder="请输入微信号"
|
|
v-model:value="form.wechatAccount"
|
|
/>
|
|
</a-form-item>
|
|
<a-form-item label="微信昵称" name="wechatName">
|
|
<a-input
|
|
placeholder="请输入微信昵称"
|
|
v-model:value="form.wechatName"
|
|
/>
|
|
</a-form-item>
|
|
</div>
|
|
|
|
<!-- 支付宝收款信息 -->
|
|
<div v-if="form.payType === 20" class="payment-info alipay-info">
|
|
<a-alert
|
|
message="支付宝收款信息"
|
|
description="请确保支付宝账号信息准确,姓名需与实名认证一致"
|
|
type="info"
|
|
show-icon
|
|
style="margin-bottom: 16px"
|
|
/>
|
|
<a-row :gutter="16">
|
|
<a-col :span="12">
|
|
<a-form-item label="支付宝姓名" name="alipayName">
|
|
<a-input
|
|
placeholder="请输入支付宝实名姓名"
|
|
disabled
|
|
v-model:value="form.alipayName"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="12">
|
|
<a-form-item label="支付宝账号" name="alipayAccount">
|
|
<a-input
|
|
placeholder="请输入支付宝账号"
|
|
disabled
|
|
v-model:value="form.alipayAccount"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
</div>
|
|
|
|
<!-- 银行卡收款信息 -->
|
|
<div v-if="form.payType === 30" class="payment-info bank-info">
|
|
<a-alert
|
|
message="银行卡收款信息"
|
|
description="请确保银行卡信息准确,开户名需与身份证姓名一致"
|
|
type="warning"
|
|
show-icon
|
|
style="margin-bottom: 16px"
|
|
/>
|
|
<a-row :gutter="16">
|
|
<a-col :span="12">
|
|
<a-form-item label="开户行名称" name="bankName">
|
|
{{ form.bankName }}
|
|
</a-form-item>
|
|
<a-form-item label="银行开户名" name="bankAccount">
|
|
{{ form.bankAccount }}
|
|
</a-form-item>
|
|
<a-form-item label="银行卡号" name="bankCard">
|
|
{{ form.bankCard }}
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
</div>
|
|
|
|
<!-- 审核信息 -->
|
|
<a-divider orientation="left">
|
|
<span style="color: #1890ff; font-weight: 600">审核信息</span>
|
|
</a-divider>
|
|
|
|
<a-row :gutter="16">
|
|
<a-col :span="12">
|
|
<a-form-item label="申请状态" name="applyStatus">
|
|
<a-select
|
|
v-model:value="form.applyStatus"
|
|
:disabled="form.applyStatus == 40 || form.applyStatus == 30"
|
|
placeholder="请选择申请状态"
|
|
>
|
|
<a-select-option :value="10">
|
|
<div class="status-option">
|
|
<a-tag color="orange">待审核</a-tag>
|
|
<span>等待审核</span>
|
|
</div>
|
|
</a-select-option>
|
|
<a-select-option :value="20">
|
|
<div class="status-option">
|
|
<a-tag color="success">审核通过</a-tag>
|
|
<span>审核通过</span>
|
|
</div>
|
|
</a-select-option>
|
|
<a-select-option :value="30">
|
|
<div class="status-option">
|
|
<a-tag color="error">审核驳回</a-tag>
|
|
<span>审核驳回</span>
|
|
</div>
|
|
</a-select-option>
|
|
<a-select-option :value="40">
|
|
<div class="status-option">
|
|
<a-tag>已打款</a-tag>
|
|
<span>已完成打款</span>
|
|
</div>
|
|
</a-select-option>
|
|
</a-select>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
<a-row :gutter="16">
|
|
<a-col :span="12">
|
|
<a-form-item
|
|
label="驳回原因"
|
|
name="rejectReason"
|
|
v-if="form.applyStatus === 30"
|
|
>
|
|
<a-textarea
|
|
v-model:value="form.rejectReason"
|
|
placeholder="请输入驳回原因"
|
|
:rows="3"
|
|
:maxlength="200"
|
|
show-count
|
|
/>
|
|
</a-form-item>
|
|
<a-form-item
|
|
label="上传支付凭证"
|
|
name="image"
|
|
v-if="form.applyStatus === 40"
|
|
>
|
|
<SelectFile
|
|
:placeholder="`请选择图片`"
|
|
:limit="2"
|
|
:data="files"
|
|
@done="chooseFile"
|
|
@del="onDeleteFile"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
|
|
<!-- 提现预览 -->
|
|
<div class="withdraw-preview" v-if="form.money && form.payType">
|
|
<a-alert
|
|
:type="getPreviewAlertType()"
|
|
:message="getPreviewText()"
|
|
show-icon
|
|
style="margin-top: 16px"
|
|
/>
|
|
</div>
|
|
</a-form>
|
|
</ele-modal>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, reactive, watch } from 'vue';
|
|
import { Form, message } from 'ant-design-vue';
|
|
import { assignObject, uuid } from 'ele-admin-pro';
|
|
import {
|
|
addShopDealerWithdraw,
|
|
updateShopDealerWithdraw
|
|
} from '@/api/shop/shopDealerWithdraw';
|
|
import { ShopDealerWithdraw } from '@/api/shop/shopDealerWithdraw/model';
|
|
import { FormInstance } from 'ant-design-vue/es/form';
|
|
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
|
|
import dayjs from 'dayjs';
|
|
import { FileRecord } from '@/api/system/file/model';
|
|
|
|
// 是否是修改
|
|
const isUpdate = ref(false);
|
|
const useForm = Form.useForm;
|
|
|
|
const props = defineProps<{
|
|
// 弹窗是否打开
|
|
visible: boolean;
|
|
// 修改回显的数据
|
|
data?: ShopDealerWithdraw | null;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'done'): void;
|
|
(e: 'update:visible', visible: boolean): void;
|
|
}>();
|
|
|
|
// 提交状态
|
|
const loading = ref<boolean>(false);
|
|
const isSuccess = ref<boolean>(false);
|
|
// 是否显示最大化切换按钮
|
|
const maxable = ref(true);
|
|
const files = ref<ItemType[]>([]);
|
|
// 表格选中数据
|
|
const formRef = ref<FormInstance | null>(null);
|
|
|
|
// 表单数据
|
|
const form = reactive<ShopDealerWithdraw>({
|
|
id: undefined,
|
|
userId: undefined,
|
|
realName: undefined,
|
|
nickname: undefined,
|
|
phone: undefined,
|
|
avatar: undefined,
|
|
money: undefined,
|
|
payType: undefined,
|
|
// 微信相关
|
|
wechatAccount: '',
|
|
wechatName: '',
|
|
// 支付宝相关
|
|
alipayName: '',
|
|
alipayAccount: '',
|
|
// 银行卡相关
|
|
bankName: '',
|
|
bankAccount: '',
|
|
bankCard: '',
|
|
// 审核相关
|
|
applyStatus: 10,
|
|
auditTime: undefined,
|
|
rejectReason: '',
|
|
platform: '',
|
|
comments: '',
|
|
tenantId: undefined,
|
|
createTime: undefined,
|
|
updateTime: undefined
|
|
});
|
|
|
|
/* 更新visible */
|
|
const updateVisible = (value: boolean) => {
|
|
emit('update:visible', value);
|
|
};
|
|
|
|
// 表单验证规则
|
|
const rules = reactive({
|
|
userId: [
|
|
{
|
|
required: true,
|
|
message: '请输入分销商用户ID',
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
money: [
|
|
{
|
|
required: true,
|
|
message: '请输入提现金额',
|
|
trigger: 'blur'
|
|
},
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (value && value <= 0) {
|
|
return Promise.reject('提现金额必须大于0');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
payType: [
|
|
{
|
|
required: true,
|
|
message: '请选择打款方式',
|
|
trigger: 'change'
|
|
}
|
|
],
|
|
platform: [
|
|
{
|
|
required: true,
|
|
message: '请选择来源平台',
|
|
trigger: 'change'
|
|
}
|
|
],
|
|
// 微信验证
|
|
wechatAccount: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 10 && !value) {
|
|
return Promise.reject('请输入微信号');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
wechatName: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 10 && !value) {
|
|
return Promise.reject('请输入微信昵称');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
// 支付宝验证
|
|
alipayName: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 20 && !value) {
|
|
return Promise.reject('请输入支付宝姓名');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
alipayAccount: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 20 && !value) {
|
|
return Promise.reject('请输入支付宝账号');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
// 银行卡验证
|
|
bankName: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 30 && !value) {
|
|
return Promise.reject('请输入开户行名称');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
bankAccount: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 30 && !value) {
|
|
return Promise.reject('请输入银行开户名');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
bankCard: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.payType === 30 && !value) {
|
|
return Promise.reject('请输入银行卡号');
|
|
}
|
|
if (form.payType === 30 && value && !/^\d{16,19}$/.test(value)) {
|
|
return Promise.reject('银行卡号格式不正确');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
applyStatus: [
|
|
{
|
|
required: true,
|
|
message: '请选择申请状态',
|
|
trigger: 'change'
|
|
}
|
|
],
|
|
rejectReason: [
|
|
{
|
|
validator: (rule: any, value: any) => {
|
|
if (form.applyStatus === 30 && !value) {
|
|
return Promise.reject('驳回时必须填写驳回原因');
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
image: [
|
|
{
|
|
required: true,
|
|
message: '请上传打款凭证',
|
|
trigger: 'change'
|
|
}
|
|
]
|
|
});
|
|
|
|
/* 打款方式改变时的处理 */
|
|
const onPayTypeChange = (e: any) => {
|
|
const payType = e.target.value;
|
|
|
|
// 清空其他支付方式的信息
|
|
if (payType !== 10) {
|
|
form.alipayAccount = '';
|
|
form.alipayName = '';
|
|
}
|
|
if (payType !== 20) {
|
|
form.alipayName = '';
|
|
form.alipayAccount = '';
|
|
}
|
|
if (payType !== 30) {
|
|
form.bankName = '';
|
|
form.bankAccount = '';
|
|
form.bankCard = '';
|
|
}
|
|
};
|
|
|
|
const chooseFile = (data: FileRecord) => {
|
|
files.value.push({
|
|
uid: data.id,
|
|
url: data.url,
|
|
status: 'done'
|
|
});
|
|
form.image = JSON.stringify(files.value.map((d) => d.url));
|
|
};
|
|
|
|
const onDeleteFile = (index: number) => {
|
|
files.value.splice(index, 1);
|
|
};
|
|
|
|
/* 获取预览提示类型 */
|
|
const getPreviewAlertType = () => {
|
|
if (!form.applyStatus) return 'info';
|
|
|
|
switch (form.applyStatus) {
|
|
case 10:
|
|
return 'processing';
|
|
case 20:
|
|
return 'success';
|
|
case 30:
|
|
return 'error';
|
|
case 40:
|
|
return 'success';
|
|
default:
|
|
return 'info';
|
|
}
|
|
};
|
|
|
|
/* 获取预览文本 */
|
|
const getPreviewText = () => {
|
|
if (!form.money || !form.payType) return '';
|
|
|
|
const amount = parseFloat(form.money.toString()).toFixed(2);
|
|
const payTypeMap = {
|
|
10: '微信',
|
|
20: '支付宝',
|
|
30: '银行卡'
|
|
};
|
|
const statusMap = {
|
|
10: '待审核',
|
|
20: '审核通过',
|
|
30: '审核驳回',
|
|
40: '已打款'
|
|
};
|
|
|
|
const payTypeName = payTypeMap[form.payType] || '未知方式';
|
|
const statusName = statusMap[form.applyStatus] || '未知状态';
|
|
|
|
return `提现金额:¥${amount},打款方式:${payTypeName},当前状态:${statusName}`;
|
|
};
|
|
|
|
const { resetFields } = useForm(form, rules);
|
|
|
|
/* 保存编辑 */
|
|
const save = () => {
|
|
if (!formRef.value) {
|
|
return;
|
|
}
|
|
if (isSuccess.value) {
|
|
console.log('isSuccess');
|
|
updateVisible(false);
|
|
emit('done');
|
|
return;
|
|
}
|
|
if (form.realName == '' || form.realName == null) {
|
|
message.error('该用户未完成实名认证!');
|
|
return;
|
|
}
|
|
formRef.value
|
|
.validate()
|
|
.then(() => {
|
|
loading.value = true;
|
|
const formData = {
|
|
...form
|
|
};
|
|
|
|
// 处理时间字段转换
|
|
if (formData.auditTime && dayjs.isDayjs(formData.auditTime)) {
|
|
formData.auditTime = formData.auditTime.valueOf();
|
|
}
|
|
|
|
// 根据支付方式清理不相关字段
|
|
if (formData.payType !== 10) {
|
|
delete formData.wechatAccount;
|
|
delete formData.wechatName;
|
|
}
|
|
if (formData.payType !== 20) {
|
|
delete formData.alipayName;
|
|
delete formData.alipayAccount;
|
|
}
|
|
if (formData.payType !== 30) {
|
|
delete formData.bankName;
|
|
delete formData.bankAccount;
|
|
delete formData.bankCard;
|
|
}
|
|
|
|
const saveOrUpdate = isUpdate.value
|
|
? updateShopDealerWithdraw
|
|
: addShopDealerWithdraw;
|
|
saveOrUpdate(formData)
|
|
.then((msg) => {
|
|
loading.value = false;
|
|
message.success(msg);
|
|
updateVisible(false);
|
|
emit('done');
|
|
})
|
|
.catch((e) => {
|
|
loading.value = false;
|
|
message.error(e.message);
|
|
});
|
|
})
|
|
.catch(() => {});
|
|
};
|
|
|
|
watch(
|
|
() => props.visible,
|
|
(visible) => {
|
|
if (visible) {
|
|
files.value = [];
|
|
if (props.data) {
|
|
assignObject(form, props.data);
|
|
// 处理时间字段
|
|
if (props.data.auditTime) {
|
|
form.auditTime = dayjs(props.data.auditTime);
|
|
}
|
|
if (props.data.image) {
|
|
const arr = JSON.parse(props.data.image);
|
|
arr.map((url: string) => {
|
|
files.value.push({
|
|
uid: uuid(),
|
|
url: url,
|
|
status: 'done'
|
|
});
|
|
});
|
|
isSuccess.value = true;
|
|
}
|
|
isUpdate.value = true;
|
|
} else {
|
|
// 重置为默认值
|
|
Object.assign(form, {
|
|
id: undefined,
|
|
userId: undefined,
|
|
money: undefined,
|
|
payType: undefined,
|
|
wechatAccount: '',
|
|
wechatName: '',
|
|
alipayName: '',
|
|
alipayAccount: '',
|
|
bankName: '',
|
|
bankAccount: '',
|
|
bankCard: '',
|
|
applyStatus: 10,
|
|
auditTime: undefined,
|
|
rejectReason: '',
|
|
platform: '',
|
|
image: '',
|
|
tenantId: undefined,
|
|
createTime: undefined,
|
|
updateTime: undefined
|
|
});
|
|
isUpdate.value = false;
|
|
}
|
|
} else {
|
|
resetFields();
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.platform-option,
|
|
.status-option {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.ant-tag {
|
|
margin-right: 8px;
|
|
}
|
|
|
|
span {
|
|
color: #666;
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
|
|
.payment-info {
|
|
background: #fafafa;
|
|
padding: 16px;
|
|
border-radius: 6px;
|
|
margin-bottom: 16px;
|
|
|
|
&.wechat-info {
|
|
border-left: 3px solid #52c41a;
|
|
}
|
|
|
|
&.alipay-info {
|
|
border-left: 3px solid #1890ff;
|
|
}
|
|
|
|
&.bank-info {
|
|
border-left: 3px solid #faad14;
|
|
}
|
|
}
|
|
|
|
.withdraw-preview {
|
|
:deep(.ant-alert) {
|
|
.ant-alert-message {
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
}
|
|
|
|
:deep(.ant-divider-horizontal.ant-divider-with-text-left) {
|
|
margin: 24px 0 16px 0;
|
|
|
|
.ant-divider-inner-text {
|
|
padding: 0 16px 0 0;
|
|
}
|
|
}
|
|
|
|
:deep(.ant-form-item) {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
:deep(.ant-radio) {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 8px;
|
|
|
|
.ant-radio-inner {
|
|
margin-right: 8px;
|
|
}
|
|
}
|
|
|
|
:deep(.ant-select-selection-item) {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
:deep(.ant-input-number) {
|
|
width: 100%;
|
|
}
|
|
|
|
:deep(.ant-alert) {
|
|
.ant-alert-message {
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
</style>
|