Commit 3c7921fc authored by GuanHua's avatar GuanHua

feat: B端APP商城装修开发

parent 38ce8f02
......@@ -71,7 +71,7 @@
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"god": "^0.2.9",
"lingxi-design-ui": "^2.0.16",
"lingxi-design-ui": "^2.0.19",
"lint-staged": "^10.0.7",
"mobx": "^5.15.4",
"mobx-react": "^6.2.2",
......
import React from 'react';
import React, { useEffect } from 'react';
import { PageConfigType } from '@lingxi-disign/core';
import { BrickDesign, useSelector } from '@lingxi-disign/react';
......@@ -10,8 +10,7 @@ interface DesignPanelPropsType {
}
const DesignPanel: React.FC<DesignPanelPropsType> = (props) => {
const { theme, pageName = 'index', onlyEidt } = props;
const { pageConfig } = useSelector(['pageConfig']);
const { pageConfig, theme, pageName = 'index', onlyEidt } = props;
return <BrickDesign
pageName={pageName}
......
import React, { useEffect } from 'react';
import { PageConfigType } from '@lingxi-disign/core';
import { BrickDesign, useSelector } from '@lingxi-disign/react';
interface DesignPanelPropsType {
pageConfig?: PageConfigType,
theme: string,
onlyEidt?: boolean,
pageName?: string
}
const DesignPanel: React.FC<DesignPanelPropsType> = (props) => {
const { theme, pageName = 'index', onlyEidt } = props;
const { pageConfig } = useSelector(['pageConfig']);
useEffect(() => {
console.log(pageConfig, 'pageConfig')
}, [pageConfig])
return <BrickDesign
pageName={pageName}
initState={{ pageConfig }}
themeName={theme}
onlyEidt={onlyEidt}
/>;
};
export default DesignPanel;
import React from 'react';
import { PageConfigType } from '@lingxi-disign/core';
// import MobileUIDemo from './mobileUIDemo'
import DesignPanel from './DesignPanel';
import DesignPreview from './DesignPreview';
import DesignPanel from './MobileDesign';
import DesignPreview from './MobilePreview';
import styles from './index.less';
import { useSelector } from '@lingxi-disign/react';
interface MobileDesignPanelPropsType {
......
import React from 'react';
import { PageConfigType } from '@lingxi-disign/core';
import { BrickPreview } from '@lingxi-disign/react';
interface DesignPanelPropsType {
pageConfig?: PageConfigType,
theme: string,
onlyEidt?: boolean,
pageName?: string
}
const DesignPanel: React.FC<DesignPanelPropsType> = (props) => {
const { pageConfig, theme, pageName = 'index', onlyEidt } = props;
return <BrickPreview
pageName={pageName}
initState={{ pageConfig }}
themeName={theme}
onlyEidt={onlyEidt}
/>;
};
export default DesignPanel;
......@@ -500,21 +500,39 @@ export const paramsBusiness = (templateId: number, pageConfig: PageConfigType) =
const { propsConfig } = getComponentConfig(configItem.componentName)
if (propsConfig.componentType) {
let tempProps: any = undefined
switch (propsConfig.componentType.type) {
case PROPS_SETTING_TYPES.mobileHeaderNavAction:
_params.adornContent['headerNav'] = contactList(_params.adornContent['headerNav'], configItem.props?.data)
break
case PROPS_SETTING_TYPES.bannerItems:
tempProps = configItem.props
_params.adornContent['banner'] = contactList(_params.adornContent['banner'], {
id: tempProps.id,
name: tempProps.name,
type: tempProps.type,
img: tempProps.img,
})
break
break
case PROPS_SETTING_TYPES.mobileNavCardNavItem:
const data: any = configItem.props
tempProps = configItem.props
_params.adornContent['navList'] = contactList(_params.adornContent['navList'], {
id: data.id,
name: data.name,
type: data.type,
url: data.url,
icon: data.icon,
id: tempProps.id,
name: tempProps.name,
type: tempProps.type,
url: tempProps.url,
icon: tempProps.icon,
})
break
case PROPS_SETTING_TYPES.mobileShowCase:
tempProps = configItem.props
_params.adornContent['showCase'] = contactList(_params.adornContent['showCase'], {
idList: tempProps.idList || [],
name: tempProps.name,
type: tempProps.type,
banner: tempProps.banner,
inner: tempProps.inner,
})
break
}
......
import { ComponentSchemaType, PROPS_TYPES, PROPS_SETTING_TYPES } from '@lingxi-disign/core';
const ShowCaseBanner: ComponentSchemaType = {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
styleType: {
label: "样式",
type: PROPS_TYPES.number,
},
},
};
const Item: ComponentSchemaType = {
fatherNodesRule: ['ShowCaseBanner.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
label: '内容',
type: PROPS_SETTING_TYPES.mobileShowCase,
},
},
};
export default {
ShowCaseBanner,
'ShowCaseBanner.Item': Item,
};
......@@ -25,6 +25,7 @@ import MobileQuality from './MobileQuality';
import MobileQuickNav from './MobileQuickNav';
import MobileRecommendShops from './MobileRecommendShops';
import MobileShowCase from './MobileShowCase';
import ShowCaseBanner from './ShowCaseBanner';
import Category from './Category';
import PlatformQuickNav from './PlatformQuickNav';
import PlatformAdvert from './PlatformAdvert';
......@@ -78,6 +79,7 @@ export default {
MobileQuickNav,
MobileRecommendShops,
MobileShowCase,
...ShowCaseBanner,
Category,
PlatformQuickNav,
PlatformAdvert,
......
import React, { useEffect, useState } from 'react';
import { BrickProvider } from '@lingxi-disign/react';
import { updatePageConfig } from '@lingxi-disign/core'
import { Prompt } from 'umi';
import { message } from 'antd';
import { GlobalConfig } from '@/global/config';
......@@ -322,6 +323,7 @@ const MallEdit: React.FC<MallEditPropsType> = (props) => {
};
setComponentConfigs(config);
setLoading(false);
updatePageConfig(config)
};
return !loading ? (
......@@ -333,7 +335,7 @@ const MallEdit: React.FC<MallEditPropsType> = (props) => {
>
<Prompt message="你确定要离开么?" />
<div className={styles['wrapper']}>
<ToolBar />
<ToolBar templateId={id} />
<div className={styles['content']}>
<div className={styles['canvas-container']}>
<DesignPanel onlyEidt theme={theme} pageConfig={componentConfigs} />
......
......@@ -3,10 +3,7 @@ import { resolveMappingPageConfig } from '@lingxi-disign/react'
import styleThemeImgDefault from './imgs/style_theme_default.png'
import styleThemeImgScience from './imgs/style_theme_science.png'
import categoryNavTemplateDefault from './imgs/category_template_default.png'
import mineIcon from './imgs/mine_icon.png'
import orderIcon from './imgs/order_icon.png'
import kefuIcon from './imgs/kefu_icon.png'
import showCaseTemplateDefault from './imgs/showcase_template_default.jpg'
export const defaultHeaderNavData = [
{
......@@ -48,7 +45,7 @@ export const defaultConfig: PageConfigType = {
position: 'relative',
},
},
childNodes: ['1', '3', '5']
childNodes: ['1', '3', '5', '7']
},
'1': {
title: '头部导航栏',
......@@ -87,18 +84,22 @@ export const defaultConfig: PageConfigType = {
margin: '8px',
},
},
childNodes: [],
childNodes: ['4'],
childComponentName: 'Banner.Items',
addBtnText: '添加广告',
},
// '4': {
// loop: '${navList}',
// title: '广告图',
// componentName: 'Banner.Items',
// props: {
// },
// },
'4': {
loop: '${banner}',
title: '${item.name}',
componentName: 'Banner.Items',
props: {
id: '${item.name}',
type: '${item.type}',
img: '${item.img}',
name: '${item.name}',
isNull: false,
},
},
'5': {
title: '分类导航',
componentName: 'MobileNavCard',
......@@ -132,6 +133,35 @@ export const defaultConfig: PageConfigType = {
empty: false,
},
},
'7': {
title: '橱窗广告',
componentName: 'ShowCaseBanner',
childComponentName: 'ShowCaseBanner.Item',
props: {
stylesthemelist: [
{
key: 0,
width: 152,
height: 105,
img: showCaseTemplateDefault,
},
]
},
addBtnText: '添加橱窗',
childNodes: ['8'],
},
'8': {
loop: '${showCase}',
title: '${item.name}',
componentName: 'ShowCaseBanner.Item',
props: {
name: '${item.name}',
banner: '${item.banner}',
inner: '${item.inner}',
type: '${item.type}',
idList: '${item.idList}',
},
},
}
// const allState = { headerNav: defaultHeaderNavData }
......
......@@ -202,8 +202,10 @@ const appMallEdit: React.FC<ShopPreviewPropsType> = (props) => {
const appConfig: any = await getAppEnterpriseConfig();
const allState = {
headerNav: appConfig?.headerNav ? appConfig.headerNav : defaultHeaderNavData,
banner: appConfig?.banner ? appConfig?.banner : [],
categoryList: await getFirstCategoryList(),
navList: appConfig?.navList ? appConfig?.navList : []
navList: appConfig?.navList ? appConfig?.navList : [],
showCase: appConfig?.showCase ? appConfig?.showCase : [],
}
const finalConfig = resolveMappingPageConfig(defaultConfig, allState)
console.log(finalConfig, 'finalConfig')
......
@import "../../../../../../global//styles/utils.less";
@import "../../common.less";
.selectBtn {
display: block;
width: 100%;
background-color: #FAFBFC;
border: 1px dashed #D8DDE6;
}
.banner {
&-box {
margin-bottom: 16px;
.uploadPreview {
border: 1px solid #EBECF0;
}
:global {
.ant-upload {
width: 100%;
}
}
&-label {
font-size: 12px;
color: #91959B;
margin-bottom: 8px;
}
&-icon {
height: 96px;
background-color: #FAFBFC;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
&>img {
width: 100%;
}
&-add {
width: 24px;
height: 24px;
}
&:hover {
.banner-box-icon-cover {
display: block;
}
}
&-cover {
position: absolute;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, .1);
display: none;
z-index: 1;
&-delete {
position: absolute;
right: 10px;
top: 10px;
font-size: 20px;
color: #fff;
}
&-bottom {
position: absolute;
height: 24px;
line-height: 24px;
text-align: center;
background-color: rgba(0, 0, 0, 0.24);
font-size: 12px;
color: #fff;
width: 100%;
bottom: 0;
left: 0;
}
}
}
}
&-record {
&-shop {
height: 56px;
border: 1px solid #EDEEEF;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 0 8px;
img {
width: 40px;
height: 40px;
margin-right: 8px;
}
span {
flex: 1;
color: #303133;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
&-integral {
height: 56px;
border: 1px solid #EDEEEF;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 0 8px;
img {
width: 40px;
height: 40px;
margin-right: 8px;
}
&-right {
flex: 1;
display: flex;
flex-direction: column;
&-top {
flex: 1;
color: #303133;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&-bottom {
flex: 1;
color: #EA8000;
font-size: 12px;
}
}
}
&-activity {
height: 56px;
border: 1px solid #EDEEEF;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 0 8px;
position: relative;
img {
width: 40px;
height: 40px;
border-radius: 4px;
margin-right: 8px;
}
&-right {
flex: 1;
display: flex;
flex-direction: column;
font-size: 12px;
&-top {
flex: 1;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&-bottom {
flex: 1;
color: #91959B;
}
}
&-tag{
position: absolute;
right: 0;
top: -3px;
}
}
}
}
import React, { useState, useEffect, useCallback } from 'react';
import { Button, Input, Select, Checkbox, message } from 'antd';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import React, { useMemo, useState } from 'react';
import { Input, Row, Col, Select, Button, Tooltip } from 'antd';
import { DeleteOutlined } from '@ant-design/icons';
import { changeProps } from '@lingxi-disign/core';
import { ReactSortable } from "react-sortablejs";
import ImageBox from '@/components/ImageBox';
import cx from 'classnames';
import isEmpty from 'lodash/isEmpty';
import ModalTable from '@/components/ModalTable';
import { PublicApi } from '@/services/api'
import UploadImage from '@/components/UploadImage';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import SearchSelect from '@/components/NiceForm/components/SearchSelect';
import Search from '@/components/NiceForm/components/Search';
import Submit from '@/components/NiceForm/components/Submit';
import { PublicApi } from '@/services/api';
import { cloneDeep } from 'lodash';
import { numFormat, priceFormat } from '@/utils/numberFomat';
import arrowRightIcon from '@/asserts/icons/arrow_right.png';
import arrowLeftIcon from '@/asserts/icons/arrow_left.png';
import arrowUpIcon from '@/asserts/icons/arrow_up.png';
import arrowDownIcon from '@/asserts/icons/arrow_down.png';
import sortIcon from '@/asserts/icons/sort_icon.png';
import tableColumn from './contant/column';
import { formProduct, basicSchema } from './contant/schema';
import ImageBox from '@/components/ImageBox'
import StatusTag from '@/components/StatusTag'
import MixDrawer from '@/pages/pageCustomized/components/drawers/mixDrawer';
import ActivityDrawer from '@/pages/pageCustomized/components/drawers/activityDrawer';
import uploadImgIcon from '@/asserts/icons/upload_img_icon.svg'
import { priceFormat } from '@/utils/numberFomat';
import styles from './index.less';
interface DataItemType {
id: number,
interface CardNavItemProps {
name: string,
/** 橱窗广告 */
outerImg: string,
/** 内页广告 */
innerImg: string,
/** 类型:1-商品 2-积分 3-店铺 4-品牌 */
type: number,
recommend: number[]
expand: boolean,
selectInfo?: any[]
// 1商城,3积分商品,4店铺,5资讯
type: any,
// 橱窗广告图
banner: string,
// 橱窗内页广告图
inner: string,
icon: string,
idList: number[],
// 当前选中组件的key
selectedKey?: any,
shopId: string,
// 频道 1: 店铺中心; 2:人气店铺; 3:行情资讯; 4:积分兑换
id?: any,
// 1.B端 2.C端 3.SRM
property?: 1 | 2 | 3,
empty?: boolean
}
interface ShowCasePropsType {
dataList: DataItemType[],
visible: boolean,
}
const ChannelTyleList_B = [
{
value: 1,
label: '店铺中心',
},
{
value: 2,
label: '人气店铺',
},
{
value: 3,
label: '行情资讯',
},
{
value: 4,
label: '积分兑换',
},
]
const ChannelTyleList_C = [
{
value: 1,
label: '店铺中心',
},
{
value: 2,
label: '人气店铺',
},
{
value: 4,
label: '积分兑换',
},
]
const modalWidthMap = {
1: 960,
2: 960,
3: 600,
4: 600
};
const RedirectTypeList = [
{
......@@ -60,626 +78,287 @@ const RedirectTypeList = [
},
{
value: 2,
label: '积分',
label: '活动',
},
{
value: 3,
label: '店铺',
label: '积分',
},
{
value: 4,
label: '品牌',
label: '店铺',
},
{
value: 5,
label: '品牌',
}
];
const ShowCase: React.FC<ShowCasePropsType> = (props) => {
const { dataList, visible } = props;
const [list, setList] = useState<DataItemType[]>([]);
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [currentInfo, setCurrentInfo] = useState<DataItemType>();
const [productRowSelection, productRowCtl] = useRowSelectionTable();
const headers: any = {
environment: "4"
};
useEffect(() => {
initDataList();
}, [dataList]);
const initDataList = () => {
if(dataList) {
const newList = cloneDeep(dataList);
const newDataList = newList.map((item: DataItemType, index: number) => {
item.id = index + 1;
item.expand = item.expand || false;
return item;
});
setList(newDataList);
}
};
const handleExpand = async (id: number, expand: boolean) => {
const newList = [...list];
for(const item of newList) {
if (item.id === id) {
item.expand = expand;
// 获取当前选择链接的信息
if(!isEmpty(item.recommend) && !item.selectInfo) {
item.selectInfo = await getSelectInfo(item);
const ShowCase: React.FC<CardNavItemProps> = (props: CardNavItemProps) => {
const { name, type, banner, inner, icon, id, property = 1, empty, shopId, selectedKey } = props;
const [categoryList, setCategoryList] = useState<{label: string, value: number}[]>([])
const [mixVisible, setMixVisible] = useState<boolean>(false);
const [actVisible, setActVisible] = useState<boolean>(false);
const [record, setRecord] = useState<any>();
const getFirstCategoryList = async () => {
if (shopId) {
PublicApi.getSearchCommodityTemplateGetFirstCategoryListByMemberId({ shopId }).then((res) => {
if (res.code === 1000 && res.data) {
const list = res.data.map(item => {
return {
label: item.name,
value: item.id
}
})
console.log(list, 'list')
setCategoryList(list)
} else {
setCategoryList([])
}
} else {
item.expand = false;
}
})
}
setList(newList);
};
/**
* 根据选中的类型和id获取信息
* @param data
*/
const getSelectInfo = (data: DataItemType): Promise<any[] | undefined> => {
return new Promise((resolve) => {
let getFn: any = null;
const param: any = {
current: 1,
pageSize: 100,
};
switch(data.type) {
case 1:
param.idInList = data.recommend;
getFn = PublicApi.postSearchMobileShopEnterpriseGetCommodityList;
break;
case 2:
headers.type = 2;
param.idInList = data.recommend;
getFn = PublicApi.postSearchMobileShopScoreGetCommodityList;
break;
case 3:
param.idList = data.recommend;
getFn = PublicApi.getTemplateWebMemberShopWebPageByIdIn;
break;
case 4:
param.idInList = data.recommend;
getFn = PublicApi.postSearchMobileShopEnterpriseGetBrandList;
break;
default:
break;
}
getFn ? getFn(param, { headers }).then(res => {
message.destroy();
resolve(res.data.data);
}).catch(() => {
resolve(undefined);
}) : resolve(undefined);
});
};
}
const sortUp = (index: number, item: DataItemType) => {
const newList = JSON.parse(JSON.stringify(list));
const tempItem = JSON.parse(JSON.stringify(item));
const temp = newList[index - 1];
newList[index - 1] = item;
newList[index - 1].id = temp.id;
newList[index] = temp;
newList[index].id = tempItem.id;
setList(newList);
changeProps({
props:Object.assign({...props}, {dataList: newList })
});
};
const sortDown = (index: number, item: DataItemType) => {
const newList = JSON.parse(JSON.stringify(list));
const temp = newList[index + 1];
const tempItem = JSON.parse(JSON.stringify(item));
newList[index + 1] = item;
newList[index + 1].id = temp.id;
newList[index] = temp;
newList[index].id = tempItem.id;
setList(newList);
changeProps({
props:Object.assign({...props}, {dataList: newList })
});
};
const handleIconChange = (url: string, id: number, key) => {
const newList = [...list];
newList.map(item => {
if (item.id === id) {
item[key] = url;
}
});
setList(newList);
changeProps({
props:Object.assign({ ...props }, { dataList: newList })
});
};
/**
* 显示隐藏模块
*/
const handleHideChange = (e) => {
const checked = e.target.checked;
changeProps({
props:Object.assign({ ...props }, { visible: !checked })
});
};
/**
* 根据id删除某一项
* @param id
*/
const handleClickItem = (id: number) => {
const newList = [...list];
const result = newList.filter(item => item.id !== id);
setList(result);
changeProps({
props:Object.assign({ ...props }, { dataList: result })
});
};
/**
* 修改跳转类型
*/
const handleTypeChange = (type: number, id: number) => {
const newList = [...list];
newList.map(item => {
if (item.id === id) {
item.type = type;
item.selectInfo = undefined;
const _onChangeByKey = (val: any, key: string, title?: string) => {
if (key === 'type' && Number(val) === 4) {
getFirstCategoryList()
}
const newProps: any = {
[key]: val,
}
if (!empty) {
if (key === 'icon') {
newProps.empty = false
}
});
setList(newList);
changeProps({
props:Object.assign({ ...props }, { dataList: newList })
});
};
}
/**
* 修改广告名称
* @param value
* @param id
*/
const handleNameChange = (value: string, id: number) => {
const newList = [...list];
newList.map(item => {
if (item.id === id) {
item.name = value;
}
});
setList(newList);
changeProps({
props:Object.assign({ ...props }, { dataList: newList })
title: title ? title : name,
props: Object.assign({ ...props }, newProps)
});
};
}
/**
* 添加广告
*/
const handleAddItem = () => {
const newList = [...list];
const newItem: DataItemType = {
id: newList.length + 1,
expand: true,
outerImg: "",
innerImg: "",
recommend: [],
type: 0,
name: ""
};
handleExpand(newItem.id, true);
setList([...newList, newItem]);
changeProps({
props:Object.assign({ ...props }, { dataList: [...newList, newItem] })
});
};
const _showChoose = useMemo(() => {
if (type === 6 || type === 5 || type === 3) {
return false
}
if(!type){
return false
}
return true;
}, [type])
/**
* 删除跳转选项
* @param sort
*/
const handleDeleteSelectItem = (id: number, delelteId: number) => {
const newList = [...list];
newList.map(item => {
if (item.id === id) {
item.recommend = item.recommend.filter(recommendId => recommendId !== delelteId);
item.selectInfo = item.selectInfo ? item.selectInfo.filter(selectInfoItem => selectInfoItem.id !== delelteId) : undefined;
}
});
setList(newList);
changeProps({
props:Object.assign({ ...props }, { dataList: newList })
});
};
const _selectOption = useMemo(() => {
if (property === 1) {
return ChannelTyleList_B
}
if (property === 2) {
return ChannelTyleList_C
}
return []
}, [property])
/**
* 根据类型显示选择的信息
* @param type 1-商品详情 2-积分详情 3-店铺主页 4-资讯详情 5-不跳转
*/
const renderSelectItemByType = useCallback((type: number, item: DataItemType) => {
switch(type) {
case 1:
const _recordDetail = useMemo(() => {
if (record) {
if (type === 1) {
return (
<div>
{
item.selectInfo && item.selectInfo.map(selectItem => (
<div className={styles.setting_line_addItem_line} key={selectItem.id}>
<div className={styles.setting_line_addItem_line_label}></div>
<div className={styles.setting_line_addItem_line_brief}>
<div className={styles.selectInfoBox}>
<ImageBox direction="column" width={60} height={60} imgUrl={selectItem.mainPic}/>
<div className={styles.selectInfo}>
<div className={styles.selectInfo_name}>{selectItem.name}</div>
<div className={styles.selectInfo_price}>{priceFormat(selectItem.min)}</div>
</div>
<div className={styles.selectInfoBox_delete} onClick={() => handleDeleteSelectItem(item.id, selectItem.id)}>
<DeleteOutlined />
</div>
</div>
</div>
</div>
))
}
</div>
);
case 2:
return (
<div>
{
item.selectInfo && item.selectInfo.map(selectItem => (
<div className={styles.setting_line_addItem_line} key={selectItem.id}>
<div className={styles.setting_line_addItem_line_label}></div>
<div className={styles.setting_line_addItem_line_brief}>
<div className={styles.selectInfoBox}>
<ImageBox direction="column" width={60} height={60} imgUrl={selectItem.mainPic}/>
<div className={cx(styles.selectInfo, styles.integral)}>
<div className={styles.selectInfo_name}>{selectItem.name}</div>
<div className={styles.selectInfo_price}>{numFormat(selectItem.min)} 积分</div>
</div>
<div className={styles.selectInfoBox_delete} onClick={() => handleDeleteSelectItem(item.id, selectItem.id)}>
<DeleteOutlined />
</div>
</div>
</div>
</div>
))
}
<div className={styles['banner-record-activity']}>
<img src={record?.logoUrl} />
<div className={styles['banner-record-activity-right']}>
<Tooltip title={record?.name}>
<div className={styles['banner-record-activity-right-top']}>{record?.name}</div>
</Tooltip>
</div>
</div>
);
case 3:
)
}
if (type === 2) {
return (
<div>
{
item.selectInfo && item.selectInfo.map(selectItem => (
<div className={styles.setting_line_addItem_line} key={selectItem.id}>
<div className={styles.setting_line_addItem_line_label}></div>
<div className={styles.setting_line_addItem_line_brief}>
<div className={styles.selectInfoBox}>
<ImageBox direction="column" width={60} height={60} imgUrl={selectItem.logo}/>
<div className={cx(styles.selectInfo, styles.shop)}>
<div className={styles.selectInfo_name}>{selectItem.memberName}</div>
</div>
<div className={styles.selectInfoBox_delete} onClick={() => handleDeleteSelectItem(item.id, selectItem.id)}>
<DeleteOutlined />
</div>
</div>
</div>
</div>
))
}
<div className={styles['banner-record-activity']}>
<img src={record?.templatePicUrl} />
<div className={styles['banner-record-activity-right']}>
<Tooltip title={record?.name}>
<div className={styles['banner-record-activity-right-top']}>{record?.name}</div>
</Tooltip>
{record?.type === 2 && <div className={styles['banner-record-activity-right-bottom']}>{record?.memberName}</div>}
</div>
<div className={styles['banner-record-activity-tag']}><StatusTag title={record?.type === 1 ? '平台' : '商家'} type={record?.type === 1 ? 'success' : 'primary'} /></div>
</div>
);
case 4:
)
}
if (type === 4) {
return (
<div>
{
item.selectInfo && item.selectInfo.map(selectItem => (
<div className={styles.setting_line_addItem_line} key={selectItem.id}>
<div className={styles.setting_line_addItem_line_label}></div>
<div className={styles.setting_line_addItem_line_brief}>
<div className={styles.selectInfoBox}>
<ImageBox direction="column" width={60} height={60} imgUrl={selectItem.logoUrl}/>
<div className={cx(styles.selectInfo, styles.shop)}>
<div className={styles.selectInfo_name}>{selectItem.name}</div>
</div>
<div className={styles.selectInfoBox_delete} onClick={() => handleDeleteSelectItem(item.id, selectItem.id)}>
<DeleteOutlined />
</div>
</div>
</div>
</div>
))
}
<div className={styles['banner-record-shop']}>
<img src={record?.logo} />
<Tooltip title={record?.memberName}>
<span>{record?.memberName}</span>
</Tooltip>
</div>
);
default:
return null;
)
}
}
}, [list]);
}, [type, record])
/**
* 根据类型查询导航栏链接名称
* @param type
*/
const findNameByType = (type: number) => {
switch(type) {
case 1:
return "商品";
case 2:
return "商品";
case 3:
return "店铺";
case 4:
return "品牌";
default:
return "商品";
const _showByType = useMemo(() => {
if (!type) {
return null
}
};
/**
* 打开选择模态框
* @param type
*/
const handleOpenSelectModal = (item: DataItemType) => {
setCurrentInfo(item);
setModalVisible(true);
};
const handleModalOk = async () => {
const selectResult = productRowCtl.selectRow;
if (!selectResult) {
message.info("请选择");
return null;
switch (type) {
case 1:
return (
<div className={styles['banner-box']}>
<div className={styles['banner-box-label']}>推荐商品</div>
<Button>选择</Button>
</div>
)
}
const newList = [...list];
newList.map(item => {
if (item.id === currentInfo?.id) {
item.recommend = [...item.recommend, ...productRowCtl.selectedRowKeys];
if(item.selectInfo) {
item.selectInfo = [...item.selectInfo, ...selectResult];
} else {
item.selectInfo = [...selectResult];
}
}
});
setList(newList);
changeProps({
props:Object.assign({ ...props }, { dataList: newList })
});
setModalVisible(false);
productRowCtl.setSelectRow([]);
productRowCtl.setSelectedRowKeys([]);
};
}, [type])
const handleModalCancel = async () => {
setModalVisible(false);
};
const _onShopClose = () => {
setMixVisible(false);
}
/**
* 获取模态框数据
* @param param
*/
const fetchTableList = async (param: any) => {
const params: any = {
...param,
const _onActClose = () => {
setActVisible(false);
}
};
let getFn: any = null;
switch(currentInfo?.type) {
case 1:
params.priceTypeList = [1];
params.idNotInList = currentInfo.recommend;
getFn = PublicApi.postSearchMobileShopEnterpriseGetCommodityList;
break;
const _onChoose = () => {
switch (type) {
case 2:
headers.type = 2;
params.priceTypeList = [3];
params.idNotInList = currentInfo.recommend;
getFn = PublicApi.postSearchMobileShopScoreGetCommodityList;
break;
case 3:
params.idList = currentInfo.recommend;
getFn = PublicApi.getTemplateWebMemberShopWebPageByIdNotIn;
setActVisible(true);
break;
case 1:
case 4:
params.idNotInList = currentInfo.recommend;
getFn = PublicApi.postSearchMobileShopEnterpriseGetBrandList;
break;
default:
setMixVisible(true);
break;
}
}
const res = getFn ? await getFn(params, { ctlType: 'none', headers }) : await new Promise((resolve) => resolve({data: [], totolCount: 0}));
return res.data;
};
/**
* 根据类型显示文案
* @param type
*/
const showTextByType = (type: number) => {
switch(type) {
case 1:
return "商品";
const _onChooseConfirm = (record) => {
setRecord(record);
switch (type) {
case 2:
return "商品";
case 3:
return "店铺";
changeProps({
props: Object.assign({ ...props }, { id: record.id })
});
_onActClose();
break;
case 1:
case 4:
return "品牌";
default:
return "";
changeProps({
props: Object.assign({ ...props }, { id: record.id })
});
_onShopClose()
break;
}
};
}
return (
<div className={styles.setting}>
<div className={styles.hideModule}>
<Checkbox checked={!visible} onChange={handleHideChange}>隐藏整个模块</Checkbox>
<div className={styles['banner']}>
<div className={styles['banner-box']}>
<div className={styles['banner-box-label']}>名称</div>
<Input key={`${selectedKey}-name`} defaultValue={name} onBlur={(e) => _onChangeByKey(e.target.value, 'name', e.target.value)} />
</div>
<ReactSortable
list={list}
setList={(newList) => {
setList(newList);
if(!isEmpty(newList)) {
changeProps({
props:Object.assign({ ...props }, { dataList: newList })
});
}
}}
handle=".draghandle"
>
{list.map((item, index) => (
<div className={styles.setting_line} key={`setting_${index}`}>
<div className={styles.setting_line_main}>
<div className={styles.setting_line_name} >
<div style={{ flex: 1 }} onClick={() => handleExpand(item.id, !item.expand)}>
{
item.expand ? <img className={styles.icon} src={arrowLeftIcon} /> : <img className={styles.icon} src={arrowRightIcon} />
}
<span>{item.name}</span>
<div className={styles['banner-box']}>
<div className={styles['banner-box-label']}>类型</div>
<Row gutter={20} style={{ marginBottom: 16 }}>
<Col span={24}>
<Select key={`${selectedKey}-type`} defaultValue={type} onChange={(value) => _onChangeByKey(value, 'type')} style={{ width: '100%' }} >
{
RedirectTypeList.map(selectItem => <Select.Option value={selectItem.value} key={`redirect_type_${selectItem.value}`}>{selectItem.label}</Select.Option>)
}
</Select>
</Col>
</Row>
{_recordDetail}
</div>
<div className={styles['banner-box']}>
<div className={styles['banner-box-label']}>橱窗广告图</div>
{ banner ? (
<div className={styles['banner-box-icon']}>
{/* <img src={icon} /> */}
<ImageBox width='100%' height={96} imgUrl={banner} direction='column' />
<div className={styles['banner-box-icon-cover']}>
<UploadImage
onChange={(url) => { _onChangeByKey(url, 'banner') }}
listType="text"
>
<div className={styles['banner-box-icon-cover-bottom']}>
添加图像
</div>
<div className={styles.setting_line_operation}>
<Button type="link" disabled={index === 0} onClick={() => sortUp(index, item)} className={styles.setting_line_operation_btn} icon={<img className={styles.setting_line_operation_btn_icon} src={arrowUpIcon} />}></Button>
<Button type="link" disabled={index === list.length - 1} onClick={() => sortDown(index, item)} className={styles.setting_line_operation_btn} icon={<img className={styles.setting_line_operation_btn_icon} src={arrowDownIcon} />}></Button>
<Button type="link" className={cx(styles.setting_line_operation_btn, "draghandle")} icon={<img className={styles.setting_line_operation_btn_icon} src={sortIcon} />}></Button>
</UploadImage>
<DeleteOutlined className={styles['banner-box-icon-cover-delete']} onClick={() => { _onChangeByKey('', 'banner') }} />
</div>
</div>
) : (
<UploadImage
onChange={(url) => { _onChangeByKey(url, 'banner') }}
listType="text"
>
<div className={styles['banner-box-icon']}>
<img src={uploadImgIcon} className={styles['banner-box-icon-add']} />
<div className={styles['banner-box-icon-cover']}>
<div className={styles['banner-box-icon-cover-bottom']}>
添加图像
</div>
</div>
{
!!item.expand && (
<div className={styles.setting_line_addItem}>
<div className={styles.deleteItem} >
<label onClick={() => handleClickItem(item.id)}>
<DeleteOutlined className={styles.deleteItem_icon} />
<span>删除入口</span>
</label>
</div>
<div className={styles.setting_line_addItem_line}>
<div className={styles.setting_line_addItem_line_label}>名称:</div>
<div className={styles.setting_line_addItem_line_brief}>
<Input value={item.name} onChange={(e) => handleNameChange(e.target.value, item.id)} />
</div>
</div>
<div className={styles.setting_line_addItem_line}>
<div className={styles.setting_line_addItem_line_label}>类型:</div>
<div className={styles.setting_line_addItem_line_brief}>
<Select style={{ width: '100%' }} value={item.type || undefined} onChange={(value) => handleTypeChange(value, item.id)}>
{
RedirectTypeList.map(item => (<Select.Option value={item.value} key={`redirect_type_${item.value}`}>{item.label}</Select.Option>))
}
</Select>
</div>
</div>
<div className={styles.setting_line_addItem_line}>
<div className={styles.setting_line_addItem_line_label}>橱窗广告:</div>
<div className={styles.setting_line_addItem_line_brief}>
<div className={styles.uploadIconWrap}>
<ImageBox className={styles.uploadPreview} width={90} height={90} imgUrl={item.outerImg} />
<UploadImage
fileMaxSize={200}
onChange={(url) => handleIconChange(url, item.id, "outerImg")}
listType="text"
>
<div className={styles.uploadIconBtn}>
<PlusOutlined className={styles.uploadIconBtnIcon} />
<span>点击上传</span>
</div>
</UploadImage>
</div>
<label className={styles.uploadIconTip}>图片建议尺寸:1920*750</label>
<label className={styles.uploadIconTip}>大小:不超过200k</label>
</div>
</div>
<div className={styles.setting_line_addItem_line}>
<div className={styles.setting_line_addItem_line_label}>内页广告:</div>
<div className={styles.setting_line_addItem_line_brief}>
<div className={styles.uploadIconWrap}>
<ImageBox className={styles.uploadPreview} width={90} height={90} imgUrl={item.innerImg} />
<UploadImage
fileMaxSize={200}
onChange={(url) => handleIconChange(url, item.id, "innerImg")}
listType="text"
>
<div className={styles.uploadIconBtn}>
<PlusOutlined className={styles.uploadIconBtnIcon} />
<span>点击上传</span>
</div>
</UploadImage>
</div>
<label className={styles.uploadIconTip}>图片建议尺寸:1920*750</label>
<label className={styles.uploadIconTip}>大小:不超过200k</label>
</div>
</div>
<div className={styles.setting_line_addItem_line}>
<div className={styles.setting_line_addItem_line_label}>推荐{findNameByType(item.type)}</div>
<div className={styles.setting_line_addItem_line_brief}>
<Button className={styles.selectBtn} icon={<PlusOutlined />} onClick={() => handleOpenSelectModal(item)}>选择{findNameByType(item.type)}</Button>
</div>
</div>
{
item.selectInfo ? renderSelectItemByType(item.type, item) : null
}
</div>
)
}
</div>
</UploadImage>
)}
</div>
<div className={styles['banner-box']}>
<div className={styles['banner-box-label']}>内页广告图</div>
{ inner ? (
<div className={styles['banner-box-icon']}>
{/* <img src={icon} /> */}
<ImageBox width='100%' height={96} imgUrl={inner} direction='column' />
<div className={styles['banner-box-icon-cover']}>
<UploadImage
onChange={(url) => { _onChangeByKey(url, 'inner') }}
listType="text"
>
<div className={styles['banner-box-icon-cover-bottom']}>
添加图像
</div>
</UploadImage>
<DeleteOutlined className={styles['banner-box-icon-cover-delete']} onClick={() => { _onChangeByKey('', 'inner') }} />
</div>
</div>
))}
</ReactSortable>
<Button disabled={list.length >= 4} className={styles.selectBtn} icon={<PlusOutlined />} onClick={handleAddItem}>添加橱窗位</Button>
<ModalTable
modalTitle={`选择${showTextByType(currentInfo?.type || 1)}`}
confirm={handleModalOk}
width={modalWidthMap[currentInfo?.type || 1]}
cancel={handleModalCancel}
visible={modalVisible}
scroll={{ y: 400 }}
columns={tableColumn[currentInfo?.type || 1]}
rowSelection={productRowSelection}
fetchTableData={params => fetchTableList(params)}
formilyProps={
{
ctx: {
schema: currentInfo?.type === 1 ? formProduct : basicSchema,
components: { ModalSearch: Search, SearchSelect, Submit } ,
effects: ($, actions) => {
actions.reset();
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
}
}
}
}
resetModal={{
destroyOnClose: true
}}
tableProps={{
rowKey: 'id',
onRow: (record) => ({
onClick: () => {
if(!productRowCtl.selectRow.includes(record)) {
productRowCtl.setSelectRow([...productRowCtl.selectRow, record]);
productRowCtl.setSelectedRowKeys([...productRowCtl.selectRow.map(item => item.id), record.id]);
} else {
productRowCtl.setSelectRow(productRowCtl.selectRow.filter(selectRowItem => selectRowItem.id !== record.id));
productRowCtl.setSelectedRowKeys(productRowCtl.selectedRowKeys.filter(selectedRowKeysItem => selectedRowKeysItem !== record.id));
}
},
})
}}
) : (
<UploadImage
onChange={(url) => { _onChangeByKey(url, 'inner') }}
listType="text"
>
<div className={styles['banner-box-icon']}>
<img src={uploadImgIcon} className={styles['banner-box-icon-add']} />
<div className={styles['banner-box-icon-cover']}>
<div className={styles['banner-box-icon-cover-bottom']}>
添加图像
</div>
</div>
</div>
</UploadImage>
)}
</div>
{
_showByType
}
<MixDrawer
onClose={_onShopClose}
property={property}
type={type}
onConfirm={_onChooseConfirm}
visible={mixVisible}
/>
<ActivityDrawer
selectId={id}
visible={actVisible}
onClose={_onActClose}
onConfirm={_onChooseConfirm}
/>
</div>
);
};
)
}
export default ShowCase;
export default ShowCase
/* eslint-disable no-case-declarations */
import React, { useEffect, useState } from 'react';
import { BrickProvider } from '@lingxi-disign/react';
import { PROPS_SETTING_TYPES } from '@lingxi-disign/core';
import { PROPS_SETTING_TYPES, updatePageConfig } from '@lingxi-disign/core';
import { Prompt } from 'umi';
import { message } from 'antd';
import { GlobalConfig } from '@/global/config';
......@@ -701,6 +701,8 @@ const getInformationByIds = (idList: number[]) => {
setComponentConfigs(config);
setLoading(false);
updatePageConfig(config)
}
};
......@@ -718,7 +720,7 @@ const getInformationByIds = (idList: number[]) => {
</div>
<div className={styles['content']}>
<div className={styles['canvas-container']}>
<DesignPanel onlyEidt theme={theme} pageConfig={componentConfigs} />
<DesignPanel onlyEidt theme={theme} />
</div>
</div>
</div>
......
declare module '*.css';
declare module '*.less';
declare module "*.png";
declare module "*.jpg";
declare module '*.svg' {
export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement
const url: string
......
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