Commit 51151037 authored by Bill's avatar Bill

fix: 修改活动页装修

parent b6868fdb
......@@ -54,6 +54,12 @@ const router = [
// component: '@/pages/pageCustomized/categoryNavigation',
// },
// {
// path: '/marketingManage/marketing/activitiesManagement/webFixtures',
// name: 'pc装修页',
// noLayout: true,
// component: '@/pages/marketingManage/marketing/marketingActivitiesManagement/activePage/fixtures/web',
// },
// {
// path: '/home',
// name: 'home',
// component: '@/pages/home',
......
......@@ -61,9 +61,9 @@
"@formily/antd": "^1.2.11",
"@formily/antd-components": "^1.2.11",
"@linkseeks/design-core": "^1.0.0",
"@linkseeks/design-react": "^1.0.0",
"@linkseeks/design-react": "^1.0.2",
"@linkseeks/design-react-web": "^1.0.0",
"@linkseeks/design-ui": "^1.0.5",
"@linkseeks/design-ui": "^1.0.9",
"@linkseeks/design-utils": "^1.0.0",
"@linkseeks/god": "^1.0.0",
"@types/crypto-js": "^4.0.1",
......
/** 活动相关 */
/** 活动推荐 */
export const ACTIVITY_HOT = 'hot';
/** 活动-特价促销 */
export const ACTIVITY_SPECIALOFFER = 'specialOffer';
/** 直降促销 */
export const ACTIVITY_PLUMMET = 'plummet';
/** 折扣促销 */
export const ACTIVITY_DISCOUNT = 'discount';
/** 满量促销-满量减 */
export const ACTIVITY_FULLQUANTITYSUB = 'fullQuantitySub';
/** 满量促销--满量折 */
export const ACTIVITY_FULLQUANTITYDISCOUNT = 'fullQuantityDiscount';
/** 满额促销--满额减 */
export const ACTIVITY_FULLMONEYSUB = 'fullMoneySub'
/** 满额促销--满额折 */
export const ACTIVITY_FULLMONEYDISCOUNT = 'fullMoneyDiscount'
/** 赠送促销-赠送商品 */
export const ACTIVITY_GIVEPRODUCT = 'giveProduct'
/** 赠送促销-赠送优惠券 */
export const ACTIVITY_GIVECOUPON = 'giveCoupon'
/** 赠送促销-多件促销 */
export const ACTIVITY_MOREPIECE = 'morePiece'
/** 赠送促销-组合促销 */
export const ACTIVITY_COMBINATION = 'combination'
/** 赠送促销-拼团 */
export const ACTIVITY_GROUPPURCHASE = 'groupPurchase'
/** 砍价 */
export const ACTIVITY_BARGAIN = 'bargain'
/** 秒杀 */
export const ACTIVITY_SECKILL = 'secKill'
/** 换购-满额换购 */
export const ACTIVITY_FULLSWAP = 'fullSwap'
/** 换购-满额换购 */
export const ACTIVITY_BUYSWAP = 'buySwap'
/** 换购-预售 */
export const ACTIVITY_PRESALE = 'preSale'
/** 套餐 */
export const ACTIVITY_SETMEAL = 'setMeal';
/** 试用 */
export const ACTIVITY_ATTEMPT = 'attempt';
/** 活动类型ID */
/** 活动-特价促销 */
export const ACTIVITY_SPECIALOFFER_NUMBER = 1;
/** 直降促销 */
export const ACTIVITY_PLUMMET_NUMBER = 2;
/** 折扣促销 */
export const ACTIVITY_DISCOUNT_NUMBER = 3;
/** 满量促销-满量减, minType: 1 */
export const ACTIVITY_FULLQUANTITYSUB_NUMBER = 4;
/** 满量促销--满量折 minType: 2 */
export const ACTIVITY_FULLQUANTITYDISCOUNT_NUMBER = 4;
/** 满额促销--满额减 minType: 1 */
export const ACTIVITY_FULLMONEYSUB_NUMBER = 5
/** 满额促销--满额折 minType: 2 */
export const ACTIVITY_FULLMONEYDISCOUNT_NUMBER = 5
/** 赠送促销-赠送商品 minType: 1 */
export const ACTIVITY_GIVEPRODUCT_NUMBER = 6
/** 赠送促销-赠送优惠券 minType: 2 */
export const ACTIVITY_GIVECOUPON_NUMBER = 6
/** 赠送促销-多件促销 */
export const ACTIVITY_MOREPIECE_NUMBER = 7
/** 赠送促销-组合促销 */
export const ACTIVITY_COMBINATION_NUMBER = 8
/** 拼团 */
export const ACTIVITY_GROUPPURCHASE_NUMBER = 9
/** 砍价 */
export const ACTIVITY_BARGAIN_NUMBER = 11
/** 秒杀 */
export const ACTIVITY_SECKILL_NUMBER = 12
/** 换购-满额换购 minType = 1 */
export const ACTIVITY_FULLSWAP_NUMBER = 13
/** 换购-满额换购 minType = 2 */
export const ACTIVITY_BUYSWAP_NUMBER = 13
/** 换购-预售 */
export const ACTIVITY_PRESALE_NUMBER = 14
/** 套餐 */
export const ACTIVITY_SETMEAL_NUMBER = 15;
/** 试用 */
export const ACTIVITY_ATTEMPT_NUMBER = 16;
export const ACTIVITY_LIST = [
ACTIVITY_HOT,
ACTIVITY_SPECIALOFFER,
ACTIVITY_PLUMMET,
ACTIVITY_DISCOUNT,
ACTIVITY_FULLQUANTITYSUB,
ACTIVITY_FULLQUANTITYDISCOUNT,
ACTIVITY_FULLMONEYSUB,
ACTIVITY_FULLMONEYDISCOUNT,
ACTIVITY_GIVEPRODUCT,
ACTIVITY_GIVECOUPON,
ACTIVITY_MOREPIECE,
ACTIVITY_COMBINATION,
ACTIVITY_GROUPPURCHASE,
ACTIVITY_BARGAIN,
ACTIVITY_SECKILL,
ACTIVITY_FULLSWAP,
ACTIVITY_BUYSWAP,
ACTIVITY_PRESALE,
ACTIVITY_SETMEAL,
ACTIVITY_ATTEMPT
] as const
......@@ -9,6 +9,7 @@ import OuterSider from './OuterSide'
import styles from '../styles/MenuSlider.less'
import { getRouters } from '@/utils/auth';
import { isDev } from '@/constants';
import menuIcon from '../../asserts/menuIcon/logo.png'
const { Sider } = Layout
const { SubMenu } = Menu;
......@@ -93,7 +94,7 @@ const MenuSlider: React.FC<MenuSliderProps> = (props) => {
<OuterSider {...props} />
<Sider theme="light" className="menu_sider" collapsed={props.collapseState}>
<Link to={`/`} className={styles.logo}>
<img src={require('../../asserts/menuIcon/logo.png')} />
<img src={menuIcon} />
</Link>
<div className={styles.menuTitle}>
{menuRouter?.name}
......
......@@ -24,7 +24,16 @@ const schema: ISchema = {
name: {
type: 'string',
title: '活动页名称',
required: true,
"x-rules": [
{
required: true,
message: '请填写活动名称'
},
{
limitByte: true,
maxByte: 60,
}
]
},
environment: {
type: 'string',
......
......@@ -8,9 +8,15 @@ type CheckboxType = {
extra?: number | string
}
type XcomponentProps = {
/** 是否是单选按钮 */
isRadio: boolean
}
interface Iprops {
props: {
enum: CheckboxType[]
enum: CheckboxType[],
'x-component-props': XcomponentProps
},
mutators: {
change: (params: number[] | string[]) => void
......@@ -21,10 +27,21 @@ interface Iprops {
const FormilyCheckBox: React.FC<Iprops> & { isFieldComponent: boolean } = (props: Iprops) => {
const { value = [], mutators } = props;
const componentProps = props.props || {};
const xComponentProps = componentProps['x-component-props'] || {} as XcomponentProps;
const isRadio = xComponentProps?.isRadio || false;
const enumsMap: CheckboxType[] = componentProps?.enum || [];
const handleChange = (isChecked: boolean, _item: CheckboxType) => {
let newList: string[] | number[] = []
let newList: string[] | number[] = [];
console.log(isChecked)
if (isRadio) {
if (isChecked) {
newList = [_item.value as string];
}
mutators.change(newList)
return;
}
if (isChecked) {
newList = (value as string[]).concat(_item.value as string);
} else {
......
......@@ -21,7 +21,10 @@ const schema: ISchema = {
status: {
type: 'string',
title: '',
"x-component": 'FormilyRadio',
"x-component": 'FormilyCheckBox',
"x-component-props": {
isRadio: true,
},
enum: [
{
label: '待上线',
......@@ -84,7 +87,10 @@ const schema: ISchema = {
environment: {
type: 'string',
title: '',
"x-component": 'FormilyRadio',
"x-component": 'FormilyCheckBox',
"x-component-props": {
isRadio: true,
},
enum: [
{
label: 'WEB',
......
import { ComponentSchemaType, PROPS_SETTING_TYPES, PROPS_TYPES } from '@linkseeks/design-core';
const View: ComponentSchemaType = {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
},
};
// const View: ComponentSchemaType = {
// propsConfig: {
// children: {
// label: '内容',
// type: PROPS_TYPES.string,
// }
// },
// };
const Advertisement: ComponentSchemaType = {
propsConfig: {
......@@ -130,13 +130,30 @@ const Combination = {
}
}
/** 热门推荐 */
const CommodityWithProcess = {
CommodityWithProcess: {
propsConfig: {}
},
'CommodityWithProcess.Item': {
propsConfig: {}
}
}
const MobileLayout = {
propsConfig: {
backgroundColor: PROPS_TYPES.string,
}
}
export default {
MobileLayout,
Commodity,
WrapCommodityList,
Advertisement,
...CommodityWithProcess,
...Coupon,
View,
// View,
...MarketingCard,
...CommodityList,
...Combination,
...WrapCommodityList,
};
......@@ -62,7 +62,8 @@ const formatData = {
const COMPONENT_NAME = {
top: 'Advertisement',
coupon: 'Coupon',
hot: "CommodityList",
hot: "CommodityWithProcess",
specialOffer: "CommodityList",
plummet: "CommodityList",
discount: "CommodityList",
fullQuantitySub: "CommodityList",
......@@ -87,7 +88,8 @@ const COMPONENT_NAME = {
/** key 对应子节点ComponentName */
const CHILD_COMPONENT_NAME = {
coupon: 'Coupon.Item',
hot: "CommodityList.Item",
hot: "CommodityWithProcess.Item",
specialOffer: "CommodityList.Item",
plummet: "CommodityList.Item",
discount: "CommodityList.Item",
fullQuantitySub: "CommodityList.Item",
......@@ -217,7 +219,9 @@ function useGetLayout() {
console.log(detail);
/** @review 该方法需要优化,因为suggestProduct 写多了一遍 */
async function setData() {
setLoading(true);
const { adornContent } = detail!;
const themeStyle = adornContent['themeStyle']
let startKey = 0;
const firstChildKeys: string[] = [];
let pageConfig = {};
......@@ -229,7 +233,7 @@ function useGetLayout() {
sort: adornContent[_item].sort
});
});
const sortedList = dataSourceList.sort((a, b) => a.sort - b.sort);
const sortedList = dataSourceList.sort((a, b) => a.sort - b.sort).filter((_item) => _item.key !== 'themeStyle');
for (const _row of sortedList) {
startKey = startKey + 1;
firstChildKeys.push(startKey.toString());
......@@ -239,11 +243,12 @@ function useGetLayout() {
const props = _row.key === 'top' ? {
imageUrl: currentProps.imageUrl
} : {
visible: currentProps.visible ?? true,
status: currentProps.visible ?? true,
theme: currentProps.theme || 0,
title: currentProps.title,
};
const suggestProductSonProps = _row.key === 'suggestProduct' ? {
hideAction: true,
childComponentName: `CommodityList.Item`,
addBtnText: '添加商品节点',
childProps: {
......@@ -263,6 +268,7 @@ function useGetLayout() {
},
};
let tempConfig = {
hideAction: true,
componentName: COMPONENT_NAME[_row.key],
title: title[_row.key] || currentProps.title,
props: props,
......@@ -362,23 +368,35 @@ function useGetLayout() {
};
pageConfig[startKey] = tempConfig;
}
// pageConfig = {
// 0: {
// "componentName": "div",
// title: '组件树',
// "props": {
// "style": {
// "width": "100%",
// "minHeight": "100%",
// "background": "#DD3041",
// "overflowX": "hidden",
// "paddingBottom": "50px",
// }
// },
// "childNodes": firstChildKeys
// },
// ...pageConfig,
// };
pageConfig = {
0: {
"componentName": "div",
title: '组件树',
"componentName": "MobileLayout",
title: `组件树`,
"props": {
"style": {
"width": "100%",
"minHeight": "100%",
"background": "#DD3041",
"overflowX": "hidden",
"paddingBottom": "50px",
}
backgroundColor: themeStyle?.props?.color || "#00A98F"
},
"childNodes": firstChildKeys
},
...pageConfig,
};
setLoading(false);
console.log("pageConfig", pageConfig);
updatePageConfig(pageConfig);
......
......@@ -220,6 +220,7 @@ function useGetWebLayout() {
console.log(detail);
/** @review 该方法需要优化,因为suggestProduct 写多了一遍 */
async function setData() {
setLoading(true)
const { adornContent } = detail!;
const themeStyle = adornContent['themeStyle']
let startKey = 0;
......@@ -380,7 +381,7 @@ function useGetWebLayout() {
},
...pageConfig,
};
setLoading(false)
console.log("pageConfig", pageConfig);
updatePageConfig(pageConfig);
}
......
import { ACTIVITY_LIST } from '@/constants/const/activity';
import { postTemplateWebActivityPageAdorn } from '@/services/TemplateV2Api';
import { CodeSandboxCircleFilled } from '@ant-design/icons';
import { message } from 'antd';
import { omit, pick } from 'lodash';
import { useState } from 'react';
import { history } from 'umi';
type Options = {
id: number;
}
/** 数组转合集 */
type TupleToUnion<T extends readonly any[]> = T[number];
type ACTIVITY_KEYS = TupleToUnion<typeof ACTIVITY_LIST>
type ActivityContent = {
[key in ACTIVITY_KEYS]?: {
props: {
/** 活动商品id */
childrenData: number[]
theme: number
/** 容器名 */
title: string
/** 显示或者隐藏 */
visible: boolean
},
/** 排序 */
sort: number
};
}
type ResultType = {
themeStyle?: {
props: {
/** 背景颜色 */
color: string;
},
sort: number
},
top?: {
props: {
/** 活动图片 */
imageUrl: string;
},
sort: number
},
coupon?: {
props: {
/** 优惠券, type => 平台或商家 */
childrenData: {id: number, type: 1 | 2 | number & {}}[]
theme: number
visible: boolean
}
sort: number
}
} & ActivityContent
function useSaveData(options: Options) {
const { id } = options
const [saving, setSaving] = useState<boolean>(false);
const generaterData = (source: ResultType, dataIndex: string, assignData: {[key: string]: any} ) => {
const result = Object.assign(source, {
[dataIndex]: assignData
});
return result;
};
const onSave = async (pageConfig: any) => {
const childNodes = pageConfig[0].childNodes;
setSaving(true);
let result: ResultType = {} as ResultType;
childNodes.map((_item, _index) => {
const target = pageConfig[_item];
const childNodes = target.childNodes;
const { props } = target || {};
const dataIndex: ACTIVITY_KEYS | 'top' | 'coupon' | 'suggestProduct' = target.otherProps.type;
const sort = _index + 1;
if (dataIndex === 'top') {
const current = { sort: sort, props: omit(props, 'style') };
result = generaterData(result, 'top', current);
} else if(dataIndex === 'coupon') {
const childrenData = childNodes.map((_record) => {
const childTargetProps = pageConfig[_record].props;
if(!childTargetProps?.id) {
return null
}
return {
id: childTargetProps.id,
type: childTargetProps.belongType
};
}).filter(Boolean);
result = generaterData(result, 'coupon', {
sort: sort,
props: {
...pick(props, ['theme']),
visible: props.status ?? true,
childrenData: childrenData
}
});
} else if (ACTIVITY_LIST.includes( dataIndex as ACTIVITY_KEYS )) {
const { ...otherProps } = props || {};
const childrenData = childNodes.map((_record) => {
const childTargetProps = pageConfig[_record].props;
return childTargetProps.id;
});
// const childrenData = products?.map((_item) => _item.id) || [];
result = generaterData(result, dataIndex, {
sort: sort,
props: {
...pick(otherProps, ['theme', 'title']),
visible: props.status ?? true,
childrenData: childrenData
}
});
} else if (dataIndex === 'suggestProduct') {
const { ...otherProps } = props || {};
const { childNodes } = target;
const temp = {
sort: sort,
props: {
visible: otherProps.status ?? true,
childrenData: childNodes?.filter((_record) => /\d+-\d+/.test(_record)).map((_row) => {
const childrenNodeTarget = pageConfig[_row];
const { ...childRestProps } = childrenNodeTarget?.props;
return {
title: childRestProps.title,
theme: childRestProps.theme || 0,
childrenData: childrenNodeTarget.childNodes?.map((_listItem) => {
const sonNodeTarget = pageConfig[_listItem];
return {
id: sonNodeTarget?.props.id,
label: sonNodeTarget?.props?.label || []
};
})
};
})
}
};
result = generaterData(result, 'suggestProduct', temp);
}
});
const withThemeStyle = {
...result,
themeStyle: {
sort: 0,
props: {
color: pageConfig[0]?.props?.backgroundColor || '#E80047'
}
}
}
const { data, code, ...rest } = await postTemplateWebActivityPageAdorn({
id: id,
adornContent: result
} as any, {ctlType: 'none'});
setSaving(false);
if (code === 1000) {
// history.goBack();
message.success("保存成功")
} else {
message.error(rest.message)
}
}
return { saving, onSave };
}
export default useSaveData
\ No newline at end of file
{
"themeStyle": {
"sort": 0,
"props": {
"color": "#00A98F"
}
},
"top":{
"sort":1,
"props": {
......
......@@ -6,15 +6,17 @@ import cx from 'classnames';
import { PlusOutlined } from '@ant-design/icons';
interface Iprops {
children,
children: React.ReactNode,
className: string
title: string,
visible?: boolean,
/** 控制显示隐藏 */
status?: boolean,
theme: number
}
const Combination: React.FC<Iprops> & { Item: typeof CombinationItem } = (props: Iprops) => {
const { children, className, title, theme, visible = true, ...other } = props;
const { children, className, title, theme, status = true, ...other } = props;
const visible = status
const classNameStr = cx(styles.combiantion, className, { [styles.hide]: !visible });
// const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState } = other as any;
......
......@@ -18,7 +18,8 @@ interface Iprops {
children: React.ReactNode,
title: string,
theme: 0 | 1 | 2,
visible: boolean,
/** 控制显示隐藏 */
status: boolean,
}
const CommodityList: React.FC<Iprops> & {
......@@ -30,7 +31,9 @@ const CommodityList: React.FC<Iprops> & {
FlashSale: typeof FlashSale
} =
(props: Iprops) => {
const { children, className, title, theme, visible = true, ...other } = props;
const { children, className, title, theme, status = true, ...other } = props;
const visible = status
const classNameStr = cx(styles.recommand, className, { [styles.hide]: !visible });
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState } = other as any;
......
.recommand {
padding: 0 8px;
margin-top: 24px;
.title {
color: #fff;
font-size: 20px;
margin-bottom: 12px;
display: block;
line-height: 28px;
margin-bottom: 8px;
}
}
.hide {
display: none;
}
.item {
margin-bottom: 8px;
}
import React from 'react';
import { Commodity, Progress } from '@linkseeks/design-ui';
import styles from './index.less';
import classNames from 'classnames';
interface IChildprops {
className: string,
onClick: () => void,
onMouseOver: () => void,
draggable?: boolean,
getOperateState: any,
productImgUrl?: string,
productName?: string,
productId?: number,
id?: number,
price?: number,
activityPrice?: number,
}
interface Iprops {
className: string,
children: React.ReactNode,
title: string,
theme: 0 | 1 | 2,
status: boolean,
}
const CommodityWithProcess: React.FC<Iprops> & { Item: typeof Item} = (props: Iprops) => {
const { children, className, title, theme, status = true, ...other } = props;
const classNameStr = classNames(styles.recommand, className);
const { onClick, onMouseOver, getOperateState } = other as any;
const visible = status;
const divProps = {
onClick, onMouseOver,
};
if (!visible) {
return null;
}
const renderChild = () => {
return (
<div>
{
React.Children.map(children, (_child: any) => {
if (_child === null) {
return null;
}
return React.cloneElement(_child, {..._child.props});
})
}
</div>
);
};
return (
<div className={classNameStr} {...divProps}>
<span className={styles.title}>{title}</span>
<div className={styles.container}>
{
renderChild()
}
</div>
</div>
)
}
const Item: React.FC<IChildprops> = (props: IChildprops) => {
const { className, onClick, onMouseOver, ...other } = props;
const divProps = {
onClick, onMouseOver,
};
return (
<div className={styles.item}>
<div {...divProps} className={className} style={{height: '100%'}}>
<Commodity
name={other.productName}
image={other.productImgUrl}
mode="horizontal"
discountPrice={other.activityPrice}
price={other.price}
progress={
<Progress
percent={50}
progressTips={"剩余50%"}
extra={
<div style={{fontSize: '10px', color: '#919598', marginLeft: '12px', minWidth: '80px'}}>
剩余<span style={{color: '#ef3346' }}>{other.restrictTotalNum}</span>
</div>
}
/>
}
/>
</div>
</div>
);
}
CommodityWithProcess.Item = Item;
export default CommodityWithProcess;
......@@ -9,26 +9,24 @@ const { CouponsItem } = MarketingCard;
interface Iprops {
children: React.ReactNode,
className: string,
visible: 0 | 1,
/** 控制显示隐藏 */
status: boolean,
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;
const { children, className, status = true, ...other } = props;
const visible = status;
const classNameStr = cx(
styles.container,
className,
);
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState } = other;
const { onClick, onMouseOver, getOperateState } = other;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver,
onClick, onMouseOver,
};
return (
<>
......@@ -49,10 +47,6 @@ interface ItemIprops {
children: React.ReactNode,
className: string,
onClick: () => void,
onDrag: () => void,
onDragEnd: () => void,
onDragEnter: () => void,
onDragStart: () => void,
onMouseOver: () => void,
draggable?: false
getOperateState: any,
......@@ -71,10 +65,10 @@ interface ItemIprops {
const CouponItem: React.FC<ItemIprops> = (props: ItemIprops) => {
const { children, className, ...other} = props;
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, ...rest} = other;
const { onClick, onMouseOver, getOperateState, ...rest} = other;
const { denomination, tag, useConditionMoney, typeName } = rest as any;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver,
onClick, onMouseOver,
};
const isNotNull = useMemo(() => rest?.id && true, [rest]);
return (
......
import React from 'react';
interface Iprops {
backgroundColor: string;
children: React.ReactNode,
}
const MobileLayout: React.FC<Iprops> = (props: Iprops) => {
const { children, backgroundColor } = props
return (
<div
style={{
width: "100%",
minHeight: "100%",
background: backgroundColor,
overflowX: "hidden",
paddingBottom: "50px",
}}
>
{children}
</div>
)
}
export default MobileLayout
\ No newline at end of file
......@@ -49,7 +49,6 @@ const WebCommodity: React.FC<Iprops> = (props: Iprops) => {
const renderLabels = () => {
const labels = productData.activityList.map((_item: ActivityListType) => _item.label).concat(productData.label).filter(Boolean);
console.log(labels);
return (
<div className={styles['commodity-info-tags']}>
{
......
import React, { useState } from 'react';
import { Tooltip } from 'antd';
import cx from 'classnames';
import _omit from 'lodash/omit';
interface Iprops {
className: any,
children: any
children: React.ReactNode,
/** 控制显示隐藏 */
status: boolean,
}
const WrapCommodityList: React.FC<Iprops> = (props: Iprops) => {
const { children, className, ...other } = props;
const { children, className, status = true, ...other } = props;
const visible = status;
const classNameStr = cx(className);
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState } = other as any;
const { onClick, onMouseOver, getOperateState } = other as any;
if (!visible) {
return null;
}
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver,
onClick, onMouseOver,
};
const renderComponent = () => {
return (
......@@ -33,11 +42,13 @@ const WrapCommodityList: React.FC<Iprops> = (props: Iprops) => {
};
return (
<div className={classNameStr} {...divProps}>
{
renderComponent()
}
</div>
<Tooltip placement="topLeft" title={"自定义模块"} arrowPointAtCenter>
<div className={classNameStr} style={{marginTop: '12px', minHeight: '50px'}} {...divProps}>
{
renderComponent()
}
</div>
</Tooltip>
);
};
......
......@@ -3,6 +3,8 @@ import Coupon from './Coupon';
import CommodityList from './CommodityList';
import WrapCommodityList from './WrapCommodityList';
import Combination from './Combination';
import CommodityWithProcess from './CommodityWithProcess';
import MobileLayout from './MobileLayout';
/** WEB, 需要到 common/configs/webSchma配置 */
import WebAdvertise from './WebAdvertise';
......@@ -16,9 +18,11 @@ import WebCustomCommodity from './WebCustomCommodity';
export default {
MobileLayout,
Advertisement,
Coupon,
CommodityList,
CommodityWithProcess,
WrapCommodityList,
Combination,
WebAdvertise,
......
......@@ -44,6 +44,7 @@
top: 0;
display: none;
padding-top: 32px;
z-index: 99;
}
&:hover {
......
@content-height: calc(100vh - 120px);
.page {
position: relative;
:global {
.ant-spin-nested-loading > div > .ant-spin,
.ant-spin-spinning {
position: absolute;
top: 50%;
left: 50%;
height: 80px;
transform: translate(-50%, -50%);
}
.ant-spin-blur {
opacity: 0;
}
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin-top: 40px;
font-size: 20px;
font-weight: 600;
}
}
.wrapper {
background: white;
display: flex;
......@@ -41,6 +71,9 @@
align-items: center;
justify-content: center;
}
.ant-tabs-ink-bar {
display: none;
}
}
.module {
......
import React, { useEffect, useState } from 'react';
import { Spin, message , Tabs } from 'antd';
import { BrickProvider, ModuleTree } from '@linkseeks/design-react';
import { BrickProvider, ModuleTree, ModuleTreeCollapse } from '@linkseeks/design-react';
import _get from 'lodash/get';
import _omit from 'lodash/omit';
import _pick from 'lodash/pick';
......@@ -11,153 +11,64 @@ import styles from './index.less';
import EditPanel from './components/EditPanel/editPanelForm';
import configs from './common/configs/pageConfigs';
import useGetLayout from './common/hooks/useGetLayout';
import Module from './components/ComponentTree';
import Module from './components/ComponentTree/web';
import ToolbarSubmit from './components/Toolbar/toolbarSubmit';
import { RenovationProvider } from './common/context/shopContext';
import { usePageStatus } from '@/hooks/usePageStatus';
import { postTemplateWebActivityPageAdorn } from '@/services/TemplateV2Api';
import useSaveData from './common/hooks/useSaveData';
const { TabPane } = Tabs;
const primaryKey = ["hot", "specialOffer", "plummet", "discount", "fullQuantitySub", "fullQuantityDiscount", "fullMoneySub", "fullMoneyDiscount", "giveProduct", "giveCoupon", "morePiece", "combination", "groupPurchase", "bargain", "secKill", "fullSwap", "buySwap", "preSale", "setMeal", "attempt"];
const Fixtures = () => {
const { id } = usePageStatus();
// const { detail, loading } = useGetData(componentConfigs as any);
const { detail, loading } = useGetLayout();
const [submitLoading, setSubmitLoading] = useState<boolean>(false);
const onSave = async (pageConfig) => {
const childNodes = pageConfig[0].childNodes;
setSubmitLoading(true);
let result: any = {};
childNodes.map((_item, _index) => {
const target = pageConfig[_item];
const childNodes = target.childNodes;
const { props } = target || {};
const dataIndex = target.otherProps.type;
const sort = _index + 1;
if (dataIndex === 'top') {
const current = { sort: sort, props: _omit(props, 'style') };
result = generaterData(result, dataIndex, current);
} else if(dataIndex === 'coupon') {
const childrenData = childNodes.map((_record) => {
const childTargetProps = pageConfig[_record].props;
return {
id: childTargetProps.id,
type: childTargetProps.belongType
};
});
result = generaterData(result, dataIndex, {
sort: sort,
props: {
..._pick(props, ['theme', 'visible']),
childrenData: childrenData
}
});
} else if (primaryKey.includes( dataIndex )) {
const { ...otherProps } = props || {};
const childrenData = childNodes.map((_record) => {
const childTargetProps = pageConfig[_record].props;
return childTargetProps.id;
});
// const childrenData = products?.map((_item) => _item.id) || [];
result = generaterData(result, dataIndex, {
sort: sort,
props: {
..._pick(otherProps, ['theme', 'visible', 'title']),
childrenData: childrenData
}
});
} else if (dataIndex === 'suggestProduct') {
const { ...otherProps } = props || {};
console.log(otherProps, "suggestProduct");
const { childNodes } = target;
const temp = {
sort: sort,
props: {
visible: true,
childrenData: childNodes?.filter((_record) => /\d+-\d+/.test(_record)).map((_row) => {
const childrenNodeTarget = pageConfig[_row];
const { ...childRestProps } = childrenNodeTarget?.props;
return {
title: childRestProps.title,
theme: childRestProps.theme || 0,
childrenData: childrenNodeTarget.childNodes?.map((_listItem) => {
const sonNodeTarget = pageConfig[_listItem];
return {
id: sonNodeTarget?.props.id,
label: sonNodeTarget?.props?.label || []
};
})
};
})
}
};
result = generaterData(result, dataIndex, temp);
}
});
const { data, code, ...rest } = await postTemplateWebActivityPageAdorn({
id: id,
adornContent: result
} as any, {ctlType: 'none'});
setSubmitLoading(false);
if (code === 1000) {
// history.goBack();
message.success("保存成功")
} else {
message.error(rest.message)
}
};
const generaterData = (source: { [key: string]: any }, dataIndex: string, assignData: {[key: string]: any} ) => {
const result = Object.assign(source, {
[dataIndex]: assignData
});
return result;
};
const { saving, onSave } = useSaveData({ id: +id });
return (
<Spin spinning={loading}>
<BrickProvider
config={configs}
warn={(msg: string) => {
message.warning(msg);
}}
>
<div className={styles['wrapper']}>
<Toolbar title="正在编辑:平台营销活动页" extra={<ToolbarSubmit loading={submitLoading} onSubmit={onSave}>保存</ToolbarSubmit>} />
<div className={styles['content']}>
<div className={styles.tree}>
<Tabs >
<TabPane tab="已添加" key="1">
<ModuleTree />
</TabPane>
<TabPane tab="全部模块" key="2">
<div className={styles.module}>
<Module />
</div>
</TabPane>
</Tabs>
</div>
<div className={styles['app-wrapper']}>
<div className={styles['app-canvas-container']}>
<MobileDesignPanel theme={'theme-mall-science'} onlyEidt />
<div className={styles.page}>
<Spin spinning={loading}>
<BrickProvider
config={configs}
warn={(msg: string) => {
message.warning(msg);
}}
>
<div className={styles['wrapper']}>
<Toolbar title="正在编辑:平台营销活动页" extra={<ToolbarSubmit loading={saving} onSubmit={onSave}>保存</ToolbarSubmit>} />
<div className={styles['content']}>
<div className={styles.tree}>
<Tabs >
<TabPane tab="已添加" key="1">
<ModuleTreeCollapse />
</TabPane>
<TabPane tab="全部模块" key="2">
<div className={styles.module}>
<Module isWeb={false} />
</div>
</TabPane>
</Tabs>
</div>
</div>
{
detail && (
<RenovationProvider value={{shopId: detail!.shopId}}>
<EditPanel />
</RenovationProvider>
)
}
<div className={styles['app-wrapper']}>
<div className={styles['app-canvas-container']}>
<MobileDesignPanel theme={'theme-mall-science'} onlyEidt />
</div>
</div>
{
detail && (
<RenovationProvider value={{shopId: detail!.shopId}}>
<EditPanel />
</RenovationProvider>
)
}
</div>
</div>
</div>
</BrickProvider>
</Spin>
</BrickProvider>
</Spin>
</div>
);
};
......
@content-height: calc(100vh - 120px);
.container {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
:global {
.ant-spin-nested-loading > div > .ant-spin,
.ant-spin-spinning {
position: fixed;
top: 50%;
left: 50%;
height: 80px;
transform: translate(-50%, -50%);
}
.ant-spin-blur {
opacity: 0;
}
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin-top: 40px;
font-size: 20px;
font-weight: 600;
}
}
.page {
position: fixed;
top: 0;
......
......@@ -5,7 +5,7 @@
flex-direction: row;
.searchPannel {
width: 320px;
width: 230px;
background-color: #fff;
border-radius: 8px;
}
......
......@@ -1822,10 +1822,26 @@
react-dom "^17.0.2"
sortablejs "^1.10.2"
"@linkseeks/design-ui@^1.0.5":
version "1.0.5"
resolved "http://10.0.0.19:4873/@linkseeks%2fdesign-ui/-/design-ui-1.0.5.tgz#0101dbb6e841239599ec9aa428ee7fb7fe3b8ba9"
integrity sha512-h9C8RCUKbbRRdyFdCYtqLiFDZDm5wt0WcQUCEul7fi3UZMYLD5wnHrfh0RSBtgPZdrPOoB3ocdnQUAuNIhYdtA==
"@linkseeks/design-react@^1.0.2":
version "1.0.2"
resolved "http://npm.shushangyun.com/@linkseeks%2fdesign-react/-/design-react-1.0.2.tgz#d91a084ddeaddc4996313cc76bca494172ba6bbc"
integrity sha512-sHpxJCJZVTWHhhnKRcmjtP3GGo6NgVrhhFAZ2N4fQU/Y25Vi48kgE5HNw14PO1DGTXwKS0bCHXlEVjUGoSKBiQ==
dependencies:
"@linkseeks/design-core" "^1.0.0"
"@linkseeks/design-hooks" "^1.0.0"
"@linkseeks/design-utils" "^1.0.0"
html2canvas "^1.0.0-rc.7"
json5 "^2.2.0"
lodash "^4.17.15"
rc-collapse "^2.0.0"
react "^17.0.2"
react-dom "^17.0.2"
sortablejs "^1.10.2"
"@linkseeks/design-ui@^1.0.9":
version "1.0.9"
resolved "http://npm.shushangyun.com/@linkseeks%2fdesign-ui/-/design-ui-1.0.9.tgz#fffef978a0846366ebc59fe951b1089affedbd40"
integrity sha512-230k00FsXrV+x5yXWXukyJZWcWi0ht11zPEtalGGHZAK894NauvGhK7pUQDrvfesABlO+lCrlRv49+NsXDDhgw==
dependencies:
"@linkseeks/design-utils" "^1.0.0"
antd "^4.15.1"
......
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