Commit c5b6a081 authored by GuanHua's avatar GuanHua

feat: app店铺装修开发

parent ac82a9dd
.textOverflowMulti2(@line: 3) {
display: -webkit-box;
/* autoprefixer: off */
-webkit-box-orient:vertical;
/* autoprefixer: on */
-webkit-line-clamp: @line;
overflow: hidden;
}
.section {
display: flex;
flex-direction: row;
align-items: center;
padding: 16px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px 0 rgba(0,0,0,0.04);
transition: width 0.5s;
overflow: hidden;
width: 72px;
height: 72px;
border: 1px solid transparent;
.img {
width: 40px;
height: 40px;
margin-right: 16px;
flex-shrink: 0;
}
&:hover {
width: 384px;
border: 1px solid @primary-color;
}
.info {
display: flex;
flex-direction: column;
flex: 1;
.titleContainer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.title {
font-size: 14px;
color: #252D37;
flex: 1;
.textOverflowMulti2(1)
}
}
.footer {
margin-top: 4px;
overflow: hidden;
.id {
margin-right: 16px;
font-size: 12px;
color: #909399;
}
}
}
}
.indeterminate {
border: 1px solid #1890ff;
}
.active {
width: 384px;
border: 1px solid @primary-color;
}
import React from 'react';
import StatusTag from '@/components/StatusTag';
import cx from 'classnames';
import styles from './activityItem.less';
interface Iprops {
id: number,
activityName: string,
activityTypeName: string,
statusName: string,
isActive: boolean,
onSelect?: ( (id: number) => void) | null,
hasChildSelected?: boolean,
activityImage: string,
}
const ActivityItem: React.FC<Iprops> = (props: Iprops) => {
const { id, activityName, activityTypeName, statusName, isActive = false, onSelect = null, hasChildSelected = false, activityImage } = props;
const triggerSelect = () => {
onSelect?.(id);
};
const mergeClasses = cx(styles.section, {
[styles.indeterminate]: hasChildSelected,
[styles.active]: isActive,
})
return (
<div onClick={triggerSelect} className={mergeClasses}>
<img className={styles.img} src={activityImage}/>
<div className={styles.info}>
<div className={styles.titleContainer}>
<span className={styles.title}>{activityName}</span>
<StatusTag title={statusName} type="success" />
</div>
<div className={styles.footer}>
<span className={styles.id}>ID: {id}</span>
<StatusTag type="default" title={activityTypeName} />
</div>
</div>
</div>
);
};
export default ActivityItem;
.productImg {
width: 64px;
height: 64px;
border-radius: 8px;
overflow: hidden;
}
.productName {
font-size: 14px;
color: #252D37;
line-height: 20px
}
.priceInfo {
font-size: 14px;
color: #D32F2F;
.unit {
color: #909399;
font-size: 12px;
}
}
.container {
display: flex;
flex-direction: column;
height: 100%;
.form {}
.table {
display: flex;
flex-direction: row;
align-items: center;
.activeItem + .activeItem {
margin-left: 8px;
}
}
.expandableTable {
margin-top: 16px;
}
.pagination {
margin-top: auto;
display: flex;
flex-direction: row-reverse;
}
}
.drawerFooter {
display: flex;
flex-direction: row-reverse;
}
/* eslint-disable react/display-name */
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Drawer, Table, Button, Space, Pagination, Spin } from 'antd';
import NiceForm from '@/components/NiceForm';
import { createFormActions } from '@formily/antd';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';
import { ColumnsType } from 'antd/es/table';
import { GetMarketingPlatformActivityListAdornResponseDetail } from '@/services/MaketingV2Api';
import StatusTag from '@/components/StatusTag';
import schema from './schema';
import styles from './activityProductDrawer.less';
import ActivityItem from './activityItem';
const actions = createFormActions();
interface Iprops {
visible: boolean,
onCancel: (() => void) | null,
fetchData?: ((params: any) => Promise<any>) | null,
onOk?: ((data: any) => void) | null,
/** 传入的已选择的活动商品 */
products: any[],
activityImage: string,
mode?: 'radio' | 'checked',
}
type SubmitType = {
id: number,
activityName: string,
}
const columns: ColumnsType<GetMarketingPlatformActivityListAdornResponseDetail["productList"][0]> = [
{
title: '商品信息',
dataIndex: 'productInfo',
render: (_text, _record) => {
return (
<Space align="center">
<img src={_record.productImgUrl} className={styles.productImg} />
<span className={styles.productName}>{_record.productName}</span>
</Space>
);
}
},
{
title: '品类',
dataIndex:'category',
render: (_text) => {
return <StatusTag title={_text} type="default" />;
}
},
{
title: '品牌',
dataIndex: 'brand'
},
{
title: '商家名称',
dataIndex: 'memberName',
},
{
title: '单价',
dataIndex: 'unit',
render: (_text, _record) => {
return (
<div className={styles.priceInfo}>
<span>{_record.price}</span>
<span className={styles.unit}>({_record.unit})</span>
</div>
);
}
},
{
title: '活动价',
dataIndex: 'activityPrice',
render: (_text, _record) => {
return (
<div className={styles.priceInfo}>
<span>{_record.activityPrice}</span>
<span className={styles.unit}>({_record.unit})</span>
</div>
);
}
}
];
const ActivityProductDrawer: React.FC<Iprops> = (props: Iprops) => {
const { visible, onCancel, fetchData = null, onOk, products = [], activityImage, mode = 'checked' } = props;
const [current, setPage] = useState<number>(1);
const [currentPageSize, setPageSize] = useState<number>(10);
const [dataSource, setDataSource] = useState<GetMarketingPlatformActivityListAdornResponseDetail[]>([]);
const [totalCount, setTotalCount] = useState<number>(0);
const [selectedKey, setSelectKey] = useState<number | null>(null);
const [selectedActivityProductList, setSelectedActivityProductList] = useState<GetMarketingPlatformActivityListAdornResponseDetail["productList"]>();
const [checkedProduct, setCheckedProduct] = useState<GetMarketingPlatformActivityListAdornResponseDetail["productList"]>([]);
const [loading, setLoading] = useState<boolean>(false);
const selectedRowKeys = useMemo(() => checkedProduct.map((_item) => `${_item.activityId!}-${_item.id!}`), [checkedProduct]);
const fetchList = useCallback(async (params: any) => {
if (fetchData === null) {
return;
}
setLoading(true);
const { data, code } = await fetchData(params);
if (code === 1000) {
batchedUpdates(() => {
setLoading(false);
setDataSource(data.data);
setTotalCount(data.totalCount);
});
}
}, [fetchData]);
useEffect(() => {
if (!visible) {
return ;
}
setCheckedProduct(products);
fetchList({ current, pageSize: currentPageSize });
}, [current, currentPageSize, visible,]);
const onSubmit = (value: SubmitType) => {
console.log(value);
fetchList({ current, pageSize: currentPageSize, ...value });
};
const onReset = () => {
// actions.reset();
fetchList({ current, pageSize: currentPageSize });
};
// useEffect(() => {})
const handleCancel = () => {
onCancel?.();
};
const onChange = (page: number, pageSize?: number) => {
batchedUpdates(() => {
setPage(page);
setPageSize(pageSize || 10);
});
};
const onSelect = (id: number) => {
setSelectKey(id);
const target = dataSource.filter((_item) => _item.id === id)[0];
setSelectedActivityProductList(target.productList);
};
const handleOk = () => {
onOk?.(checkedProduct);
};
const handleRowSelect = (record: GetMarketingPlatformActivityListAdornResponseDetail["productList"][0], selected: boolean, selectedRows: GetMarketingPlatformActivityListAdornResponseDetail["productList"]) => {
if (mode === 'checked') {
if (selected) {
setCheckedProduct((prev) => prev.concat(record));
} else {
const key = `${record.activityId!}-${record.id!}`;
setCheckedProduct((prev) => prev.filter((_item) => {
const tempKey = `${_item.activityId}-${_item.id}`;
return key !== tempKey;
}));
}
return;
}
setCheckedProduct([record]);
};
const rowSelection = {
type: mode,
onSelect: handleRowSelect,
selectedRowKeys: selectedRowKeys
};
const drawerStyle = { background: '#FAFBFC' };
return (
<Drawer
onClose={handleCancel}
headerStyle={drawerStyle}
bodyStyle={drawerStyle}
footerStyle={drawerStyle}
title="选择活动商品"
visible={visible}
width={950}
footer={
<div className={styles.drawerFooter}>
<Space>
<Button onClick={handleCancel}>取消</Button>
<Button onClick={handleOk}>确定</Button>
</Space>
</div>
}
>
<div className={styles.container}>
<div className={styles.form}>
<NiceForm
schema={schema}
actions={actions}
onReset={onReset}
onSubmit={onSubmit}
effects={($, actions) => {
useStateFilterSearchLinkageEffect($, actions, 'id', FORM_FILTER_PATH);
}}
></NiceForm>
</div>
<div className={styles.table}>
{
dataSource?.map((_item) => {
const { outerStatusName, id, activityName, activityTypeName } = _item;
const isActive = selectedKey === id;
const hasChildSelected = selectedRowKeys.some((_rowKey) => _rowKey.split("-")[0] === id.toString());
return (
<div key={_item.id} className={styles.activeItem}>
<ActivityItem
onSelect={onSelect}
isActive={isActive}
id={id}
activityName={activityName}
statusName={outerStatusName}
activityTypeName={activityTypeName}
hasChildSelected={hasChildSelected}
activityImage={activityImage}
/>
</div>
);
})
}
</div>
<div className={styles.expandableTable}>
<Table
rowSelection={rowSelection as any}
rowKey={(_record) => `${_record.activityId!}-${_record.id!}` }
loading={loading}
columns={columns} dataSource={selectedActivityProductList}></Table>
</div>
<div className={styles.pagination}>
<Pagination pageSize={currentPageSize} current={current} showQuickJumper total={totalCount} onChange={onChange}/>
</div>
</div>
</Drawer>
);
};
export default ActivityProductDrawer;
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { ISchema } from '@formily/antd';
const schema: ISchema = {
type: 'object',
properties: {
megaLayout: {
type: 'object',
'x-component': 'mega-layout',
properties: {
id: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
placeholder: '搜索',
align: 'flex-left',
tip: '输入活动ID进行搜索',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
full: true,
aotoRow: true,
},
properties: {
activityName: {
type: 'string',
"x-component-props": {
placeholder: '活动名称'
}
},
activityType: {
type: 'string',
enum: [],
"x-component-props": {
placeholder: '活动类型'
}
},
'[startTime, endTime]': {
"x-mega-props": {
span: 2,
},
type: 'daterange',
'x-component-props': {
placeholder: ['活动开始时间', "活动结束时间"]
}
},
product: {
type: 'string',
"x-component-props": {
placeholder: '活动名称'
}
},
merchantName: {
type: 'string',
"x-component-props": {
placeholder: '商家名称'
}
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
},
},
},
},
};
export default schema;
......@@ -13,8 +13,8 @@ import Search from '@/components/NiceForm/components/Search';
import Submit from '@/components/NiceForm/components/Submit'
import StatusTag from '@/components/StatusTag'
import CouponPlatformIcon from '@/pages/pageCustomized/icons/coupon_platform.png';
import CouponShopIcon from '@/pages/pageCustomized/icons/coupon_shop.png';
import CouponPlatformIcon from '@/assets/couponIcons/coupon_platform.png';
import CouponShopIcon from '@/assets/couponIcons/coupon_shop.png';
import * as tableSchemas from './schema';
......@@ -33,9 +33,9 @@ interface CouponsDrawerProps {
}
const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps) => {
const { visible, onClose, onConfirm, selectId, belongType } = props;
const { visible, onClose, onConfirm, selectId } = props;
const { query: { shopId } }: any = history.location
const [type, setType] = useState(belongType || 1);
const [type, setType] = useState(2);
const [selectedRowKeys, setSelectedRowKeys] = useState<any>(selectId ? [selectId] : []);
const [selectedRows, setSelectedRows] = useState<any>([]);
const ref = useRef<any>({});
......@@ -129,16 +129,7 @@ const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps)
const fetchTableData = async (params: any) => {
const _params = { ...params, shopId };
let _fetch: any;
switch (type) {
case 1:
_fetch = PublicApi.getMarketingCouponPlatformActivityPageSelectPage
break;
case 2:
_fetch = PublicApi.getMarketingCouponPlatformActivityPageSelectMerchantPage
break;
}
const { data } = await _fetch(_params);
const { data } = await PublicApi.getMarketingCouponActivityPageSelectPage(_params);
return data;
}
const rowSelection: any = {
......@@ -197,22 +188,22 @@ const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps)
span: 16
}
}}
formilyChilds={{
children: (
<div style={{ textAlign: 'right' }}>
<Radio.Group
options={options}
onChange={_onRadioChange}
value={type}
optionType="button"
/>
</div>
),
layouts: {
order: 2,
span: 8
}
}}
// formilyChilds={{
// children: (
// <div style={{ textAlign: 'right' }}>
// <Radio.Group
// options={options}
// onChange={_onRadioChange}
// value={type}
// optionType="button"
// />
// </div>
// ),
// layouts: {
// order: 2,
// span: 8
// }
// }}
/>
</Drawer>
)
......
......@@ -79,13 +79,6 @@ export const CouponSchema2: ISchema = {
allowClear: true,
},
},
memberName: {
type: 'string',
'x-component-props': {
placeholder: '商家名称',
allowClear: true,
},
},
sumbit: {
'x-component': 'Submit',
'x-mega-props': {
......
......@@ -4,7 +4,7 @@ import { cloneDeep } from 'lodash';
import { updatePageConfig, STATE_PROPS, SelectedInfoType, PageConfigType } from '@lingxi-disign/core';
import { useSelector } from '@lingxi-disign/react';
import * as MarketingConfigs from '../../../mobileTemplate/shopTemplateEdit/page_config';
import * as MarketingConfigs from '../../../mobileTemplate/shopTemplateEdit/marketing_config';
import styles from './index.less';
......
import {
ComponentSchemaType,
PROPS_SETTING_TYPES,
PROPS_TYPES,
} from '@lingxi-disign/core';
const CouponsModal: ComponentSchemaType = {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.couponsModal,
},
},
};
const CouponsItem: ComponentSchemaType = {
fatherNodesRule: ['CouponsModal.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.marketingCardCoupon,
},
},
};
export default {
CouponsModal,
'CouponsModal.CouponsItem': CouponsItem,
};
import {
ComponentSchemaType,
PROPS_SETTING_TYPES,
PROPS_TYPES,
} from '@lingxi-disign/core';
const MarketingCard: ComponentSchemaType = {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const Header: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.marketingCardHeader,
},
},
};
const CommonContainer: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const CollageContainer: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const PackageContainer: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const PackageContainerTabs: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.PackageContainer.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const PackageContainerTabsTabPane: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.PackageContainerTabs.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const DetailItem: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.PackageContainer.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.marketingCardDetailItem,
},
},
};
const CollageContainerItem: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.CollageContainer.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.marketingCardGood,
},
},
};
const GoodsItem: ComponentSchemaType = {
fatherNodesRule: [
'MarketingCard.CommonContainer.children',
'MarketingCard.PackageContainerTabsTabPane.children',
],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.marketingCardGood,
},
},
};
const CouponsItem: ComponentSchemaType = {
fatherNodesRule: ['MarketingCard.CommonContainer.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.marketingCardCoupon,
},
},
};
export default {
MarketingCard,
'MarketingCard.Header': Header,
'MarketingCard.CommonContainer': CommonContainer,
'MarketingCard.CollageContainer': CollageContainer,
'MarketingCard.PackageContainer': PackageContainer,
'MarketingCard.PackageContainerTabs': PackageContainerTabs,
'MarketingCard.PackageContainerTabsTabPane': PackageContainerTabsTabPane,
'MarketingCard.DetailItem': DetailItem,
'MarketingCard.CollageContainerItem': CollageContainerItem,
'MarketingCard.GoodsItem': GoodsItem,
'MarketingCard.CouponsItem': CouponsItem,
};
......@@ -47,6 +47,8 @@ import MobileShopHeader from './MobileShopHeader'
import MobileNavCard from './MobileNavCard'
import Banner from './Banner'
import MobileShopCommodity from './MobileShopCommodity'
import CouponsModal from './CouponsModal'
import MarketingCard from './MarketingCard';
export default {
View,
......@@ -89,4 +91,6 @@ export default {
...MobileNavCard,
...Banner,
...MobileShopCommodity,
...CouponsModal,
...MarketingCard
}
......@@ -25,6 +25,7 @@ const MobileSettingPanel: React.FC<MobileSettingPanelProps> = (props)=> {
const [ newSelectInfo, setNewSelectInfo ] = useState<SelectedInfoType>()
useEffect(() => {
console.log(pageConfig, 'pageConfig')
const updateSelectInfo = () => {
if(selectedInfo) {
const { props: oldProps ,selectedKey } = selectedInfo
......@@ -47,7 +48,7 @@ const MobileSettingPanel: React.FC<MobileSettingPanelProps> = (props)=> {
{
(propsConfig && propsConfig.componentType) && (
<TabPane tab="编辑" key="props">
<PropsSettings selectedInfo={newSelectInfo} {...props} />
<PropsSettings selectedInfo={newSelectInfo} pageConfig={pageConfig} {...props} />
</TabPane>
)
}
......
@import "../../common.less";
.couponsModal {
&-box {
margin-bottom: 16px;
&-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;
&>img {
width: 40px;
height: 40px;
}
}
}
}
import React, { useEffect } from 'react';
import { Input } from 'antd';
import { changeProps, changeStylesByKey } from '@lingxi-disign/core';
import styles from './index.less';
interface CouponsModalProps {
// 自定title
title?: string
// 当前选中组件的key
selectedKey?: any
}
const CouponsModal: React.FC<CouponsModalProps> = (props: CouponsModalProps) => {
const { title, selectedKey } = props;
useEffect(() => {
changeStylesByKey({
key: '8',
style: {
display: 'block'
}
})
return () => {
changeStylesByKey({
key: '8',
style: {
display: 'none'
}
})
}
}, [])
const _onChangeTitle = (e: any) => {
const _val = e.target.value;
changeProps({
props: Object.assign({ ...props }, { title: _val })
})
}
return (
<div className={styles['couponsModal']}>
<div className={styles['couponsModal-box']}>
<div className={styles['couponsModal-box-label']}>标题</div>
<Input key={`${selectedKey}-title`} defaultValue={title} onBlur={_onChangeTitle} />
</div>
</div>
);
}
export default CouponsModal;
@import "../../common.less";
.marketingCardCoupon {
&-box {
margin-top: 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 12px;
&-label {
color: #91959B;
width: 80px;
}
&-content {
flex: 1;
color: #303133;
}
}
}
import React, { useState, useEffect } from 'react';
import { Button } from 'antd';
import { changeProps, changeStylesByKey } from '@lingxi-disign/core';
import moment from 'moment';
import { formatTimeString } from '@/utils'
import { priceFormat } from '@/utils/numberFomat'
import { PublicApi } from '@/services/api';
import CouponsDrawer from '@/pages/editor/components/drawer/couponsDrawer';
import styles from './index.less';
interface MarketingCardCouponProps {
id?: number,
belongType?: 1 | 2,
// 当前选中组件的key
selectedKey?: any,
}
const MarketingCardCoupon: React.FC<MarketingCardCouponProps> = (props: MarketingCardCouponProps) => {
const { id, belongType, selectedKey } = props;
const [drawerVisible, setDrawerVisible] = useState(false);
const [record, setRecord] = useState<any>();
useEffect(() => {
changeStylesByKey({
key: '8',
style: {
display: 'block'
}
})
return () => {
changeStylesByKey({
key: '8',
style: {
display: 'none'
}
})
}
}, [])
const _onClose = () => {
setDrawerVisible(false);
}
useEffect(() => {
if (id && id != record?.id) {
PublicApi.postMarketingCouponPlatformActivityPageSelectDetail({ couponList: [{ couponType: belongType, id: id }] }).then((res) => {
if (res.code === 1000) {
setRecord(res.data[0]);
}else{
setRecord('')
}
}).catch(_ => setRecord(''))
}else if(!id){
setRecord('');
}
}, [id, belongType])
const _onChooseConfirm = (record) => {
setRecord(record);
changeProps({
title: record?.name,
props: Object.assign({ ...props }, { ...record, expiredDay: moment(record?.releaseTimeEnd || moment()).diff(moment(), 'days'), isnull: false })
})
_onClose();
}
return (
<div className={styles['marketingCardCoupon']}>
<Button onClick={() => { setDrawerVisible(true) }}>选择</Button>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>优惠券ID:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.id}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>优惠券名称:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.name}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>类型:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.typeName}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>领劵方式:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.getWayName}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>商家名称:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.belongName}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>面额:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.denomination ? `¥ ${priceFormat(record?.denomination)}` : ''}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>使用条件:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.useConditionMoney ? `满 ${record?.useConditionMoney} 元使用` : ''}</div>
</div>
<div className={styles['marketingCardCoupon-box']}>
<div className={styles['marketingCardCoupon-box-label']}>有效期:</div>
<div className={styles['marketingCardCoupon-box-content']}>{record?.releaseTimeStart ? `${formatTimeString(record?.releaseTimeStart)} 至 ${formatTimeString(record?.releaseTimeEnd)}` : ''}</div>
</div>
<CouponsDrawer
visible={drawerVisible}
belongType={belongType}
onClose={_onClose}
onConfirm={_onChooseConfirm}
selectId={id}
/>
</div>
);
}
export default MarketingCardCoupon;
@import "../../common.less";
.suggestProductCommodity {
&-box {
margin-bottom: 16px;
&-label {
font-size: 12px;
color: #91959B;
margin-bottom: 8px;
}
}
&-detail {
height: 80px;
border: 1px solid #F7F8FA;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 6px 8px;
margin-bottom: 16px;
position: relative;
overflow: hidden;
img {
height: 60px;
width: 60px;
margin-right: 10px;
}
&-right {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
&-title {
color: #303133;
font-size: 12px;
word-break: break-all;
overflow: hidden; // 超出的文本隐藏
text-overflow: ellipsis;
display: -webkit-box; // 将对象作为弹性伸缩盒子模型显示。
-webkit-box-orient: vertical; //从上到下垂直排列子元素(设置伸缩盒子的子元素排列方式)
-webkit-line-clamp: 2; // 结合上面两个属性,表示显示的行数。
}
&-price {
color: #D32F2F;
font-size: 14px;
}
}
&:hover {
.suggestProductCommodity-detail-cover {
display: block;
}
}
&-cover {
position: absolute;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, .1);
display: none;
z-index: 1;
cursor: pointer;
&-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;
}
}
}
&-activityList {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-bottom: 8px;
cursor: pointer;
img {
width: 24px;
height: 24px;
}
&-name {
flex: 1;
font-size: 12px;
color: #303133;
margin: 0 8px;
word-break: break-all;
overflow: hidden; // 超出的文本隐藏
text-overflow: ellipsis;
}
}
}
.site-tag-plus {
background: #fff;
border-style: dashed;
}
.edit-tag {
user-select: none;
}
.tag-input {
width: 78px;
margin-right: 8px;
vertical-align: top;
}
@import "../../common.less";
.marketingCardHeader {
&-box {
margin-bottom: 16px;
: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: 40px;
height: 40px;
border-radius: 50%;
}
&-add {
font-size: 40px;
}
&:hover {
.marketingCardHeader-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;
}
}
}
}
}
import React from 'react';
import { Input } from 'antd';
import { PlusCircleOutlined, DeleteOutlined } from '@ant-design/icons';
import { changeProps } from '@lingxi-disign/core';
import UploadImage from '@/components/UploadImage';
import ICONS_CONFIG from '../../../../components/mobileClientEditLeft/iconsConfig';
import styles from './index.less';
interface MarketingCardHeaderProps {
// 活动类型
type: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19,
// 自定title
title?: string,
// 自定info
explain?: string,
// 自定icon
icon?: any,
// 倒计时数组[时,分,秒]
countDown?: string[],
selectedKey?: any
}
const MarketingCardHeader: React.FC<MarketingCardHeaderProps> = (props: MarketingCardHeaderProps) => {
const { type, title, explain, icon, selectedKey } = props;
const _defaultInfo = ICONS_CONFIG.filter((item) => item.type === type)[0]
const _onChangeTitle = (e: any) => {
const _val = e.target.value;
changeProps({
props: Object.assign({ ...props }, { title: _val })
});
}
const _onChangeExplain = (e: any) => {
const _val = e.target.value;
changeProps({
props: Object.assign({ ...props }, { explain: _val })
});
}
const _onChangeIcon = (url: any) => {
changeProps({
props: Object.assign({ ...props }, { icon: url })
});
}
return (
<div className={styles['marketingCardHeader']}>
<div className={styles['marketingCardHeader-box']}>
<div className={styles['marketingCardHeader-box-label']}>标题</div>
<Input key={`${selectedKey}-title`} defaultValue={title || _defaultInfo?.title} onBlur={_onChangeTitle} />
</div>
<div className={styles['marketingCardHeader-box']}>
<div className={styles['marketingCardHeader-box-label']}>标题说明</div>
<Input key={`${selectedKey}-explain`} defaultValue={explain || _defaultInfo?.explain} onBlur={_onChangeExplain} />
</div>
<div className={styles['marketingCardHeader-box']}>
<div className={styles['marketingCardHeader-box-label']}>图标</div>
{icon ? (
<div className={styles['marketingCardHeader-box-icon']}>
<img src={icon} />
<div className={styles['marketingCardHeader-box-icon-cover']}>
<UploadImage
onChange={(url) => { _onChangeIcon(url) }}
listType="text"
>
<div className={styles['marketingCardHeader-box-icon-cover-bottom']}>
添加图像
</div>
</UploadImage>
<DeleteOutlined className={styles['marketingCardHeader-box-icon-cover-delete']} onClick={() => { _onChangeIcon('') }} />
</div>
</div>
) : (
<UploadImage
onChange={(url) => { _onChangeIcon(url) }}
listType="text"
>
<div className={styles['marketingCardHeader-box-icon']}>
<img src={_defaultInfo.icon} />
<div className={styles['marketingCardHeader-box-icon-cover']}>
<div className={styles['marketingCardHeader-box-icon-cover-bottom']}>
添加图像
</div>
</div>
</div>
</UploadImage>
)}
</div>
</div>
);
}
export default MarketingCardHeader;
import React from 'react'
import { SelectedInfoType, PROPS_SETTING_TYPES } from '@lingxi-disign/core';
import { SelectedInfoType, PROPS_SETTING_TYPES, PageConfigType } from '@lingxi-disign/core';
import HeaderNav from './components/headerNav'
import Banner from './components/banner'
import QuickNav from './components/quickNav'
......@@ -9,22 +9,28 @@ import BottomNavigation from './components/bottomNavigation'
import MobileChannelGoods from './components/channelGoods'
import MobileChannelInformation from './components/channelInformation'
import CardNavItem from './components/cardNavItem'
import CouponsModal from './components/couponsModal'
import MarketingCardCoupon from './components/marketingCardCoupon';
import MarketingCardGood from './components/marketingCardGood'
import MarketingCardHeader from './components/marketingCardHeader'
import styles from './index.less'
interface PropsSettingsPropsType {
selectedInfo: SelectedInfoType | undefined,
pageConfig: PageConfigType,
shopId: number,
}
const PropsSettings: React.FC<PropsSettingsPropsType> = (props) => {
const { selectedInfo, } = props
const { selectedInfo, pageConfig } = props
const renderSettingItem = () => {
const { props: initProps, propsConfig } = selectedInfo || {};
const { props: initProps, propsConfig, parentKey } = selectedInfo || {};
const _props = { ...initProps, ...props, selectedKey: selectedInfo?.selectedKey }
const componentType = propsConfig?.componentType
if (componentType) {
console.log(componentType.type, 'componentType.type')
switch (componentType.type) {
case PROPS_SETTING_TYPES.mobileShopHeaderNav:
return <HeadBackground {..._props} />
......@@ -46,6 +52,18 @@ const PropsSettings: React.FC<PropsSettingsPropsType> = (props) => {
return <BottomNavigation {..._props} />
case PROPS_SETTING_TYPES.mobileNavCardNavItem:
return <CardNavItem {..._props} />
case PROPS_SETTING_TYPES.couponsModal:
return <CouponsModal {..._props} />
case PROPS_SETTING_TYPES.marketingCardHeader:
return <MarketingCardHeader {..._props} />
case PROPS_SETTING_TYPES.marketingCardCoupon:
return <MarketingCardCoupon />
case PROPS_SETTING_TYPES.marketingCardGood:
case PROPS_SETTING_TYPES.marketingCardDetailItem:
const _parentKey: any = parentKey;
const _type = pageConfig?.[_parentKey]?.props?.type;
const _exType = pageConfig?.[_parentKey]?.props?.exType;
return <MarketingCardGood {..._props} actType={_type} exType={_exType} pageConfig={pageConfig} />
default:
return null
}
......
import { PROPS_SETTING_TYPES, PageConfigType } from '@lingxi-disign/core'
import categoryNavTemplateDefault from './img/category_template_default.png'
import RED_PACKAGE from './img/red_package.png';
export const defaultConfig: PageConfigType = {
export const mallLayoutConfig : PageConfigType = {
'0': {
componentName: 'MallLayout',
props: {
......@@ -13,7 +14,7 @@ export const defaultConfig: PageConfigType = {
"paddingBottom": "50px",
}
},
childNodes: ['1', '2', '4', '6']
childNodes: ['1', '2', '4']
},
'1': {
componentName: 'MobileShopHeader',
......@@ -80,6 +81,9 @@ export const defaultConfig: PageConfigType = {
isnull: false,
},
},
}
export const defaultConfig: PageConfigType = {
'6': {
componentName: 'MobileShopCommodity',
title: '推荐商品',
......@@ -100,135 +104,29 @@ export const defaultConfig: PageConfigType = {
dataList: '${item.dataList}',
num: '${item.num}',
},
}
}
export const mallLayoutConfig = {
key: "0",
"0": {
"componentName": "MallLayout",
"props": {
"style": {
"width": "100%",
"minHeight": "100%",
"background": "#F7F8FA",
"overflowX": "hidden",
"paddingBottom": "50px",
}
},
"childNodes": ["1", "2", "5"]
},
}
export const mobileShopHeaderNav = {
key: "1",
"1": {
"componentName": "MobileShopHeaderNav",
"componentType": PROPS_SETTING_TYPES.mobileShopHeaderNav,
"title": "背景图编辑",
"canEdit": true,
"canHide": false,
"props": {},
}
}
export const divWrap = {
key: "2",
"2": {
"componentName": "div",
"props": {
"style": {
position: "relative",
marginTop: -24,
backgroundColor: "#FFF",
borderTopLeftRadius: '16px',
borderTopRightRadius: '16px',
zIndex: 6,
padding: '2px 4px',
}
'8': {
title: '优惠券弹窗',
componentName: 'CouponsModal',
props: {
style: {
display: "none",
position: 'absolute',
backgroundImage: `url(${RED_PACKAGE})`,
width: 312,
height: 425,
top: 0,
left: 0,
bottom: 0,
right: 0,
margin: 'auto',
zIndex: 1,
},
},
"childNodes": ["3", "4"]
}
}
export const mobileBanner = {
key: "3",
"3": {
"componentName": "MobileBanner",
"componentType": PROPS_SETTING_TYPES.mobileBanner,
"title": "轮播广告",
"canEdit": true,
"canHide": false,
"props": {
dataList: []
}
}
}
export const mobileQuickNav = {
key: "4",
"4": {
"componentName": "MobileQuickNav",
"componentType": PROPS_SETTING_TYPES.mobileQuickNav,
"title": "导航模块",
"canEdit": true,
"canHide": false,
"props": {
dataList: [
{
"id":1,
"expand":false,
"icon":"https://shushangyun-lingxi.oss-cn-shenzhen.aliyuncs.com/c5d66f1488cc47d0a73279ce1ef11c991610677462848.png",
"type":1,
"name":"商城",
"url":""
},
{
"id":2,
"expand":false,
"icon":"https://shushangyun-lingxi.oss-cn-shenzhen.aliyuncs.com/9f105bdebcfb4010b5827f7b64fb53281610696444606.png",
"type":2,
"name":"分类",
"url":""
},
{
"id":3,
"expand":false,
"icon":"https://shushangyun-lingxi.oss-cn-shenzhen.aliyuncs.com/d4383c684c6e4707b405f46f281796d71610696469970.png",
"type":3,
"name":"积分兑换",
"url":""
},
{
"id":4,
"expand":false,
"icon":"https://shushangyun-lingxi.oss-cn-shenzhen.aliyuncs.com/d4383c684c6e4707b405f46f281796d71610696469970.png",
"type":4,
"name":"公司介绍",
"url":""
},
{
"id":5,
"expand":false,
"icon":"https://shushangyun-lingxi.oss-cn-shenzhen.aliyuncs.com/441a66ebeb3b45e6a64ecfa9977f411c1610696489991.png",
"type":5,
"name":"成为会员",
"url":""
},
]
}
}
}
export const mobileShopCommodityList = {
key: "5",
"5": {
"componentName": "MobileShopCommodityList",
"componentType": PROPS_SETTING_TYPES.mobileShopCommodity,
"title": "商品推荐",
"canEdit": true,
"canHide": false,
"props": {}
}
childNodes: [],
childComponentName: 'CouponsModal.CouponsItem',
addBtnText: '添加优惠券',
canEdit: true,
canHide: false,
},
}
import { PROPS_SETTING_TYPES } from '@lingxi-disign/core';
import RED_PACKAGE from './img/red_package.png';
export const mallLayoutConfig = {
'0': {
componentName: 'MallLayout',
props: {
style: {
width: '100%',
minHeight: '100%',
background: '#F7F8FA',
overflowX: 'hidden',
paddingBottom: '56px',
position: 'relative',
},
},
childNodes: ['1'],
},
};
export const headerConfig = {
'1': {
title: '顶部导航',
canEdit: false,
canHide: true,
componentName: 'HeaderNav',
props: {},
childNodes: ['1-1', '1-2'],
childComponentName: 'HeaderNav.ActionItem',
},
'1-1': {
title: '客服',
canEdit: false,
canHide: true,
componentName: 'HeaderNav.ActionItem',
props: {
key: 3,
data: {
name: '客服',
content: '',
status: true,
type: 3,
},
},
},
'1-2': {
title: '搜索框',
canEdit: false,
canHide: true,
componentName: 'HeaderNav.ActionItem',
props: {
key: 4,
data: {
name: '搜索框',
content: '灯具',
status: true,
type: 4,
},
},
},
};
export const bannerConfig = {
'2': {
title: '广告图',
canEdit: true,
canHide: false,
componentName: 'Banner',
props: {
style: {
margin: '8px',
},
},
childNodes: [],
childComponentName: 'Banner.Items',
addBtnText: '添加广告',
},
};
export const categoryGuidanceConfig = {
'3': {
title: '品类导航',
canEdit: true,
canHide: false,
componentName: 'MobileNavCard',
props: {
style: {
margin: '8px',
},
},
childNodes: [],
childComponentName: 'MobileNavCard.NavItem',
addBtnText: '添加导航',
},
};
export const marketingConfig = {
'11': {
title: '活动',
......@@ -807,67 +712,3 @@ export const marketingConfig_19 = {
addBtnText: '添加商品',
},
};
export const suggestProductConfig = {
'10': {
title: '推荐商品',
componentName: 'SuggestProduct',
props: {},
childNodes: [],
childComponentName: 'SuggestProduct.Items',
addBtnText: '添加分类',
canEdit: true,
canHide: false,
maxLength: 4,
childProps: {
title: '商品容器',
canEdit: true,
canHide: false,
componentName: 'SuggestProduct.Items',
props: {},
childComponentName: 'SuggestProduct.Commodity',
maxLength: 50,
// addBtnText: '添加商品',
childNodes: [],
},
},
};
export const bottomNavigationConfig = {
'12': {
title: '底部标签',
componentName: 'BottomNavigation',
props: {},
childNodes: [],
childComponentName: 'BottomNavigation.Items',
addBtnText: '添加标签',
canEdit: true,
canHide: false,
},
};
export const couponsModalConfig = {
'13': {
title: '优惠券弹窗',
componentName: 'CouponsModal',
props: {
style: {
position: 'absolute',
backgroundImage: `url(${RED_PACKAGE})`,
width: 312,
height: 425,
top: 0,
left: 0,
bottom: 0,
right: 0,
margin: 'auto',
zIndex: 1,
},
},
childNodes: [],
childComponentName: 'CouponsModal.CouponsItem',
addBtnText: '添加优惠券',
canEdit: true,
canHide: false,
},
};
......@@ -29,6 +29,7 @@ import * as EnhanceV2Api from './EnhanceV2Api';
import * as MessageV2 from './MessageV2Api';
import * as LogiticsV2 from './LogiticsV2Api';
import * as MarketingApi from './MarketingApi';
import * as MaketingV2Api from './MaketingV2Api'
import * as AfterServiceV2Api from './AfterServiceV2Api';
......@@ -72,5 +73,6 @@ export const PublicApi = {
...MessageV2,
...LogiticsV2,
...MarketingApi,
...MaketingV2Api,
...AfterServiceV2Api,
}
......@@ -31,6 +31,7 @@ const tokenList = [
{ name: 'MessageV2', token: '69a667ec9861e8bdc25b89238d0b908a2123d9fce26e72fec3cdf6cd0b1f2681', categoryIds: [0], }, // 消息中心v2
{ name: 'LogiticsV2', token: '732fb8e33970ff5dee830423a630e8e85c3ef3293abba7581b16749dfce8608b', categoryIds: [0], }, // 物流能力v2
{ name: 'Marketing', token: 'd952d25c4e8272a6dff69245dbddf983dc886521e2623464e476922fc95f43af', categoryIds: [0], }, // 营销能力
{ name: 'MaketingV2', token: 'f6d5cee2383ca203dfa2882b84dfa02a1d79de3c3ad892b42f030437fdc5ea21', categoryIds: [0] }, // 营销活动v2
{ name: 'AfterServiceV2', token: '58748fc89dcdb33ec5cac520c00293ba92abca362a8ddb979df589effd0db9bd', categoryIds: [0], }, // 售后能力V2
]
......
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