Commit d9c68147 authored by Bill's avatar Bill

feat: 对接装修页优惠券

parent 270fbe94
import React from 'react';
import { TagOutlined } from '@ant-design/icons';
import { PageConfigType, PROPS_SETTING_TYPES } from '@lingxi-disign/core';
import React from 'react';
/**
* 以下对应的组件全部在Layout 文件夹中
*
......@@ -58,34 +58,8 @@ const couponContainer: PageConfigType = {
title: "优惠券",
canEdit: true,
canHide: false,
props: {
money: 100,
info: '满69可使用',
tag: '平台通用券',
key: 1,
},
},
"2-2": {
"componentName": 'Coupon.Item',
title: "优惠券",
canEdit: true,
canHide: false,
props: {},
},
"2-3": {
"componentName": 'Coupon.Item',
title: "优惠券",
canEdit: true,
canHide: false,
props: {},
},
"2-4": {
"componentName": 'Coupon.Item',
title: "优惠券",
canEdit: true,
canHide: false,
props: {},
}
};
/** 活动推荐 */
......
......@@ -3,6 +3,7 @@ import _sortBy from 'lodash/sortBy';
import { updatePageConfig } from '@lingxi-disign/core';
import cloneDeep from 'lodash/cloneDeep';
import { PublicApi } from '@/services/api';
import { PostMarketingCouponPlatformActivityPageSelectDetailResponse } from '@/services/MaketingV2Api';
import mock from '../mock/index.json';
type PageConfigType = {
......@@ -43,13 +44,41 @@ function getData(): Promise<any> {
}
const SERVICE_MAP = {
// "coupon": {
// service: PublicApi.getMarketingCouponPlatformSummaryPage,
// format: () => {},
// },
hot: {
"coupon": {
prefixFormat: (data) => {
const list = data.map((_item) => {
return {
couponType: _item.type,
id: _item.id,
};
});
return { couponList: list };
},
service: PublicApi.postMarketingCouponPlatformActivityPageSelectDetail,
propsName: 'list',
format: (res: PostMarketingCouponPlatformActivityPageSelectDetailResponse) => {
return {
list: res.map((_item) => ({
money: _item.denomination,
info: `满${_item.useConditionMoney}可用`,
tag: _item.couponTypeName,
isnull: false,
..._item,
})),
};
},
},
"hot": {
prefixFormat: (data) => {
return { ids: data };
},
service: PublicApi.getMarketingPlatformActivityGoodsAdorn,
format: () => {}
propsName: 'products',
format: (res) => {
return {
products: res,
};
}
}
};
......@@ -105,7 +134,7 @@ function useGetData(pageConfig: PageConfigType) {
const newSortChild: string[] = [];
/** _item: "top" | "coupon" | string */
for (let _item of sortedArray) {
for (const _item of sortedArray) {
if(prevSortMap[_item]) {
const current = prevSortMap[_item];
const targetPageConfig = newPageConfig[current];
......@@ -119,15 +148,17 @@ function useGetData(pageConfig: PageConfigType) {
/** 先拿一层儿子的config */
const defaultChildConfig = newPageConfig[`${current}-1`];
const newChildKeys: string[] = [];
const { service = null, format, prefixFormat, propsName } = SERVICE_MAP[_item] || {};
/** @request */
const { service = null, format } = SERVICE_MAP[_item] || {};
if (service && sortedChildren[_item]?.props?.children?.length > 0) {
const { data, code } = await service({ids: sortedChildren[_item].props.children});
const postData = prefixFormat && prefixFormat(sortedChildren[_item].props.children);
const { data, code } = await service(postData, {ctlType: 'none'});
if (code === 1000) {
const formatedData = format(data);
newPageConfig[`${current}`].props = {
...newPageConfig[`${current}`].props,
products: data,
}
...formatedData
};
}
}
......@@ -143,6 +174,7 @@ function useGetData(pageConfig: PageConfigType) {
newPageConfig[`${current}-${_index + 1}`].props = {
...childrenProps,
..._row,
...newPageConfig[`${current}`]?.props?.[propsName]?.[_index] || {},
};
newChildKeys.push(`${current}-${_index + 1}`);
});
......@@ -161,10 +193,10 @@ function useGetData(pageConfig: PageConfigType) {
const restNode = childrenNodes?.filter((_item) => !newSortChild.includes(_item));
newPageConfig[0]["childNodes"] = newSortChild.concat(restNode as string[]);
// setPageConfigData(newPageConfig);
setLoading(false)
setLoading(false);
updatePageConfig(newPageConfig);
}
setPageConfigData()
setPageConfigData();
}, [dataSource]);
return { dataSource, loading};
......
......@@ -13,10 +13,7 @@
"theme":0,
"visible": 1,
"children": [
{"id":1, "type":1},
{"id":2, "type":1},
{"id":1, "type":2},
{"id":2, "type":2}
{"id": 4, "type": 1}
]
}
},
......
......@@ -3,13 +3,13 @@ import { Tabs , Input, Button, Select } from 'antd';
import { useEventEmitter, useToggle } from '@umijs/hooks';
import { PublicApi } from '@/services/api';
import { GetMarketingPlatformActivityListAdornRequest } from '@/services/MaketingV2Api';
import _group from 'lodash/groupBy';
import { changeProps } from '@lingxi-disign/core';
import styles from './index.less';
import ActivityProductDrawer from './activityProductDrawer';
import ThemeItem from './themeItem';
import Drawer from '../Drawer';
import { Product } from '../ProductPanel';
import _group from 'lodash/groupBy'
import { changeProps } from '@lingxi-disign/core';
const { TabPane } = Tabs;
......@@ -19,36 +19,18 @@ interface Iprops {
visible: boolean,
onCancel: null | (() => void),
products: any[],
title?: string,
}
/** mock */
const initialValue = [
{
id: 19,
activityId: 52,
productImgUrl: "https://shushangyun01.oss-cn-shenzhen.aliyuncs.com/QQ截图20210729134628e0a6e93460d6472ca387f47023512b3d.png",
productName: "牛仔裤_1_1_1",
label: ["折扣促销"],
activitys: [
{
name: '双11促销活动页-APP',
tag: '折扣促销'
},
{
name: '双11促销活动页-APP',
tag: '折扣促销'
},
]
},
];
const defaultProduct = []
const defaultProduct = [];
const ActivityAreaSetting: React.FC<Iprops> = (props: Iprops) => {
const { visible, onCancel, products = defaultProduct, ...rest } = props;
const { state: productVisible, toggle: setProductVisible } = useToggle();
const [listType, setListType] = useState<{label: string, value: number}[]>([]);
const [selectedType, setSelectedType] = useState<number>(0);
const [innerProducts, setInnerProducts] = useState<any[]>(products)
const [innerProducts, setInnerProducts] = useState<any[]>(products);
const [innerTitle, setInnerTitle] = useState<string>(rest?.title || '');
console.log("products", products, rest);
......@@ -81,11 +63,18 @@ const ActivityAreaSetting: React.FC<Iprops> = (props: Iprops) => {
return;
}
setInnerProducts(products as any);
}, [visible, products])
}, [visible, products]);
useEffect(() => {
if (!visible) {
return;
}
setInnerTitle(rest?.title || '');
}, [visible, rest.title]);
const onOk = (data: any) => {
setInnerProducts(data);
setProductVisible(false)
setProductVisible(false);
};
const onConfirm = () => {
......@@ -97,7 +86,7 @@ const ActivityAreaSetting: React.FC<Iprops> = (props: Iprops) => {
products: innerProducts,
}
});
}
};
return (
<>
......@@ -107,7 +96,7 @@ const ActivityAreaSetting: React.FC<Iprops> = (props: Iprops) => {
<div className={styles.container}>
<div className={styles.name}>
<span className={styles.label}>名称</span>
<Input />
<Input value={innerTitle} />
</div>
<div className={styles.name}>
<span className={styles.label}>活动类型</span>
......@@ -128,7 +117,7 @@ const ActivityAreaSetting: React.FC<Iprops> = (props: Iprops) => {
<div key={`${_item.activityId}-${_item.id}`} className={styles.productItem}>
<Product />
</div>
)
);
})
}
</div>
......
.couponImage {
background-color: #3899FF;
width: 40px;
height: 40px;
}
.wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #252D37;
font-size: 14px;
margin-bottom: 0px;
}
.id {
color: #909399;
font-size: 12px;
margin-bottom: 0px;
}
}
.denomination {
font-size: 14px;
color: #D32F2F;
}
.icon {
width: 14px;
height: 14px;
font-size: 14px;
color: #91959B;
}
.time {
display: inline-block;
color: #252D37;
font-size: 12px;
margin-bottom: 4px;
margin-left: 4px;
}
import React, { useCallback, useRef, useState } from 'react';
import React from 'react';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { ISchema } from '@formily/antd';
import { Radio } from 'antd';
import { PublicApi } from '@/services/api';
import { Space } from 'antd';
import { priceFormat } from '@/utils/numberFomat';
import { PlayCircleOutlined, PoweroffOutlined } from '@ant-design/icons';
import moment from 'moment';
import TableModal from './tableModal';
import styles from './index.less';
interface Iprops {
visible: boolean,
onCancel: () => void,
/** 单选或者多选 */
mode: "checkbox" | 'radio',
formExtra: React.ReactNode,
fetchData: (params: any) => Promise<{
totalCount: number,
data: any[]
}>,
onOk: (selectedKeys, selectedRow) => void,
value: any[]
}
const CouponSelect: React.FC<Iprops> = (props: Iprops) => {
const { visible, onCancel, mode = "checkbox" } = props;
const ref = useRef();
const [radioValue, setRadioValue] = useState(1);
const format = 'YYYY-MM-DD HH:mm:ss';
/* eslint-disable react/display-name */
const CouponSelect: React.FC<Iprops> = React.forwardRef((props: Iprops, couponRef) => {
const { visible, onCancel, mode = "checkbox", formExtra, fetchData, onOk, value } = props;
const columns = [
{
title: '优惠券信息',
dataIndex: 'couponInfo'
dataIndex: 'couponInfo',
render: (_text, _record) => {
return (
<Space align="center">
<img className={styles.couponImage} />
<div className={styles.wrap}>
<div className={styles.title}>{_record.name}</div>
<div className={styles.id}>ID: {_record.id}</div>
</div>
</Space>
);
}
},
{
title: '类型',
dataIndex: 'type',
dataIndex: 'typeName',
},
{
title: '领券方式',
dataIndex: 'method'
dataIndex: 'getWayName'
},
{
title: '面额',
dataIndex: 'price'
dataIndex: 'denomination',
render: (_text, _record) => {
return (
<span className={styles.denomination}>
{`¥${priceFormat(_record.denomination)}`}
</span>
);
}
},
{
title: '使用条件',
dataIndex: 'condition'
dataIndex: 'condition',
render: (text, _record) => {
return (
<span>{`满 ${_record.useConditionMoney} 元使用`}</span>
);
}
},
{
title: '有效期',
dataIndex: 'time'
dataIndex: 'time',
render: (_text, _record) => {
return (
<div>
<div>
<PlayCircleOutlined className={styles.icon} />
<span className={styles.time}>{moment(_record.releaseTimeStart).format(format)}</span>
</div>
<div>
<PoweroffOutlined className={styles.icon}/>
<span className={styles.time}>
{_record.releaseTimeEnd && moment(_record.releaseTimeEnd).format(format)}
</span>
</div>
</div>
);
},
},
{
title: '所属',
......@@ -49,39 +99,12 @@ const CouponSelect: React.FC<Iprops> = (props: Iprops) => {
}
];
const fetchData = useCallback(async (params: any) => {
const { radio = 1, ...rest } = params;
const service = radio === 1 ? PublicApi.getMarketingCouponPlatformActivityPageSelectPage : PublicApi.getMarketingCouponActivityPageSelectPage;
/** @tofix shopId */
const { data, code } = await service({...rest, shopId: 3 });
if (code === 1000) {
return data;
}
return {
totalCount: 0,
data: []
};
}, []);
const triggerOk = () => {
console.log(123);
const triggerOk = (selectRowKeys, selectedRow) => {
console.log("row", selectRowKeys, selectedRow);
onOk?.(selectRowKeys, selectedRow);
};
const paginationStyle = { position: 'absolute', right: 0, bottom: '-40px' };
const options = [
{ label: '平台', value: 1 },
{ label: '商家', value: 2 },
];
const onChange = (e) => {
setRadioValue(e.target.value);
const values = (ref?.current as any)?.formValues(["id", "couponName"]);
const pageInfo = (ref?.current as any)?.getPaginationInfo();
(ref?.current as any)?.reload({...values, current: pageInfo.page, pageSize: pageInfo.pageSize, radio: e.target.value});
};
const schema: ISchema = {
type: 'object',
......@@ -133,7 +156,7 @@ const CouponSelect: React.FC<Iprops> = (props: Iprops) => {
return (
<>
<TableModal
ref={ref}
ref={couponRef as any}
modalType={"Drawer"}
width={920}
visible={visible}
......@@ -143,29 +166,21 @@ const CouponSelect: React.FC<Iprops> = (props: Iprops) => {
schema={schema}
onOk={triggerOk}
fetchData={fetchData}
paginationStyle={paginationStyle}
radioOptions={options}
formExtra={
<div style={{position: 'absolute', top: '4px', right: 0}}>
<Radio.Group
options={options}
value={radioValue}
onChange={onChange}
optionType="button"
/>
</div>
}
paginationStyle={paginationStyle as any}
// radioOptions={options}
formExtra={formExtra}
radioChange
tableProps={{
rowKey: (record) => `id`,
rowKey: (record) => record.id,
}}
effects={($, actions) => {
useStateFilterSearchLinkageEffect($, actions, 'id', FORM_FILTER_PATH);
}}
mode={mode}
value={value}
/>
</>
);
};
});
export default CouponSelect;
......@@ -20,6 +20,11 @@
.name {
color: #91959B;
font-size: 12px;
min-width: 72px;
}
.value {
color: #303133;
font-size: 12px;
}
}
}
......
import React from 'react';
import { Button } from 'antd';
/* eslint-disable react/display-name */
import React, { useRef, useState, useCallback, useEffect, useMemo } from 'react';
import { Button , Radio, Space, message } from 'antd';
import { useToggle } from '@umijs/hooks';
import { PublicApi } from '@/services/api';
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';
import moment from 'moment';
import { changeProps } from '@lingxi-disign/core';
import styles from './index.less';
import Drawer from '../Drawer';
import CouponSelect from '../CouponSelect';
......@@ -20,9 +25,21 @@ interface Iprops {
}
}
const PLATFORM = 1;
const BUSINESS = 2;
const format = 'YYYY-MM-DD HH:mm:ss';
const options = [
{ label: '平台', value: PLATFORM },
{ label: '商家', value: BUSINESS },
];
const CouponSetting: React.FC<Iprops> = (props: Iprops) => {
const { visible, onCancel, value = null } = props;
const { state: drawerVisible, toggle: setDrawerVisible } = useToggle();
const [radioValue, setRadioValue] = useState(PLATFORM);
const [innerValue, setInnerValue] = useState<any>(value);
const ref = useRef();
const columns: ColumnType<any>[] = [
{
......@@ -35,28 +52,101 @@ const CouponSetting: React.FC<Iprops> = (props: Iprops) => {
},
{
title: '优惠券类型',
dataIndex: 'type'
dataIndex: 'typeName'
},
{
title: '领券方式',
dataIndex: 'methods'
dataIndex: 'getWayName'
},
{
title: '面额',
dataIndex: 'price'
dataIndex: 'denomination'
},
{
title: '使用条件',
dataIndex: 'condition'
dataIndex: 'useConditionMoney'
},
{
title: "有效期",
dataIndex: 'validityTime'
dataIndex: 'validityTime',
render: (_text, _record) => {
return (
<div>
<span>{_record?.releaseTimeStart && moment(_record?.releaseTimeStar).format(format)}</span>
<span>{_record?.releaseTimeEnd && moment(_record?.releaseTimeEnd).format(format)}</span>
</div>
);
}
}
];
useEffect(() => {
if (!visible) {
return ;
}
setInnerValue(value);
}, [visible, value]);
const onChange = (e) => {
setRadioValue(e.target.value);
const pageInfo = (ref?.current as any)?.getPaginationInfo();
const values = (ref?.current as any)?.formValues(["id", "couponName"]);
(ref?.current as any)?.reload({...values, current: pageInfo?.page || 1, pageSize: pageInfo?.pageSize || 10, radio: e.target.value});
};
const formExtra = (
<div style={{position: 'absolute', top: '4px', right: 0}}>
<Radio.Group
options={options}
value={radioValue}
onChange={onChange}
optionType="button"
/>
</div>
);
const onOk = (selectedKey: string[], selectedRow: any[]) => {
batchedUpdates(() => {
setInnerValue(selectedRow[0]);
setDrawerVisible(false);
});
};
const fetchData = useCallback(async (params: any) => {
const { radio = PLATFORM, ...rest } = params;
const service = radio === PLATFORM ? PublicApi.getMarketingCouponPlatformActivityPageSelectPage : PublicApi.getMarketingCouponPlatformActivityPageSelectMerchantPage;
/** @tofix shopId */
const { data, code } = await service({...rest, shopId: 3 });
if (code === 1000) {
return data;
}
return {
totalCount: 0,
data: []
};
}, []);
const handleSubmit = () => {
if (innerValue === null) {
message.error("请选择优惠券");
return;
}
changeProps({
props: {
...innerValue,
money: innerValue.denomination,
info: `满${innerValue.useConditionMoney}可用`,
tag: innerValue.typeName,
isnull: false,
}
});
};
const selectedValue = useMemo(() => [innerValue], [innerValue]);
return (
<Drawer title="优惠券" visible={visible} onCancel={onCancel}>
<Drawer title="优惠券" visible={visible} onCancel={onCancel} onSubmit={handleSubmit}>
<div className={styles.container}>
<div className={styles.content}>
<div className={styles.module}>
......@@ -70,7 +160,7 @@ const CouponSetting: React.FC<Iprops> = (props: Iprops) => {
<span className={styles.name}>{_item.title}</span>
<span className={styles.value}>
{
_item?.render?.(value?.[_item.dataIndex], value)
(_item?.render?.(innerValue?.[_item.dataIndex], innerValue)) || innerValue?.[_item.dataIndex]
}
</span>
</div>
......@@ -80,7 +170,16 @@ const CouponSetting: React.FC<Iprops> = (props: Iprops) => {
</div>
</div>
</div>
<CouponSelect visible={drawerVisible} onCancel={() => setDrawerVisible(false)} mode="radio"/>
<CouponSelect
visible={drawerVisible}
onCancel={() => setDrawerVisible(false)}
mode="radio"
formExtra={formExtra}
ref={ref as any}
fetchData={fetchData}
onOk={onOk}
value={selectedValue}
/>
</Drawer>
);
};
......
......@@ -50,12 +50,18 @@ const EditPanel = () => {
...selectedInfo?.props || {},
};
const componentType = selectedInfo?.propsConfig?.componentType?.type || '';
const componentType: any = selectedInfo?.propsConfig?.componentType?.type || '';
const Component = componentType && ComponentsMap[componentType as unknown as "Advertisement"];
if (!Component) {
return null;
}
if(componentType === 'CouponSetting') {
return <Component visible={visible} onCancel={handleOncancel} value={selectedInfo?.props} />;
}
return (
Component && <Component {...dataProps} /> || null
);
};
......
......@@ -28,7 +28,6 @@ interface Iprops {
const CommodityList: React.FC<Iprops> & { Item: typeof CommodityItem, CommodityTab: typeof CommodityTab } = (props: Iprops) => {
const { children, className, title, theme, ...other } = props;
const classNameStr = cx(styles.recommand, className);
console.log("CommodityList", other);
const render2Columns = () => {
return (
......
......@@ -8,22 +8,32 @@ const { CouponsItem } = MarketingCard;
interface Iprops {
children: React.ReactNode,
className: string,
visible: 0 | 1
visible: 0 | 1,
onClick: () => void,
onDrag: () => void,
onDragEnd: () => void,
onDragEnter: () => void,
onDragStart: () => void,
onMouseOver: () => void,
getOperateState: any,
}
const Coupon: React.FC<Iprops> & { Item: typeof CouponItem } = (props: Iprops) => {
const { children, className, visible = true, ...other } = props;
console.log(visible);
const classNameStr = cx(
styles.container,
className,
);
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState } = other;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState,
};
return (
<>
{
!!visible && (
<div className={classNameStr} {...other}>
<div {...divProps} className={classNameStr}>
{children}
</div>
) || null
......@@ -41,15 +51,20 @@ interface ItemIprops {
onDragEnter: () => void,
onDragStart: () => void,
onMouseOver: () => void,
getOperateState: any,
}
const CouponItem: React.FC<ItemIprops> = (props: ItemIprops) => {
const { children, className, ...other} = props;
// console.log("CouponItem", props);
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, ...rest} = other;
console.log("CouponItem", props);
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, ...rest} = other;
const { money, isnull, tag, info, } = rest as any;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState,
};
return (
<div className={cx(className, styles.item)} {...other} >
<CouponsItem {...rest} className={styles.couponItem} />
<div {...divProps} className={cx(className, styles.item)}>
<CouponsItem money={money} isnull={isnull} tag={tag} info={info} className={styles.couponItem} />
</div>
);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment