mirror of
https://github.com/certd/certd.git
synced 2026-07-09 06:07:37 +08:00
feat: 商业版支持邀请返佣功能
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { request } from "/@/api/service";
|
||||
|
||||
export async function GetSettings() {
|
||||
return await request({ url: "/sys/invite/settings/get", method: "post" });
|
||||
}
|
||||
|
||||
export async function SaveSettings(data: any) {
|
||||
return await request({ url: "/sys/invite/settings/save", method: "post", data });
|
||||
}
|
||||
|
||||
export async function GetWithdraws(query: any) {
|
||||
return await request({ url: "/sys/wallet/withdraw/page", method: "post", data: query });
|
||||
}
|
||||
|
||||
export async function ApproveWithdraw(id: number, remark?: string) {
|
||||
return await request({ url: "/sys/wallet/withdraw/approve", method: "post", data: { id, remark } });
|
||||
}
|
||||
|
||||
export async function RejectWithdraw(id: number, remark: string) {
|
||||
return await request({ url: "/sys/wallet/withdraw/reject", method: "post", data: { id, remark } });
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import { compute, CreateCrudOptionsProps, CreateCrudOptionsRet, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
|
||||
import { useFormDialog } from "/@/use/use-dialog";
|
||||
|
||||
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const { openFormDialog } = useFormDialog();
|
||||
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetWithdraws(query);
|
||||
};
|
||||
|
||||
async function approve(row: any) {
|
||||
Modal.confirm({
|
||||
title: "确认提现已线下打款?",
|
||||
async onOk() {
|
||||
await api.ApproveWithdraw(row.id);
|
||||
await crudExpose.doRefresh();
|
||||
notification.success({ message: "已审核通过" });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function reject(row: any) {
|
||||
await openFormDialog({
|
||||
title: "拒绝提现申请",
|
||||
wrapper: {
|
||||
width: 520,
|
||||
},
|
||||
initialForm: {
|
||||
remark: "",
|
||||
},
|
||||
columns: {
|
||||
remark: {
|
||||
title: "拒绝理由",
|
||||
type: "textarea",
|
||||
form: {
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
component: {
|
||||
name: "a-textarea",
|
||||
vModel: "value",
|
||||
rows: 4,
|
||||
placeholder: "请填写拒绝理由",
|
||||
},
|
||||
rules: [{ required: true, message: "请填写拒绝理由" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
async onSubmit(form: any) {
|
||||
const remark = form.remark.trim();
|
||||
if (!remark) {
|
||||
notification.error({ message: "请填写拒绝理由" });
|
||||
throw new Error("请填写拒绝理由");
|
||||
}
|
||||
await api.RejectWithdraw(row.id, remark);
|
||||
await crudExpose.doRefresh();
|
||||
notification.success({ message: "已拒绝并退回余额" });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: { pageRequest },
|
||||
actionbar: { show: false },
|
||||
toolbar: { show: false },
|
||||
rowHandle: {
|
||||
width: 150,
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
view: { show: false },
|
||||
edit: { show: false },
|
||||
copy: { show: false },
|
||||
remove: { show: false },
|
||||
approve: {
|
||||
text: "通过",
|
||||
type: "link",
|
||||
show: compute(({ row }) => row.status === "pending"),
|
||||
click: ({ row }) => approve(row),
|
||||
},
|
||||
reject: {
|
||||
text: "拒绝",
|
||||
type: "link",
|
||||
show: compute(({ row }) => row.status === "pending"),
|
||||
click: ({ row }) => reject(row),
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
userId: { title: "用户ID", type: "number", search: { show: true }, column: { width: 100 } },
|
||||
amount: {
|
||||
title: "金额",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 120,
|
||||
component: { name: PriceInput, vModel: "modelValue", edit: false },
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
search: { show: true },
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "待审核", value: "pending", color: "warning" },
|
||||
{ label: "已通过", value: "approved", color: "success" },
|
||||
{ label: "已拒绝", value: "rejected", color: "error" },
|
||||
],
|
||||
}),
|
||||
column: { width: 110 },
|
||||
},
|
||||
channel: {
|
||||
title: "提现渠道",
|
||||
type: "dict-select",
|
||||
search: { show: true },
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "支付宝", value: "alipay" },
|
||||
{ label: "银行卡", value: "bank" },
|
||||
],
|
||||
}),
|
||||
column: { width: 110 },
|
||||
},
|
||||
realName: { title: "真实姓名", type: "text", search: { show: true }, column: { width: 120 } },
|
||||
account: { title: "收款账号", type: "text", column: { width: 180 } },
|
||||
bankName: { title: "开户银行", type: "text", column: { width: 160 } },
|
||||
auditRemark: { title: "审核备注", type: "text", column: { minWidth: 180 } },
|
||||
createTime: { title: "申请时间", type: "datetime", column: { width: 180 } },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<fs-page class="page-sys-invite-setting">
|
||||
<template #header>
|
||||
<div class="title">邀请返佣设置</div>
|
||||
</template>
|
||||
<div class="page-body">
|
||||
<a-form ref="formRef" :model="settings" :label-col="{ style: { width: '140px' } }" class="settings-form">
|
||||
<a-form-item label="开启返佣" name="enabled">
|
||||
<a-switch v-model:checked="settings.enabled" />
|
||||
</a-form-item>
|
||||
<a-form-item label="返佣比例" name="commissionRate">
|
||||
<a-input-number v-model:value="settings.commissionRate" :min="0" :max="100" addon-after="%" />
|
||||
</a-form-item>
|
||||
<a-form-item label="最低提现金额" name="minWithdrawAmountYuan">
|
||||
<a-input-number v-model:value="settings.minWithdrawAmountYuan" :min="0" addon-after="元" />
|
||||
</a-form-item>
|
||||
<a-form-item label="提现渠道" name="withdrawChannels">
|
||||
<a-checkbox-group v-model:value="settings.withdrawChannels" :options="withdrawChannelOptions" />
|
||||
</a-form-item>
|
||||
<a-form-item label=" ">
|
||||
<a-button type="primary" @click="saveSettings">保存设置</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive } from "vue";
|
||||
import { notification } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
import { util } from "/@/utils";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
|
||||
defineOptions({ name: "SysInviteCommissionSetting" });
|
||||
|
||||
const settings = reactive<any>({ enabled: false, commissionRate: 0, minWithdrawAmountYuan: 0, withdrawChannels: ["alipay", "bank"] });
|
||||
const withdrawChannelOptions = [
|
||||
{ label: "支付宝", value: "alipay" },
|
||||
{ label: "银行卡", value: "bank" },
|
||||
];
|
||||
|
||||
async function loadSettings() {
|
||||
const data: any = await api.GetSettings();
|
||||
settings.enabled = !!data?.enabled;
|
||||
settings.commissionRate = data?.commissionRate || 0;
|
||||
settings.minWithdrawAmountYuan = util.amount.toYuan(data?.minWithdrawAmount || 0);
|
||||
settings.withdrawChannels = data?.withdrawChannels?.length ? data.withdrawChannels : ["alipay", "bank"];
|
||||
}
|
||||
|
||||
async function saveSettings() {
|
||||
await api.SaveSettings({
|
||||
enabled: settings.enabled,
|
||||
commissionRate: settings.commissionRate || 0,
|
||||
minWithdrawAmount: util.amount.toCent(settings.minWithdrawAmountYuan || 0),
|
||||
withdrawChannels: settings.withdrawChannels || [],
|
||||
});
|
||||
await useSettingStore().loadSysSettings();
|
||||
notification.success({ message: "保存成功" });
|
||||
}
|
||||
|
||||
onMounted(loadSettings);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.page-sys-invite-setting {
|
||||
.page-body {
|
||||
padding: 20px;
|
||||
}
|
||||
.settings-form {
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<fs-page class="page-sys-invite-withdraw">
|
||||
<template #header>
|
||||
<div class="title">提现申请记录</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding" />
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated, onMounted } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud-withdraw";
|
||||
|
||||
defineOptions({ name: "SysInviteWithdraw" });
|
||||
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
|
||||
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
@@ -174,6 +174,30 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
},
|
||||
},
|
||||
},
|
||||
rebateAmount: {
|
||||
title: "返利抵扣",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 110,
|
||||
component: {
|
||||
name: PriceInput,
|
||||
vModel: "modelValue",
|
||||
edit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
thirdPartyPayAmount: {
|
||||
title: "实付金额",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 110,
|
||||
component: {
|
||||
name: PriceInput,
|
||||
vModel: "modelValue",
|
||||
edit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
search: { show: true },
|
||||
@@ -200,6 +224,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
{ label: "支付宝", value: "alipay" },
|
||||
{ label: "微信", value: "wxpay" },
|
||||
{ label: "免费", value: "free" },
|
||||
{ label: "返利余额", value: "rebate" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
|
||||
Reference in New Issue
Block a user