Commit 26d8c6aa authored by Bill's avatar Bill

feat: 品类导航页

parent eb76a0c9
......@@ -46,8 +46,12 @@ const RangeTime: React.FC<Iprops> = (props: Iprops) => {
...innerRangeTime,
[mode]: date,
};
onChange?.([newObject.startTime as unknown as Moment, newObject.endTime as unknown as Moment]);
setInnerRangeTime(newObject);
if (onChange) {
onChange?.([newObject.startTime as unknown as Moment, newObject.endTime as unknown as Moment]);
} else {
setInnerRangeTime(newObject);
}
};
const getDisableDate = useCallback((current: Moment, mode: "startTime" | "endTime") => {
......@@ -69,16 +73,18 @@ const RangeTime: React.FC<Iprops> = (props: Iprops) => {
}
}, [innerRangeTime]);
return (
<div className={cx(styles.container, containerStyle)}>
<div className={styles.wrapFlex}>
<DatePicker
style={{width: '100%'}}
value={innerRangeTime.startTime} onChange={(date: Moment | null, dateString: string) => handleChange(date, dateString, "startTime")}
value={innerRangeTime.startTime}
onChange={(date: Moment | null, dateString: string) => handleChange(date, dateString, "startTime")}
disabledDate={(current) => getDisableDate(current, 'startTime')}
placeholder={placeholader![0]}
disabled={disabled}
showTime
showTime={showTime}
/>
</div>
<span className={styles.splitChar}>~</span>
......@@ -90,7 +96,7 @@ const RangeTime: React.FC<Iprops> = (props: Iprops) => {
disabledDate={(current) => getDisableDate(current, 'endTime')}
placeholder={placeholader![1]}
disabled={disabled}
showTime
showTime={showTime}
/>
</div>
</div>
......
......@@ -59,3 +59,16 @@
.fileEmpty {
margin-bottom: 0;
}
.uploadContainer {
& > span {
width: 100%;
display: flex;
:global {
.ant-upload {
width: 100%;
}
}
}
}
......@@ -24,7 +24,15 @@ interface PickUploadProps extends Pick<UploadProps, PickProps> {
customizeItemRender?: ((files: UploadFile[], handleRemove: (fileItem: UploadFile) => void) => React.ReactNode) | null,
onRemove?: ((fileItem: UploadFile) => void) | null,
/** 是否显示文件 */
showFiles?: boolean
showFiles?: boolean,
/**
* 上传最大数
*/
maxCount?: number,
/**
* 自定义渲染child
*/
renderUploadChild?: (fileList: any[]) => React.ReactNode,
}
const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
......@@ -43,9 +51,12 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
mode,
buttonText,
fileContainerClassName,
showFiles
showFiles,
renderUploadChild,
maxCount,
} = props;
const hasFileListProps = "fileList" in props;
const hasMaxCount = typeof maxCount !== 'undefined' ? { maxCount } : {};
const auth = getAuth();
const [files, setFiles] = useState<UploadFile[]>(() => props.fileList || []);
// const renderFiles = hasFileListProps ? props.fileList : files;
......@@ -97,7 +108,8 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
onChange(info);
}
},
beforeUpload
beforeUpload,
...hasMaxCount
};
const handleRemove = (fileItem: UploadFile) => {
......@@ -165,10 +177,11 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
renderFileContainer()
}
{
<div style={{ order: uploadOrder }}>
<div style={{ order: uploadOrder }} className={styles.uploadContainer}>
<Upload {...uploadProps} >
{renderUploadChild?.(files)}
{
children || (
typeof children !== 'undefined' ? children : (
<Button type={mode} icon={<CloudUploadOutlined />}>
{buttonText}
</Button>
......
......@@ -76,6 +76,9 @@ const schema: ISchema = {
type: 'object',
title: '活动页有效时间',
"x-component": 'RangeTime',
"x-component-props": {
showTime: true,
},
required: true,
},
shopId: {
......
......@@ -238,6 +238,7 @@ const ActivityProductDrawer: React.FC<Iprops> = (props: Iprops) => {
rowSelection={rowSelection as any}
rowKey={(_record) => `${_record.activityId!}-${_record.id!}` }
loading={loading}
pagination={false}
columns={columns} dataSource={selectedActivityProductList}></Table>
</div>
<div className={styles.pagination}>
......
......@@ -59,7 +59,7 @@ const ActivityAreaSetting: React.FC<Iprops> = (props: Iprops) => {
shopId: shopId!
};
const isWithActivityType = selectedType ? {...common, activityType: selectedType} : common;
return await PublicApi.getMarketingPlatformActivityListAdorn(isWithActivityType as any);
return await PublicApi.getMarketingAdornListAdorn(isWithActivityType as any);
};
useEffect(() => {
......
......@@ -51,7 +51,7 @@ const ProductPanel: React.FC<Iprops> = (props: Iprops) => {
...withActivityType
};
const isWithActivityType = common;
return await PublicApi.getMarketingPlatformActivityListAdorn(isWithActivityType as any);
return await PublicApi.getMarketingAdornListAdorn(isWithActivityType as any);
};
const onOk = (data: any) => {
......
......@@ -138,9 +138,14 @@ const Fixtures = () => {
<MobileDesignPanel theme={'theme-mall-science'} onlyEidt />
</div>
</div>
<RenovationProvider value={{shopId: detail!.shopId}}>
<EditPanel />
</RenovationProvider>
{
detail && (
<RenovationProvider value={{shopId: detail!.shopId}}>
<EditPanel />
</RenovationProvider>
)
}
</div>
</div>
......
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { updatePageConfig } from '@lingxi-disign/core';
import { cloneDeep } from 'lodash';
import pageConfig from '../schema/pageConfig';
import mock from '../mock/index.json';
const getData = async () => {
const random = Math.floor(Math.random() * 3) + 1;
return new Promise((resolve) => {
setTimeout(() => {
resolve(mock);
}, random);
});
};
function useGetLayout() {
const [info, setInfo] = useState<any>(null);
useEffect(() => {
updatePageConfig(pageConfig);
async function fetchData() {
const data = await getData();
setInfo(data);
}
fetchData();
}, []);
useEffect(() => {
if(info === null) {
return;
}
const { category } = info;
const startKey = 7;
/** mock data key 对应创建的组件名 */
const componentMap = {
secondary: 'SecondaryNavigation',
flashSale: 'SimpleCommodityList',
saleRanking: 'SimpleCommodityList',
brand: "CategoryList",
suggestProduct: "Container",
};
const grandSonCompoentMap = {
"secondary": 'SecondaryNavigation.Item',
flashSale: 'SimpleCommodityList.Item',
saleRanking: 'SimpleCommodityList.Item',
brand: "CategoryList.Item",
suggestProduct: "Product",
};
let config = {};
const tabKeys: string[] = [];
category.forEach((_item, _index) => {
const tabName = "CustomizeTabs.TabItem";
const configKey = startKey + _index;
tabKeys.push(configKey.toString());
const children = Object.keys(_item.children);
const tabConfig: any = {
componentName: tabName,
title: _item.name,
props: {
name: _item.name,
id: _item.id,
visible: _item.visible,
},
childNodes: [],
};
const tabChild = {};
children.forEach((_child, _childKey) => {
const tabChildKey = `${configKey}-${_childKey + 1}`;
const componentName = componentMap[_child];
const childConfig = {
componentName: componentName,
title: children[_child]?.title || `${configKey}-${_childKey + 1}`,
props: {... children[_child] || {}},
childNodes: [],
childComponentName: grandSonCompoentMap[_child],
addBtnText: '添加子节点',
};
tabChild[tabChildKey] = childConfig;
// const grandsonConfig = {};
// const grandson = _child.children;
// grandson.forEach((_grandsonItem, _grandsonKey) => {
// const grandsonKey = `${tabChildKey}-${_grandsonKey}`;
// const grandsonItemConfig = {
// componentName: grandSonCompoentMap[_child],
// };
// });
});
tabConfig.childNodes = Object.keys(tabChild);
config[configKey] = tabConfig;
config = {
...config,
...tabChild
};
});
const cloneconfig = cloneDeep(pageConfig);
const nodes = [...cloneconfig?.["4"]?.childNodes || [], ...tabKeys];
cloneconfig["4"].childNodes = nodes;
const newConfig = {
...cloneconfig,
...config
};
updatePageConfig(newConfig);
}, [info]);
}
export default useGetLayout;
......@@ -3,108 +3,48 @@
"category":[
{
"id":1,
"status":false,
"visible":false,
"name":"成品皮1",
"children":[
{"id":5, "icon":"logo.png", "name":"牛皮"},
{"id":6, "icon":"logo.png", "name":"牛皮"}
],
"flashSale":{
"status":true,
"title":"限时抢购",
"id":[1, 2, 3]
},
"saleRanking":{
"status":true,
"title":"销量排行榜",
"product":[
{"id":1, "sale":5000},
{"id":2, "sale":10000}
]
},
"brand":{
"status":true,
"title":"精选品牌",
"id":[1, 2, 3]
},
"suggestProduct":{
"status":true,
"title":"新品 - 自定义商品(装修那里需要显示商品, 并且可以设置活动标签)",
"type":3,
"num":null,
"customize":[
{"id":1, "lable":["特价", "满299减30"]},
{"id":2, "lable":[]},
{"id":3, "lable":["特价", "满299减30", "赠帆布袋"]}
]
}
},
{
"id":2,
"status":false,
"name":"成品皮2",
"children":[
{"id":7, "icon":"logo.png", "name":"牛皮"},
{"id":8, "icon":"logo.png", "name":"牛皮"}
],
"flashSale":{
"status":true,
"title":"限时抢购",
"id":[1, 2, 3]
},
"saleRanking":{
"status":true,
"title":"销量排行榜",
"product":[
{"id":1, "sale":5000},
{"id":2, "sale":10000}
]
},
"brand":{
"status":true,
"title":"精选品牌",
"id":[1, 2, 3]
},
"suggestProduct":{
"status":true,
"title":"新品 - 自动按上架时间排序展示(装修那里是不会显示商品的, 所以不需要活动标签)",
"type":2,
"num":50,
"customize":null
}
},
{
"id":3,
"status":false,
"name":"成品皮3",
"children":[
{"id":9, "icon":"logo.png", "name":"牛皮"}
],
"flashSale":{
"status":true,
"title":"限时抢购",
"id":[1, 2, 3]
},
"saleRanking":{
"status":true,
"title":"销量排行榜",
"product":[
{"id":1, "sale":5000},
{"id":2, "sale":10000}
]
},
"brand":{
"status":true,
"title":"精选品牌",
"id":[1, 2, 3]
},
"suggestProduct":{
"status":true,
"title":"新品 - 自动按销量排序展示(装修那里是不会显示商品的, 所以不需要活动标签)",
"type":1,
"num":50,
"customize":null
}
"children": {
"secondary": {
"title": "二级导航",
"children": [
{"id":5, "icon":"logo.png", "name":"牛皮"},
{"id":6, "icon":"logo.png", "name":"牛皮"}
]
}
,
"saleRanking":{
"visible":true,
"title":"销量排行榜",
"children":[
{"id":1, "sale":5000},
{"id":2, "sale":10000}
]
},
"flashSale":{
"visible":true,
"title":"限时抢购",
"children":[1, 2, 3]
},
"brand":{
"visible":true,
"title":"精选品牌",
"children":[1, 2, 3]
},
"suggestProduct":{
"visible":true,
"title":"新品 - 自定义商品(装修那里需要显示商品, 并且可以设置活动标签)",
"type":3,
"num":null,
"children":[
{"id":1, "lable":["特价", "满299减30"]},
{"id":2, "lable":[]},
{"id":3, "lable":["特价", "满299减30", "赠帆布袋"]}
]
}
}
}
]
}
......@@ -19,13 +19,26 @@ const HeaderNav: {[key: string]: ComponentSchemaType} = {
}
};
const CustomizeTabs: ComponentSchemaType = {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
const CustomizeTabs: {[key: string]: ComponentSchemaType} = {
CustomizeTabs: {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
},
},
"CustomizeTabs.TabItem": {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: "TabItem",
},
},
}
};
const SecondaryNavigation: {[key: string]: ComponentSchemaType} = {
......@@ -42,7 +55,10 @@ const SecondaryNavigation: {[key: string]: ComponentSchemaType} = {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
},
componentType: {
type: "SecondaryNavigationItem",
},
},
}
};
......@@ -79,7 +95,10 @@ const SimpleCommodity: {[key: string]: ComponentSchemaType} = {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
},
componentType: {
type: "SimpleCommodityListItem",
},
},
}
};
......@@ -99,7 +118,10 @@ const CategoryList: {[key: string]: ComponentSchemaType} = {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
},
componentType: {
type: "CategoryListItem",
},
},
}
};
......@@ -109,7 +131,10 @@ const Product: ComponentSchemaType = {
children: {
label: '内容',
type: PROPS_TYPES.string,
}
},
componentType: {
type: "ProductItem",
},
},
};
......@@ -117,7 +142,7 @@ export default {
...HeaderNav,
...SecondaryNavigation,
...SimpleCommodity,
CustomizeTabs,
...CustomizeTabs,
CustomizeCard,
Container,
...CategoryList,
......
......@@ -11,77 +11,27 @@ const template = {
childNodes: []
},
"6-2": {
componentName: 'Container',
componentName: 'SimpleCommodityList',
title: '秒杀',
props: {
cardProps: {
title: '今日大牌秒杀',
headStyle: {
padding: '0 12px'
},
bodyStyle: {
padding: '0 12px 12px 12px',
overflowX: 'auto'
},
},
listStyle: {
marginRight: '-12px',
},
itemStyle: {
marginRight: '12px',
}
},
addBtnText: '添加秒杀商品',
childComponentName: 'SimpleCommodityList.Item',
props: {},
childNodes: []
},
"6-3": {
componentName: 'Container',
componentName: 'SimpleCommodityList',
title: '品类销量排行',
addBtnText: '添加销量排行商品',
childComponentName: 'SimpleCommodityList.Item',
props: {
cardProps: {
title: '品类销量排行',
headStyle: {
padding: '0 12px'
},
bodyStyle: {
padding: '0 12px 12px 12px',
overflowX: 'auto'
},
},
listStyle: {
marginRight: '-12px',
},
itemStyle: {
marginRight: '12px',
}
},
props: {},
childNodes: []
},
"6-4": {
componentName: 'Container',
componentName: 'CategoryList',
title: '品牌',
addBtnText: '添加品牌',
childComponentName: 'CategoryList.Item',
props: {
cardProps: {
bodyStyle: {
padding: '12px 16px',
},
bordered: false,
},
listStyle: {
marginRight: '-34px',
marginBottom: '-12px',
flexWrap : 'wrap',
alignItems: 'center',
},
itemStyle: {
flexBasic: '25%',
paddingRight: '24px',
marginBottom: '12px',
}
},
props: {},
childNodes: []
},
"6-5": {
......@@ -162,24 +112,24 @@ const tab: PageConfigType = {
"4": {
componentName: 'CustomizeTabs',
title: 'tab',
props: {
defaultActiveKey: "2",
},
childComponentName: 'div',
props: {},
childComponentName: 'CustomizeTabs.TabItem',
addBtnText: '添加Tab',
childNodes: ['5', "6"],
childNodes: ["5",],
childProps: {
title: 'tab',
props: {
tab: 'tab',
}
}
},
template: template,
},
},
"5": {
componentName: 'div',
title: '首页',
props: {
tab: '首页',
name: '首页',
disabled: true,
// children: 123123
},
......@@ -190,13 +140,11 @@ const tab: PageConfigType = {
const tabContent: PageConfigType = {
"6": {
componentName: 'div',
componentName: 'CustomizeTabs.TabItem',
title: '数码',
props: {
tab: '数码',
style: {
padding: '8px 8px 0 8px'
}
id: 1,
},
childNodes: ['6-1', "6-2", "6-3", "6-4", "6-5"],
},
......@@ -205,35 +153,19 @@ const tabContent: PageConfigType = {
title: "二级导航",
addBtnText: '添加导航',
childComponentName: 'SecondaryNavigation.Item',
childNodes: ['6-1-1']
childNodes: ['6-1-1'],
},
"6-1-1": {
componentName: 'SecondaryNavigation.Item',
title: "二级导航-标签",
},
"6-2": {
componentName: 'Container',
componentName: 'SimpleCommodityList',
title: '秒杀',
addBtnText: '添加秒杀商品',
childComponentName: 'SimpleCommodityList.Item',
props: {
cardProps: {
title: '今日大牌秒杀',
headStyle: {
padding: '0 12px'
},
bodyStyle: {
padding: '0 12px 12px 12px',
overflowX: 'auto'
},
},
listStyle: {
marginRight: '-12px',
},
itemStyle: {
marginRight: '12px',
}
},
props: {},
childNodes: ["6-2-1"]
},
"6-2-1": {
......@@ -246,28 +178,11 @@ const tabContent: PageConfigType = {
}
},
"6-3": {
componentName: 'Container',
componentName: 'SimpleCommodityList',
title: '品类销量排行',
addBtnText: '添加销量排行商品',
childComponentName: 'SimpleCommodityList.Item',
props: {
cardProps: {
title: '品类销量排行',
headStyle: {
padding: '0 12px'
},
bodyStyle: {
padding: '0 12px 12px 12px',
overflowX: 'auto'
},
},
listStyle: {
marginRight: '-12px',
},
itemStyle: {
marginRight: '12px',
}
},
props: {},
childNodes: ["6-3-1"]
},
"6-3-1": {
......@@ -280,29 +195,11 @@ const tabContent: PageConfigType = {
}
},
"6-4": {
componentName: 'Container',
componentName: 'CategoryList',
title: '品牌',
addBtnText: '添加品牌',
childComponentName: 'CategoryList.Item',
props: {
cardProps: {
bodyStyle: {
padding: '12px 16px',
},
bordered: false,
},
listStyle: {
marginRight: '-34px',
marginBottom: '-12px',
flexWrap : 'wrap',
alignItems: 'center',
},
itemStyle: {
flexBasic: '25%',
paddingRight: '24px',
marginBottom: '12px',
}
},
props: {},
childNodes: ["6-4-1"]
},
"6-4-1": {
......@@ -341,7 +238,7 @@ const configs = {
...mallLayoutConfig,
...header,
...tab,
...tabContent,
// ...tabContent,
// ...spike,
// ...rank,
// ...category,
......
.editPanel {
background-color: #fff;
position: absolute;
bottom: 0;
right: 0;
top: 0;
overflow-y: auto;
transition: width .25s;
display: flex;
flex-direction: column;
&.hide {
width: 0;
}
&.show {
width: 400px;
}
.header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid #f5f6f7;
.title {
font-size: 16px;
color: #252d37;
}
}
.content {
padding: 16px;
flex: 1,
}
.footer {
display: flex;
flex-direction: row-reverse;
padding: 12px;
border-top: 1px solid #f5f6f7;
}
.image {
margin-top: 8px;
width: 100%;
background-color: #fafbfc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
height: 96px;
.imageIcon {
width: 40px;
height: 40px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
}
}
import React, { useEffect, useMemo, useState } from 'react';
import { changeProps, PageConfigType, SelectedInfoType, StateType, STATE_PROPS, } from '@lingxi-disign/core';
import { useSelector } from '@lingxi-disign/react';
import cs from 'classnames';
import { usePrevious, useToggle } from '@umijs/hooks';
import { CloseOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { Button, Space, Spin , message } from 'antd';
import { createFormActions, FormEffectHooks } from '@formily/antd';
import styles from './editPanel.less';
import { tabTitleSchema, secondaryTabSchema, blockSchema } from './schema';
import NiceForm from '@/components/NiceForm';
import FormilyUpload from '@/components/UploadFiles/FormilyUploadFiles';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { PublicApi } from '@/services/api';
import { DATE_SELECT_TYPE } from '@/components/NiceForm/components/DateSelect';
type SettingPanelType = {
selectedInfo: SelectedInfoType,
pageConfig: PageConfigType,
activeKey?: string,
domKey?: string,
}
const ComponentSchema = {
TabItem: tabTitleSchema,
SecondaryNavigationItem: secondaryTabSchema,
CategoryListItem: secondaryTabSchema
};
const DEFAULT = {
data: [],
totalCount: 0,
};
const formActions = createFormActions();
const { onFieldInputChange$, onFieldChange$ } = FormEffectHooks;
const EditPanel = () => {
const { selectedInfo, pageConfig, activeKey, domKey } = useSelector<SettingPanelType, STATE_PROPS | "activeKey" | "domKey">(['selectedInfo', 'pageConfig', 'activeKey', "domKey"]);
const {state: visible, toggle: setVisible } = useToggle(true);
const [schema, setSchema] = useState<any>(null);
const previousActiveKey = usePrevious(activeKey);
const [formValue, setFormValue] = useState({});
const [type, setType] = useState<string>("TabItem");
useEffect(() => {
if (activeKey === null || previousActiveKey !== activeKey) {
if(activeKey === null) {
message.info("请先选择一级导航类型");
}
setType("TabItem");
const primaryTabProps = pageConfig[domKey!].props;
setFormValue({
primary: primaryTabProps?.id,
title: primaryTabProps?.name,
});
setSchema(tabTitleSchema);
setVisible(true);
return;
}
const componentType = selectedInfo?.propsConfig?.componentType?.type;
const targetSchema = ComponentSchema[componentType as any] || null;
console.log(type);
setType(componentType as string);
if (targetSchema) {
setSchema(targetSchema);
setVisible(true);
} else {
setVisible(false);
}
}, [selectedInfo, activeKey]);
const handleOncancel = () => {
setVisible(false);
};
const className = cs(styles.editPanel, {
[styles.hide]: !visible,
[styles.show]: visible
});
const renderUploadChild = (value) => {
const target = value[0];
return (
<div className={styles.image}>
<div className={styles.imageIcon}>
<Spin spinning={target?.status === 'uploading'}>
{
target ? <img src={target?.url} style={{width: '100%', height: '100%'}} /> : <PlusCircleOutlined />
}
</Spin>
</div>
</div>
);
};
const handleSubmit = (values) => {
console.log(values);
/** 如果是tab 类型修改 */
const key = selectedInfo?.selectedKey || domKey;
console.log(key);
changeProps({
treeKey: key,
props: {
name: values.title,
id: values.primary,
},
title: values.title,
});
};
const fetchPrimaryOption = async () => {
const { data, code } = await PublicApi.getSearchCommodityTemplateGetFirstCategoryListByMemberId({
shopId: 251
});
return data;
};
const fetchSecondaryOption = async () => {
console.log(activeKey);
if(!activeKey) {
return DEFAULT;
}
const { data, code } = await PublicApi.getSearchCommodityTemplateGetSecondCategoryListByMemberId({
shopId: 251,
categoryId: activeKey,
});
return data;
};
/** 这样写纯粹是为了区分修改tab 跟修改该 二级菜单的,因为如果form 挂载了,那么二级菜单在一级菜单修改时就不会再请求接口了,没想到好的方法 */
const renderForm = () => {
const props = {
value: formValue,
onSubmit: handleSubmit,
expressionScope: {
renderUploadChild,
},
actions: formActions,
components: {FormilyUpload},
};
return (
<NiceForm
{...props}
schema={schema}
effects={($, actions) => {
useAsyncSelect('primary', fetchPrimaryOption, ["name", "id"]);
useAsyncSelect('secondary', fetchSecondaryOption, ["name", "id"]);
onFieldInputChange$('*(primary, secondary)').subscribe(fieldState => {
const { originAsyncData } = fieldState;
const target = originAsyncData.filter((_item) => _item.value === fieldState.value)[0];
actions.setFieldValue('title', target.label);
});
}}
/>
);
};
return (
<div style={{position: 'relative', width: '400px'}}>
<div className={className}>
<div className={styles.header}>
<span className={styles.title}>内容</span>
<CloseOutlined onClick={handleOncancel} />
</div>
<div className={styles.content}>
{
renderForm()
}
</div>
<div className={styles.footer}>
<Space>
<Button>取消</Button>
<Button type="primary" onClick={() => formActions.submit()}>确认</Button>
</Space>
</div>
</div>
</div>
);
};
export default EditPanel;
import EditPanel from "./editPanel";
export {
EditPanel
};
.label {
color: #91959b;
font-size: 12px;
margin-bottom: 8px;
}
.container {
display: flex;
flex-direction: column;
}
.image {
margin-top: 8px;
width: 100%;
.imgContainer {
background-color: #fafbfc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
height: 96px;
.imageIcon {
width: 40px;
height: 40px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
}
}
import React from 'react';
import { Select, Input } from 'antd';
import { PlusCircleOutlined } from '@ant-design/icons';
import styles from './panelContent.less';
import UploadFiles from '@/components/UploadFiles/UploadFiles';
interface Icategory {
title: string,
options: []
}
const Category = () => {
return (
<div className={styles.container}>
<p className={styles.label}>品类</p>
<Select />
</div>
);
};
const EditBlockTitle = () => {
return (
<div className={styles.container}>
<p className={styles.label}>标题</p>
<Input />
</div>
);
};
const EditSecondaryCategoryBlock = () => {
return (
<div className={styles.wrap}>
<Category />
<div className={styles.image}>
<p className={styles.label}>图标</p>
<div className={styles.imgContainer}>
<UploadFiles>
<div className={styles.imageIcon}>
<PlusCircleOutlined />
</div>
</UploadFiles>
</div>
</div>
</div>
);
};
const PanelContent: {
Category: typeof Category,
EditBlockTitle: typeof EditBlockTitle,
EditSecondaryCategoryBlock: typeof EditSecondaryCategoryBlock
} = {
Category: Category,
EditBlockTitle: EditBlockTitle,
EditSecondaryCategoryBlock: EditSecondaryCategoryBlock
};
export default PanelContent;
import { ISchema } from "@formily/antd";
/** 一级标签 */
export const tabTitleSchema: ISchema = {
type: 'Object',
properties: {
layout: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: "top"
},
properties: {
primary: {
type: 'string',
title: '类型',
enum: [],
},
title: {
type: 'string',
display: false,
}
}
}
}
};
/** 二级标签 */
export const secondaryTabSchema: ISchema = {
type: 'Object',
properties: {
layout: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: "top"
},
properties: {
secondary: {
type: 'string',
title: '类型',
enum: [],
},
title: {
type: 'string',
display: false,
},
icon: {
type: 'string',
title: '图标',
"x-component": 'FormilyUpload',
"x-component-props": {
renderUploadChild: '{{renderUploadChild}}',
showFiles: false,
customizeItemRender: null,
children: null,
maxCount: 1,
},
}
}
}
}
};
/** 区块标题 */
export const blockSchema: ISchema = {
type: 'Object',
properties: {
layout: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: "top"
},
properties: {
title: {
type: 'string',
title: '标题',
},
}
}
}
};
import React from 'react';
import cs from 'classnames';
import styles from './index.less';
import CustomizeCard from '../Card';
import Container from '../Container';
interface Iprops {
children: React.ReactElement
......@@ -9,29 +9,32 @@ interface Iprops {
const CategoryList: React.FC<Iprops> & { Item: typeof CategoryItem } = (props: Iprops) => {
const { children } = props;
const cardProps = {
bodyStyle: {
padding: '12px 16px',
},
bordered: false,
};
const listStyle = {
marginRight: '-34px',
marginBottom: '-12px',
flexWrap : 'wrap',
alignItems: 'center',
};
const itemStyle = {
flexBasic: '25%',
paddingRight: '24px',
marginBottom: '12px',
};
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, className, ...rest} = props as any;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, className
};
const wrapClass = cs(className, styles.wrap);
return (
<div className={wrapClass} {...divProps}>
<CustomizeCard bordered={false} bodyStyle={{padding: '12px 16px'}}>
<div className={styles.list}>
{
React.Children.map(children, (_child, _index) => {
const node = React.cloneElement(_child);
return (
<div key={_index} className={styles.item}>
{node}
</div>
);
})
}
</div>
</CustomizeCard>
</div>
<Container cardProps={cardProps} listStyle={listStyle as any} itemStyle={itemStyle as any} {...divProps}>
{children}
</Container>
);
};
......
......@@ -2,6 +2,7 @@ import React from 'react';
import { SimpleCommodity, CustomizeTag } from '@lingxi-disign/ui';
import cs from 'classnames';
import styles from './simple.less';
import Container from '../Container';
interface Iprops {
......@@ -10,19 +11,33 @@ interface Iprops {
const SimpleCommodityList: React.FC<Iprops> & { Item: typeof SimpleItem } = (props: Iprops) => {
const { children } = props;
const cardProps = {
title: '今日大牌秒杀',
headStyle: {
padding: '0 12px'
},
bodyStyle: {
padding: '0 12px 12px 12px',
overflowX: 'auto'
},
};
const listStyle = {
marginRight: '-12px',
};
const itemStyle = {
marginRight: '12px',
};
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, className, ...rest} = props as any;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, className
};
return (
<div className={styles.list}>
<Container card={true} cardProps={cardProps as any} listStyle={listStyle} itemStyle={itemStyle} {...divProps}>
{
React.Children.map(children, (_child, _index) => {
const node = React.cloneElement(_child);
return (
<div key={_index} className={styles.simpleItem}>
{node}
</div>
);
})
}
</div>
children
}
</Container>
);
};
......
......@@ -4,12 +4,12 @@ import { Card } from 'antd';
import styles from './index.less';
import CustomizeCard from '../Card';
type CardProps = React.ComponentProps<typeof Card>;
type CardProps = Omit<React.ComponentProps<typeof Card>, 'children'>;
interface Iprops {
children: React.ReactElement,
card: boolean,
card?: boolean,
cardProps?: CardProps,
listStyle?: CSSProperties,
itemStyle?: CSSProperties
......@@ -31,6 +31,9 @@ const Container: React.FC<Iprops> = (props: Iprops) => {
<div className={styles.list} style={listStyle}>
{
React.Children.map(children, (_child, _index) => {
if(_child === null) {
return null;
}
const node = React.cloneElement(_child);
return (
<div key={_index} className={styles.item} style={itemStyle}>
......@@ -45,6 +48,9 @@ const Container: React.FC<Iprops> = (props: Iprops) => {
<div className={styles.list} style={listStyle}>
{
React.Children.map(children, (_child, _index) => {
if(_child === null) {
return null;
}
const node = React.cloneElement(_child);
return (
<div key={_index} className={styles.item} style={itemStyle}>
......
......@@ -22,6 +22,10 @@ const SecondaryNavigation: React.FC<Iprops> & { Item: typeof Item } = (props: Ip
<div className={styles.list}>
{
React.Children.map(children, (_item) => {
console.log(children);
if (_item === null) {
return null;
}
return React.cloneElement(_item);
})
}
......
import React from 'react';
import React, { Children, useState } from 'react';
import { Tabs } from 'antd';
import cs from 'classnames';
import {createActions} from '@lingxi-disign/react';
import styles from './index.less';
const { TabPane } = Tabs;
interface Iprops {
......@@ -10,8 +12,10 @@ interface Iprops {
children: React.ReactElement,
}
const CustomizeTabs: React.FC<Iprops> = (props: Iprops) => {
const { children, defaultActiveKey } = props;
const CustomizeTabs: React.FC<Iprops> & { TabItem: typeof TabItem } = (props: Iprops) => {
const { children } = props;
const [activeKey, setActiveKey] = useState<string>("2");
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, className, ...rest} = props as any;
/** guaidLine 属性 */
const divProps = {
......@@ -19,26 +23,53 @@ const CustomizeTabs: React.FC<Iprops> = (props: Iprops) => {
};
const node = React.Children.map(children, (_item, index) => {
if(_item === null) {
return null;
}
const cloneNode = React.cloneElement(_item);
return (
<TabPane tab={_item.props.tab} key={index.toString()} disabled={_item.props.disabled || false}>
<div {...divProps}>
{/* <SecondaryNavigation></SecondaryNavigation> */}
<TabPane tab={_item.props.name} key={`id_${_item.props?.id?.toString()}`} disabled={_item.props.disabled || false}>
{/* <div {...divProps}>
{ cloneNode }
</div>
</div> */}
{cloneNode}
</TabPane>
);
});
const wrapClass = cs(className, styles.wrap);
const onChange = async (activeKey: string) => {
const matches = activeKey.match(/id_(.*)\/\.\$(\d+)/);
createActions({ type: 'onChangeTabKey', payload: { activeKey: matches?.[1] === 'undefined' ? null : matches?.[1] , domKey: matches?.[2] } });
setActiveKey(activeKey);
};
return (
<div {...divProps} className={wrapClass}>
<Tabs defaultActiveKey={defaultActiveKey} tabBarStyle={{background: '#fff', padding: '0 12px'}}>
<div className={wrapClass}>
<Tabs onChange={onChange} activeKey={activeKey} tabBarStyle={{background: '#fff', padding: '0 12px'}}>
{node}
</Tabs>
</div>
);
};
const TabItem = (props) => {
const { children } = props;
const { onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, getOperateState, className } = props as any;
const divProps = {
onClick, onDrag, onDragEnd, onDragEnter, onDragStart, onMouseOver, className
};
return (
<div {...divProps} style={{padding: '8px'}}>
{/* <SecondaryNavigation></SecondaryNavigation> */}
{ children }
</div>
);
};
CustomizeTabs.TabItem = TabItem;
export default CustomizeTabs;
......@@ -2,12 +2,23 @@ import React from 'react';
import { Spin, message } from 'antd';
import { BrickProvider, ModuleTree } from '@lingxi-disign/react';
import ToolbarSubmit from '@/pages/marketing/marketingActivitiesManagement/activePage/fixtures/components/Toolbar/toolbarSubmit';
import Toolbar from '@/pages/marketing/marketingActivitiesManagement/activePage/fixtures/components/Toolbar';
import MobileDesignPanel from '@/pages/marketing/marketingActivitiesManagement/activePage/fixtures/components/MobileDesignPanel';
import styles from './index.less';
import configs from './common/schema';
import useGetLayout from './common/hooks/useGetLayout';
import { EditPanel } from './components/EditPanel';
import MobileDesignPanel from '@/pages/marketing/marketingActivitiesManagement/activePage/fixtures/components/MobileDesignPanel';
import Toolbar from '@/pages/marketing/marketingActivitiesManagement/activePage/fixtures/components/Toolbar';
import ToolbarSubmit from '@/pages/marketing/marketingActivitiesManagement/activePage/fixtures/components/Toolbar/toolbarSubmit';
const customReducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case 'onChangeTabKey':
return { ...state, index: { ...state.index, ...payload } };
default:
return state;
}
};
const CategoryNavigation = () => {
useGetLayout();
......@@ -21,19 +32,20 @@ const CategoryNavigation = () => {
warn={(msg: string) => {
message.warning(msg);
}}
customReducer={customReducer}
>
<div className={styles['wrapper']}>
<Toolbar title="正在编辑:平台营销活动页" extra={<ToolbarSubmit loading={false} onSubmit={onSave}>保存</ToolbarSubmit>} />
<Toolbar title="正在编辑:品类导航页" extra={<ToolbarSubmit loading={false} onSubmit={onSave}>保存</ToolbarSubmit>} />
<div className={styles['content']}>
<div className={styles.tree}>
<ModuleTree />
</div>
<div className={styles['app-wrapper']}>
<div className={styles['app-canvas-container']}>
<MobileDesignPanel theme={'theme-mall-science'} onlyEidt />
</div>
</div>
<EditPanel />
</div>
</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