mirror of
https://github.com/certd/certd.git
synced 2026-06-26 13:17:33 +08:00
chore: 佣金等级功能
This commit is contained in:
@@ -8,6 +8,30 @@ export async function SaveSettings(data: any) {
|
||||
return await request({ url: "/sys/invite/settings/save", method: "post", data });
|
||||
}
|
||||
|
||||
export async function GetLevels(query: any) {
|
||||
return await request({ url: "/sys/invite/level/page", method: "post", data: query });
|
||||
}
|
||||
|
||||
export async function GetLevelList() {
|
||||
return await request({ url: "/sys/invite/level/list", method: "post", data: {} });
|
||||
}
|
||||
|
||||
export async function AddLevel(data: any) {
|
||||
return await request({ url: "/sys/invite/level/add", method: "post", data });
|
||||
}
|
||||
|
||||
export async function UpdateLevel(data: any) {
|
||||
return await request({ url: "/sys/invite/level/update", method: "post", data });
|
||||
}
|
||||
|
||||
export async function GetUserLevels(query: any) {
|
||||
return await request({ url: "/sys/invite/user/page", method: "post", data: query });
|
||||
}
|
||||
|
||||
export async function SetUserLevel(data: any) {
|
||||
return await request({ url: "/sys/invite/user/setLevel", method: "post", data });
|
||||
}
|
||||
|
||||
export async function GetWithdraws(query: any) {
|
||||
return await request({ url: "/sys/wallet/withdraw/page", method: "post", data: query });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import { AddReq, compute, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, dict } from "@fast-crud/fast-crud";
|
||||
import * as api from "./api";
|
||||
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
|
||||
|
||||
export default function (): CreateCrudOptionsRet {
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetLevels(query);
|
||||
};
|
||||
const addRequest = async ({ form }: AddReq) => {
|
||||
return await api.AddLevel(form);
|
||||
};
|
||||
const editRequest = async ({ form, row }: EditReq) => {
|
||||
form.id = row.id;
|
||||
return await api.UpdateLevel(form);
|
||||
};
|
||||
const delRequest = async ({ row }: DelReq) => {
|
||||
row.disabled = true;
|
||||
return await api.UpdateLevel(row);
|
||||
};
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: { pageRequest, addRequest, editRequest, delRequest },
|
||||
rowHandle: {
|
||||
width: 180,
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
view: { show: false },
|
||||
copy: { show: false },
|
||||
remove: {
|
||||
text: "禁用",
|
||||
show: compute(({ row }) => row.disabled !== true),
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
type: "number",
|
||||
form: { show: false },
|
||||
column: { width: 90 },
|
||||
},
|
||||
name: {
|
||||
title: "等级名称",
|
||||
type: "text",
|
||||
search: { show: true },
|
||||
form: {
|
||||
rules: [{ required: true, message: "请输入等级名称" }],
|
||||
},
|
||||
column: { width: 140 },
|
||||
},
|
||||
minAmount: {
|
||||
title: "升级金额",
|
||||
type: "number",
|
||||
form: {
|
||||
component: { name: PriceInput, vModel: "modelValue", edit: true },
|
||||
rules: [{ required: true, message: "请输入升级金额" }],
|
||||
},
|
||||
column: {
|
||||
width: 140,
|
||||
component: { name: PriceInput, vModel: "modelValue", edit: false },
|
||||
},
|
||||
},
|
||||
commissionRate: {
|
||||
title: "佣金比例",
|
||||
type: "number",
|
||||
form: {
|
||||
component: { min: 0, max: 100, addonAfter: "%" },
|
||||
rules: [{ required: true, message: "请输入佣金比例" }],
|
||||
},
|
||||
column: { width: 110, align: "center", cellRender: ({ value }) => `${value || 0}%` },
|
||||
},
|
||||
isHidden: {
|
||||
title: "隐藏等级",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "普通等级", value: false, color: "success" },
|
||||
{ label: "隐藏等级", value: true, color: "warning" },
|
||||
],
|
||||
}),
|
||||
form: { value: false },
|
||||
column: { width: 120, align: "center" },
|
||||
},
|
||||
sort: {
|
||||
title: "排序",
|
||||
type: "number",
|
||||
form: { value: 10 },
|
||||
column: { width: 90, align: "center" },
|
||||
},
|
||||
disabled: {
|
||||
title: "状态",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "启用", value: false, color: "success" },
|
||||
{ label: "禁用", value: true, color: "error" },
|
||||
],
|
||||
}),
|
||||
form: { value: false },
|
||||
column: { width: 100, align: "center" },
|
||||
},
|
||||
createTime: { title: "创建时间", type: "datetime", form: { show: false }, column: { width: 170 } },
|
||||
updateTime: { title: "更新时间", type: "datetime", form: { show: false }, column: { width: 170 } },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import { compute, CreateCrudOptionsProps, CreateCrudOptionsRet, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { 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 levelDict = dict({
|
||||
url: "/sys/invite/level/list",
|
||||
value: "id",
|
||||
label: "name",
|
||||
});
|
||||
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetUserLevels(query);
|
||||
};
|
||||
|
||||
async function openSetLevel(row: any) {
|
||||
await openFormDialog({
|
||||
title: "指定推广等级",
|
||||
wrapper: { width: 560 },
|
||||
initialForm: {
|
||||
userId: row.userId,
|
||||
levelId: row.levelId,
|
||||
levelLocked: row.levelLocked === true,
|
||||
},
|
||||
columns: {
|
||||
levelId: {
|
||||
title: "推广等级",
|
||||
type: "dict-select",
|
||||
dict: levelDict,
|
||||
form: {
|
||||
col: { span: 24 },
|
||||
rules: [{ required: true, message: "请选择推广等级" }],
|
||||
},
|
||||
},
|
||||
levelLocked: {
|
||||
title: "锁定等级",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "自动升级", value: false, color: "success" },
|
||||
{ label: "锁定", value: true, color: "warning" },
|
||||
],
|
||||
}),
|
||||
form: {
|
||||
col: { span: 24 },
|
||||
helper: "隐藏等级会自动锁定,不参与自动升级。",
|
||||
},
|
||||
},
|
||||
},
|
||||
async onSubmit(form: any) {
|
||||
await api.SetUserLevel(form);
|
||||
await crudExpose.doRefresh();
|
||||
notification.success({ message: "推广等级已更新" });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: { pageRequest },
|
||||
actionbar: { show: false },
|
||||
toolbar: { show: false },
|
||||
rowHandle: {
|
||||
width: 130,
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
view: { show: false },
|
||||
edit: { show: false },
|
||||
copy: { show: false },
|
||||
remove: { show: false },
|
||||
setLevel: {
|
||||
text: "指定等级",
|
||||
type: "link",
|
||||
click: ({ row }) => openSetLevel(row),
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
userId: { title: "用户ID", type: "number", search: { show: true }, column: { width: 100 } },
|
||||
username: { title: "用户名", type: "text", search: { show: true }, column: { width: 160 } },
|
||||
userDisplay: { title: "显示名称", type: "text", column: { width: 160 } },
|
||||
enabled: {
|
||||
title: "开通状态",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "未开通", value: false, color: "default" },
|
||||
{ label: "已开通", value: true, color: "success" },
|
||||
],
|
||||
}),
|
||||
column: { width: 110, align: "center" },
|
||||
},
|
||||
levelId: {
|
||||
title: "当前等级",
|
||||
type: "dict-select",
|
||||
dict: levelDict,
|
||||
search: { show: true },
|
||||
column: { width: 130 },
|
||||
},
|
||||
levelLocked: {
|
||||
title: "升级方式",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "自动升级", value: false, color: "success" },
|
||||
{ label: "锁定", value: true, color: "warning" },
|
||||
],
|
||||
}),
|
||||
column: { width: 110, align: "center" },
|
||||
},
|
||||
isHidden: {
|
||||
title: "隐藏等级",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "否", value: false, color: "default" },
|
||||
{ label: "是", value: true, color: "warning" },
|
||||
],
|
||||
}),
|
||||
column: { width: 100, align: "center", show: compute(({ row }) => row.levelId) },
|
||||
},
|
||||
commissionRate: { title: "佣金比例", type: "number", column: { width: 110, align: "center", cellRender: ({ value }) => (value == null ? "-" : `${value}%`) } },
|
||||
promotionAmount: {
|
||||
title: "累计推广金额",
|
||||
type: "number",
|
||||
column: { width: 140, component: { name: PriceInput, vModel: "modelValue", edit: false } },
|
||||
},
|
||||
createTime: { title: "开通时间", type: "datetime", column: { width: 170 } },
|
||||
updateTime: { title: "更新时间", type: "datetime", column: { width: 170 } },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<fs-page class="page-sys-invite-level">
|
||||
<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-level";
|
||||
|
||||
defineOptions({ name: "SysInviteLevel" });
|
||||
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
|
||||
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<fs-page class="page-sys-invite-setting">
|
||||
<template #header>
|
||||
<div class="title">邀请返佣设置</div>
|
||||
<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-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 label="推广协议" name="agreementContent">
|
||||
<a-textarea v-model:value="settings.agreementContent" :rows="10" placeholder="请输入用户开通激励计划前需要确认的推广协议内容" />
|
||||
</a-form-item>
|
||||
<a-form-item label="最低提现金额" name="minWithdrawAmountYuan">
|
||||
<a-input-number v-model:value="settings.minWithdrawAmountYuan" :min="0" addon-after="元" />
|
||||
@@ -34,7 +34,8 @@ import { useSettingStore } from "/@/store/settings";
|
||||
|
||||
defineOptions({ name: "SysInviteCommissionSetting" });
|
||||
|
||||
const settings = reactive<any>({ enabled: false, commissionRate: 0, minWithdrawAmountYuan: 0, withdrawChannels: ["alipay", "bank"] });
|
||||
const defaultAgreement = "请遵守平台推广规则,不得通过虚假注册、刷单、恶意诱导等方式获取收益。平台有权对异常推广行为进行核查,并根据实际情况暂停结算或关闭激励计划资格。";
|
||||
const settings = reactive<any>({ enabled: false, agreementContent: "", minWithdrawAmountYuan: 0, withdrawChannels: ["alipay", "bank"] });
|
||||
const withdrawChannelOptions = [
|
||||
{ label: "支付宝", value: "alipay" },
|
||||
{ label: "银行卡", value: "bank" },
|
||||
@@ -43,7 +44,7 @@ const withdrawChannelOptions = [
|
||||
async function loadSettings() {
|
||||
const data: any = await api.GetSettings();
|
||||
settings.enabled = !!data?.enabled;
|
||||
settings.commissionRate = data?.commissionRate || 0;
|
||||
settings.agreementContent = data?.agreementContent || defaultAgreement;
|
||||
settings.minWithdrawAmountYuan = util.amount.toYuan(data?.minWithdrawAmount || 0);
|
||||
settings.withdrawChannels = data?.withdrawChannels?.length ? data.withdrawChannels : ["alipay", "bank"];
|
||||
}
|
||||
@@ -51,7 +52,7 @@ async function loadSettings() {
|
||||
async function saveSettings() {
|
||||
await api.SaveSettings({
|
||||
enabled: settings.enabled,
|
||||
commissionRate: settings.commissionRate || 0,
|
||||
agreementContent: settings.agreementContent || "",
|
||||
minWithdrawAmount: util.amount.toCent(settings.minWithdrawAmountYuan || 0),
|
||||
withdrawChannels: settings.withdrawChannels || [],
|
||||
});
|
||||
@@ -68,7 +69,7 @@ onMounted(loadSettings);
|
||||
padding: 20px;
|
||||
}
|
||||
.settings-form {
|
||||
max-width: 720px;
|
||||
max-width: 860px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<fs-page class="page-sys-invite-user-level">
|
||||
<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-user-level";
|
||||
|
||||
defineOptions({ name: "SysInviteUserLevel" });
|
||||
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
|
||||
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user