提交 3f1f71dc 作者: 18928357778

添-活动管理-活动列表,优惠券管理-活动优惠券,裂变优惠券,优惠券明细

上级 db0faf09
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -18,11 +18,13 @@
"antd": "^5.4.2",
"axios": "^1.4.0",
"dayjs": "^1.11.7",
"file-saver": "^2.0.5",
"js-base64": "^3.7.3",
"js-cookie": "^3.0.1",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"match-sorter": "^6.3.1",
"moment": "^2.29.4",
"pinyin-pro": "^3.14.0",
"qs": "^6.10.3",
"query-string": "^8.1.0",
......@@ -34,6 +36,7 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/file-saver": "^2.0.5",
"@types/js-cookie": "^3.0.1",
"@types/lodash": "^4.14.182",
"@types/node": "^20.1.3",
......
import { PointManageAPI } from './modules/pointManageAPI';
import { ActivityManageAPI } from './modules/activityManage';
import { CouponManageAPI } from './modules/couponManage'
import { CommonAPI } from "./modules/common";
import { MakeManageAPI } from './modules/makeManage'
export { PointManageAPI };
export {
PointManageAPI,
ActivityManageAPI,
CommonAPI,
CouponManageAPI,
MakeManageAPI
};
// 活动-裂变优惠券下拉类型
import { InterFunction, InterItemFunction } from "~/api/interface";
import { SplitCouponItemType } from "~/api/interface/couponManage";
// 裂变优惠券-下拉
export type splitCouponDownType = InterFunction<
{ type: number },
SplitCouponItemType[]
>;
// 活动新增-type
export type addActivityItemType = {
activityImg: string;
activityName: string;
bindingCouponId?: number;
activityType: number;
endTime: string;
helpType: number;
limitNum: number;
shareNum: number;
show: number;
startTime: string;
time?: any[];
redirectPath?: "";
};
export type addActivityType = InterFunction<addActivityItemType, null>;
// 活动-列表
export type activityItemType = addActivityItemType & {
bindingCouponName: string;
couponActivityDTO: SplitCouponItemType;
activityStatus: number;
activityType: number;
id: number;
};
export type activeTableItemType = InterItemFunction<any, activityItemType[]>;
// 活动-结束
export type endActivityType = InterFunction<{ activityId: number }, null>;
// 活动-数据
export type activityDataType = InterFunction<
{ activityId: number },
{ countFinishParticipate: number; countParticipate: number }
>;
// 活动-编辑
export type activityEditType = InterFunction<
addActivityItemType & { id: number },
null
>;
import {
InterFunction,
InterItemFunction,
InterListFunction,
} from "~/api/interface";
import { PaginationEntity } from "~/common/interface/PaginationEntity";
// 裂变优惠券-表格数据类型
export type SplitCouponItemType = {
id: number;
activityRole: string;
couponStatus: boolean;
amountReceived: number;
userTag: number;
peopleNumber: number;
beSharedCoupon: SplitCouponItemType;
isFixedTime?: number;
} & shareCouponType &
baseInfoType;
export type SplitCouponSearchType = {
couponId?: string;
couponName?: string;
endTime?: string;
startTime?: string;
useType?: number;
state?: boolean;
};
export type SplitCouponListType = InterItemFunction<
SplitCouponSearchType,
SplitCouponItemType[]
>;
// 裂变优惠券-新建-数据类型
// 基本信息
export type baseInfoType = {
couponName: string;
};
// 分享者优惠券
export type shareCouponType = {
useType: number;
primaryKey: number[];
useStartTime: string;
useEndTime: string;
couponMoney: number;
couponType: number;
minPrice: number;
couponDiscount: number;
verificationType: number;
couponTotal: number;
restrictedAccess: number;
userTag: number;
};
// 被分享者优惠券
export type sharedCouponType = {
beSharedCouponDiscount: number;
beSharedCouponMoney: number;
beSharedCouponType: number;
beSharedMinPrice: number;
beSharedPrimaryKey: number[];
beSharedUseType: number;
beSharedVerificationType: number;
beSharedCouponTotal: number;
};
export type SplitCouponAddType = InterItemFunction<
baseInfoType & shareCouponType & sharedCouponType,
null
>;
// 优惠券列表-分页
export type CouponPageListType = InterListFunction<
{
couponId?: string;
couponName?: string;
endTime?: string;
startTime?: string;
state?: boolean;
useType?: number;
},
{
file: any;
couponDay: number;
couponDiscount: number;
couponMoney: number;
couponName: string;
couponStatus: boolean;
couponTotal: number;
couponType: number;
createTime: string;
getType: number;
id: number;
isDel: boolean;
isFixedTime: number;
isLimited: boolean;
lastTotal: number;
minPrice: number;
preferentialLimit: number;
primaryKey: string;
restrictedAccess: number;
updateTime: string;
useEndTime: string;
useStartTime: string;
useType: number;
userTag: number;
verificationType: boolean;
fileUrl: string;
}
>;
// 优惠券明细
export type couponDetailSearchType = {
couponId?: number;
createTime?: string;
endTime?: string;
gainType?: string;
orderNumber?: string;
startTime?: string;
state?: number;
uid?: string;
useTime?: string;
userPhone?: string;
};
export type couponDetailItemType = {
cid: number;
couponId: number;
couponName: string;
uid: string;
userPhone: string;
gainType: string;
status: number;
useTime: string;
orderNo: string;
useType: number;
createTime: string;
conversionRatio: number;
transferorUid: string;
receiveUid: string;
transferorTime: string;
};
export type couponDetailType = InterItemFunction<
couponDetailSearchType,
couponDetailItemType[]
>;
export type couponDetailExportType = InterFunction<
couponDetailSearchType & Pick<PaginationEntity, "pageNo" | "pageSize">,
any
>;
// 品牌列表
export type ListBrandInfoType = InterListFunction<
{},
{ brandName: string; createTime: string; id: number }
>;
// 新增优惠券
export type CouponSaveType = InterFunction<any, any>;
// 增发优惠券
export type CouponIncreaseType = InterFunction<
{ id: number; count: number },
{}
>;
// 获取优惠券使用数据
export type CouponGetDataType = InterFunction<
{ id: number },
{
accountPaid: number;
availability: string;
claimRate: string;
couponTotal: number;
receiveQuantity: number;
usageAmount: number;
}
>;
// 关闭优惠券类型
export type CouponShutDownType = InterFunction<{ id: number }, {}>;
import { InterFunction, InterItemFunction } from "~/api/interface";
// 品牌管理-新增
export type MakeAddType = InterFunction<{ brandName: string }, null>;
// 品牌编辑
export type MakeEditType = InterFunction<{ brandName: string; id: any }, null>;
// 品牌管理-列表
export type MakeItemEntity = {
createTime: string;
brandName: string;
id: number;
};
export type MakeListType = InterItemFunction<{}, MakeItemEntity[]>;
// 品牌刪除
export type MakeDeleteType = InterFunction<{ id: number }, null>;
import {
activeTableItemType,
activityDataType,
activityEditType,
addActivityType,
endActivityType,
splitCouponDownType,
} from "../interface/activityManage";
import axios from "../request";
export class ActivityManageAPI {
// 活动-裂变优惠券-下拉
static getActivityCouponPullDown: splitCouponDownType = (params) => {
return axios.get("userpay/coupon/back/getActivityCouponPullDown", {
params,
});
};
// 活动-新增
static createActivity: addActivityType = (data) => {
return axios.post("malluser/activity/create", data);
};
// 活动-编辑
static editActivity: activityEditType = (data) => {
return axios.post("malluser/activity/update", data);
};
// 活动-列表
static getActivityList: activeTableItemType = (params) => {
return axios.get("malluser/activity/list", { params });
};
// 活动-结束
static endActivity: endActivityType = (params) => {
return axios.get("malluser/activity/stop", { params });
};
// 活动-数据
static getActivityData: activityDataType = (params) => {
return axios.get("malluser/activity/dataInfo", { params });
};
}
import axios from "../request";
// 运营人员
export interface operateEntity {
userName: string;
accountNo: string;
id: number;
uid: string;
}
export interface loginEntity {
accountNo: string;
passWord: string;
remember: boolean;
}
export class CommonAPI {
static Login = (data: Pick<loginEntity, "accountNo" | "passWord">): any => {
return axios.post("userservlet/auth/platformLogin", {
...data,
portType: 1,
});
};
// 上传图片
static commonUpload = (data: FormData) => {
return axios.post("ossservlet/upload/osses", data);
};
// 上传图片
static fileUpload = (data: FormData) => {
return axios.post("ossservlet/upload/oss", data);
};
// 运营人员列表
static operateList(operateName: string) {
return axios.post("orderservlet/ordertask/listOperate", { operateName });
}
// 销售人员列表
static getSaleList() {
return axios.get("userservlet/useraccount/getSaleList");
}
}
import axios from "../request";
import {
couponDetailExportType,
couponDetailType,
CouponGetDataType,
CouponIncreaseType,
CouponPageListType,
CouponSaveType,
CouponShutDownType,
ListBrandInfoType,
SplitCouponAddType,
SplitCouponListType,
} from "~/api/interface/couponManage";
export class CouponManageAPI {
// 优惠券管理-裂变优惠券列表
static getPageActivityList: SplitCouponListType = (data) => {
return axios.post("userpay/coupon/back/pageActivityList", data);
};
// 优惠券管理-裂变优惠券新建
static saveActivity: SplitCouponAddType = (data) => {
return axios.post("userpay/coupon/back/saveActivity", data);
};
// 优惠券管理-裂变优惠券新建
static CouponPageList: CouponPageListType = (data) => {
return axios.post("userpay/coupon/back/pageList", data);
};
// 优惠券明细
static getCouponDetail: couponDetailType = (data) => {
return axios.post("userpay/coupon/back/getUserCouponList", data);
};
// 优惠券明细-导出
static downloadCouponUserList: couponDetailExportType = (data) => {
return axios.post("userpay/coupon/back/downloadCouponUserList", data, {
responseType: "blob",
});
};
// 新增优惠券
static CouponSave: CouponSaveType = (data) => {
return axios.post("/userpay/coupon/back/save", data, {
headers: { "Content-Type": "multipart/form-data" },
});
};
// 增发优惠券
static CouponIncrease: CouponIncreaseType = (params) => {
return axios.post("/userpay/coupon/back/increase", {}, { params });
};
// 获取优惠券详情
static CouponGetData: CouponGetDataType = (params) => {
return axios.get("/userpay/coupon/back/getData", { params });
};
// 关闭优惠券
static CouponShutDown: CouponShutDownType = (params) => {
return axios.post("/userpay/coupon/back/shutDown", {}, { params });
};
}
import {
MakeAddType,
MakeDeleteType,
MakeEditType,
MakeListType,
} from "~/api/interface/makeManage";
import axios from "../request";
export class MakeManageAPI {
// 品牌-新增
static addBrandInfo: MakeAddType = (params) => {
return axios.get("uavgoods/brand/addBrandInfo", { params });
};
// 品牌-编辑
static editBrandInfo: MakeEditType = (params) => {
return axios.get("uavgoods/brand/editBrandInfo", { params });
};
// 品牌-列表
static getListBrandInfo: MakeListType = (params) => {
return axios.get("uavgoods/brand/listBrandInfo", { params });
};
// 品牌刪除
static deleteBrandInfo: MakeDeleteType = (params) => {
return axios.get("uavgoods/brand/deleteBrandInfo", { params });
};
}
......@@ -4,7 +4,7 @@ import { limitEntity } from "@/api/modules/role";
function useOptionShow(id: number) {
// const [show, setShow] = useState<boolean>(false);
return JSON.parse(localStorage.getItem("routeList") as string).some(
return JSON.parse(localStorage.getItem("routeList") as string)?.some(
(v: limitEntity) => v.id === id
);
// useEffect(() => {
......
/*
* @Author: 龚洪江
* @Date: 2022-07-26 11:43:44
* @LastEditors: 龚洪江
* @LastEditTime: 2022-07-26 11:45:29
* @FilePath: \code\mmc-store\src\common\PaginationEntity\index.ts
* @Description:
*
* Copyright (c) 2022 by 龚洪江 2238959530@qq.com, All Rights Reserved.
*/
export interface PaginationEntity {
pageNo: number;
pageSize: number;
totalCount: number;
}
export interface PropsType {
title?: string;
isModalVisible: boolean;
handleOk: Function;
handleCancel: Function;
}
.box-wrap {
background-color: #fff;
border-radius: 10px;
margin-bottom: 15px;
min-height: 50px;
padding: 10px 20px 0 20px;
box-sizing: border-box;
.ant-form-item {
margin-bottom: 10px;
}
}
import React from "react";
import "./index.scss";
interface PropsType {
children: React.ReactNode;
}
const Box: React.FC<PropsType> = ({ children }) => {
return <div className="box-wrap">{children}</div>;
};
export default Box;
import React from "react";
interface PropsType {
children: React.ReactNode;
}
export const TableBox: React.FC<PropsType> = (props) => {
const { children } = props;
return <div className="table-body-box">{children}</div>;
};
import { Modal, Table } from "antd";
import { FC } from "react";
import { ColumnsType } from "antd/es/table";
import { PropsType } from "~/common/interface/modal";
import { activityDataType } from "~/api/interface/activityManage";
// 活动数据-类型
type dataType = (ReturnType<activityDataType> extends Promise<infer T>
? T
: never)["result"];
interface selfProps {
activityData: dataType | undefined;
}
const ActivityDataModal: FC<
Pick<PropsType, "isModalVisible" | "handleCancel"> & selfProps
> = ({ isModalVisible, handleCancel, activityData }) => {
const columns: ColumnsType<dataType> = [
{
title: "参与总人数",
dataIndex: "countFinishParticipate",
align: "center",
},
{
title: "参与成功人数",
dataIndex: "countParticipate",
align: "center",
},
];
return (
<Modal
open={isModalVisible}
title="活动数据"
onCancel={() => handleCancel()}
footer={null}
>
{activityData && (
<Table
columns={columns}
pagination={false}
dataSource={[activityData]}
bordered
rowKey="countFinishParticipate"
/>
)}
</Modal>
);
};
export default ActivityDataModal;
import {
FC,
ForwardedRef,
forwardRef,
useState,
useImperativeHandle,
} from "react";
import {
DatePicker,
Form,
Input,
message,
Modal,
Radio,
Select,
Upload,
} from "antd";
import { PlusOutlined } from "@ant-design/icons";
import type { UploadFile } from "antd/es/upload/interface";
import dayjs from "dayjs";
import { RangePickerProps } from "antd/es/date-picker";
import { PropsType } from "~/common/interface/modal";
import { CommonAPI } from "~/api";
import { SplitCouponItemType } from "~/api/interface/couponManage";
import { addActivityItemType } from "~/api/interface/activityManage";
import {ActivityManageAPI} from "~/api/modules/activityManage";
interface selfProps {
couponData: SplitCouponItemType[];
activityTypeChangeEvent: (value: number) => void;
ref: ForwardedRef<any>;
}
const AddOrEditModal: FC<PropsType & selfProps> = forwardRef(
(
{
isModalVisible,
handleOk,
handleCancel,
couponData,
activityTypeChangeEvent,
title,
},
ref
) => {
const [createActivityForm] = Form.useForm<
Exclude<
addActivityItemType,
{
startTime: string;
endTime: string;
helpType: number;
shareNum: number;
}
>
>();
const [activityId, setActivityId] = useState<number>(-1);
const [currentActivityType, setCurrentActivityType] = useState<number>(1);
// 文件
const [fileList, setFileList] = useState<UploadFile[]>([]);
const handleOkEvent = () => {
createActivityForm.validateFields().then((value: any) => {
const splitCouponItem = couponData.find(
(v) => v.id === value.bindingCouponId
);
const startTime = `${dayjs(value.time[0]).format(
"YYYY-MM-DD"
)} 00:00:00`;
const endTime = `${dayjs(value.time[1]).format("YYYY-MM-DD")} 23:59:59`;
delete value.time;
ActivityManageAPI[
activityId === -1 ? "createActivity" : "editActivity"
]({
id: activityId === -1 ? undefined : activityId,
...value,
limitNum: Number(value.limitNum),
helpType:
splitCouponItem?.beSharedCoupon?.userTag ||
splitCouponItem?.userTag,
shareNum:
currentActivityType === 1
? splitCouponItem?.peopleNumber
: undefined,
startTime,
endTime,
}).then(({ code }) => {
if (code === "200") {
message.success(activityId ? "编辑成功" : "新增成功");
createActivityForm.resetFields();
setFileList([]);
handleOk();
}
});
});
};
const handleCancelEvent = () => {
handleCancel();
createActivityForm.resetFields();
setFileList([]);
};
// 上传
const beforeUpload = (file: UploadFile) => {
const reg = /\/(png|jpg|gif|jpeg|webp)$/;
const isType = reg.test(file.type as string);
if (!isType) {
message.warning("文件格式错误");
}
return isType;
};
const customRequest = (value: any) => {
const formData = new FormData();
formData.append("uploadFile", value.file);
CommonAPI.commonUpload(formData).then((res: any) => {
if (res.code === "200") {
setFileList([
{
uid: "uid",
name: "image",
url: res.result[0],
status: "done",
},
]);
createActivityForm.setFieldValue("activityImg", res.result[0]);
}
});
};
const onRemove = (file: UploadFile) => {
const list = fileList.filter((v: UploadFile) => v.uid !== file.uid);
setFileList(list);
setTimeout(() => {
createActivityForm.setFieldValue("activityImg", undefined);
});
};
// 活动类型改变
const activityTypeChange = (e: any) => {
createActivityForm.setFieldValue("bindingCouponId", undefined);
setCurrentActivityType(e.target.value);
activityTypeChangeEvent(e.target.value);
};
// 正则
const negativeNumberValidator = (
rule: any,
value: string,
callback: (error?: string) => void
) => {
if (!value) {
return Promise.reject(new Error(`请输入参与次数!`));
}
const reg = /^\+?[1-9][0-9]*$/;
if (!reg.test(value)) {
return Promise.reject(new Error(`参与次数为非零的正整数!`));
}
if (Number(value) > 5) {
return Promise.reject(new Error("参与次数最大值为5!"));
}
// const bindingCouponId =
// createActivityForm.getFieldValue("bindingCouponId");
// if (bindingCouponId) {
// const splitCouponObj = couponData.find(
// (v) => v.id === bindingCouponId
// );
// if (splitCouponObj && Number(value) > splitCouponObj.restrictedAccess) {
// return Promise.reject("参与次数不能大于关联优惠券每人限领张数");
// }
// }
return Promise.resolve();
};
// rangPicker disabledDate
const disabledDate: RangePickerProps["disabledDate"] = (currentDate) => {
// const bindingCouponId = createActivityForm.getFieldValue("bindingCouponId");
// const couponObj = couponData.find((v) => v.id === bindingCouponId);
// const activityType = createActivityForm.getFieldValue("activityType");
// if (bindingCouponId) {
// switch (activityType) {
// case 1:
// return !(
// currentDate.isBefore(couponObj?.useEndTime) &&
// currentDate.isAfter(couponObj?.useStartTime)
// );
// case 2:
// return (
// couponObj?.isFixedTime === 0 &&
// !(
// currentDate.isBefore(couponObj?.useEndTime) &&
// currentDate.isAfter(couponObj?.useStartTime)
// )
// );
// }
// }
return currentDate < dayjs().subtract(1, "day");
};
useImperativeHandle(ref, () => ({
getForm: () => createActivityForm,
setFileList: (fileList: UploadFile[]) => {
setFileList(fileList);
},
setId: (id: number) => {
setActivityId(id);
},
}));
return (
<Modal
open={isModalVisible}
onOk={handleOkEvent}
onCancel={handleCancelEvent}
title={title}
>
<Form
labelCol={{ span: 5 }}
wrapperCol={{ span: 14 }}
form={createActivityForm}
initialValues={{ show: 1, activityType: 1 }}
>
<Form.Item
label="活动标题"
name="activityName"
rules={[{ required: true, message: "请输入活动标题!" }]}
>
<Input placeholder="请输入活动标题" maxLength={25} />
</Form.Item>
<Form.Item label="活动类型" name="activityType">
<Radio.Group onChange={activityTypeChange}>
<Radio value={1}>裂变活动</Radio>
<Radio value={2}>普通活动</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="活动中心展示" name="show">
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={0}></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label="推广简图"
name="activityImg"
rules={[{ required: true, message: "请上传推广简图!" }]}
>
<Upload
listType="picture-card"
fileList={fileList}
beforeUpload={beforeUpload}
customRequest={customRequest}
onRemove={onRemove}
accept="image/*"
>
{fileList.length < 1 && <PlusOutlined />}
</Upload>
</Form.Item>
<Form.Item label="关联优惠券" name="bindingCouponId">
<Select
placeholder="请选择关联优惠券"
showSearch
filterOption={(input, option: any) =>
(option!.children as unknown as string)
.toLowerCase()
.includes(input.toLowerCase())
}
>
{couponData.map((v) => (
<Select.Option value={v.id} key={v.id}>
{v.couponName}
</Select.Option>
))}
</Select>
</Form.Item>
{currentActivityType === 1 && (
<Form.Item
label="参与次数"
name="limitNum"
rules={[{ required: true, validator: negativeNumberValidator }]}
>
<Input placeholder="请输入参与次数" suffix="次" />
</Form.Item>
)}
<Form.Item
label="生效时间"
rules={[{ required: true, message: "请选择生效时间!" }]}
name="time"
>
<DatePicker.RangePicker disabledDate={disabledDate} />
</Form.Item>
</Form>
</Modal>
);
}
);
export default AddOrEditModal;
import { FC, useEffect, useRef, useState } from "react";
import { Button, Image, message, Modal, Table } from "antd";
import { ColumnsType } from "antd/es/table";
import dayjs from "dayjs";
import Box from "~/components/box";
import AddOrEditModal from "./components/addOrEditModal";
import ActivityDataModal from "./components/activityDataModal";
import { ActivityManageAPI } from "~/api/modules/activityManage";
import { SplitCouponItemType } from "~/api/interface/couponManage";
import { PaginationEntity } from "~/common/interface/PaginationEntity";
import {
activityDataType,
activityItemType,
} from "~/api/interface/activityManage";
import useOperate from "~/common/hook/optionHook";
// 活动数据-类型
type dataType = (ReturnType<activityDataType> extends Promise<infer T>
? T
: never)["result"];
const ActivityList: FC<{}> = () => {
const activityRef = useRef();
const tableColumns: ColumnsType<activityItemType> = [
{
title: "ID",
align: "center",
dataIndex: "id",
},
{
title: "活动标题",
align: "center",
dataIndex: "activityName",
},
{
title: "活动类型",
align: "center",
dataIndex: "activityType",
render: (text: string, record: activityItemType) => (
<div>{record.activityType === 1 ? "裂变活动" : "普通活动"}</div>
),
},
{
title: "是否展示",
align: "center",
render: (text: number, record: activityItemType) => (
<div>{record.show ? "展示" : "隐藏"}</div>
),
},
{
title: "推广简图",
align: "center",
render: (text: string, record: activityItemType) => (
<Image src={record.activityImg} width={50} />
),
},
{
title: "关联优惠",
align: "center",
dataIndex: "bindingCouponName",
},
{
title: "参与次数",
align: "center",
dataIndex: "limitNum",
},
{
title: "状态",
align: "center",
render: (text: string, record: activityItemType) =>
record.activityStatus === 1 ? "进行中" : "已下线",
},
{
title: "有效期",
align: "center",
render: (text: string, record: activityItemType) => (
<div>
<div>起:{record.startTime}</div>
<div>止:{record.endTime}</div>
</div>
),
},
{
title: "操作",
align: "center",
render: (text: string, record: activityItemType, index: number) => (
<>
<Button
type="link"
onClick={() => endActivityClick(record)}
disabled={record.activityStatus !== 1 || !isEndBtnShow}
>
结束
</Button>
{/* <Button type="link" onClick={() => addOrEditActivity(record)}> */}
{/* 编辑 */}
{/* </Button> */}
<Button
type="link"
onClick={() => showActivityData(record)}
disabled={!isDataBtnShow}
>
数据
</Button>
</>
),
},
];
const [tableData, setTableData] = useState<activityItemType[]>([]);
const [pagination, setPagination] = useState<PaginationEntity>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const [loading, setLoading] = useState<boolean>(false);
// 活动数据
const [activityData, setActivityData] = useState<dataType>();
const [addOrEditModalShow, setAddOrEditModalShow] = useState<boolean>(false);
const [addOrEditModalTitle, setAddOrEditModalTitle] = useState("创建活动");
const [activityDataModalShow, setActivityDataModalShow] =
useState<boolean>(false);
const [couponData, setCouponData] = useState<SplitCouponItemType[]>([]);
// 按钮权限
const isEndBtnShow = useOperate(19150);
const isDataBtnShow = useOperate(19200);
// 活动列表
const getActivityList = (
data: Pick<PaginationEntity, "pageNo" | "pageSize">
) => {
// setLoading(true);
const list:any =[
{
"id": 4,
"activityName": "裂变活动测试",
"activityCode": "AC77674",
"activityImg": "https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/87681f78-67db-4603-aaf3-4bdbdb4546d2.jpg",
"bindingCouponId": 10000148,
"bindingCouponName": "裂变优惠券测试",
"activityStatus": 2,
"activityType": 1,
"shareNum": 2,
"startTime": "2023-04-23 00:00:00",
"endTime": "2023-04-30 23:59:59",
"limitNum": 1,
"deleted": null,
"show": 1,
"redirectPath": null,
"couponActivityDTO": null,
"couponDTO": null
},
{
"id": 3,
"activityName": "裂变活动测试",
"activityCode": "AC55159",
"activityImg": "https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/6e4f318f-3081-43b7-ad6a-79afabd9ddb9.jpg",
"bindingCouponId": 10000141,
"bindingCouponName": "测试裂变",
"activityStatus": 2,
"activityType": 1,
"shareNum": 2,
"startTime": "2023-04-23 00:00:00",
"endTime": "2023-04-30 23:59:59",
"limitNum": 1,
"deleted": null,
"show": 1,
"redirectPath": null,
"couponActivityDTO": null,
"couponDTO": null
},
{
"id": 2,
"activityName": "认证裂变",
"activityCode": "AC17946",
"activityImg": "https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/b22e0f43-fd04-4147-adc6-73d96b76c740.png",
"bindingCouponId": null,
"bindingCouponName": null,
"activityStatus": 2,
"activityType": 1,
"shareNum": null,
"startTime": "2023-04-19 00:00:00",
"endTime": "2023-12-31 23:59:59",
"limitNum": 1,
"deleted": null,
"show": 1,
"redirectPath": null,
"couponActivityDTO": null,
"couponDTO": null
},
{
"id": 1,
"activityName": "测试裂变",
"activityCode": "AC01841",
"activityImg": "https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/40f09893-01c5-4cc6-a64a-75dac1963791.jpg",
"bindingCouponId": 10000141,
"bindingCouponName": "测试裂变",
"activityStatus": 2,
"activityType": 1,
"shareNum": 2,
"startTime": "2023-04-19 00:00:00",
"endTime": "2023-04-19 23:59:59",
"limitNum": 1,
"deleted": null,
"show": 1,
"redirectPath": null,
"couponActivityDTO": null,
"couponDTO": null
}
]
setTableData(list)
ActivityManageAPI.getActivityList(data).then(({ result }) => {
setLoading(false);
setTableData(result.list || []);
setPagination({
pageNo: data.pageNo,
pageSize: data.pageSize,
totalCount: result.totalCount,
});
});
};
// 裂变优惠券数据
const getActivityCouponPullDown = (type: number) => {
ActivityManageAPI.getActivityCouponPullDown({ type }).then(({ result }) => {
setCouponData(result || []);
});
};
// 活动结束
const endActivityClick = (record: activityItemType) => {
Modal.confirm({
content: "即将停止该活动,关联优惠券会停止发放",
onOk: () => {
ActivityManageAPI.endActivity({ activityId: record.id }).then(
({ code }) => {
if (code === "200") {
message.success("操作成功,该活动已结束");
getActivityList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
});
}
}
);
},
});
};
// 新增,编辑弹窗
const addOrEditActivity = (record?: activityItemType) => {
setAddOrEditModalTitle(record ? "编辑活动" : "创建活动");
if (record) {
const activityForm = (activityRef.current as any)?.getForm();
activityForm.setFieldsValue({
activityName: record.activityName,
activityType: record.activityType,
show: record.show,
activityImg: record.activityImg,
bindingCouponId: record.bindingCouponId || undefined,
redirectPath: record?.redirectPath,
limitNum: record.limitNum,
time: [dayjs(record.startTime), dayjs(record.endTime)],
});
const setFileList = (activityRef.current as any)?.setFileList;
setFileList([
{
uid: "uid",
name: "image",
url: record.activityImg,
status: "done",
},
]);
}
const setId = (activityRef.current as any)?.setId;
setId(record ? record.id : -1);
setAddOrEditModalShow(true);
};
const addOrEditModalOk = () => {
setAddOrEditModalShow(false);
getActivityList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
});
};
const addOrEditModalCancel = () => {
setAddOrEditModalShow(false);
};
// 活动数据弹窗
const showActivityData = (record: activityItemType) => {
ActivityManageAPI.getActivityData({ activityId: record.id }).then(
({ result }) => {
setActivityData(result || undefined);
}
);
setActivityDataModalShow(true);
};
const activityDataModalCancel = () => {
setActivityDataModalShow(false);
};
// 活动类型选择
const activityTypeChangeEvent = (value: number) => {
getActivityCouponPullDown(value);
};
// 分页
const paginationChange = (pageNo: number, pageSize: number) => {
getActivityList({ pageNo, pageSize });
};
useEffect(() => {
getActivityCouponPullDown(1);
getActivityList({ pageNo: 1, pageSize: 10 });
}, []);
return (
<div className="activity-list">
<Box>
<Button type="primary" onClick={() => addOrEditActivity()}>
新增
</Button>
</Box>
<Table
columns={tableColumns}
bordered
rowKey="id"
dataSource={tableData}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) =>
paginationChange(page, pageSize),
showTotal: (total, range) =>
`当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
loading={loading}
/>
{/* 新增,编辑 */}
<AddOrEditModal
isModalVisible={addOrEditModalShow}
handleOk={addOrEditModalOk}
handleCancel={addOrEditModalCancel}
couponData={couponData}
activityTypeChangeEvent={activityTypeChangeEvent}
ref={activityRef}
title={addOrEditModalTitle}
/>
{/* 活动数据 */}
<ActivityDataModal
isModalVisible={activityDataModalShow}
handleCancel={activityDataModalCancel}
activityData={activityData}
/>
</div>
);
};
export default ActivityList;
import { FC } from "react";
import { Modal, Descriptions } from "antd";
import { PropsType } from "~/common/interface/modal";
import { couponDetailItemType } from "~/api/interface/couponManage";
const contentStyle = { width: "100px" };
const DataModal: FC<
Pick<PropsType, "isModalVisible" | "handleCancel"> & {
couponDetailItem: couponDetailItemType | undefined;
}
> = ({ isModalVisible, handleCancel, couponDetailItem }) => {
return (
<Modal
open={isModalVisible}
title="查看详情"
footer={null}
onCancel={() => handleCancel()}
width={650}
>
<Descriptions bordered size="small">
<Descriptions.Item label="兑换时间" contentStyle={contentStyle}>
{couponDetailItem?.createTime}
</Descriptions.Item>
<Descriptions.Item label="兑换比例" contentStyle={contentStyle}>
{couponDetailItem?.conversionRatio}
</Descriptions.Item>
{(couponDetailItem?.gainType === "presented" ||
couponDetailItem?.gainType === "acquire") && (
<>
<Descriptions.Item label="转赠人UID" contentStyle={contentStyle}>
{couponDetailItem?.transferorUid}
</Descriptions.Item>
<Descriptions.Item label="获赠人UID" contentStyle={contentStyle}>
{couponDetailItem?.receiveUid}
</Descriptions.Item>
<Descriptions.Item label="转赠时间" contentStyle={contentStyle}>
{couponDetailItem?.transferorTime}
</Descriptions.Item>
<Descriptions.Item label="获赠时间" contentStyle={contentStyle}>
{couponDetailItem?.createTime}
</Descriptions.Item>
</>
)}
</Descriptions>
</Modal>
);
};
export default DataModal;
import { Button, Table } from "antd";
import { ColumnsType } from "antd/es/table";
import React, { useEffect, useState } from "react";
import dayjs from "dayjs";
import FileSaver from "file-saver";
import { useNavigate } from "react-router-dom";
import qs from "query-string";
import { ExportOutlined } from "@ant-design/icons";
import SearchBox, { searchColumns } from "~/components/search-box";
import { CouponManageAPI } from "~/api";
import { PaginationEntity } from "~/common/interface/PaginationEntity";
import {
couponDetailSearchType,
couponDetailItemType,
} from "~/api/interface/couponManage";
import DataModal from "./components/dataModal";
import useOperate from "~/common/hook/optionHook";
const gainTypeList = [
{ id: "receive", name: "用户领取" },
{ id: "send", name: "系统发放" },
{ id: "presented", name: "赠送" },
{ id: "acquire", name: "获赠" },
{ id: "exchange", name: "积分兑换" },
];
const stateList = [
{ id: 0, name: "未使用" },
{ id: 1, name: "已使用" },
{ id: 2, name: "已失效" },
{ id: 3, name: "已转赠" },
{ id: 4, name: "使用中" },
];
const CouponDetailed = () => {
const history = useNavigate();
const searchColumns: searchColumns[] = [
{
type: "input",
name: "uid",
label: "UID",
placeholder: "请输入用户UID",
},
{
type: "input",
name: "userPhone",
label: "手机号",
placeholder: "请输入用户手机号",
},
{
type: "input",
name: "couponId",
label: "优惠券ID",
placeholder: "请输入优惠券ID",
},
{
type: "DatePicker",
name: "createTime",
label: "领取时间",
placeholder: "",
},
{
type: "DatePicker",
name: "useTime",
label: "使用时间",
placeholder: "",
},
{
type: "input",
name: "orderNumber",
label: "订单编号",
placeholder: "请输入订单编号",
},
{
type: "select",
name: "gainType",
label: "流通方式",
placeholder: "请选择流通方式",
options: gainTypeList,
},
{
type: "select",
name: "state",
label: "全部状态",
placeholder: "请选择状态",
options: stateList,
},
];
const tableColumns: ColumnsType<couponDetailItemType> = [
{
title: "优惠券ID",
align: "center",
dataIndex: "couponId",
},
{
title: "优惠券名称",
align: "center",
dataIndex: "couponName",
},
{
title: "用户UID",
align: "center",
dataIndex: "uuid",
},
{
title: "手机号码",
align: "center",
dataIndex: "userPhone",
},
{
title: "流通方式",
align: "center",
render: (text: string, record: couponDetailItemType) => (
<div>
{gainTypeList.find((v) => v.id === record.gainType)?.name || ""}
</div>
),
},
{
title: "领取时间",
align: "center",
dataIndex: "createTime",
},
{
title: "状态",
align: "center",
render: (text: string, record: couponDetailItemType) => (
<div>{stateList.find((v) => v.id === record.status)?.name || ""}</div>
),
},
{
title: "使用时间",
align: "center",
dataIndex: "useTime",
},
{
title: "订单编号",
align: "center",
dataIndex: "orderNo",
render: (text: string, record: couponDetailItemType) =>
record.orderNo && (
<Button type="link" onClick={() => toOrderDetail(record)}>
{record.orderNo}
</Button>
),
},
{
title: "操作",
align: "center",
render: (text: string, record: couponDetailItemType) => (
<Button
type="link"
onClick={() => showDataModalClick(record)}
disabled={!isLookBtn || record.useType !== 1}
>
查看
</Button>
),
},
];
const [pagination, setPagination] = useState<PaginationEntity>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const [tableData, setTableData] = useState<couponDetailItemType[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [query, setQuery] = useState<couponDetailSearchType>();
const [dataModalShow, setDataModalShow] = useState<boolean>(false);
const [couponDetailItem, setCouponDetailItem] =
useState<couponDetailItemType>();
// 按钮权限
const isExportBtn = useOperate(26301);
const isLookBtn = useOperate(26302);
// 获取优惠券明细
const getCouponDetail = (
data: Pick<PaginationEntity, "pageNo" | "pageSize"> & couponDetailSearchType
) => {
// setLoading(true);
setTableData([
{
"id": 45,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 5058,
"uuid": "UID8723232",
"userPhone": "13522927229",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-06-01 21:42:45",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 44,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 5102,
"uuid": "UID9585857",
"userPhone": "17507736658",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-31 21:01:15",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 43,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 68,
"uuid": "UID0080718",
"userPhone": "19168592452",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-29 19:53:05",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 42,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 5107,
"uuid": "UID8562549",
"userPhone": "17891113617",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-29 13:23:26",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 41,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 5103,
"uuid": "UID6512850",
"userPhone": "15678897088",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-29 10:54:11",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 40,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 5101,
"uuid": "UID3723715",
"userPhone": "15129481077",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-29 10:41:45",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 39,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 4358,
"uuid": "UID1649471",
"userPhone": "15991160565",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-29 09:06:22",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 38,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 5083,
"uuid": "UID4145719",
"userPhone": "18931209999",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-27 18:00:48",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 37,
"couponId": 10000147,
"cid": null,
"orderNo": null,
"uid": 2376,
"uuid": "UID3278532",
"userPhone": "15912163681",
"couponName": "科比特品牌优惠券",
"couponType": 1,
"useType": 2,
"couponMoney": null,
"minPrice": null,
"couponDiscount": 5,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-25 16:07:09",
"updateTime": null,
"startTime": "2023-04-21 00:00:00",
"endTime": "2023-12-31 23:59:59",
"useTime": null,
"primaryKey": "25",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": 10000,
"brandIds": null,
"discountCouponPrice": null
},
{
"id": 35,
"couponId": 10000156,
"cid": null,
"orderNo": null,
"uid": 5055,
"uuid": "UID2886699",
"userPhone": "15185632216",
"couponName": "人党的飞飞",
"couponType": 3,
"useType": 2,
"couponMoney": 12,
"minPrice": null,
"couponDiscount": null,
"remainingBalance": null,
"gainType": "send",
"status": 0,
"createTime": "2023-05-25 15:34:13",
"updateTime": null,
"startTime": "2023-05-26 00:00:00",
"endTime": "2023-06-22 23:59:59",
"useTime": null,
"primaryKey": "31",
"conversionRatio": null,
"transferorUid": null,
"receiveUid": null,
"transferorTime": null,
"verificationType": false,
"preferentialLimit": null,
"brandIds": null,
"discountCouponPrice": null
}
])
CouponManageAPI.getCouponDetail(data).then(({ result }) => {
const tableData = (result.list || []).map((v) => ({
...v,
selfId: Math.random(),
}));
setLoading(false);
setTableData(tableData);
setPagination({
pageNo: data.pageNo,
pageSize: data.pageSize,
totalCount: result.totalCount,
});
});
};
// 数据筛选
const searchDataEvents = (data: any) => {
data.createTime = data.createTime
? dayjs(data.createTime).format("YYYY-MM-DD")
: undefined;
data.useTime = data.useTime
? dayjs(data.useTime).format("YYYY-MM-DD")
: undefined;
setQuery(data);
getCouponDetail({ pageNo: 1, pageSize: 10, ...data });
};
// 导出
const exportEvent = () => {
CouponManageAPI.downloadCouponUserList({
...query,
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
}).then((res: any) => {
const blob = new Blob([res], {
type: "application/vnd.ms-excel",
});
FileSaver.saveAs(
blob,
`优惠券明细数据导出_${new Date().toLocaleString()}`
);
});
};
// 分页
const paginationChange = (pageNo: number, pageSize: number) => {
getCouponDetail({ pageNo, pageSize, ...query });
};
// vip 券数据详情
const showDataModalClick = (record: couponDetailItemType) => {
setCouponDetailItem(record);
setDataModalShow(true);
};
const dataModalCancel = () => {
setDataModalShow(false);
};
// 跳转订单详情
const toOrderDetail = (record: couponDetailItemType) => {
history({
pathname: "/orderManage/list/detail",
search: qs.stringify({
id: record.cid,
}),
});
};
useEffect(() => {
getCouponDetail({ pageNo: 1, pageSize: 10 });
}, []);
return (
<div className="coupon-detailed">
<SearchBox
search={searchColumns}
searchData={searchDataEvents}
otherChild={
<Button
onClick={exportEvent}
type="primary"
icon={<ExportOutlined disabled={!isExportBtn} />}
>
导出
</Button>
}
/>
<Table
columns={tableColumns}
bordered
dataSource={tableData}
rowKey="selfId"
loading={loading}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) =>
paginationChange(page, pageSize),
showTotal: (total, range) =>
`当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
<DataModal
isModalVisible={dataModalShow}
handleCancel={dataModalCancel}
couponDetailItem={couponDetailItem}
/>
</div>
);
};
export default CouponDetailed;
import React, { useState } from "react";
import { DatePicker, Form, Input, message, Modal, Radio } from "antd";
import moment from "moment";
// 传参类型
interface propType {
title: string;
open: boolean;
closed: any;
data?: any;
}
export const AddEditModal: React.FC<propType> = (props: propType) => {
// 组件默认值
AddEditModal.defaultProps = {
data: null,
};
// 参数
const { title, open, closed, data } = props;
// 表单钩子
const [form] = Form.useForm();
// 生效时间单选
const [radioValue, setRadioValue] = useState(0);
// 关闭弹窗
const handleCancel = () => {
closed();
};
// 提交弹窗
const handleOk = () => {
form
.validateFields()
.then((values) => {
console.log("handleOk -->", values);
})
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then();
});
};
return (
<Modal
open={open}
title={title}
onCancel={handleCancel}
onOk={handleOk}
destroyOnClose
>
<Form
name="addForm"
form={form}
labelAlign="right"
// layout="inline"
>
<Form.Item
label="规则名称"
name="ruleName"
rules={[{ required: true, message: "请输入规则名称" }]}
>
<Input placeholder="请输入规则名称" maxLength={20} allowClear />
</Form.Item>
<Form.Item label="兑换比例(积分:券额)" required>
<Form.Item
name="year"
rules={[{ required: true, message: "请输入积分比例" }]}
style={{ display: "inline-block", width: "calc(50% - 8px)" }}
>
<Input placeholder="请输入积分比例" />
</Form.Item>
<Form.Item
name="month"
rules={[{ required: true, message: "请输入券额比例" }]}
style={{
display: "inline-block",
width: "calc(50% - 8px)",
margin: "0 8px",
}}
>
<Input placeholder="请输入券额比例" />
</Form.Item>
</Form.Item>
<div style={{ transform: "translateY(-10px)" }}>
说明:若兑换比例为1:20,则1积分可兑20元VIP优惠券,且为无门槛优惠券
</div>
<Form.Item
label="生效时间"
name="ruleSetting"
rules={[{ required: true, message: "请选择生效时间" }]}
initialValue={0}
>
<Radio.Group
options={[
{ label: "立即生效", value: 0 },
{ label: "手动设置", value: 1 },
]}
value={radioValue}
onChange={({ target: { value } }) => {
setRadioValue(value);
}}
/>
</Form.Item>
{radioValue === 1 && (
<Form.Item
label="手动设置"
name="ruleTime"
rules={[{ required: radioValue === 1, message: "请设置生效时间" }]}
>
<DatePicker
placeholder="请输入账号有效期"
allowClear
showTime={{ format: "HH:mm:ss" }}
format="YYYY-MM-DD HH:mm:ss"
style={{ width: "100%" }}
disabledDate={(current) => {
// 限制时间不可早于当日
return current && current <= moment();
}}
/>
</Form.Item>
)}
</Form>
</Modal>
);
};
import React, { useEffect, useState } from "react";
import { Descriptions, message, Modal } from "antd";
import { CouponManageAPI } from "~/api";
import { CouponGetDataType } from "~/api/interface/couponManage";
// 传参类型
interface propType {
title: string;
open: boolean;
closed: any;
data?: any;
}
// 列表的类型
type DetailType = (ReturnType<CouponGetDataType> extends Promise<infer T>
? T
: never)["result"];
const contentStyle = { width: "100px" };
export const DataModal: React.FC<propType> = (props: propType) => {
// 组件默认值
DataModal.defaultProps = {
data: null,
};
// 参数
const { title, open, closed, data } = props;
// 使用数据
const [couponDetail, setCouponDetail] = useState<DetailType>();
// 关闭弹窗
const handleCancel = () => {
closed();
};
// 获取优惠券使用数据
const getCouponGetData = async () => {
const res = await CouponManageAPI.CouponGetData({
id: data.id,
});
if (res && res.code === "200") {
setCouponDetail(res.result);
}
};
// 组件加载
useEffect(() => {
if (!data) return;
getCouponGetData().then();
}, [open]);
return (
<Modal
open={open}
title={title}
onCancel={handleCancel}
footer={null}
destroyOnClose
width={650}
>
<Descriptions column={3} bordered size="small">
<Descriptions.Item contentStyle={contentStyle} label="总发行量">
{couponDetail?.couponTotal}
</Descriptions.Item>
<Descriptions.Item contentStyle={contentStyle} label="领取量">
{couponDetail?.receiveQuantity}
</Descriptions.Item>
<Descriptions.Item contentStyle={contentStyle} label="领取率">
{couponDetail?.claimRate}
</Descriptions.Item>
<Descriptions.Item contentStyle={contentStyle} label="使用量">
{couponDetail?.usageAmount}
</Descriptions.Item>
<Descriptions.Item contentStyle={contentStyle} label="有效使用量">
{couponDetail?.accountPaid}
</Descriptions.Item>
<Descriptions.Item contentStyle={contentStyle} label="有效使用率">
{couponDetail?.availability}
</Descriptions.Item>
</Descriptions>
</Modal>
);
};
import React, { useEffect } from "react";
import { Form, Input, message, Modal } from "antd";
import { maxLength } from "~/utils/validateUtils";
import { CouponManageAPI } from "~/api";
// 传参类型
interface propType {
title: string;
open: boolean;
closed: any;
data?: any;
}
export const IncreaseModal: React.FC<propType> = (props: propType) => {
// 组件默认值
IncreaseModal.defaultProps = {
data: null,
};
// 参数
const { title, open, closed, data } = props;
// 表单钩子
const [form] = Form.useForm();
// 关闭弹窗
const handleCancel = () => {
form.resetFields();
closed();
};
// 提交弹窗
const handleOk = () => {
form
.validateFields()
.then(async (values) => {
await handleSubmit(values);
// console.log("handleOk -->", values);
})
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then();
});
};
// 新增发行量监听
const handleIncrease = ({ target: { value } }: any) => {
if (value) {
form.setFieldsValue({
lastTotalBefore: Number(data.lastTotal) + Number(value),
});
} else {
form.setFieldsValue({
lastTotalBefore: data.lastTotal,
});
}
};
// 提交数据
const handleSubmit = async (values: { count: number }) => {
const res = await CouponManageAPI.CouponIncrease({
id: data.id,
count: Number(values.count),
});
if (res && res.code === "200") {
message.success("操作成功").then();
handleCancel();
}
};
useEffect(() => {
if (!data) return;
// console.log("IncreaseModal --->", data);
form.setFieldsValue({
...data,
lastTotalBefore: data.lastTotal,
});
}, [data]);
return (
<Modal
open={open}
title={title}
onCancel={handleCancel}
onOk={handleOk}
destroyOnClose
width={400}
>
<Form
name="addForm"
form={form}
labelAlign="right"
labelCol={{ span: 8 }}
// layout="inline"
>
<Form.Item label="当前发行总量" name="lastTotal">
<Input
placeholder="请输入当前发行总量"
maxLength={20}
allowClear
disabled
suffix="张"
/>
</Form.Item>
<Form.Item
label="新增发行量"
name="count"
rules={[
{ required: true, message: "请输入新增发行量" },
// 增发合计不能超过100000
{
validator: (rule, value) => {
if (Number(data.lastTotal) + Number(value) > 100000) {
return Promise.reject("增发合计不能超过100000");
}
return Promise.resolve();
},
},
]}
>
<Input
placeholder="请输入新增发行量"
maxLength={20}
allowClear
prefix="+"
suffix="张"
type="number"
onChange={handleIncrease}
onInput={maxLength}
/>
</Form.Item>
<Form.Item label="更新后总发行量" name="lastTotalBefore">
<Input
placeholder="请输入更新后总发行量"
maxLength={20}
allowClear
disabled
suffix="张"
/>
</Form.Item>
</Form>
</Modal>
);
};
import React, { useEffect, useState } from "react";
import qs from "query-string";
import { useNavigate } from "react-router-dom";
import {
Button,
Checkbox,
DatePicker,
Form,
Input,
InputNumber,
message,
Radio,
RadioChangeEvent,
Select,
Space,
Upload,
UploadProps,
} from "antd";
import { UploadOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import { CheckboxChangeEvent } from "antd/es/checkbox";
import saveAs from "file-saver";
import { isNull } from "lodash";
import { TableDetailView } from "~/components/tableDetailView";
import { CommonAPI, CouponManageAPI, MakeManageAPI } from "~/api";
import { CouponPageListType } from "~/api/interface/couponManage";
import {
maxLength,
maxLength6,
maxLength8,
maxNumber,
} from "~/utils/validateUtils";
import { Uploader } from "~/components/uploader";
// 列表的类型
type DetailType = (ReturnType<CouponPageListType> extends Promise<infer T>
? T
: never)["result"]["list"][0];
export default function CouponDetail (props: { location: { search: string } }){
// 参数解析
const option: any = qs.parse(props.location.search);
// 路由钩子
const history: any = useNavigate();
// 表单钩子
const [form] = Form.useForm();
// 当前是否能编辑
const [editDisable, setEditDisable] = useState(false);
// 有效期类型
const [isFixedTime, setIsFixedTime] = useState(0);
// 优惠券类型
const [couponType, setCouponType] = useState(1);
// 打折条件
const [discountRule, setDiscountRule] = useState(1);
// 发放方式
const [getType, setGetType] = useState(1);
// 最多优惠
const [maxDiscount, setMaxDiscount] = useState(false);
// 是否限量
const [isLimited, setIsLimited] = useState(true);
// 优惠券数据
const [couponDetail, setCouponDetail] = useState<DetailType>();
// 品牌列表
const [primaryOptions, setPrimaryOptions] =
useState<{ label: string; value: number }[]>();
// 获取优惠券详情
const getCouponDetail = async ({
id,
type,
}: {
id: string;
type: number;
}) => {
const res = await CouponManageAPI.CouponPageList({
couponId: id,
useType: type,
pageNo: 1,
pageSize: 1,
});
if (res && res.code === "200") {
const data = res.result.list[0];
// 优惠券详情
setCouponDetail(data);
// 回显表单
form.setFieldsValue({
...data,
rangeTime: [dayjs(data.useStartTime), dayjs(data.useEndTime)],
// useStartTime: data.useStartTime && dayjs(data.useStartTime),
// useEndTime: data.useEndTime && dayjs(data.useEndTime),
primaryKey: data.primaryKey?.split(",")?.map((i) => Number(i)),
});
// 设置有效期类型
setIsFixedTime(data.isFixedTime);
// 设置券类型
setCouponType(data.couponType);
// 当券为有最低消费且为打折券时,设置打折券的类型
if (data.couponType === 1 && !isNull(data.minPrice)) {
setDiscountRule(2);
} else {
setDiscountRule(1);
}
// 设置发放方式
setGetType(data.getType);
// 回显最多优惠
if (data.preferentialLimit) {
setMaxDiscount(true);
}
// console.log("getCouponDetail --->", data.preferentialLimit);
}
};
// 获取品牌列表
const getListBrandInfo = async () => {
const res = await MakeManageAPI.getListBrandInfo({
pageNo: 1,
pageSize: 9999,
});
setPrimaryOptions(
res.result?.list?.map((i) => {
return { label: i.brandName, value: i.id };
})
);
};
// 有效期状态
const handleFixedTime = ({ target: { value } }: RadioChangeEvent) => {
setIsFixedTime(value);
};
// 优惠券类型
const handleCouponType = ({ target: { value } }: RadioChangeEvent) => {
// 切换时候清除已填数据(未考虑编辑情况)
form.setFieldsValue({
minPrice: undefined,
couponDiscount: undefined,
preferentialLimit: undefined,
couponMoney: undefined,
});
setCouponType(value);
};
// 打折条件
const handleDiscountRule = ({ target: { value } }: RadioChangeEvent) => {
setDiscountRule(value);
};
// 最多优惠
const handleMaxDiscount = ({ target: { checked } }: CheckboxChangeEvent) => {
setMaxDiscount(checked);
};
// 发放方式
const handleGetType = ({ target: { value } }: RadioChangeEvent) => {
setGetType(value);
};
// 是否限量
const handleIsLimited = ({ target: { value } }: RadioChangeEvent) => {
setIsLimited(value);
if (!value) {
form.setFieldValue("couponTotal", "0");
} else {
form.setFieldValue("couponTotal", undefined);
}
};
// 校验数据
const handleOk = () => {
if (editDisable) {
return history(-1);
}
form
.validateFields()
.then(async (values) => {
await handleSubmit({
...values,
// couponDiscount: Number(values.couponDiscount),
primaryKey: values.primaryKey.join(","),
useStartTime:
values.rangeTime &&
dayjs(values.rangeTime[0]).format("YYYY-MM-DD 00:00:00"),
useEndTime:
values.rangeTime &&
dayjs(values.rangeTime[1]).format("YYYY-MM-DD 23:59:59"),
useType: option.type,
});
})
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then();
});
};
// 提交数据
const handleSubmit = async (data: DetailType) => {
// console.log("handleSubmit --->", data);
const formData = new FormData();
const blob = new Blob([JSON.stringify(data)], {
type: "application/json",
});
formData.append("couponInfoVO", blob);
formData.append("file", data.file);
const res = await CouponManageAPI.CouponSave(formData);
if (res && res.code === "200") {
message.success("操作成功", 1).then(() => history(-1));
} else {
message.error(res.message);
}
};
// 组件加载
useEffect(() => {
// 获取品牌列表
getListBrandInfo().then();
if (!option.id) return;
// 获取回显数据
getCouponDetail(option).then();
// 设置是否可以编辑
setEditDisable(true);
}, []);
return (
<>
<TableDetailView
isBack
isFooter
onCancel={() => {
history(-1);
}}
onOK={handleOk}
>
<div className="detail-form">
<Form
name="addForm"
form={form}
labelAlign="right"
disabled={editDisable}
// labelCol={{ span: 3 }}
>
<div className="detail-label">基本信息</div>
<Form.Item
label="优惠券名称"
name="couponName"
rules={[{ required: true, message: "请输入优惠券名称" }]}
>
<Input
placeholder="请输入优惠券名称"
maxLength={10}
allowClear
showCount
/>
</Form.Item>
<Form.Item
name="isFixedTime"
label="有效期"
rules={[{ required: true, message: "请选择有效期" }]}
initialValue={0}
>
<Radio.Group
style={{ marginTop: "2px" }}
options={[
{ value: 0, label: "起始日期 至 结束日期" },
{ value: 1, label: "领取当日起" },
{ value: 2, label: "领取次日起" },
]}
value={isFixedTime}
onChange={handleFixedTime}
/>
</Form.Item>
{isFixedTime === 0 && (
<Form.Item
label={" "}
colon={false}
name="rangeTime"
rules={[{ required: true, message: "请输入有效期" }]}
required
style={{
width: "400px",
marginLeft: "55px",
}}
>
<DatePicker.RangePicker
format="YYYY-MM-DD"
disabledDate={(current) => {
// 限制时间不可早于昨日
return current && current < dayjs().subtract(1, "days");
}}
/>
</Form.Item>
)}
{isFixedTime === 1 && (
<Form.Item
label={" "}
colon={false}
name="couponDay"
rules={[{ required: true, message: "请输入有效期" }]}
style={{ width: "200px", marginLeft: "55px" }}
>
<Input
placeholder="请输入天数"
allowClear
suffix="天内可用"
type="number"
onInput={maxLength}
/>
</Form.Item>
)}
{isFixedTime === 2 && (
<Form.Item
label={" "}
colon={false}
name="couponDay"
rules={[{ required: true, message: "请输入有效期" }]}
style={{ width: "200px", marginLeft: "55px" }}
>
<Input
placeholder="请输入天数"
maxLength={10}
allowClear
suffix="天内可用"
type="number"
onInput={maxLength}
/>
</Form.Item>
)}
<Form.Item
name="primaryKey"
label="品牌范围"
rules={[{ required: true, message: "请选择品牌范围" }]}
>
<Select
mode="multiple"
placeholder="请选择品牌范围"
maxLength={50}
allowClear
options={primaryOptions}
/>
</Form.Item>
{/* <div className="detail-form-tips"> */}
{/* 说明:一张优惠券最多可以选择50个指定品牌。优惠券一旦创建,指定品牌只能增加,不能删除。 */}
{/* </div> */}
<Form.Item
label="发放方式"
name="getType"
rules={[{ required: true, message: "请选择发放方式" }]}
initialValue={1}
>
<Radio.Group
style={{ marginTop: "4px" }}
options={[
{ label: "主动领取", value: 1 },
{ label: "系统发放", value: 2 },
{ label: "批量导入用户", value: 3 },
{ label: "活动裂变券", value: 4, disabled: true },
]}
value={getType}
onChange={handleGetType}
/>
</Form.Item>
{getType === 2 && (
<Form.Item
name="userTag"
label="用户标签"
rules={[{ required: true, message: "请选择用户标签" }]}
>
<Select
placeholder="请选择用户标签"
allowClear
maxLength={50}
options={[
{ label: "新用户", value: 1 },
{ label: "实名认证", value: 2 },
{ label: "企业认证", value: 3 },
]}
/>
</Form.Item>
)}
{getType === 3 && (
<>
<Form.Item
name="fileUrl"
label="文件地址"
rules={[{ required: true, message: "请上传文件" }]}
wrapperCol={{ span: 6 }}
hidden
>
<Input placeholder="请上传文件" />
</Form.Item>
<Form.Item
name="file"
label="上传模板"
rules={[{ required: true, message: "请上传模板" }]}
>
<Uploader
listType="text"
fileType={[
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-excel",
]}
fileUpload={false}
onChange={(file) => {
// 上传到服务器
const formData = new FormData();
formData.append("uploadFile", file[0]);
CommonAPI.fileUpload(formData).then((res: any) => {
if (res && res.code === "200") {
form.setFieldValue("fileUrl", res?.result?.filePath);
form.setFieldValue("file", file[0]);
} else {
message.error("文件上传失败").then();
}
});
}}
// 默认文件列表
defaultFileList={
couponDetail?.fileUrl
? [{ url: couponDetail?.file, name: "用户数据.xlsx" }]
: []
}
>
<Button icon={<UploadOutlined />}>上传文件</Button>
</Uploader>
<Button
type="link"
onClick={() => {
// 使用file-save保存文件,文件链接为:https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/doc/coupon-template.xlsx
saveAs(
"https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/doc/coupon-template.xlsx",
"导入模板.xlsx"
);
}}
style={{ position: "absolute", top: "0px", right: "120px" }}
>
模板下载
</Button>
</Form.Item>
</>
)}
<div className="detail-label">面额信息</div>
<Form.Item
label="优惠类型"
name="couponType"
rules={[{ required: true, message: "请选择优惠类型" }]}
initialValue={1}
>
<Radio.Group
style={{ marginTop: "4px" }}
options={[
{ label: "折扣券", value: 1 },
{ label: "满减券", value: 2 },
{ label: "无门槛", value: 3 },
]}
value={couponType}
onChange={handleCouponType}
/>
</Form.Item>
{couponType === 1 && (
<>
<Form.Item
label="打折条件"
rules={[{ required: true, message: "请选择打折条件" }]}
>
<Radio.Group
style={{ marginTop: "4px" }}
options={[
{ label: "无门槛", value: 1 },
{ label: "有门槛", value: 2 },
]}
value={discountRule}
onChange={handleDiscountRule}
/>
</Form.Item>
{discountRule === 2 && (
<Form.Item
name="minPrice"
label="订单满"
rules={[{ required: true, message: "请输入金额" }]}
wrapperCol={{ span: 6 }}
>
<Input
placeholder="请输入金额"
suffix="元"
type="number"
onInput={maxLength8}
/>
</Form.Item>
)}
<Form.Item
name="couponDiscount"
label="打"
rules={[
{ required: true, message: "请输入数字" },
{
pattern: /^10(\.00)?$|^(\d|[1-9])(\.\d{1,2})?$/,
message: "只能输入0.01到10.00的两位小数",
},
]}
wrapperCol={{ span: 6 }}
>
<Input
placeholder="请输入数字"
suffix="折"
type="number"
// onInput={onlyNumber}
/>
</Form.Item>
<Checkbox
onChange={handleMaxDiscount}
style={{ marginTop: "6px", marginRight: "10px" }}
checked={maxDiscount}
/>
<Form.Item
name="preferentialLimit"
label="最多优惠"
rules={[{ required: maxDiscount, message: "请输入金额" }]}
wrapperCol={{ span: 7 }}
style={{ display: "inline-block", width: "85%" }}
>
<Input
placeholder="请输入金额"
suffix="元"
type="number"
onInput={maxLength8}
/>
</Form.Item>
<div className="detail-form-tips">
说明:最多优惠金额不可高于满折后的价格。
</div>
</>
)}
{couponType === 2 && (
<>
<Form.Item style={{ marginLeft: "30px" }}>
<Form.Item
name="minPrice"
label="满"
colon={false}
rules={[{ required: true, message: "请输入金额" }]}
style={{
display: "inline-block",
width: "calc(40% - 8px)",
}}
>
<Input
placeholder="请输入金额"
suffix="元"
type="number"
onInput={maxLength8}
onChange={() => {
form.validateFields(["couponMoney"]).then();
}}
/>
</Form.Item>
<Form.Item
name="couponMoney"
label="减"
colon={false}
rules={[
{ required: true, message: "请输入金额" },
// 满减金额不能大于原价
{
validator: (_, value) =>
Number(value) > Number(form.getFieldValue("minPrice"))
? Promise.reject("满减金额不能大于原价")
: Promise.resolve(),
},
]}
style={{
display: "inline-block",
width: "calc(40% - 8px)",
margin: "0 8px",
}}
>
<Input
placeholder="请输入金额"
suffix="元"
type="number"
onInput={maxLength8}
/>
</Form.Item>
</Form.Item>
</>
)}
{couponType === 3 && (
<>
<Form.Item
name="couponMoney"
label="券的面额"
rules={[
{ required: true, message: "请输入面额" },
{
validator: (_, value) =>
Number(value) > 200000
? Promise.reject("面额不得超过20万元")
: Promise.resolve(),
},
]}
wrapperCol={{ span: 6 }}
>
<Input
placeholder="请输入面额"
suffix="元"
type="number"
onInput={maxLength6}
/>
</Form.Item>
<div className="detail-form-tips">
说明:请输入整数金额,面额不得超过20万元。
</div>
<Form.Item
label="核销方式"
name="verificationType"
rules={[{ required: true, message: "请选择核销方式" }]}
>
<Radio.Group
style={{ marginTop: "4px" }}
options={[
{ label: "单次核销", value: false },
{ label: "多次核销", value: true },
]}
/>
</Form.Item>
</>
)}
<Form.Item
label="是否限量"
name="isLimited"
rules={[{ required: true, message: "请选择核销方式" }]}
initialValue
hidden
>
<Radio.Group
style={{ marginTop: "4px" }}
options={[
{ label: "限量", value: true },
{ label: "不限量", value: false },
]}
value={isLimited}
onChange={handleIsLimited}
/>
</Form.Item>
<Form.Item
name="couponTotal"
label="发行量"
rules={[
{ required: true, message: "请输入发行量" },
{ max: 100000, message: "最大不能超过100000" },
]}
hidden={!isLimited}
>
<Input
placeholder="至少1张,不超过10万"
suffix="张"
type="number"
onInput={maxNumber}
/>
</Form.Item>
<div className="detail-form-tips" style={{ color: "red" }}>
说明:优惠券创建后,发行量只能增加不能减少,请谨慎设置。
</div>
<Form.Item
name="restrictedAccess"
label="每人限领"
rules={[{ required: true, message: "请选择限领张数" }]}
>
<Select
placeholder="至少1张,不超过10万"
options={[
{ label: "1张", value: 1 },
{ label: "2张", value: 2 },
{ label: "3张", value: 3 },
{ label: "4张", value: 4 },
{ label: "5张", value: 5 },
// { label: "不限", value: 0 },
]}
// onChange={(e) => {
// if (e === 0) {
// form.setFieldsValue({ isLimited: false });
// } else {
// form.setFieldsValue({ isLimited: true });
// }
// }}
/>
</Form.Item>
</Form>
</div>
</TableDetailView>
</>
);
};
import React, { useEffect, useState } from "react";
import { Button, message, Modal, Radio, RadioChangeEvent, Table } from "antd";
import { ColumnsType } from "antd/es/table";
import { PlusOutlined } from "@ant-design/icons";
import { useNavigate } from "react-router-dom";
import moment from "moment";
import SearchView from "~/components/search-box/index";
import { CouponManageAPI } from "~/api";
import { TableBox } from "~/components/tableBox";
import { IncreaseModal } from "~/pages/couponManage/couponList/comp/increaseModal";
import { DataModal } from "~/pages/couponManage/couponList/comp/dataModal";
import { CouponPageListType } from "~/api/interface/couponManage";
import useOperate from "~/common/hook/optionHook";
// 列表的类型
type TableType = (ReturnType<CouponPageListType> extends Promise<infer T>
? T
: never)["result"]["list"];
type ReqType = Parameters<CouponPageListType>[0];
// 搜索表单的数据
let query: ReqType = {};
// 规则状态
const stateOptions = [
// { id: null, name: "全部状态" },
{ id: true, name: "领取中" },
{ id: false, name: "已结束" },
];
// 优惠券类型
const couponType = [
{ label: "打折券", value: 1 },
{ label: "减免券", value: 2 },
{ label: "无门槛", value: 3 },
];
export default function CouponList () {
const { confirm } = Modal;
// 路由操作
const history = useNavigate();
const [useType, setUseType] = useState(2);
// 增发弹窗是否显示
const [increaseVisible, setIncreaseVisible] = useState(false);
// 数据弹窗是否显示
const [dataVisible, setDataVisible] = useState(false);
// 编辑的数据
const [recordData, setRecordData] = useState<TableType[0]>();
// 表格数据
const [tableData, setTableData] = useState<TableType>([]);
// 表格分页配置
const [pagination, setPagination] = useState({
total: 0,
pageSize: 10,
current: 1,
totalPage: 0,
});
// 按钮权限
const isAddCouponBtn = useOperate(26101);
const isLookCouponBtn = useOperate(26102);
const isAddIssueCouponBtn = useOperate(26103);
const isDataCouponBtn = useOperate(26104);
const isEndCouponBtn = useOperate(26105);
// +++++++++++++++++++++++++++++++++++++++++++++++++++ //
// 新版通用部分(ES6+ for React) ZhangLK 2022/08/30 Start
// 加载列表
const getTableList = async (value = {}) => {
// 只需要修改这个地方的接口即可
setTableData([
{
"id": 10000157,
"couponName": "2223",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": null,
"couponTotal": 13,
"lastTotal": 13,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32,31",
"isFixedTime": 0,
"useStartTime": "2023-05-27 00:00:00",
"useEndTime": "2023-06-16 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"couponStatus": true,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 17:47:50",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000158,
"couponName": "2223",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 1,
"couponTotal": 12,
"lastTotal": 12,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32",
"isFixedTime": 0,
"useStartTime": "2023-05-27 00:00:00",
"useEndTime": "2023-06-16 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": 1,
"couponStatus": true,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 17:47:50",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000156,
"couponName": "人党的飞飞",
"couponMoney": 12,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 3,
"couponTotal": 12,
"lastTotal": 0,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "31",
"isFixedTime": 0,
"useStartTime": "2023-05-26 00:00:00",
"useEndTime": "2023-06-22 23:59:59",
"couponDay": null,
"getType": 2,
"userTag": 1,
"couponStatus": true,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 17:05:52",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000155,
"couponName": "44444",
"couponMoney": 44,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 3,
"couponTotal": 44,
"lastTotal": 44,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32,24",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-19 23:59:59",
"couponDay": null,
"getType": 1,
"userTag": null,
"couponStatus": true,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 17:01:11",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000153,
"couponName": "列表优惠券测试小嗯嗯",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": null,
"couponTotal": 3,
"lastTotal": 3,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32,26",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-21 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"couponStatus": false,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 17:00:06",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000154,
"couponName": "列表优惠券测试小嗯嗯",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 1,
"couponTotal": 33,
"lastTotal": 33,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-21 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": 1,
"couponStatus": false,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 17:00:06",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000152,
"couponName": "444",
"couponMoney": 444,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 2,
"couponTotal": 444,
"lastTotal": 444,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-22 23:59:59",
"couponDay": null,
"getType": 2,
"userTag": 1,
"couponStatus": false,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 16:57:44",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000151,
"couponName": "iii",
"couponMoney": 12,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 2,
"couponTotal": 12,
"lastTotal": 12,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-20 23:59:59",
"couponDay": null,
"getType": 1,
"userTag": null,
"couponStatus": false,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 16:53:16",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000150,
"couponName": "333",
"couponMoney": 33,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 2,
"couponTotal": 33,
"lastTotal": 33,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32,31",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-20 23:59:59",
"couponDay": null,
"getType": 2,
"userTag": 1,
"couponStatus": false,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-05-24 16:46:32",
"updateTime": null,
"fileUrl": null
},
{
"id": 10000148,
"couponName": "裂变优惠券测试",
"couponMoney": 1000,
"couponDiscount": 9,
"isLimited": true,
"restrictedAccess": null,
"couponTotal": 3,
"lastTotal": 3,
"couponType": 1,
"useType": 2,
"minPrice": 4000,
"primaryKey": "31",
"isFixedTime": 0,
"useStartTime": "2023-04-23 00:00:00",
"useEndTime": "2023-04-30 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"couponStatus": false,
"isDel": false,
"preferentialLimit": null,
"verificationType": false,
"createTime": "2023-04-23 16:10:18",
"updateTime": null,
"fileUrl": null
}
])
const res = await CouponManageAPI.CouponPageList({
useType,
pageNo: pagination.current,
pageSize: pagination.pageSize,
...value,
...query,
});
if (res && res.code === "200") {
const { list, pageNo, totalCount, pageSize, totalPage } = res.result; // 解构
// console.log("getTableList --->", list);
setPagination({
total: totalCount,
current: pageNo,
pageSize,
totalPage,
});
setTableData(list);
} else {
message.warning(res.message);
// 递归遍历一个数组
}
};
// 翻页
const paginationChange = (pageNo: number, pageSize: number) => {
getTableList({ pageNo, pageSize }).then();
};
// 表单提交
const onFinish = (data: any) => {
const obj = {
...data,
startTime: data.effectTime && data.effectTime[0],
endTime: data.effectTime && data.effectTime[1],
};
// console.log(data.effectTime);
pagination.current = 1;
query = obj;
getTableList(obj).then();
};
// +++++++++++++++++++++++++++++++++++++++++++++++++++ //
// 切换表格的数据
const handleChange = async ({ target: { value } }: RadioChangeEvent) => {
setUseType(value);
setPagination({
total: 0,
pageSize: 10,
current: 1,
totalPage: 0,
});
await getTableList();
};
// 结束优惠券
const handleEnd = (record: TableType[0]) => {
confirm({
title: "提示",
content: "确认结束后,将停止发放该券,已领的优惠券可继续使用",
onOk: async () => {
const res = await CouponManageAPI.CouponShutDown({
id: record.id,
});
if (res && res.code === "200") {
message.success("操作成功").then();
paginationChange(pagination.current, pagination.pageSize);
}
// console.log("删除成功 --->", record);
},
});
};
// 一键关闭全部弹窗
const handleCloseAll = () => {
setIncreaseVisible(false);
setDataVisible(false);
setRecordData(undefined);
// 刷新当前页面
paginationChange(pagination.current, pagination.pageSize);
};
// 查看详情
const handleAdd = (record?: TableType[0]) => {
if (record?.id) {
history({
pathname: "/couponManage/couponList/detail",
search: `id=${record?.id}&type=${useType}`,
})
// history.push({
// pathname: "/couponManage/couponList/detail",
// search: `id=${record?.id}&type=${useType}`,
// });
} else {
history({
pathname: "/couponManage/couponList/detail",
search: `type=${useType}`,
});
// history.push({
// pathname: "/couponManage/couponList/detail",
// search: `type=${useType}`,
// });
}
// console.log("handleAdd -->", type, record);
};
// 表格结构
const columns: ColumnsType<TableType[0]> = [
{
title: "优惠券ID",
dataIndex: "id",
align: "center",
},
{
title: "优惠券名称",
dataIndex: "couponName",
align: "center",
},
{
title: "满减规则",
align: "center",
render: (value, record) => {
if (record.couponType === 1)
return `${record.couponDiscount}${
couponType.find((i) => i.value === record.couponType)?.label
}`;
if (record.couponType === 2)
return `${record.minPrice}元减${record.couponMoney}`;
if (record.couponType === 3)
return `${record.couponMoney}${
couponType.find((i) => i.value === record.couponType)?.label
}`;
},
},
{
title: "有效期",
align: "center",
width: 280,
render: (value, record) => {
if (record.isFixedTime === 0)
return `${record.useStartTime} ${record.useEndTime}`;
if (record.isFixedTime === 1)
return `领取成功后${record.couponDay}天内可用`;
if (record.isFixedTime === 2)
return `领取成功后次日${record.couponDay}天内可用`;
},
},
{
title: "状态",
align: "center",
render: (value, record) => {
if (!record.couponStatus) return "已结束";
if (record.couponDay) return "领取中";
// const after = moment(record.useStartTime).isAfter(moment());
const before = moment(record.useEndTime).isBefore(moment());
// if (after) return "未开始";
if (before) return "已过期";
return "领取中";
},
},
{
title: "限领",
dataIndex: "restrictedAccess",
align: "center",
},
{
title: "剩余/发行量",
dataIndex: "proportion",
align: "center",
render: (value, record, index) =>
record.isLimited
? `${record.lastTotal}/${record.couponTotal}`
: "不限量",
},
// {
// title: "使用量",
// dataIndex: "proportion",
// align: "center",
// render: (value, record, index) =>
// record.isLimited
// ? Math.floor(record.couponTotal - record.lastTotal)
// : "不限量",
// },
{
title: "创建时间",
dataIndex: "createTime",
align: "center",
},
{
title: "操作",
align: "center",
fixed: "right",
width: "180px",
render: (value, record, index) => {
const disabled =
moment(record.useEndTime).isBefore(moment()) ||
record.isDel ||
!record.couponStatus;
return (
<div className="table-body-action">
<Button
type="link"
onClick={() => handleAdd(record)}
disabled={!isLookCouponBtn}
>
查看
</Button>
<Button
type="link"
onClick={() => {
setRecordData(JSON.parse(JSON.stringify(record)));
setIncreaseVisible(true);
}}
disabled={disabled || !isAddIssueCouponBtn || !record.isLimited}
>
增发
</Button>
<Button
type="link"
onClick={() => {
setRecordData(JSON.parse(JSON.stringify(record)));
setDataVisible(true);
}}
disabled={!isDataCouponBtn}
>
数据
</Button>
<Button
type="link"
onClick={() => handleEnd(record)}
disabled={disabled || !isEndCouponBtn}
>
结束
</Button>
</div>
);
},
},
];
useEffect(() => {
query = {};
(async () => {
await getTableList();
})();
}, []);
return (
<>
<SearchView
search={[
{
label: "规则状态",
name: "state",
type: "select",
placeholder: "请选择规则状态",
options: stateOptions,
},
{
label: "生效时间",
name: "effectTime",
type: "rangePicker",
placeholder: "请选择生效时间",
},
{
label: "优惠券ID",
name: "couponId",
type: "input",
placeholder: "请输入优惠券ID",
},
{
label: "优惠券名称",
name: "couponName",
type: "input",
placeholder: "请输入优惠券名称",
},
]}
searchData={onFinish}
sufFixBtn={
<>
<Button
icon={<PlusOutlined />}
type="primary"
onClick={() => {
handleAdd();
}}
// disabled={!isAddCouponBtn}
>
创建品牌券
</Button>
<Button icon={<PlusOutlined />} type="primary" disabled>
创建商品券
</Button>
<Button icon={<PlusOutlined />} type="primary" disabled>
创建店铺券
</Button>
</>
}
/>
<TableBox>
<Radio.Group
onChange={handleChange}
value={useType}
options={[
// { label: "VIP券", value: 1 },
{ label: "品牌优惠券", value: 2 },
{ label: "商品优惠券", value: 3, disabled: true },
{ label: "店铺优惠券", value: 4, disabled: true },
{ label: "数据概览", value: 5, disabled: true },
]}
optionType="button"
style={{ marginBottom: "10px" }}
/>
<Table
size="small"
dataSource={tableData}
columns={columns}
rowKey="id"
scroll={{ x: 1500 }}
bordered
pagination={{
total: pagination.total,
pageSize: pagination.pageSize,
current: pagination.current,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) =>
paginationChange(page, pageSize),
showTotal: (total, range) =>
`当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
</TableBox>
<IncreaseModal
open={increaseVisible}
title="增发优惠券"
data={recordData}
closed={handleCloseAll}
/>
<DataModal
open={dataVisible}
title="优惠券使用数据"
data={recordData}
closed={handleCloseAll}
/>
</>
);
};
import { FC, forwardRef, useImperativeHandle } from "react";
import "./index.scss";
import { Form, Input } from "antd";
import { baseInfoType } from "~/api/interface/couponManage";
interface selfPops {
ref: any;
isDetail: boolean;
}
const BaseInfo: FC<selfPops> = forwardRef(({ isDetail }, ref) => {
const [baseInfoForm] = Form.useForm<baseInfoType>();
useImperativeHandle(ref, () => ({
getForm: () => baseInfoForm,
}));
return (
<div className="split-coupon-base-info">
<div className="title">基本信息</div>
<div className="base-info-form">
<Form
labelCol={{ span: 2 }}
wrapperCol={{ span: 5 }}
form={baseInfoForm}
disabled={isDetail}
>
<Form.Item
label="优惠券名称"
name="couponName"
rules={[{ required: true, message: "请输入优惠券名称" }]}
>
<Input placeholder="请输入优惠券名称" maxLength={10} />
</Form.Item>
</Form>
</div>
</div>
);
});
export default BaseInfo;
import { FC, forwardRef, useImperativeHandle, useState } from "react";
import { DatePicker, Form, Input, Radio, Select } from "antd";
import dayjs from "dayjs";
import { RangePickerProps } from "antd/es/date-picker";
import { shareCouponType } from "~/api/interface/couponManage";
import { MakeItemEntity } from "~/api/interface/makeManage";
import { splitCouponType, splitCouponUseType } from "~/utils/dictionary";
interface selfProps {
ref: any;
makeList: MakeItemEntity[];
isDetail: boolean;
}
const ShareCouponInfo: FC<selfProps> = forwardRef(
({ makeList, isDetail }, ref) => {
const [shareCouponForm] = Form.useForm<shareCouponType>();
// 优惠券类型
const [couponType, setCouponType] = useState<number>(3);
useImperativeHandle(ref, () => ({
getForm: () => shareCouponForm,
setCouponType: (type: number) => setCouponType(type),
}));
// 门槛类型选择
const couponTypeChange = (e: any) => {
shareCouponForm.setFieldValue(
"verificationType",
e.target.value === 3 ? 0 : undefined
);
setCouponType(e.target.value);
shareCouponForm.setFieldValue("minPrice", undefined);
};
// 表单规则
// 钱-基本校验
const moneyValidator = (value: string) => {
if (Number(value) < 0) {
return Promise.reject(new Error("金额不能为负值!"));
}
if (Number(value) > 99999.99) {
return Promise.reject(new Error("金额不能大于99999.99!"));
}
if (Number(value) < 0) {
return Promise.reject(new Error("金额不能为负值!"));
}
const reg = /^0\.([1-9]|\d[1-9])$|^[0-9]\d{0,8}\.\d{0,2}$|^[0-9]\d{0,8}$/;
if (!reg.test(value) && value) {
return Promise.reject(new Error("金额应为整数,小数且小数保留后两位"));
}
return Promise.resolve();
};
// 优惠金额是否超标
const isOverstep = () => {
const minPrice = shareCouponForm.getFieldValue("minPrice");
const discount = shareCouponForm.getFieldValue("couponDiscount");
const couponMoney = shareCouponForm.getFieldValue("couponMoney");
return (
minPrice &&
discount &&
couponMoney &&
Number(couponMoney) > Number(minPrice) * Number(discount) * 0.1
);
};
const couponMoneyValidator = async (rule: any, value: string) => {
if (!value) {
return Promise.reject(new Error("请输入优惠金额"));
}
const res: any = await moneyValidator(value);
if (res) {
return Promise.reject(res);
}
const minPrice = shareCouponForm.getFieldValue("minPrice");
if (couponType === 1) {
if (isOverstep()) {
return Promise.reject(
new Error("优惠金额超出最高优惠金额,请重新输入")
);
}
if (
shareCouponForm.getFieldValue("couponDiscount") &&
!shareCouponForm.isFieldValidating("couponDiscount")
) {
await shareCouponForm.validateFields(["couponDiscount"]);
}
}
if (couponType !== 3) {
if (minPrice && Number(minPrice) < Number(value)) {
return Promise.reject(new Error("优惠金额应小于减免券金额"));
}
if (minPrice && !shareCouponForm.isFieldValidating("minPrice")) {
await shareCouponForm.validateFields(["minPrice"]);
}
}
return Promise.resolve();
};
const minPriceValidator = async (rule: any, value: string) => {
if (!value) {
return Promise.reject(new Error("请输入满减金额"));
}
const res: any = await moneyValidator(value);
if (res) {
return Promise.reject(res);
}
const couponMoney = shareCouponForm.getFieldValue("couponMoney");
if (couponMoney && Number(couponMoney) > Number(value)) {
return Promise.reject(new Error("满减金额应大于优惠金额!"));
}
if (couponMoney && !shareCouponForm.isFieldValidating("couponMoney")) {
shareCouponForm.validateFields(["couponMoney"]).then().catch();
}
return Promise.resolve();
};
const discountValidator = (rule: any, value: string) => {
if (!value) {
return Promise.reject(new Error(`请输入折扣!`));
}
if (Number(value) <= 0) {
return Promise.reject(new Error("折扣不能小于等于0!"));
}
if (Number(value) >= 10) {
return Promise.reject(new Error("折扣应小于10"));
}
const reg = /^0\.([1-9]|\d[1-9])$|^[0-9]\d{0,8}\.\d{0,2}$|^[0-9]\d{0,8}$/;
if (!reg.test(value)) {
return Promise.reject(new Error("折扣应为整数,小数且小数保留后两位"));
}
if (isOverstep()) {
return Promise.reject(new Error("优惠金额超出最高优惠金额!"));
}
if (
shareCouponForm.getFieldValue("couponMoney") &&
!shareCouponForm.isFieldValidating("couponMoney")
) {
shareCouponForm.validateFields(["couponMoney"]).then().catch();
}
return Promise.resolve();
};
const negativeNumberValidator = (
rule: any,
value: string,
callback: (error?: string) => void,
label: string
) => {
if (!value) {
return Promise.reject(new Error(`请输入${label}!`));
}
const reg = /^[0-9]*$/;
if (!reg.test(value)) {
return Promise.reject(new Error(`${label}为正数!`));
}
switch (label) {
case "发行量":
if (Number(value) < 1 || Number(value) > 100000) {
return Promise.reject(new Error(`${label}至少1张且不超过10万`));
}
break;
case "限领数量":
if (Number(value) > 5) {
return Promise.reject(new Error(`${label}限领数量最大为5`));
}
break;
}
return Promise.resolve();
};
// 选择时间禁用
const disabledDate: RangePickerProps["disabledDate"] = (current) => {
// Can not select days before today
return current && current < dayjs().subtract(1, "day");
};
return (
<div className="share-coupon-info">
<div className="title">分享者优惠券</div>
<div className="share-coupon-form">
<Form
labelCol={{ span: 2 }}
wrapperCol={{ span: 5 }}
form={shareCouponForm}
initialValues={{ useType: 2, couponType: 3, verificationType: 0 }}
disabled={isDetail}
>
<Form.Item
label="券类型"
name="useType"
rules={[{ required: true, message: "请选择券类型" }]}
>
<Radio.Group>
{splitCouponUseType.map((v) => (
<Radio value={v.val} key={v.val} disabled={v.val !== 2}>
{v.label}
</Radio>
))}
</Radio.Group>
</Form.Item>
<Form.Item
label="品牌"
name="primaryKey"
rules={[{ required: true, message: "请选择品牌" }]}
>
<Select
placeholder="请选择品牌"
mode="multiple"
maxTagCount={50}
filterOption={(input, option) =>
(option!.children as unknown as string)
.toLowerCase()
.includes(input.toLowerCase())
}
>
{makeList.map((v) => (
<Select.Option value={v.id} key={v.id}>
{v.brandName}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label="有效期"
name="time"
rules={[{ required: true, message: "请选择有效期" }]}
>
<DatePicker.RangePicker disabledDate={disabledDate} />
</Form.Item>
<Form.Item
label="优惠金额"
name="couponMoney"
rules={[
{
required: true,
validator: couponMoneyValidator,
},
]}
>
<Input placeholder="请输入优惠券金额" suffix="元" />
</Form.Item>
<Form.Item
label="使用门槛"
name="couponType"
rules={[{ required: true, message: "请选择使用门槛" }]}
>
<Radio.Group onChange={couponTypeChange}>
{splitCouponType.map((v) => (
<Radio value={v.val} key={v.val}>
{v.label}
</Radio>
))}
</Radio.Group>
</Form.Item>
{couponType !== 3 && (
<Form.Item
label="满"
style={{ marginLeft: "30px" }}
name="minPrice"
rules={[
{
required: true,
validator: minPriceValidator,
},
]}
>
<Input placeholder="请输入金额" suffix="元" />
</Form.Item>
)}
{couponType === 1 && (
<>
<Form.Item
label="打"
style={{ marginLeft: "30px" }}
name="couponDiscount"
rules={[
{
required: true,
validator: discountValidator,
},
]}
>
<Input placeholder="请输入折扣" suffix="折" />
</Form.Item>
{/* <Form.Item */}
{/* label="最多优惠" */}
{/* style={{ marginLeft: "30px" }} */}
{/* name="preferentialLimit" */}
{/* rules={[ */}
{/* { */}
{/* required: true, */}
{/* validator: (rule, value, callback) => */}
{/* moneyValidator(rule, value, callback, "最多优惠"), */}
{/* }, */}
{/* ]} */}
{/* > */}
{/* <Input placeholder="请输入最多优惠" suffix="元" /> */}
{/* </Form.Item> */}
</>
)}
{couponType === 3 && (
<Form.Item
label="核销方式"
name="verificationType"
rules={[{ required: true, message: "请选择核销方式" }]}
>
<Radio.Group>
<Radio value={0}>单次核销</Radio>
<Radio value={1}>多次核销</Radio>
</Radio.Group>
</Form.Item>
)}
<Form.Item
label="发行量"
name="couponTotal"
rules={[
{
required: true,
validator: (rule, value, callback) =>
negativeNumberValidator(rule, value, callback, "发行量"),
},
]}
>
<Input placeholder="请输入发行量" suffix="张" />
</Form.Item>
{/* <Form.Item */}
{/* label="每人限领" */}
{/* name="restrictedAccess" */}
{/* rules={[ */}
{/* { */}
{/* required: true, */}
{/* validator: (rule, value, callback) => */}
{/* negativeNumberValidator(rule, value, callback, "限领数量"), */}
{/* }, */}
{/* ]} */}
{/* > */}
{/* <Input placeholder="请输入限领数量" suffix="张" /> */}
{/* </Form.Item> */}
<Form.Item
label="分享人数"
name="peopleNumber"
rules={[
{
required: true,
message: "请选择分享人数",
},
]}
>
<Select placeholder="请输入分享人数">
<Select value={2}>2人</Select>
<Select value={3}>3人</Select>
<Select value={5}>5人</Select>
</Select>
</Form.Item>
<Form.Item label="被分享用户标签" name="userTag">
<Select placeholder="请选择标签" allowClear>
<Select.Option value={1}>新人</Select.Option>
<Select.Option value={2}>实名认证</Select.Option>
<Select.Option value={3}>企业认证</Select.Option>
</Select>
</Form.Item>
</Form>
</div>
</div>
);
}
);
export default ShareCouponInfo;
import { FC, forwardRef, useImperativeHandle, useState } from "react";
import { Col, Form, Input, Radio, Row, Select } from "antd";
import { MakeItemEntity } from "~/api/interface/makeManage";
import { sharedCouponType } from "~/api/interface/couponManage";
import { splitCouponType, splitCouponUseType } from "~/utils/dictionary";
interface selfProps {
ref: any;
makeList: MakeItemEntity[];
shareCouponRef: any;
isDetail: boolean;
}
const SharedCouponInfo: FC<selfProps> = forwardRef(
({ makeList, shareCouponRef, isDetail }, ref) => {
const [sharedCouponForm] = Form.useForm<sharedCouponType>();
// 优惠券类型
const [couponType, setCouponType] = useState<number>(3);
useImperativeHandle(ref, () => ({
getForm: () => sharedCouponForm,
setCouponType: (type: number) => setCouponType(type),
}));
// 门槛类型选择
const couponTypeChange = (e: any) => {
sharedCouponForm.setFieldValue(
"beSharedVerificationType",
e.target.value === 3 ? 0 : undefined
);
sharedCouponForm.setFieldValue("beSharedMinPrice", undefined);
setCouponType(e.target.value);
};
// 获取被分享者最低发行量
const getMinBeSharedCouponTotal = (): number => {
const shareCouponRefObj = shareCouponRef.current;
const couponTotal = shareCouponRefObj
.getForm()
.getFieldValue("couponTotal");
const peopleNumber = shareCouponRefObj
.getForm()
.getFieldValue("peopleNumber");
return (
(couponTotal &&
peopleNumber &&
Number(couponTotal) * Number(peopleNumber) * 1.5) ||
0
);
};
// 表单规则
// 钱-基本校验
const moneyValidator = (value: string) => {
if (Number(value) < 0) {
return Promise.reject(new Error("金额不能为负值!"));
}
if (Number(value) > 99999.99) {
return Promise.reject(new Error("金额不能大于99999.99!"));
}
if (Number(value) < 0) {
return Promise.reject(new Error("金额不能为负值!"));
}
const reg = /^0\.([1-9]|\d[1-9])$|^[0-9]\d{0,8}\.\d{0,2}$|^[0-9]\d{0,8}$/;
if (!reg.test(value) && value) {
return Promise.reject(new Error("金额应为整数,小数且小数保留后两位"));
}
return Promise.resolve();
};
// 优惠金额是否超标
const isOverstep = () => {
const minPrice = sharedCouponForm.getFieldValue("beSharedMinPrice");
const discount = sharedCouponForm.getFieldValue("beSharedCouponDiscount");
const couponMoney = sharedCouponForm.getFieldValue("beSharedCouponMoney");
return (
minPrice &&
discount &&
couponMoney &&
Number(couponMoney) > Number(minPrice) * Number(discount) * 0.1
);
};
const couponMoneyValidator = async (rule: any, value: string) => {
if (!value) {
return Promise.reject(new Error("请输入优惠金额"));
}
const res: any = await moneyValidator(value);
if (res) {
return Promise.reject(res);
}
const minPrice = sharedCouponForm.getFieldValue("beSharedMinPrice");
if (couponType === 1) {
if (isOverstep()) {
return Promise.reject(
new Error("优惠金额超出最高优惠金额,请重新输入")
);
}
if (
sharedCouponForm.getFieldValue("beSharedCouponDiscount") &&
!sharedCouponForm.isFieldValidating("beSharedCouponDiscount")
) {
await sharedCouponForm.validateFields(["beSharedCouponDiscount"]);
}
}
if (couponType !== 3) {
if (minPrice && Number(minPrice) < Number(value)) {
return Promise.reject(new Error("优惠金额应小于减免券金额"));
}
if (
minPrice &&
!sharedCouponForm.isFieldValidating("beSharedMinPrice")
) {
await sharedCouponForm.validateFields(["minPrice"]);
}
}
return Promise.resolve();
};
const minPriceValidator = async (rule: any, value: string) => {
if (!value) {
return Promise.reject(new Error("请输入满减金额"));
}
const res: any = await moneyValidator(value);
if (res) {
return Promise.reject(res);
}
const couponMoney = sharedCouponForm.getFieldValue("beSharedCouponMoney");
if (couponMoney && Number(couponMoney) > Number(value)) {
return Promise.reject(new Error("满减金额应大于优惠金额!"));
}
if (
couponMoney &&
!sharedCouponForm.isFieldValidating("beSharedCouponMoney")
) {
sharedCouponForm.validateFields(["couponMoney"]).then().catch();
}
return Promise.resolve();
};
const discountValidator = (rule: any, value: string) => {
if (value === "") {
return Promise.reject(new Error(`请输入折扣!`));
}
if (Number(value) <= 0) {
return Promise.reject(new Error("折扣不能小于等于0!"));
}
if (Number(value) >= 10) {
return Promise.reject(new Error("折扣应小于10"));
}
const reg = /^0\.([1-9]|\d[1-9])$|^[0-9]\d{0,8}\.\d{0,2}$|^[0-9]\d{0,8}$/;
if (!reg.test(value)) {
return Promise.reject(new Error("折扣应为整数,小数且小数保留后两位"));
}
if (isOverstep()) {
return Promise.reject(new Error("优惠金额超出最高优惠金额!"));
}
if (
sharedCouponForm.getFieldValue("beSharedCouponMoney") &&
!sharedCouponForm.isFieldValidating("beSharedCouponMoney")
) {
sharedCouponForm.validateFields(["beSharedCouponMoney"]).then().catch();
}
return Promise.resolve();
};
const beSharedCouponTotalValidator = (rule: any, value: string) => {
if (!value) {
return Promise.reject(new Error(`请输入被分享者优惠券发行量`));
}
const reg = /^[0-9]*$/;
if (!reg.test(value)) {
return Promise.reject(new Error(`被分享者优惠券发行量为正数!`));
}
if (Number(value) < getMinBeSharedCouponTotal()) {
return Promise.reject(
new Error("被分享者券发行量大于等于分享者券发行量*分享人数*1.5")
);
}
return Promise.resolve();
};
return (
<div className="shared-coupon-info">
<div className="title">被分享者优惠券</div>
<div className="shared-coupon-form">
<Form
labelCol={{ span: 2 }}
wrapperCol={{ span: 5 }}
form={sharedCouponForm}
initialValues={{
beSharedUseType: 2,
beSharedCouponType: 3,
beSharedVerificationType: 0,
}}
disabled={isDetail}
>
<Form.Item
label="券类型"
name="beSharedUseType"
rules={[{ required: true, message: "请选择券类型" }]}
>
<Radio.Group>
{splitCouponUseType.map((v) => (
<Radio value={v.val} key={v.val} disabled={v.val !== 2}>
{v.label}
</Radio>
))}
</Radio.Group>
</Form.Item>
<Form.Item
label="品牌"
name="beSharedPrimaryKey"
rules={[{ required: true, message: "请选择品牌" }]}
>
<Select
placeholder="请选择品牌"
mode="multiple"
maxTagCount={50}
filterOption={(input, option) =>
(option!.children as unknown as string)
.toLowerCase()
.includes(input.toLowerCase())
}
>
{makeList.map((v) => (
<Select.Option value={v.id} key={v.id}>
{v.brandName}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label="优惠金额"
name="beSharedCouponMoney"
rules={[
{
required: true,
validator: couponMoneyValidator,
},
]}
>
<Input placeholder="请输入优惠券金额" suffix="元" />
</Form.Item>
<Form.Item
label="使用门槛"
name="beSharedCouponType"
rules={[{ required: true, message: "请选择使用门槛" }]}
>
<Radio.Group onChange={couponTypeChange}>
{splitCouponType.map((v) => (
<Radio value={v.val} key={v.val}>
{v.label}
</Radio>
))}
</Radio.Group>
</Form.Item>
{couponType !== 3 && (
<Form.Item
label="满"
style={{ marginLeft: "30px" }}
name="beSharedMinPrice"
rules={[
{
required: true,
validator: minPriceValidator,
},
]}
>
<Input placeholder="请输入金额" suffix="元" />
</Form.Item>
)}
{couponType === 1 && (
<Form.Item
label="打"
style={{ marginLeft: "30px" }}
name="beSharedCouponDiscount"
rules={[
{
required: true,
validator: discountValidator,
},
]}
>
<Input placeholder="请输入折扣" suffix="折" />
</Form.Item>
)}
{/* <Form.Item */}
{/* label="最多优惠" */}
{/* style={{ marginLeft: "30px" }} */}
{/* name="beSharedPreferentialLimit" */}
{/* rules={[ */}
{/* { */}
{/* required: false, */}
{/* validator: (rule, value, callback) => */}
{/* moneyValidator(rule, value, callback, "最多优惠"), */}
{/* }, */}
{/* ]} */}
{/* > */}
{/* <Input placeholder="请输入最多优惠" suffix="元" /> */}
{/* </Form.Item> */}
{couponType === 3 && (
<Form.Item
label="核销方式"
name="beSharedVerificationType"
rules={[{ required: true, message: "请选择核销方式" }]}
>
<Radio.Group>
<Radio value={0}>单次核销</Radio>
<Radio value={1}>多次核销</Radio>
</Radio.Group>
</Form.Item>
)}
<Form.Item
label="发行量"
name="beSharedCouponTotal"
rules={[
{
required: true,
validator: beSharedCouponTotalValidator,
},
]}
>
<Input placeholder="请输入发行量" suffix="张" />
</Form.Item>
<Row>
<Col span={2} />
<Col span={22} style={{ color: "#1677ff" }}>
被分享者券发行量大于等于分享者券发行量*分享人数*1.5
</Col>
</Row>
<Form.Item label="每人限领">1张</Form.Item>
</Form>
</div>
</div>
);
}
);
export default SharedCouponInfo;
.add-or-edit-or-detail-wrap{
min-width: 1200px;
height: 100%;
position: relative;
.add-or-edit-or-detail{
height: calc(100% - 50px);
overflow-y: auto;
.split-coupon-base-info,.share-coupon-info,.shared-coupon-info{
padding: 10px;
background-color: #fff;
margin-bottom: 20px;
.title{
font-size: 20px;
font-weight: bold;
color: #000;
margin-bottom: 10px;
}
}
.ant-form-item{
margin-bottom: 10px;
}
}
.footer-operate{
position: absolute;
bottom: -15px;
left: -10px;
height: 80px;
width: calc(100% + 20px) ;
background-color: #fff;
box-shadow: 0 -1px 2px 0 rgba(0,0,0,0.1);
display: flex;
align-items: center;
justify-content: center;
button{
width: 100px;
}
button:first-child{
margin-right: 150px;
}
}
}
import { FC, useEffect, useRef, useState } from "react";
import "./index.scss";
import { Button, message } from "antd";
import { useNavigate } from "react-router-dom";
import dayJs from "dayjs";
import qs from "query-string";
import BaseInfo from "./components/baseInfo";
import ShareCouponInfo from "./components/shareCouponInfo";
import SharedCouponInfo from "./components/sharedCouponInfo";
import { MakeManageAPI } from "~/api/modules/makeManage";
import { MakeItemEntity } from "~/api/interface/makeManage";
import { CouponManageAPI } from "~/api";
const SplitCouponOperate: FC<any> = (props) => {
const history = useNavigate();
const baseInfoRef = useRef<any>();
const shareCouponRef = useRef<any>();
const sharedCouponRef = useRef<any>();
// 品牌列表数据
const [makeList, setMakeList] = useState<MakeItemEntity[]>([]);
// 品牌-列表
const getMakeList = () => {
MakeManageAPI.getListBrandInfo({ pageNo: 1, pageSize: 999999 }).then(
({ result }) => {
setMakeList(result.list || []);
}
);
};
const [splitCouponId, setSplitCouponId] = useState<string>("");
// 详情
const getSplitCouponDetail = (couponId: string) => {
CouponManageAPI.getPageActivityList({
couponId,
pageNo: 1,
pageSize: 10,
useType: 2,
}).then(({ result }) => {
if (result.list[0]) {
(shareCouponRef.current as any).setCouponType(
result.list[0].couponType
);
const { beSharedCoupon } = result.list[0];
(sharedCouponRef.current as any).setCouponType(
beSharedCoupon.couponType
);
(baseInfoRef.current as any).getForm().setFieldsValue({
couponName: result.list[0].couponName,
});
(shareCouponRef.current as any).getForm().setFieldsValue({
primaryKey: (result.list[0].primaryKey as any).split(",").map(Number),
time: [
dayJs(result.list[0].useStartTime),
dayJs(result.list[0].useEndTime),
],
couponMoney: result.list[0].couponMoney,
couponType: result.list[0].couponType,
minPrice: result.list[0].minPrice || undefined,
couponDiscount: result.list[0].couponDiscount || undefined,
verificationType: result.list[0].verificationType ? 1 : 0,
couponTotal: result.list[0].couponTotal,
restrictedAccess: result.list[0].restrictedAccess,
peopleNumber: result.list[0].peopleNumber,
userTag: beSharedCoupon.userTag || undefined,
});
(sharedCouponRef.current as any).getForm().setFieldsValue({
beSharedPrimaryKey: (beSharedCoupon.primaryKey as any)
.split(",")
.map(Number),
beSharedCouponMoney: beSharedCoupon.couponMoney,
beSharedCouponType: beSharedCoupon.couponType,
beSharedMinPrice: beSharedCoupon.minPrice || undefined,
beSharedCouponDiscount: beSharedCoupon.couponDiscount || undefined,
beSharedVerificationType: beSharedCoupon.verificationType ? 1 : 0,
beSharedCouponTotal: beSharedCoupon.couponTotal,
});
}
});
};
const addSplitCouponSubmit = () => {
const { getForm: getBaseInfoForm } = baseInfoRef.current;
const { getForm: getShareCouponForm } = shareCouponRef.current;
const { getForm: getSharedCouponForm } = sharedCouponRef.current;
Promise.all([
getBaseInfoForm().validateFields(),
getShareCouponForm().validateFields(),
getSharedCouponForm().validateFields(),
])
.then((values) => {
values[1].useStartTime = `${dayJs(values[1].time[0]).format(
"YYYY-MM-DD"
)} 00:00:00`;
values[1].useEndTime = `${dayJs(values[1].time[1]).format(
"YYYY-MM-DD"
)} 23:59:59`;
values[1].primaryKey = values[1].primaryKey.join(",");
values[2].beSharedPrimaryKey = values[2].beSharedPrimaryKey.join(",");
delete values[1].time;
CouponManageAPI.saveActivity({
...values[0],
...values[1],
...values[2],
}).then(({ code, message: msg }) => {
if (code === "200") {
message.success("新增成功");
getBaseInfoForm().resetFields();
getShareCouponForm().resetFields();
getSharedCouponForm().resetFields();
backRoute();
} else {
message.error(msg);
}
});
})
.catch((error) => {
message.error(error.errorFields[0].errors[0]);
});
};
// 返回
const backRoute = () => {
history(-1);
};
useEffect(() => {
getMakeList();
if (props.location) {
const { id: splitCouponId }: any = qs.parse(props.location.search);
setSplitCouponId(splitCouponId);
if (splitCouponId) {
getSplitCouponDetail(splitCouponId);
}
}
}, []);
return (
<div className="add-or-edit-or-detail-wrap">
<div className="add-or-edit-or-detail">
{/* 基本信息 */}
<BaseInfo ref={baseInfoRef} isDetail={!!splitCouponId} />
{/* 分享者优惠券 */}
<ShareCouponInfo
ref={shareCouponRef}
makeList={makeList}
isDetail={!!splitCouponId}
/>
{/* 被分享者优惠券 */}
<SharedCouponInfo
ref={sharedCouponRef}
makeList={makeList}
shareCouponRef={shareCouponRef}
isDetail={!!splitCouponId}
/>
</div>
<div className="footer-operate">
<Button onClick={backRoute}>返回</Button>
{!splitCouponId && (
<Button type="primary" onClick={addSplitCouponSubmit}>
确定
</Button>
)}
</div>
</div>
);
};
export default SplitCouponOperate;
.split-coupon-list{
.ant-table-thead > tr > th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan])::before{
width: 0;
}
.ant-table-tbody > tr{
border-bottom: 1px solid #999;
}
}
import { FC, useEffect, useState } from "react";
import { Button, Table, Modal, message } from "antd";
import { PlusOutlined } from "@ant-design/icons";
import { ColumnsType } from "antd/es/table";
import { useNavigate } from "react-router-dom";
import qs from "query-string";
import SearchBox, { searchColumns } from "~/components/search-box";
import { PaginationEntity } from "~/common/interface/PaginationEntity";
import {
SplitCouponItemType,
SplitCouponSearchType,
} from "~/api/interface/couponManage";
import { CouponManageAPI } from "~/api";
import { splitCouponType, splitCouponUseType } from "~/utils/dictionary";
import { DataModal } from "~/pages/couponManage/couponList/comp/dataModal";
import useOperate from "~/common/hook/optionHook";
import "./index.scss";
const SplitCouponList: FC = () => {
const history = useNavigate();
const searchData: searchColumns[] = [
{
type: "input",
placeholder: "请输入优惠券ID",
label: "ID",
name: "couponId",
},
{
type: "input",
placeholder: "请输入优惠券名称",
label: "名称",
name: "couponName",
},
// {
// type: "input",
// placeholder: "请输入面额",
// label: "面额",
// name: "",
// },
{
type: "select",
placeholder: "请选中状态",
name: "state",
label: "状态",
options: [
{
id: 0,
name: "已结束",
},
{
id: 1,
name: "领取中",
},
],
},
{
type: "rangePicker",
placeholder: "",
label: "日期",
name: "time",
},
];
const tableColumns: ColumnsType<SplitCouponItemType> = [
{
title: "优惠券ID",
align: "center",
dataIndex: "id",
onCell: (record: SplitCouponItemType, rowIndex: any) => ({
rowSpan: rowIndex % 2 ? 0 : 2,
}),
},
{
title: "优惠券名称",
align: "center",
dataIndex: "couponName",
},
{
title: "角色",
align: "center",
dataIndex: "activityRole",
render: (text: string, record: SplitCouponItemType) => (
<div>{record.activityRole === "share" ? "分享者" : "被分享者"}</div>
),
},
{
title: "状态",
align: "center",
dataIndex: "couponStatus",
render: (text: string, record: SplitCouponItemType) => (
<div>{record.couponStatus ? "领取中" : "已结束"}</div>
),
},
{
title: "面额",
align: "center",
dataIndex: "couponMoney",
render: (text: string, record: SplitCouponItemType) => (
<div className="table-self-cell">
<div>{record.couponMoney.toLocaleString()}</div>
</div>
),
},
{
title: "门槛",
align: "center",
dataIndex: "couponType",
render: (text: string, record: SplitCouponItemType) => (
<div>{getCouponTypeById(record.couponType)}</div>
),
},
{
title: "券类型",
align: "center",
dataIndex: "useType",
render: (text: string, record: SplitCouponItemType) => (
<div>{getCouponUseTypeById(record.useType)}</div>
),
},
{
title: "有效期",
align: "center",
width: "15%",
render: (text: string, record: SplitCouponItemType) => (
<div>
<div>起:{record.useStartTime}</div>
<div>止:{record.useEndTime}</div>
</div>
),
},
// {
// title: "限领",
// align: "center",
// dataIndex: "restrictedAccess",
// render: (text: string, record: SplitCouponItemType) => (
// <div>{record.restrictedAccess}</div>
// ),
// },
{
title: "发行量",
align: "center",
dataIndex: "couponTotal",
render: (text: string, record: SplitCouponItemType) => (
<div>{record.couponTotal}</div>
),
},
{
title: "已领取",
align: "center",
dataIndex: "amountReceived",
render: (text: string, record: SplitCouponItemType) => (
<div>{record.amountReceived}</div>
),
},
{
title: "操作",
align: "center",
render: (text: string, record: SplitCouponItemType, index: number) => (
<>
<Button
type="link"
onClick={() =>
toAddOrDetailSplitCoupon(
record.activityRole === "share"
? record
: tableDataSource[index - 1]
)
}
disabled={!isLookBtn}
>
查看
</Button>
<Button
type="link"
onClick={() => showDataModalClick(record)}
disabled={!isDataBtn}
>
数据
</Button>
<Button
type="link"
onClick={() =>
endSplitCoupon(
record.activityRole === "share"
? record
: tableDataSource[index - 1]
)
}
disabled={!record.couponStatus || !isEndBtn}
>
结束
</Button>
</>
),
// onCell: (record: SplitCouponItemType, rowIndex: any) => ({
// rowSpan: rowIndex % 2 ? 0 : 2,
// }),
},
];
const [tableDataSource, setTableDataSource] = useState<SplitCouponItemType[]>(
[]
);
const [queryData, setQueryData] = useState<SplitCouponSearchType>({
useType: 2,
});
const [pagination, setPagination] = useState<PaginationEntity>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const [loading, setLoading] = useState<boolean>(false);
const [splitCouponItem, setSplitCouponItem] = useState<SplitCouponItemType>();
const [dataModalShow, setDataModalShow] = useState<boolean>(false);
// 按钮权限
const isAddBtn = useOperate(26201);
const isLookBtn = useOperate(26202);
const isDataBtn = useOperate(26203);
const isEndBtn = useOperate(26204);
const searchSubmitEvent = (data: any) => {
const query = {
...data,
startTime: (data.time && data.time[0]) || undefined,
endTime: (data.time && data.time[1]) || undefined,
useType: 2,
state: data.state === undefined ? "" : !!data.state,
};
delete query.time;
setQueryData(query);
pagination.pageNo = 1;
pagination.pageSize = 10;
getSplitCoupon({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
});
};
// get split coupon
const getSplitCoupon = (
data: SplitCouponSearchType & Pick<PaginationEntity, "pageSize" | "pageNo">
) => {
// setLoading(true);
setTableDataSource([
{
"id": 10000157,
"couponName": "2223",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": null,
"couponTotal": 13,
"lastTotal": 13,
"amountReceived": 0,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32,31",
"isFixedTime": 0,
"useStartTime": "2023-05-27 00:00:00",
"useEndTime": "2023-06-16 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"verificationType": false,
"createTime": "2023-05-24 17:47:50",
"updateTime": null,
"couponStatus": true,
"parentId": null,
"peopleNumber": 2,
"activityRole": "share",
"beSharedCoupon": {
"id": 10000158,
"couponName": "2223",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 1,
"couponTotal": 12,
"lastTotal": 12,
"amountReceived": 0,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32",
"isFixedTime": 0,
"useStartTime": "2023-05-27 00:00:00",
"useEndTime": "2023-06-16 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": 1,
"verificationType": false,
"createTime": "2023-05-24 17:47:50",
"updateTime": null,
"couponStatus": true,
"parentId": 10000157,
"peopleNumber": null,
"activityRole": "beShare",
"beSharedCoupon": null
}
},
{
"id": 10000153,
"couponName": "列表优惠券测试小嗯嗯",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": null,
"couponTotal": 3,
"lastTotal": 3,
"amountReceived": 0,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32,26",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-21 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"verificationType": false,
"createTime": "2023-05-24 17:00:06",
"updateTime": null,
"couponStatus": false,
"parentId": null,
"peopleNumber": 2,
"activityRole": "share",
"beSharedCoupon": {
"id": 10000154,
"couponName": "列表优惠券测试小嗯嗯",
"couponMoney": 22,
"couponDiscount": null,
"isLimited": true,
"restrictedAccess": 1,
"couponTotal": 33,
"lastTotal": 33,
"amountReceived": 0,
"couponType": 3,
"useType": 2,
"minPrice": null,
"primaryKey": "32",
"isFixedTime": 0,
"useStartTime": "2023-05-24 00:00:00",
"useEndTime": "2023-06-21 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": 1,
"verificationType": false,
"createTime": "2023-05-24 17:00:06",
"updateTime": null,
"couponStatus": false,
"parentId": 10000153,
"peopleNumber": null,
"activityRole": "beShare",
"beSharedCoupon": null
}
},
{
"id": 10000148,
"couponName": "裂变优惠券测试",
"couponMoney": 1000,
"couponDiscount": 9,
"isLimited": true,
"restrictedAccess": null,
"couponTotal": 3,
"lastTotal": 3,
"amountReceived": 0,
"couponType": 1,
"useType": 2,
"minPrice": 4000,
"primaryKey": "31",
"isFixedTime": 0,
"useStartTime": "2023-04-23 00:00:00",
"useEndTime": "2023-04-30 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"verificationType": false,
"createTime": "2023-04-23 16:10:18",
"updateTime": null,
"couponStatus": false,
"parentId": null,
"peopleNumber": 2,
"activityRole": "share",
"beSharedCoupon": {
"id": 10000149,
"couponName": "裂变优惠券测试",
"couponMoney": 1000,
"couponDiscount": 9,
"isLimited": true,
"restrictedAccess": 1,
"couponTotal": 9,
"lastTotal": 8,
"amountReceived": 1,
"couponType": 1,
"useType": 2,
"minPrice": 4000,
"primaryKey": "31",
"isFixedTime": 0,
"useStartTime": "2023-04-23 00:00:00",
"useEndTime": "2023-04-30 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": 1,
"verificationType": false,
"createTime": "2023-04-23 16:10:18",
"updateTime": null,
"couponStatus": false,
"parentId": 10000148,
"peopleNumber": null,
"activityRole": "beShare",
"beSharedCoupon": null
}
},
{
"id": 10000141,
"couponName": "测试裂变",
"couponMoney": 800,
"couponDiscount": 8,
"isLimited": false,
"restrictedAccess": null,
"couponTotal": 10,
"lastTotal": 11,
"amountReceived": -1,
"couponType": 1,
"useType": 2,
"minPrice": 10000,
"primaryKey": "31",
"isFixedTime": 0,
"useStartTime": "2023-04-19 00:00:00",
"useEndTime": "2023-04-19 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"verificationType": false,
"createTime": "2023-04-19 13:46:06",
"updateTime": null,
"couponStatus": false,
"parentId": null,
"peopleNumber": 2,
"activityRole": "share",
"beSharedCoupon": {
"id": 10000142,
"couponName": "测试裂变",
"couponMoney": 500,
"couponDiscount": 9,
"isLimited": true,
"restrictedAccess": 1,
"couponTotal": 100,
"lastTotal": 97,
"amountReceived": 3,
"couponType": 1,
"useType": 2,
"minPrice": 10000,
"primaryKey": "31",
"isFixedTime": 0,
"useStartTime": "2023-04-19 00:00:00",
"useEndTime": "2023-04-19 23:59:59",
"couponDay": null,
"getType": 4,
"userTag": null,
"verificationType": false,
"createTime": "2023-04-19 13:46:06",
"updateTime": null,
"couponStatus": false,
"parentId": 10000141,
"peopleNumber": null,
"activityRole": "beShare",
"beSharedCoupon": null
}
}
])
CouponManageAPI.getPageActivityList(data).then(({ result }) => {
if (result.list) {
const couponList = result.list.reduce(
(pre: SplitCouponItemType[], cur: SplitCouponItemType) => {
pre.push(cur);
if (cur.beSharedCoupon) {
pre.push(cur.beSharedCoupon);
}
return pre;
},
[]
);
setLoading(false);
setTableDataSource(couponList);
pagination.pageSize = data.pageSize;
pagination.pageNo = data.pageNo;
pagination.totalCount = result.totalCount;
setPagination({ ...pagination });
}
});
};
// 分页监听
const paginationChange = (pageNo: number, pageSize: number) => {
getSplitCoupon({ ...queryData, pageNo, pageSize: pageSize / 2 });
};
// 新建
const toAddOrDetailSplitCoupon = (record?: SplitCouponItemType) => {
history({
pathname: "/couponManage/addOrEditOrDetail",
search: record
? qs.stringify({
id: record.id,
})
: "",
});
};
const getCouponTypeById = (id: number) => {
return splitCouponType.find((v) => v.val === id)?.label || "";
};
const getCouponUseTypeById = (id: number) => {
return splitCouponUseType.find((v) => v.val === id)?.label || "";
};
// 裂变优惠券数据
const dataModalClose = () => {
setDataModalShow(false);
};
const showDataModalClick = (record: SplitCouponItemType) => {
setSplitCouponItem(record);
setDataModalShow(true);
};
// 结束
const endSplitCoupon = (record: SplitCouponItemType) => {
Modal.confirm({
content: "确认结束后,将停止发放该券,已领的优惠券可继续使用",
onOk: () => {
CouponManageAPI.CouponShutDown({ id: record.id }).then(({ code }) => {
if (code === "200") {
message.success("操作成功");
getSplitCoupon({
...queryData,
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
});
}
});
},
});
};
useEffect(() => {
getSplitCoupon({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
useType: 2,
});
}, []);
return (
<div className="split-coupon-list">
<SearchBox
search={searchData}
searchData={searchSubmitEvent}
sufFixBtn={
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => toAddOrDetailSplitCoupon()}
// disabled={!isAddBtn}
>
新建
</Button>
}
/>
<Table
columns={tableColumns}
rowKey="id"
dataSource={tableDataSource}
loading={loading}
pagination={{
total: pagination.totalCount * 2,
pageSize: pagination.pageSize * 2,
current: pagination.pageNo,
showSizeChanger: false,
showQuickJumper: true,
onChange: (page: number, pageSize: number) =>
paginationChange(page, pageSize),
showTotal: (total, range) =>
`当前 ${Math.ceil(range[0] / 2)}-${range[1] / 2} 条记录 / 共 ${
total / 2
} 条数据`,
}}
/>
{/* 优惠券数据 */}
<DataModal
title="裂变优惠券数据"
open={dataModalShow}
closed={dataModalClose}
data={splitCouponItem}
/>
</div>
);
};
export default SplitCouponList;
......@@ -2,7 +2,7 @@ import React from 'react';
import { Navigate, RouteObject } from 'react-router-dom';
import ErrorPage from '~/pages/common/error';
import LayoutView from '~/components/layout';
import { AccountBookOutlined, MacCommandOutlined } from '@ant-design/icons';
import { AccountBookOutlined, MacCommandOutlined ,GiftOutlined,PayCircleOutlined} from '@ant-design/icons';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { AgnosticIndexRouteObject } from '@remix-run/router';
......@@ -15,10 +15,15 @@ import DivideOrder from '~/pages/pointManage/divideOrder';
import DivideRules from '~/pages/pointManage/divideRules';
import LoginView from '~/pages/common/login';
const ActivityList = React.lazy(() => import('src/pages/activityManage/activityList'));//活动管理
const ProductOrderView = React.lazy(() => import('src/pages/orderManage/productOrder')); //销售订单
const EquipmentOrderView = React.lazy(() => import('src/pages/orderManage/equipmentOrder')); //设备订单
const ServiceOrderView = React.lazy(() => import('src/pages/orderManage/serviceOrder')); //服务订单
const CouponList = React.lazy(() => import('src/pages/couponManage/couponList'));//优惠券管理
const CouponDetail = React.lazy(() => import('src/pages/couponManage/couponList/detail'));//优惠券明细
const SplitCouponList = React.lazy(() => import('src/pages/couponManage/splitCouponList'));//裂变优惠券
const SplitCouponOperate = React.lazy(() => import('src/pages/couponManage/splitCouponList/addOrEditOrDetail'));//裂变优惠券操作
const CouponDetailed = React.lazy(() => import('src/pages/couponManage/couponDetailed'));//优惠券明细
export interface RouteObjectType {
path: AgnosticIndexRouteObject['path'];
element: any;
......@@ -48,6 +53,27 @@ const withLoadingComponent = (comp: JSX.Element) => (
// 路由数组
export const routerList: Array<RouteObjectType> = [
{
path: '/activityManage',
element: <LayoutView />,
errorElement: <ErrorPage />,
meta: {
id: 19000,
icon: <GiftOutlined />,
title: '活动管理',
},
children: [
{
path: '/activityManage/activityList',
element: withLoadingComponent(<ActivityList />),
meta: {
id: 19100,
title: '活动列表',
icon: <GiftOutlined />,
},
},
],
},
{
path: '/orderManage',
element: <LayoutView />,
errorElement: <ErrorPage />,
......@@ -107,7 +133,9 @@ export const routerList: Array<RouteObjectType> = [
},
{
path: '/pointManage/pointList/detail',
element: withLoadingComponent(<PointDetail />),
element: withLoadingComponent(<PointDetail location={{
search: ''
}} />),
meta: {
id: 25100,
title: '个人积分明细',
......@@ -126,7 +154,9 @@ export const routerList: Array<RouteObjectType> = [
},
{
path: '/pointManage/pointList/list',
element: withLoadingComponent(<PointDetailList />),
element: withLoadingComponent(<PointDetailList location={{
search: ''
}} />),
meta: {
id: 25100,
title: '积分明细',
......@@ -155,6 +185,69 @@ export const routerList: Array<RouteObjectType> = [
},
],
},
{
path: '/couponManage',
element: <LayoutView />,
errorElement: <ErrorPage />,
meta: {
id: 26000,
icon: <PayCircleOutlined />,
title: '优惠券管理',
},
children: [
{
path: '/couponManage/couponList',
element: withLoadingComponent(<CouponList />),
meta: {
id: 26100,
title: '活动优惠券',
icon: <PayCircleOutlined />,
},
},
{
path: '/couponManage/couponList/detail',
element: withLoadingComponent(<CouponDetail location={{
search: ''
}} />),
meta: {
id: 26100,
title: '活动优惠券操作',
icon: <PayCircleOutlined />,
hidden:true,
selectKey:'/couponManage/couponList'
},
},
{
path: '/couponManage/splitCouponList',
element: withLoadingComponent(<SplitCouponList />),
meta: {
id: 26200,
title: '裂变优惠券',
icon: <PayCircleOutlined />,
},
},
{
path: '/couponManage/addOrEditOrDetail',
element: withLoadingComponent(<SplitCouponOperate />),
meta: {
id: 26200,
title: '裂变优惠券操作',
icon: <PayCircleOutlined />,
hidden:true,
selectKey:'/couponManage/splitCouponList'
},
},
{
path: '/couponManage/couponDetailed',
element: withLoadingComponent(<CouponDetailed />),
meta: {
id: 26300,
title: '优惠券明细',
icon: <PayCircleOutlined />,
},
},
],
},
];
// 路由白名单
export const whiteRouterList: Array<RouteObject & RouteObjectType> = [
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论