Commit 033cd60f authored by 前端-钟卫鹏's avatar 前端-钟卫鹏
parents 543344d2 999b1347
.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'; ...@@ -13,8 +13,8 @@ import Search from '@/components/NiceForm/components/Search';
import Submit from '@/components/NiceForm/components/Submit' import Submit from '@/components/NiceForm/components/Submit'
import StatusTag from '@/components/StatusTag' import StatusTag from '@/components/StatusTag'
import CouponPlatformIcon from '@/pages/pageCustomized/icons/coupon_platform.png'; import CouponPlatformIcon from '@/assets/couponIcons/coupon_platform.png';
import CouponShopIcon from '@/pages/pageCustomized/icons/coupon_shop.png'; import CouponShopIcon from '@/assets/couponIcons/coupon_shop.png';
import * as tableSchemas from './schema'; import * as tableSchemas from './schema';
...@@ -33,9 +33,9 @@ interface CouponsDrawerProps { ...@@ -33,9 +33,9 @@ interface CouponsDrawerProps {
} }
const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: 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 { query: { shopId } }: any = history.location
const [type, setType] = useState(belongType || 1); const [type, setType] = useState(2);
const [selectedRowKeys, setSelectedRowKeys] = useState<any>(selectId ? [selectId] : []); const [selectedRowKeys, setSelectedRowKeys] = useState<any>(selectId ? [selectId] : []);
const [selectedRows, setSelectedRows] = useState<any>([]); const [selectedRows, setSelectedRows] = useState<any>([]);
const ref = useRef<any>({}); const ref = useRef<any>({});
...@@ -129,16 +129,7 @@ const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps) ...@@ -129,16 +129,7 @@ const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps)
const fetchTableData = async (params: any) => { const fetchTableData = async (params: any) => {
const _params = { ...params, shopId }; const _params = { ...params, shopId };
let _fetch: any; const { data } = await PublicApi.getMarketingCouponActivityPageSelectPage(_params);
switch (type) {
case 1:
_fetch = PublicApi.getMarketingCouponPlatformActivityPageSelectPage
break;
case 2:
_fetch = PublicApi.getMarketingCouponPlatformActivityPageSelectMerchantPage
break;
}
const { data } = await _fetch(_params);
return data; return data;
} }
const rowSelection: any = { const rowSelection: any = {
...@@ -197,22 +188,22 @@ const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps) ...@@ -197,22 +188,22 @@ const CouponsDrawer: React.FC<CouponsDrawerProps> = (props: CouponsDrawerProps)
span: 16 span: 16
} }
}} }}
formilyChilds={{ // formilyChilds={{
children: ( // children: (
<div style={{ textAlign: 'right' }}> // <div style={{ textAlign: 'right' }}>
<Radio.Group // <Radio.Group
options={options} // options={options}
onChange={_onRadioChange} // onChange={_onRadioChange}
value={type} // value={type}
optionType="button" // optionType="button"
/> // />
</div> // </div>
), // ),
layouts: { // layouts: {
order: 2, // order: 2,
span: 8 // span: 8
} // }
}} // }}
/> />
</Drawer> </Drawer>
) )
......
...@@ -79,13 +79,6 @@ export const CouponSchema2: ISchema = { ...@@ -79,13 +79,6 @@ export const CouponSchema2: ISchema = {
allowClear: true, allowClear: true,
}, },
}, },
memberName: {
type: 'string',
'x-component-props': {
placeholder: '商家名称',
allowClear: true,
},
},
sumbit: { sumbit: {
'x-component': 'Submit', 'x-component': 'Submit',
'x-mega-props': { 'x-mega-props': {
......
...@@ -4,7 +4,7 @@ import { cloneDeep } from 'lodash'; ...@@ -4,7 +4,7 @@ import { cloneDeep } from 'lodash';
import { updatePageConfig, STATE_PROPS, SelectedInfoType, PageConfigType } from '@lingxi-disign/core'; import { updatePageConfig, STATE_PROPS, SelectedInfoType, PageConfigType } from '@lingxi-disign/core';
import { useSelector } from '@lingxi-disign/react'; 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 styles from './index.less';
......
import {
ComponentSchemaType,
PROPS_SETTING_TYPES,
PROPS_TYPES,
} from '@lingxi-disign/core';
const BottomNavigation: ComponentSchemaType = {
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
},
};
const BottomNavigationItems: ComponentSchemaType = {
fatherNodesRule: ['BottomNavigation.children'],
propsConfig: {
children: {
label: '内容',
type: PROPS_TYPES.string,
},
componentType: {
type: PROPS_SETTING_TYPES.bottomNavigationItems,
},
},
};
export default {
BottomNavigation,
'BottomNavigation.Items': BottomNavigationItems,
};
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 ShopHeader: 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 VerticalContainer: 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.ShopHeader': ShopHeader,
'MarketingCard.CommonContainer': CommonContainer,
'MarketingCard.VerticalContainer': VerticalContainer,
'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,9 @@ import MobileShopHeader from './MobileShopHeader' ...@@ -47,6 +47,9 @@ import MobileShopHeader from './MobileShopHeader'
import MobileNavCard from './MobileNavCard' import MobileNavCard from './MobileNavCard'
import Banner from './Banner' import Banner from './Banner'
import MobileShopCommodity from './MobileShopCommodity' import MobileShopCommodity from './MobileShopCommodity'
import CouponsModal from './CouponsModal'
import MarketingCard from './MarketingCard'
import BottomNavigation from './BottomNavigation'
export default { export default {
View, View,
...@@ -89,4 +92,7 @@ export default { ...@@ -89,4 +92,7 @@ export default {
...MobileNavCard, ...MobileNavCard,
...Banner, ...Banner,
...MobileShopCommodity, ...MobileShopCommodity,
...CouponsModal,
...MarketingCard,
...BottomNavigation
} }
...@@ -6,15 +6,18 @@ import cx from 'classnames' ...@@ -6,15 +6,18 @@ import cx from 'classnames'
import { Tabs } from 'antd' import { Tabs } from 'antd'
import StyleSettings from './styleSettings' import StyleSettings from './styleSettings'
import PropsSettings from './propsSettings' import PropsSettings from './propsSettings'
import { LAYOUT_TYPE } from '@/constants'
import styles from './index.less' import styles from './index.less'
type SettingPanelType = { type SettingPanelType = {
selectedInfo: SelectedInfoType, selectedInfo: SelectedInfoType,
pageConfig: PageConfigType, pageConfig: PageConfigType,
} }
interface MobileSettingPanelProps { interface MobileSettingPanelProps {
shopId: number shopId: number,
layoutType: LAYOUT_TYPE
} }
const { TabPane } = Tabs const { TabPane } = Tabs
...@@ -34,7 +37,6 @@ const MobileSettingPanel: React.FC<MobileSettingPanelProps> = (props)=> { ...@@ -34,7 +37,6 @@ const MobileSettingPanel: React.FC<MobileSettingPanelProps> = (props)=> {
setNewSelectInfo(updateSelectInfo) setNewSelectInfo(updateSelectInfo)
} }
} }
updateSelectInfo() updateSelectInfo()
}, [selectedInfo, pageConfig]) }, [selectedInfo, pageConfig])
...@@ -47,7 +49,7 @@ const MobileSettingPanel: React.FC<MobileSettingPanelProps> = (props)=> { ...@@ -47,7 +49,7 @@ const MobileSettingPanel: React.FC<MobileSettingPanelProps> = (props)=> {
{ {
(propsConfig && propsConfig.componentType) && ( (propsConfig && propsConfig.componentType) && (
<TabPane tab="编辑" key="props"> <TabPane tab="编辑" key="props">
<PropsSettings selectedInfo={newSelectInfo} {...props} /> <PropsSettings selectedInfo={newSelectInfo} pageConfig={pageConfig} {...props} />
</TabPane> </TabPane>
) )
} }
......
@import "../../common.less";
.bottomNavigationClient {
&-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;
}
&-add{
font-size: 40px;
}
&:hover {
.bottomNavigationClient-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, { useMemo } from 'react';
import { Input, Select } from 'antd';
import { PlusCircleOutlined, DeleteOutlined } from '@ant-design/icons';
import { changeProps } from '@lingxi-disign/core';
import UploadImage from '@/components/UploadImage';
import uploadImgIcon from '@/assets/icons/upload_img_icon.svg'
import styles from './index.less';
interface BottomNavigationClientProps {
// 默认icon
defaultIcon?: any,
// 选中icon
selectIcon?: any,
// 导航标题
name?: any,
// 链接类型
/** 类型:1-首页 2-分类 3-进货单 4-工作台 5-我的 6-找现货 7-找供应 8-求购 9-换积分 10-找店铺 */
type?: any,
// 当前选中组件的key
selectedKey?: any,
// 1.B端 2.C端 3.SRM
property?: 1 | 2 | 3
}
const RedirectTypeList_B = [
{
value: 1,
label: '首页',
},
{
value: 2,
label: '分类',
},
{
value: 3,
label: '进货单',
},
{
value: 4,
label: '消息',
},
{
value: 5,
label: '我的',
},
{
value: 6,
label: '找现货',
},
{
value: 7,
label: '找供应',
},
{
value: 8,
label: '换积分',
},
{
value: 9,
label: '找店铺',
},
];
const RedirectTypeList_C = [
{
value: 1,
label: '首页',
},
{
value: 2,
label: '分类',
},
{
value: 3,
label: '购物车',
},
{
value: 4,
label: '我的',
},
{
value: 5,
label: '消息',
},
{
value: 6,
label: '积分兑换',
},
{
value: 7,
label: '在线客服',
},
];
const BottomNavigationClient: React.FC<BottomNavigationClientProps> = (props: BottomNavigationClientProps) => {
const { defaultIcon, selectIcon, name, type, property = 2, selectedKey } = props;
const _isNull = (list) => {
let _number = 0;
for (let key in list) {
if (list[key]) {
_number += 1
}
}
return _number === list.length ? false : true;
}
const _onChangeName = (e: any) => {
const _val = e.target.value;
changeProps({
title: _val || '',
props: Object.assign({ ...props }, { name: _val, isnull: _isNull([defaultIcon, selectIcon, _val, type]) })
});
}
const _onChangeType = (value: any) => {
changeProps({
props: Object.assign({ ...props }, { type: value, isnull: _isNull([defaultIcon, selectIcon, name, value]) })
});
}
const _onChangeDefaultIcon = (url: any) => {
changeProps({
props: Object.assign({ ...props }, { defaultIcon: url, isnull: _isNull([url, selectIcon, name, type]) })
});
}
const _onChangeSelectIcon = (url: any) => {
changeProps({
props: Object.assign({ ...props }, { selectIcon: url, isnull: _isNull([defaultIcon, url, name, type]) })
});
}
const RedirectTypeList = useMemo(() => {
if(property === 1){
return RedirectTypeList_B
}else if(property === 2){
return RedirectTypeList_C
}
}, [property])
return (
<div className={styles['bottomNavigationClient']}>
<div className={styles['bottomNavigationClient-box']}>
<div className={styles['bottomNavigationClient-box-label']}>名称</div>
<Input key={`${selectedKey}-name`} defaultValue={name} onBlur={_onChangeName} />
</div>
<div className={styles['bottomNavigationClient-box']}>
<div className={styles['bottomNavigationClient-box-label']}>链接</div>
<Select key={`${selectedKey}-type`} defaultValue={type} onChange={_onChangeType} style={{ width: '100%' }} >
{
RedirectTypeList?.map(selectItem => <Select.Option value={selectItem.value} key={`redirect_type_${selectItem.value}`}>{selectItem.label}</Select.Option>)
}
</Select>
</div>
<div className={styles['bottomNavigationClient-box']}>
<div className={styles['bottomNavigationClient-box-label']}>图标-默认</div>
{defaultIcon ? (
<div className={styles['bottomNavigationClient-box-icon']}>
<img src={defaultIcon} />
<div className={styles['bottomNavigationClient-box-icon-cover']}>
<UploadImage
onChange={(url) => { _onChangeDefaultIcon(url) }}
listType="text"
>
<div className={styles['bottomNavigationClient-box-icon-cover-bottom']}>
添加图像
</div>
<DeleteOutlined className={styles['bottomNavigationClient-box-icon-cover-delete']} onClick={(e) => { e.stopPropagation(); e.preventDefault(); _onChangeDefaultIcon('') }} />
</UploadImage>
</div>
</div>
) : (
<UploadImage
onChange={(url) => { _onChangeDefaultIcon(url) }}
listType="text"
>
<div className={styles['bottomNavigationClient-box-icon']}>
<img src={uploadImgIcon} className={styles['bottomNavigationClient-box-icon-add']} />
<div className={styles['bottomNavigationClient-box-icon-cover']}>
<div className={styles['bottomNavigationClient-box-icon-cover-bottom']}>
添加图像
</div>
</div>
</div>
</UploadImage>
)}
</div>
<div className={styles['bottomNavigationClient-box']}>
<div className={styles['bottomNavigationClient-box-label']}>图标-选中</div>
{selectIcon ? (
<div className={styles['bottomNavigationClient-box-icon']}>
<img src={selectIcon} />
<div className={styles['bottomNavigationClient-box-icon-cover']}>
<UploadImage
onChange={(url) => { _onChangeSelectIcon(url) }}
listType="text"
>
<div className={styles['bottomNavigationClient-box-icon-cover-bottom']}>
添加图像
</div>
<DeleteOutlined className={styles['bottomNavigationClient-box-icon-cover-delete']} onClick={(e) => { e.stopPropagation(); e.preventDefault(); _onChangeSelectIcon('') }} />
</UploadImage>
</div>
</div>
) : (
<UploadImage
onChange={(url) => { _onChangeSelectIcon(url) }}
listType="text"
>
<div className={styles['bottomNavigationClient-box-icon']}>
<img src={uploadImgIcon} className={styles['bottomNavigationClient-box-icon-add']} />
<div className={styles['bottomNavigationClient-box-icon-cover']}>
<div className={styles['bottomNavigationClient-box-icon-cover-bottom']}>
添加图像
</div>
</div>
</div>
</UploadImage>
)}
</div>
</div>
)
}
export default BottomNavigationClient
@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 { LAYOUT_TYPE } from '@/constants'
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,
layoutType: LAYOUT_TYPE
}
const MarketingCardHeader: React.FC<MarketingCardHeaderProps> = (props: MarketingCardHeaderProps) => {
const { type, title, explain, icon, selectedKey, layoutType } = 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>
{
layoutType !== LAYOUT_TYPE.shop && (
<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 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 HeaderNav from './components/headerNav'
import Banner from './components/banner' import Banner from './components/banner'
import QuickNav from './components/quickNav' import QuickNav from './components/quickNav'
...@@ -9,18 +9,26 @@ import BottomNavigation from './components/bottomNavigation' ...@@ -9,18 +9,26 @@ import BottomNavigation from './components/bottomNavigation'
import MobileChannelGoods from './components/channelGoods' import MobileChannelGoods from './components/channelGoods'
import MobileChannelInformation from './components/channelInformation' import MobileChannelInformation from './components/channelInformation'
import CardNavItem from './components/cardNavItem' 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 BottomNavigationClient from './components/bottomNavigationClient'
import { LAYOUT_TYPE } from '@/constants'
import styles from './index.less' import styles from './index.less'
interface PropsSettingsPropsType { interface PropsSettingsPropsType {
selectedInfo: SelectedInfoType | undefined, selectedInfo: SelectedInfoType | undefined,
pageConfig: PageConfigType,
layoutType: LAYOUT_TYPE,
shopId: number, shopId: number,
} }
const PropsSettings: React.FC<PropsSettingsPropsType> = (props) => { const PropsSettings: React.FC<PropsSettingsPropsType> = (props) => {
const { selectedInfo, } = props const { selectedInfo, pageConfig } = props
const renderSettingItem = () => { const renderSettingItem = () => {
const { props: initProps, propsConfig } = selectedInfo || {}; const { props: initProps, propsConfig, parentKey } = selectedInfo || {};
const _props = { ...initProps, ...props, selectedKey: selectedInfo?.selectedKey } const _props = { ...initProps, ...props, selectedKey: selectedInfo?.selectedKey }
const componentType = propsConfig?.componentType const componentType = propsConfig?.componentType
...@@ -46,6 +54,20 @@ const PropsSettings: React.FC<PropsSettingsPropsType> = (props) => { ...@@ -46,6 +54,20 @@ const PropsSettings: React.FC<PropsSettingsPropsType> = (props) => {
return <BottomNavigation {..._props} /> return <BottomNavigation {..._props} />
case PROPS_SETTING_TYPES.mobileNavCardNavItem: case PROPS_SETTING_TYPES.mobileNavCardNavItem:
return <CardNavItem {..._props} /> 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} />
case PROPS_SETTING_TYPES.bottomNavigationItems:
return <BottomNavigationClient {..._props} />
default: default:
return null return null
} }
......
import { PROPS_SETTING_TYPES, PageConfigType } from '@lingxi-disign/core' import { PROPS_SETTING_TYPES, PageConfigType } from '@lingxi-disign/core'
import categoryNavTemplateDefault from './img/category_template_default.png' 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': { '0': {
componentName: 'MallLayout', componentName: 'MallLayout',
props: { props: {
...@@ -13,7 +14,7 @@ export const defaultConfig: PageConfigType = { ...@@ -13,7 +14,7 @@ export const defaultConfig: PageConfigType = {
"paddingBottom": "50px", "paddingBottom": "50px",
} }
}, },
childNodes: ['1', '2', '4', '6'] childNodes: ['1', '2', '4']
}, },
'1': { '1': {
componentName: 'MobileShopHeader', componentName: 'MobileShopHeader',
...@@ -80,6 +81,9 @@ export const defaultConfig: PageConfigType = { ...@@ -80,6 +81,9 @@ export const defaultConfig: PageConfigType = {
isnull: false, isnull: false,
}, },
}, },
}
export const defaultConfig: PageConfigType = {
'6': { '6': {
componentName: 'MobileShopCommodity', componentName: 'MobileShopCommodity',
title: '推荐商品', title: '推荐商品',
...@@ -100,135 +104,50 @@ export const defaultConfig: PageConfigType = { ...@@ -100,135 +104,50 @@ export const defaultConfig: PageConfigType = {
dataList: '${item.dataList}', dataList: '${item.dataList}',
num: '${item.num}', 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"]
}, },
} '8': {
title: '优惠券弹窗',
export const mobileShopHeaderNav = { componentName: 'CouponsModal',
key: "1", props: {
"1": { style: {
"componentName": "MobileShopHeaderNav", display: "none",
"componentType": PROPS_SETTING_TYPES.mobileShopHeaderNav, position: 'absolute',
"title": "背景图编辑", backgroundImage: `url(${RED_PACKAGE})`,
"canEdit": true, width: 312,
"canHide": false, height: 425,
"props": {}, top: 0,
} left: 0,
} bottom: 0,
right: 0,
export const divWrap = { margin: 'auto',
key: "2", zIndex: 1,
"2": { },
"componentName": "div",
"props": {
"style": {
position: "relative",
marginTop: -24,
backgroundColor: "#FFF",
borderTopLeftRadius: '16px',
borderTopRightRadius: '16px',
zIndex: 6,
padding: '2px 4px',
}
}, },
"childNodes": ["3", "4"] childNodes: [],
} childComponentName: 'CouponsModal.CouponsItem',
} addBtnText: '添加优惠券',
canEdit: true,
export const mobileBanner = { canHide: false,
key: "3", },
"3": { // '9': {
"componentName": "MobileBanner", // title: '底部标签栏',
"componentType": PROPS_SETTING_TYPES.mobileBanner, // componentName: 'BottomNavigation',
"title": "轮播广告", // props: {},
"canEdit": true, // childNodes: ['10'],
"canHide": false, // childComponentName: 'BottomNavigation.Items',
"props": { // addBtnText: '添加标签',
dataList: [] // maxLength: 5,
} // },
} // '10': {
} // loop: '${bottom}',
// title: '${item.name}',
export const mobileQuickNav = { // componentName: 'BottomNavigation.Items',
key: "4", // props: {
"4": { // defaultIcon: '${item.defaultIcon}',
"componentName": "MobileQuickNav", // selectIcon: '${item.selectIcon}',
"componentType": PROPS_SETTING_TYPES.mobileQuickNav, // name: '${item.name}',
"title": "导航模块", // type: '${item.type}',
"canEdit": true, // isnull: false,
"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": {}
}
} }
...@@ -26,7 +26,11 @@ const CouponItem = (props) => { ...@@ -26,7 +26,11 @@ const CouponItem = (props) => {
<div className={styles.couponItemRight}> <div className={styles.couponItemRight}>
<div className={styles.couponItemRight_type}>{fieldListData.typeName}</div> <div className={styles.couponItemRight_type}>{fieldListData.typeName}</div>
<div className={styles.couponItemRight_info}>{fieldListData.name}</div> <div className={styles.couponItemRight_info}>{fieldListData.name}</div>
<div className={styles.couponItemRight_date}>{format(fieldListData.effectiveTimeStart)}-{format(fieldListData.effectiveTimeEnd)}</div> { fieldListData.effectiveType === 1 ? (
<div className={styles.couponItemRight_date}>{format(fieldListData.effectiveTimeStart)}-{format(fieldListData.effectiveTimeEnd)}</div>
) : (
<div className={styles.couponItemRight_date}>{fieldListData.invalidDay}&nbsp;</div>
)}
</div> </div>
</Col> </Col>
</Row> </Row>
......
...@@ -55,7 +55,7 @@ export interface ProductLayoutProps { ...@@ -55,7 +55,7 @@ export interface ProductLayoutProps {
/** 最外层标号 */ /** 最外层标号 */
index: number, index: number,
/** list 数据 */ /** list 数据 */
list: ListProps[], list: any[],
/** 删除某一个 */ /** 删除某一个 */
onDeletion: (_index: number) => void, onDeletion: (_index: number) => void,
/** 输入数量或者套餐价格 */ /** 输入数量或者套餐价格 */
...@@ -73,6 +73,8 @@ const ProductLayout: React.FC<ProductLayoutProps> = (props: any) => { ...@@ -73,6 +73,8 @@ const ProductLayout: React.FC<ProductLayoutProps> = (props: any) => {
onEntry(name, Number(e.target.value), _index) onEntry(name, Number(e.target.value), _index)
} }
console.log(list)
return ( return (
<Fragment> <Fragment>
{/* 套餐价格 */} {/* 套餐价格 */}
...@@ -118,7 +120,7 @@ const ProductLayout: React.FC<ProductLayoutProps> = (props: any) => { ...@@ -118,7 +120,7 @@ const ProductLayout: React.FC<ProductLayoutProps> = (props: any) => {
)} )}
{remind.value !== 1 && ( {remind.value !== 1 && (
<div className={style.couponLayout_contenxt}> <div className={style.couponLayout_contenxt}>
<Row style={{ height: '100%' }} wrap={false}> <Row style={{ height: '100%', marginLeft: 10 }} wrap={false}>
<Col flex='none'> <Col flex='none'>
<div className={style.couponLayout_item_left}> <div className={style.couponLayout_item_left}>
<p>¥<span>{_item.denomination}</span></p> <p>¥<span>{_item.denomination}</span></p>
......
...@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; ...@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { Drawer, Button, Form, message } from 'antd'; import { Drawer, Button, Form, message } from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import CollapseLayout from './components/collapseLayout'; import CollapseLayout from './components/collapseLayout';
import { isEmpty } from 'lodash'; import { isArray, isEmpty } from 'lodash';
import ProductLayout from './components/productLayout'; import ProductLayout from './components/productLayout';
import CouponsLayout from '@/pages/transaction/marketingAbility/selfManagement/readySubmitExamine/components/couponsLayout'; import CouponsLayout from '@/pages/transaction/marketingAbility/selfManagement/readySubmitExamine/components/couponsLayout';
...@@ -24,8 +24,7 @@ type RemindLayoutProps = { ...@@ -24,8 +24,7 @@ type RemindLayoutProps = {
message?: { [key: number]: string }, message?: { [key: number]: string },
} }
interface ListModalLayoutProps { interface CouponsListLayoutProps {
idNotInList?: number[],
/** messges */ /** messges */
remind?: RemindLayoutProps, remind?: RemindLayoutProps,
/** 数据回显 */ /** 数据回显 */
...@@ -34,8 +33,6 @@ interface ListModalLayoutProps { ...@@ -34,8 +33,6 @@ interface ListModalLayoutProps {
title?: string, title?: string,
/** 显示隐藏 */ /** 显示隐藏 */
visible?: boolean, visible?: boolean,
/** 适用商城 */
shopIdList?: number[],
/** 关闭 */ /** 关闭 */
onClose?: () => void, onClose?: () => void,
/** 确定 */ /** 确定 */
...@@ -48,21 +45,11 @@ interface CouponGroupListProps { ...@@ -48,21 +45,11 @@ interface CouponGroupListProps {
/** 换购门槛优惠门槛数量或金额 */ /** 换购门槛优惠门槛数量或金额 */
limitValue?: number, limitValue?: number,
/** 明细 */ /** 明细 */
list?: { list?: any[]
id?: number,
/** 活动商品id */
activityGoodsId?: number,
/** 优惠券id */
couponId: number,
/** 优惠券名称 */
couponName: string,
/** 赠送数量 */
num?: number,
}[]
} }
const CouponsListLayout: React.FC<ListModalLayoutProps> = (props: any) => { const CouponsListLayout: React.FC<CouponsListLayoutProps> = (props: any) => {
const { idNotInList, remind, value, shopIdList, title, visible, onClose, onConfirm } = props; const { remind, value, title, visible, onClose, onConfirm } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
const [couponSource, setCouponSource] = useState<CouponGroupListProps[]>([]); const [couponSource, setCouponSource] = useState<CouponGroupListProps[]>([]);
const [tableModalVisible, setTableModalVisible] = useState<boolean>(false); const [tableModalVisible, setTableModalVisible] = useState<boolean>(false);
...@@ -83,35 +70,114 @@ const CouponsListLayout: React.FC<ListModalLayoutProps> = (props: any) => { ...@@ -83,35 +70,114 @@ const CouponsListLayout: React.FC<ListModalLayoutProps> = (props: any) => {
} }
/** 组合数据到dataSource */
const handleComposed = (selectRowRecord?: any) => {
const fields: CouponGroupListProps[] = [...couponSource];
fields[idx].groupNo = (idx + 1);
if (isArray(selectRowRecord)) {
fields[idx].list = [...selectRowRecord]
}
fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => {
form.setFieldsValue({
[`dataSource_${idx}`]: fields[idx].list,
[`limitValue_${_index}`]: item.limitValue,
[`num_${_index}_${__index}`]: _item.num,
})
})
})
setCouponSource(fields);
}
const handleCouponSubmit = (selectRowRecord: any) => { const handleCouponSubmit = (selectRowRecord: any) => {
console.log(selectRowRecord, 10086) if (isEmpty(selectRowRecord)) {
message.warning(remind.message[1])
return
}
handleComposed(selectRowRecord)
toggle(false);
} }
const handleClick = () => { const handleClick = () => {
console.log('提交') form.validateFields().then(_res => {
if (isEmpty(_res)) {
message.warning(remind.message[2])
return
}
onConfirm(couponSource)
})
} }
/** 删除一个 */ /** 删除一个 */
const handleDeletion = (index: number) => { const handleDeletion = (index: number) => {
console.log(index) const fields = [...couponSource];
fields.splice(index, 1);
fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => {
form.setFieldsValue({
[`limitValue_${_index}`]: item.limitValue,
[`num_${_index}_${__index}`]: _item.num,
})
})
})
setCouponSource(fields);
} }
/** 选择搭配优惠券 */ /** 选择搭配优惠券 */
const handleCollocation = (_idx: number) => { const handleCollocation = (_idx: number) => {
const fields = [...couponSource];
fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => {
form.setFieldsValue({
[`limitValue_${_index}`]: item.limitValue,
[`num_${_index}_${__index}`]: _item.num,
})
})
})
setIdx(_idx); setIdx(_idx);
toggle(true) toggle(true)
} }
/** 输入一个价格或者数量 */ /** 输入一个价格或者数量 */
const handleEntryNumber = (index: number, name: string, num: number, _index?: number) => { const handleEntryNumber = (index: number, name: string, num: number, _index?: number) => {
console.log(index, name, num, _index) const fields: CouponGroupListProps[] = [...couponSource];
if (name === 'limitValue') {
fields[index][name] = Number(num);
} else {
fields[index].list[_index][name] = Number(num);
}
setCouponSource(fields)
} }
/** 删除一个赠送优惠券 */ /** 删除一个赠送优惠券 */
const handleDeletionColloCation = (index: number, _index: number) => { const handleDeletionColloCation = (index: number, _index: number) => {
console.log(index, _index) const fields: CouponGroupListProps[] = [...couponSource];
fields[index].list.splice(_index, 1);
fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => {
form.setFieldsValue({
[`limitValue_${_index}`]: item.limitValue,
[`num_${_index}_${__index}`]: _item.num,
})
})
})
setCouponSource(fields);
} }
useEffect(() => {
const fields = [...value];
fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => {
form.setFieldsValue({
[`dataSource_${_index}`]: fields[_index].list,
[`limitValue_${_index}`]: item.limitValue,
[`num_${_index}_${__index}`]: _item.num,
})
})
})
setCouponSource(value);
}, [value])
return ( return (
<Drawer <Drawer
width={600} width={600}
...@@ -169,6 +235,7 @@ const CouponsListLayout: React.FC<ListModalLayoutProps> = (props: any) => { ...@@ -169,6 +235,7 @@ const CouponsListLayout: React.FC<ListModalLayoutProps> = (props: any) => {
visible={tableModalVisible} visible={tableModalVisible}
onClose={() => toggle(false)} onClose={() => toggle(false)}
onSubmit={handleCouponSubmit} onSubmit={handleCouponSubmit}
value={couponSource[idx]}
/> />
</Drawer> </Drawer>
) )
......
...@@ -110,8 +110,14 @@ const ListModalLayout: React.FC<ListModalLayoutProps> = (props: any) => { ...@@ -110,8 +110,14 @@ const ListModalLayout: React.FC<ListModalLayoutProps> = (props: any) => {
} }
})] })]
} }
form.setFieldsValue({ fields.forEach((item, _index) => {
[`dataSource_${idx}`]: fields[idx].list, item.list.forEach((_item, __index) => {
form.setFieldsValue({
[`dataSource_${idx}`]: fields[idx].list,
[`limitValue_${_index}`]: item.limitValue,
[`num_${_index}_${__index}`]: _item.num,
})
})
}) })
setDataSource(fields); setDataSource(fields);
} }
...@@ -162,7 +168,6 @@ const ListModalLayout: React.FC<ListModalLayoutProps> = (props: any) => { ...@@ -162,7 +168,6 @@ const ListModalLayout: React.FC<ListModalLayoutProps> = (props: any) => {
const handleDeletion = (index: number) => { const handleDeletion = (index: number) => {
const fields = [...dataSource]; const fields = [...dataSource];
fields.splice(index, 1); fields.splice(index, 1);
form.resetFields()
fields.forEach((item, _index) => { fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => { item.list.forEach((_item, __index) => {
form.setFieldsValue({ form.setFieldsValue({
...@@ -195,7 +200,6 @@ const ListModalLayout: React.FC<ListModalLayoutProps> = (props: any) => { ...@@ -195,7 +200,6 @@ const ListModalLayout: React.FC<ListModalLayoutProps> = (props: any) => {
const handleDeletionColloCation = (index: number, _index: number) => { const handleDeletionColloCation = (index: number, _index: number) => {
const fields: GoodsSubsidiaryListProps[] = [...dataSource]; const fields: GoodsSubsidiaryListProps[] = [...dataSource];
fields[index].list.splice(_index, 1); fields[index].list.splice(_index, 1);
form.resetFields()
fields.forEach((item, _index) => { fields.forEach((item, _index) => {
item.list.forEach((_item, __index) => { item.list.forEach((_item, __index) => {
form.setFieldsValue({ form.setFieldsValue({
......
...@@ -2,13 +2,14 @@ import React, { useEffect, useMemo, useState } from 'react'; ...@@ -2,13 +2,14 @@ import React, { useEffect, useMemo, useState } from 'react';
import { Button, message, Table, Form, FormInstance } from 'antd'; import { Button, message, Table, Form, FormInstance } from 'antd';
import { Columns } from './columns'; import { Columns } from './columns';
import { EventEmitter } from '@umijs/hooks/lib/useEventEmitter' import { EventEmitter } from '@umijs/hooks/lib/useEventEmitter'
import CardLayout from '../card'; import CardLayout from '../../selfManagement/readySubmitExamine/components/card';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { PublicApi } from '@/services/api'; import { PublicApi } from '@/services/api';
import ListModalLayout from '@/pages/transaction/marketingAbility/components/listModalLayout'; import ListModalLayout from '@/pages/transaction/marketingAbility/components/listModalLayout';
import CollocationLayout from '@/pages/transaction/marketingAbility/components/collocationLayout'; import CollocationLayout from '@/pages/transaction/marketingAbility/components/collocationLayout';
import { remindLayout, RemindLayoutProps } from '@/pages/transaction/marketingAbility/paltformSign/readySubmitExamine/components/productListLayout/remind'; import { remindLayout, RemindLayoutProps } from '@/pages/transaction/marketingAbility/paltformSign/readySubmitExamine/components/productListLayout/remind';
import CouponsListLayout from '@/pages/transaction/marketingAbility/components/couponsListLayout';
type optionProps = { type optionProps = {
/** key */ /** key */
...@@ -21,16 +22,20 @@ type optionProps = { ...@@ -21,16 +22,20 @@ type optionProps = {
interface ProductListProps { interface ProductListProps {
/** 活动id */ /** 活动id */
activityId?: number, activityId?: any,
form?: FormInstance, form?: FormInstance,
/** umi-hooks */ /** umi-hooks */
focus$?: EventEmitter<void>, focus$?: EventEmitter<void>,
/** 适用商城 */ /** 适用商城 */
shopIdList?: number[], shopIdList?: number[],
/** 接口 */
fieldApi?: () => Promise<unknown>,
/** 活动规则 -> 有则不调用form.getFieldValue */
getActivityDefinedBO?: any,
} }
const ProductListLayout: React.FC<ProductListProps> = (props: any) => { const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
const { activityId, form, focus$, shopIdList } = props; const { activityId, form, focus$, shopIdList, fieldApi, getActivityDefinedBO } = props;
const [value, setValue] = useState<number>(1); const [value, setValue] = useState<number>(1);
const [productVisible, setProductVisible] = useState<boolean>(false); const [productVisible, setProductVisible] = useState<boolean>(false);
const [listModalVisible, setListModalVisible] = useState<boolean>(false); const [listModalVisible, setListModalVisible] = useState<boolean>(false);
...@@ -69,15 +74,16 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -69,15 +74,16 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
/** 设置搭配 */ /** 设置搭配 */
const handlCollocation = (record: any) => { const handlCollocation = (record: any) => {
const tableRecord: any = {...record} const tableRecord: any = { ...record }
if (tableRecord.goodsSubsidiaryGroupList !== undefined) { if (remind.value !== 1 && tableRecord.couponGroupList !== undefined) {
setCollocation(tableRecord.couponGroupList)
} else if (remind.value === 1 && tableRecord.goodsSubsidiaryGroupList !== undefined) {
setCollocation(tableRecord.goodsSubsidiaryGroupList) setCollocation(tableRecord.goodsSubsidiaryGroupList)
} else { } else {
setCollocation([]) setCollocation([])
} }
setSkuId(tableRecord.skuId) setSkuId(tableRecord.skuId)
setListModalVisible(true); setListModalVisible(true);
console.log(record)
} }
const columns = useMemo(() => { const columns = useMemo(() => {
...@@ -85,7 +91,7 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -85,7 +91,7 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
}, [value, dataSource]) }, [value, dataSource])
const toggle = (flag: boolean) => { const toggle = (flag: boolean) => {
const activityDefinedBO = form.getFieldValue('activityDefinedBO'); const activityDefinedBO = form.getFieldValue('activityDefinedBO') || getActivityDefinedBO;
if (isEmpty(shopIdList)) { if (isEmpty(shopIdList)) {
message.warning('请选择适用商城!'); message.warning('请选择适用商城!');
return return
...@@ -121,12 +127,12 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -121,12 +127,12 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
} }
useEffect(() => { useEffect(() => {
if (activityId) { if (!isEmpty(activityId)) {
PublicApi.getMarketingMerchantActivityDetailGoodsPage({ current: '1', pageSize: '999', activityId }).then(res => { fieldApi({ current: '1', pageSize: '999', ...activityId }).then(res => {
if (res.code !== 1000) { if (res.code !== 1000) {
return return
} }
const activityDefinedBO = form.getFieldValue('activityDefinedBO'); const activityDefinedBO = form.getFieldValue('activityDefinedBO') || getActivityDefinedBO;
if (value === 6) { if (value === 6) {
setRemind(remindLayout(value, activityDefinedBO.giveType, activityDefinedBO.giftType)); setRemind(remindLayout(value, activityDefinedBO.giveType, activityDefinedBO.giftType));
} }
...@@ -143,12 +149,13 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -143,12 +149,13 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
setIdNotInList([...idNotInList, ...res.data.data.map(item => item.skuId)]) setIdNotInList([...idNotInList, ...res.data.data.map(item => item.skuId)])
}) })
} }
}, [activityId]) }, [!isEmpty(activityId)])
useEffect(() => { useEffect(() => {
handlesStFieldsValue() handlesStFieldsValue()
}, [dataSource]) }, [dataSource])
/** 设置搭配商品 */
const handleConfirm = (params: any) => { const handleConfirm = (params: any) => {
const fields = [...dataSource]; const fields = [...dataSource];
fields.forEach(item => { fields.forEach(item => {
...@@ -160,6 +167,18 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -160,6 +167,18 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
setDataSource(fields) setDataSource(fields)
} }
/** 设置优惠券 */
const handleCouponConfirm = (params: any) => {
const fields = [...dataSource];
fields.forEach(item => {
if (item.skuId === skuId) {
item.couponGroupList = [...params]
}
})
setListModalVisible(false)
setDataSource(fields)
}
return ( return (
<CardLayout <CardLayout
id="productListLayout" id="productListLayout"
...@@ -187,7 +206,7 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -187,7 +206,7 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
onConfirm={handleSelectActiveProducts} onConfirm={handleSelectActiveProducts}
/> />
{/* 设置搭配商品 */} {/* 设置搭配商品 */}
{(!isEmpty(remind) && remind.value !== 1) && ( {(!isEmpty(remind) && remind.value === 1) && (
<ListModalLayout <ListModalLayout
title={remind.modalTitle} title={remind.modalTitle}
remind={remind} remind={remind}
...@@ -199,6 +218,17 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => { ...@@ -199,6 +218,17 @@ const ProductListLayout: React.FC<ProductListProps> = (props: any) => {
value={collocation} value={collocation}
/> />
)} )}
{/* 设置优惠券 */}
{(!isEmpty(remind) && remind.value !== 1) && (
<CouponsListLayout
title={remind.modalTitle}
remind={remind}
visible={listModalVisible}
onClose={() => setListModalVisible(false)}
onConfirm={handleCouponConfirm}
value={collocation}
/>
)}
</Form.Item> </Form.Item>
</CardLayout> </CardLayout>
) )
......
import React, { Fragment, useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { Button, message } from 'antd'; import { Button, Form } from 'antd';
import { history, Prompt } from 'umi'; import { history, Prompt } from 'umi';
import { useEventEmitter } from '@umijs/hooks';
import { Context } from '@/pages/transaction/components/detailLayout/components/context'; import { Context } from '@/pages/transaction/components/detailLayout/components/context';
import PeripheralLayout from '@/pages/transaction/components/detailLayout'; import PeripheralLayout from '@/pages/transaction/components/detailLayout';
import ProgressLayout from '@/pages/transaction/components/detailLayout/components/progressLayout'; import ProgressLayout from '@/pages/transaction/components/detailLayout/components/progressLayout';
...@@ -14,8 +15,8 @@ import ActivityUserLayout from '../../components/activityUserLayout'; ...@@ -14,8 +15,8 @@ import ActivityUserLayout from '../../components/activityUserLayout';
import DemandLayout from '../../components/demandLayout'; import DemandLayout from '../../components/demandLayout';
import { PublicApi } from '@/services/api'; import { PublicApi } from '@/services/api';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import ProductListLayout from './components/productListLayout';
import { SaveOutlined } from '@ant-design/icons'; import { SaveOutlined } from '@ant-design/icons';
import ProductListLayout from '../../components/productListLayout';
const TABLINK = [ const TABLINK = [
{ id: 'progressLayout', title: '流转进度' }, { id: 'progressLayout', title: '流转进度' },
...@@ -30,15 +31,20 @@ const TABLINK = [ ...@@ -30,15 +31,20 @@ const TABLINK = [
const DetialLayout = () => { const DetialLayout = () => {
const { query: { activityId, signUpId }, pathname } = history.location; const { query: { activityId, signUpId }, pathname } = history.location;
const [path] = useState(pathname.split('/')[pathname.split('/').length - 1]); const [path] = useState(pathname.split('/')[pathname.split('/').length - 1]);
const focus$ = useEventEmitter();
const [form] = Form.useForm();
const [loading, setLoading] = useState<boolean>(false) const [loading, setLoading] = useState<boolean>(false)
const [unsaved, setUnsaved] = useState<boolean>(false); const [unsaved, setUnsaved] = useState<boolean>(false);
const [productList, setProductList] = useState<any[]>([]); const [shopIdList, setShopIdList] = useState<number[]>([]);
const [signUpIds, setSignUpIds] = useState<number>();
const format = (text, fmt?: string) => { const format = (text, fmt?: string) => {
return <>{moment(text).format(fmt || "YYYY-MM-DD HH:mm:ss")}</> return <>{moment(text).format(fmt || "YYYY-MM-DD HH:mm:ss")}</>
} }
const [dataSource, setDataSource] = useState<any>({}); const [dataSource, setDataSource] = useState<any>({});
const [basicEffect, setBasicEffect] = useState<any>([]); const [basicEffect, setBasicEffect] = useState<any>([]);
const [generalEffect, setGeneralEffect] = useState<any>([]); const [generalEffect, setGeneralEffect] = useState<any>([]);
const [activityDefinedBO, setActivityDefinedBO] = useState<any>({});
const handleBasicEffect = (data: any) => { const handleBasicEffect = (data: any) => {
setBasicEffect([ setBasicEffect([
...@@ -72,7 +78,7 @@ const DetialLayout = () => { ...@@ -72,7 +78,7 @@ const DetialLayout = () => {
} }
} }
const fetchDataSource = useCallback(async () => { const fetchDataSource = async () => {
await PublicApi.getMarketingPlatformActivitySignupDetail({ activityId }).then((res: any) => { await PublicApi.getMarketingPlatformActivitySignupDetail({ activityId }).then((res: any) => {
if (res.code !== 1000) { if (res.code !== 1000) {
return return
...@@ -89,27 +95,51 @@ const DetialLayout = () => { ...@@ -89,27 +95,51 @@ const DetialLayout = () => {
}) })
}) })
data.externalLogStates = externalLogStates; data.externalLogStates = externalLogStates;
const option: any = { value: data.activityType };
focus$.emit(option)
setDataSource(data); setDataSource(data);
handleBasicEffect(data) handleBasicEffect(data);
setShopIdList(data.shopList.map(item => { return item.shopId }));
setActivityDefinedBO(data.activityDefinedBO)
handleGeneralEffect(data.activityDefinedBO, data.activityType) handleGeneralEffect(data.activityDefinedBO, data.activityType)
setSignUpIds(signUpId)
}).catch(() => { }) }).catch(() => { })
}, []) }
useEffect(() => { useEffect(() => {
fetchDataSource(); fetchDataSource();
// handleGeneralEffect(_data);
}, []) }, [])
const handleSubmit = useCallback(async () => { const handleSubmit = () => {
const params: any = { form.validateFields().then(res => {
activityId, const param: any = {
productList, activityId,
} productList: res.productList.map(item => {
signUpId !== null && (params.id = signUpId) if (item.couponGroupList) {
if (!isEmpty(productList)) { return {
...item,
couponGroupList: item.couponGroupList.map(_item => {
return {
..._item,
list: _item.list.map(__item => {
return {
activityGoodsId: item.productId,
couponId: __item.id,
couponName: __item.name,
num: __item.num,
}
})
}
})
}
}
return item
})
}
signUpId !== null && (param.id = signUpId);
setLoading(true) setLoading(true)
const fieldApi = (path === 'add' ? PublicApi.postMarketingPlatformActivitySignupSave : PublicApi.postMarketingPlatformActivitySignupUpdate) const fieldApi = (path === 'add' ? PublicApi.postMarketingPlatformActivitySignupSave : PublicApi.postMarketingPlatformActivitySignupUpdate)
fieldApi({ ...params }).then(res => { fieldApi({ ...param }).then(res => {
if (res.code !== 1000) { if (res.code !== 1000) {
setLoading(false) setLoading(false)
return return
...@@ -120,17 +150,7 @@ const DetialLayout = () => { ...@@ -120,17 +150,7 @@ const DetialLayout = () => {
}).catch(_err => { }).catch(_err => {
setLoading(false) setLoading(false)
}) })
})
} else {
message.warn('请选择活动商品!')
}
}, [productList])
const handleGetDataSoure = (e) => {
if (!unsaved) {
setUnsaved(true)
}
setProductList([...e])
} }
return ( return (
...@@ -150,7 +170,14 @@ const DetialLayout = () => { ...@@ -150,7 +170,14 @@ const DetialLayout = () => {
</Button> </Button>
} }
components={ components={
<Fragment> <Form
form={form}
onValuesChange={() => {
if (!unsaved) {
setUnsaved(true)
}
}}
>
<ProgressLayout /> <ProgressLayout />
<BasicLayout effect={basicEffect} /> <BasicLayout effect={basicEffect} />
<GeneralLayout <GeneralLayout
...@@ -159,11 +186,11 @@ const DetialLayout = () => { ...@@ -159,11 +186,11 @@ const DetialLayout = () => {
anchor="activityRuleLayout" anchor="activityRuleLayout"
effect={generalEffect} effect={generalEffect}
/> />
<ProductListLayout signUpId={signUpId !== 'null' && signUpId} data={dataSource} getDataSource={handleGetDataSoure} /> <ProductListLayout getActivityDefinedBO={activityDefinedBO} activityId={signUpIds && { signUpId: signUpIds }} form={form} focus$={focus$} shopIdList={shopIdList} fieldApi={PublicApi.getMarketingPlatformActivitySignupDetailGoodsPage} />
<ActivityUserLayout dataScoure={dataSource} /> <ActivityUserLayout dataScoure={dataSource} />
<DemandLayout storeList={dataSource.shopList} /> <DemandLayout storeList={dataSource.shopList} />
<RecordLyout /> <RecordLyout />
</Fragment> </Form>
} }
/> />
<Prompt when={unsaved} message="您还有未保存的内容,是否确定要离开?" /> <Prompt when={unsaved} message="您还有未保存的内容,是否确定要离开?" />
......
...@@ -32,15 +32,15 @@ export const remindLayout = (int, giveType?, giftType?) => { ...@@ -32,15 +32,15 @@ export const remindLayout = (int, giveType?, giftType?) => {
label: { label: {
1: '优惠门槛', 1: '优惠门槛',
2: giveType === 1 ? '元' : '个', 2: giveType === 1 ? '元' : '个',
3: '赠送商品', 3: giveType === 1 ? '赠送商品' : '赠送优惠券',
4: '赠送数量', 4: '赠送数量',
5: '买', 5: '买',
6: '', 6: '',
}, },
message: { message: {
1: '请选择赠送商品!', 1: giveType === 1 ? '请选择赠送商品!' : '请选择赠送优惠券!',
2: '请设置赠送商品!', 2: giveType === 1 ? '请设置赠送商品!' : '请设置赠送优惠券!',
3: '请选择赠送商品!', 3: giveType === 1 ? '请选择赠送商品!' : '请选择赠送优惠券!',
4: '请输入优惠门槛!', 4: '请输入优惠门槛!',
5: '请输入赠送数量!', 5: '请输入赠送数量!',
} }
......
...@@ -286,7 +286,7 @@ export const GeneralEffect = (int, data) => { ...@@ -286,7 +286,7 @@ export const GeneralEffect = (int, data) => {
return [ return [
{ {
col: [ col: [
{ label: '每日秒杀时间段', extra: `${format(data.startTime, 'HH:mm:ss')}~${format(data.endTime, 'HH:mm:ss')}` }, { label: '每日秒杀时间段', extra: <>{format(data.startTime, 'HH:mm:ss')}~{format(data.endTime, 'HH:mm:ss')}</>},
{ label: '活动描述', extra: data.describe } { label: '活动描述', extra: data.describe }
] ]
}, },
...@@ -363,13 +363,13 @@ export const GeneralEffect = (int, data) => { ...@@ -363,13 +363,13 @@ export const GeneralEffect = (int, data) => {
return [ return [
{ {
col: [ col: [
{ label: '抽取用户时间', extra: '' }, { label: '抽取用户时间', extra: data.extractAttemptUserTime && format(data.extractAttemptUserTime, 'YYYY-MM-DD HH:mm:ss') },
{ label: '活动描述', extra: data.describe }, { label: '活动描述', extra: data.describe },
] ]
}, },
{ {
col: [ col: [
{ label: '试用结束时间', extra: '' }, { label: '试用结束时间', extra: data.attemptEndTime && format(data.attemptEndTime, 'YYYY-MM-DD HH:mm:ss') },
] ]
} }
] ]
......
...@@ -7,7 +7,7 @@ import PeripheralLayout from '@/pages/transaction/components/detailLayout'; ...@@ -7,7 +7,7 @@ import PeripheralLayout from '@/pages/transaction/components/detailLayout';
import BasicInfoLayout from './components/basicInfoLayout'; import BasicInfoLayout from './components/basicInfoLayout';
import RulesLayout from './components/rulesLayout'; import RulesLayout from './components/rulesLayout';
import ShopLayout from './components/shopLayout'; import ShopLayout from './components/shopLayout';
import ProductListLayout from './components/productListLayout'; import ProductListLayout from '../../components/productListLayout';
import PartakeUserLayout from './components/partakeUserLayout'; import PartakeUserLayout from './components/partakeUserLayout';
import moment from 'moment'; import moment from 'moment';
import { PublicApi } from '@/services/api'; import { PublicApi } from '@/services/api';
...@@ -96,7 +96,42 @@ const AddedMarketing = () => { ...@@ -96,7 +96,42 @@ const AddedMarketing = () => {
oldMember: (res.allUser.includes(4) ? 1 : 0), oldMember: (res.allUser.includes(4) ? 1 : 0),
memberLevelList, memberLevelList,
shopList: res.shopList, shopList: res.shopList,
productList: res.productList productList: res.productList.map(item => {
if (item.couponGroupList) {
return {
...item,
couponGroupList: item.couponGroupList.map(_item => {
return {
..._item,
list: _item.list.map(__item => {
return {
activityGoodsId: item.productId,
couponId: __item.id,
couponName: __item.name,
num: __item.num,
}
})
}
})
}
}
return item
})
}
if (res['activityDefinedBO']['assembleTime']) {
params['activityDefinedBO'].assembleTime = Number(moment(res['activityDefinedBO']['assembleTime']).format('x'));
}
if (res['activityDefinedBO']['startTime']) {
params['activityDefinedBO']['startTime'] = Number(moment(res['activityDefinedBO']['startTime']).format('x'));
}
if (res['activityDefinedBO']['endTime']) {
params['activityDefinedBO']['endTime'] = Number(moment(res['activityDefinedBO']['endTime']).format('x'));
}
if (res['activityDefinedBO']['extractAttemptUserTime']) {
params['activityDefinedBO']['extractAttemptUserTime'] = Number(moment(res['activityDefinedBO']['extractAttemptUserTime']).format('x'));
}
if (res['activityDefinedBO']['attemptEndTime']) {
params['activityDefinedBO']['attemptEndTime'] = Number(moment(res['activityDefinedBO']['attemptEndTime']).format('x'));
} }
setLoading(true) setLoading(true)
path !== 'add' && (params.id = id); path !== 'add' && (params.id = id);
...@@ -126,6 +161,21 @@ const AddedMarketing = () => { ...@@ -126,6 +161,21 @@ const AddedMarketing = () => {
} }
})[0] })[0]
focus$.emit(option) focus$.emit(option)
if (data['activityDefinedBO']['assembleTime']) {
data['activityDefinedBO']['assembleTime'] = moment(data['activityDefinedBO']['assembleTime']);
}
if (data['activityDefinedBO']['startTime']) {
data['activityDefinedBO']['startTime'] = moment(data['activityDefinedBO']['startTime']);
}
if (data['activityDefinedBO']['endTime']) {
data['activityDefinedBO']['endTime'] = moment(data['activityDefinedBO']['endTime']);
}
if (data['activityDefinedBO']['extractAttemptUserTime']) {
data['activityDefinedBO']['extractAttemptUserTime'] = moment(data['activityDefinedBO']['extractAttemptUserTime']);
}
if (data['activityDefinedBO']['attemptEndTime']) {
data['activityDefinedBO']['attemptEndTime'] = moment(data['activityDefinedBO']['attemptEndTime']);
}
form.setFieldsValue({ form.setFieldsValue({
allUser: [data.newUser && 1, data.oldUser && 2, data.newMember && 3, data.oldMember && 4], allUser: [data.newUser && 1, data.oldUser && 2, data.newMember && 3, data.oldMember && 4],
activityDefinedBO: data.activityDefinedBO, activityDefinedBO: data.activityDefinedBO,
...@@ -179,7 +229,7 @@ const AddedMarketing = () => { ...@@ -179,7 +229,7 @@ const AddedMarketing = () => {
<BasicInfoLayout form={form} focus$={focus$} /> <BasicInfoLayout form={form} focus$={focus$} />
<RulesLayout form={form} focus$={focus$} /> <RulesLayout form={form} focus$={focus$} />
<ShopLayout onGetShopList={handleGetShopList} onSetShopList={shopList} /> <ShopLayout onGetShopList={handleGetShopList} onSetShopList={shopList} />
<ProductListLayout activityId={activityId} form={form} focus$={focus$} shopIdList={shopIdList} /> <ProductListLayout activityId={activityId && { activityId: activityId }} form={form} focus$={focus$} shopIdList={shopIdList} fieldApi={PublicApi.getMarketingMerchantActivityDetailGoodsPage} />
<PartakeUserLayout onGetLevel={handleGetLevel} onSetLevel={memberLevelList} setMemberType={memberType} /> <PartakeUserLayout onGetLevel={handleGetLevel} onSetLevel={memberLevelList} setMemberType={memberType} />
</Form> </Form>
} }
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Drawer, Space, Form, Select, Input, Button, Row, Col, Checkbox, Empty } from 'antd'; import { Drawer, Space, Form, Select, Input, Button, Row, Col, Checkbox, Empty, Pagination } from 'antd';
import { CaretDownOutlined } from '@ant-design/icons'; import { CaretDownOutlined } from '@ant-design/icons';
import { PublicApi } from '@/services/api'; import { PublicApi } from '@/services/api';
import CouponItem from '@/pages/transaction/marketingAbility/components/couponItem'; import CouponItem from '@/pages/transaction/marketingAbility/components/couponItem';
import styles from './index.less'; import styles from './index.less';
import { isEmpty } from 'lodash';
interface CouponsLayoutProps { interface CouponsLayoutProps {
/** 显示 */ /** 显示 */
...@@ -12,10 +13,12 @@ interface CouponsLayoutProps { ...@@ -12,10 +13,12 @@ interface CouponsLayoutProps {
onClose?: () => void, onClose?: () => void,
/** 提交 */ /** 提交 */
onSubmit?: (e: any) => void, onSubmit?: (e: any) => void,
/** 已选择的id */
value?: any,
} }
const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
const { visible, onClose, onSubmit } = props; const { visible, onClose, onSubmit, value } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
const [state, setState] = useState({ const [state, setState] = useState({
filterSearch: false filterSearch: false
...@@ -24,9 +27,11 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { ...@@ -24,9 +27,11 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
current: 1, current: 1,
pageSize: 10, pageSize: 10,
}) })
const [total, setTotal] = useState<number>(0);
const [couponList, setCouponList] = useState<any[]>([]); const [couponList, setCouponList] = useState<any[]>([]);
const [chekedId, setCheckedId] = useState<number[]>([]); // 已选择的优惠券 const [chekedId, setCheckedId] = useState<number[]>([]); // 已选择的优惠券
const [couponsList, setCouponsList] = useState<any[]>([]); const [selectCouponList, setSelectCouponList] = useState<any[]>([]); // checkbox 勾选到的数据 需要去重
const [couponsList, setCouponsList] = useState<any[]>([]); // 提交的优惠券
const changeFilterVisible = () => { const changeFilterVisible = () => {
setState({ setState({
filterSearch: !state.filterSearch, filterSearch: !state.filterSearch,
...@@ -40,8 +45,9 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { ...@@ -40,8 +45,9 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
if (res.code !== 1000) { if (res.code !== 1000) {
return return
} }
const { data } = res.data const { data, totalCount } = res.data
setCouponList(data) setCouponList(data)
setTotal(totalCount)
}) })
}) })
} }
...@@ -56,7 +62,7 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { ...@@ -56,7 +62,7 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
if (visible) { if (visible) {
handleSubmit() handleSubmit()
} }
}, [visible]) }, [visible, params])
const handleOnOk = () => { const handleOnOk = () => {
onSubmit(couponsList) onSubmit(couponsList)
...@@ -75,17 +81,39 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { ...@@ -75,17 +81,39 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
) )
} }
const _setCheckList = (_e, item: any) => { const _setCheckList = (_e, _item) => {
const ids = [...chekedId] const ids = [...chekedId];
const selcetLits = [...selectCouponList];
if (!ids.includes(_e)) { if (!ids.includes(_e)) {
setCouponsList([...couponsList, item]) setCheckedId([...ids, _e])
setCheckedId([...chekedId, _e]) setSelectCouponList([...selcetLits, _item])
} else { } else {
setCouponsList(couponsList.filter(_item => _item.couponId !== _e))
setCheckedId(ids.filter(_item => _item !== _e)); setCheckedId(ids.filter(_item => _item !== _e));
setSelectCouponList(selcetLits.filter(_item => _item.id !== _e))
} }
} }
useEffect(() => {
const newData = selectCouponList.filter(_item => chekedId.includes(_item.id));
console.log(newData, 98)
setCouponsList(newData)
}, [chekedId])
useEffect(() => {
if (!isEmpty(value)) {
const newChekedId = value.list.map((_item: any) => _item.id);
setCheckedId(newChekedId)
setSelectCouponList(value.list)
}
}, [value])
const handlePagination = (page, pageSize) => {
setParams({
current: page,
pageSize: pageSize,
})
}
return ( return (
<Drawer <Drawer
width={630} width={630}
...@@ -93,6 +121,7 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { ...@@ -93,6 +121,7 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
visible={visible} visible={visible}
onClose={onClose} onClose={onClose}
footer={renderFooter()} footer={renderFooter()}
destroyOnClose
> >
<Form <Form
form={form} form={form}
...@@ -150,6 +179,9 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => { ...@@ -150,6 +179,9 @@ const CouponsLayout: React.FC<CouponsLayoutProps> = (props: any) => {
</Col> </Col>
) )
})} })}
<Col span={24} style={{ display: 'flex' ,justifyContent: 'flex-end'}}>
<Pagination size="small" total={total} current={params.current} onChange={handlePagination}/>
</Col>
</Row> </Row>
)} )}
</Form> </Form>
......
...@@ -29,6 +29,7 @@ import * as EnhanceV2Api from './EnhanceV2Api'; ...@@ -29,6 +29,7 @@ import * as EnhanceV2Api from './EnhanceV2Api';
import * as MessageV2 from './MessageV2Api'; import * as MessageV2 from './MessageV2Api';
import * as LogiticsV2 from './LogiticsV2Api'; import * as LogiticsV2 from './LogiticsV2Api';
import * as MarketingApi from './MarketingApi'; import * as MarketingApi from './MarketingApi';
import * as MaketingV2Api from './MaketingV2Api'
import * as AfterServiceV2Api from './AfterServiceV2Api'; import * as AfterServiceV2Api from './AfterServiceV2Api';
...@@ -72,5 +73,6 @@ export const PublicApi = { ...@@ -72,5 +73,6 @@ export const PublicApi = {
...MessageV2, ...MessageV2,
...LogiticsV2, ...LogiticsV2,
...MarketingApi, ...MarketingApi,
...MaketingV2Api,
...AfterServiceV2Api, ...AfterServiceV2Api,
} }
...@@ -31,6 +31,7 @@ const tokenList = [ ...@@ -31,6 +31,7 @@ const tokenList = [
{ name: 'MessageV2', token: '69a667ec9861e8bdc25b89238d0b908a2123d9fce26e72fec3cdf6cd0b1f2681', categoryIds: [0], }, // 消息中心v2 { name: 'MessageV2', token: '69a667ec9861e8bdc25b89238d0b908a2123d9fce26e72fec3cdf6cd0b1f2681', categoryIds: [0], }, // 消息中心v2
{ name: 'LogiticsV2', token: '732fb8e33970ff5dee830423a630e8e85c3ef3293abba7581b16749dfce8608b', categoryIds: [0], }, // 物流能力v2 { name: 'LogiticsV2', token: '732fb8e33970ff5dee830423a630e8e85c3ef3293abba7581b16749dfce8608b', categoryIds: [0], }, // 物流能力v2
{ name: 'Marketing', token: 'd952d25c4e8272a6dff69245dbddf983dc886521e2623464e476922fc95f43af', categoryIds: [0], }, // 营销能力 { name: 'Marketing', token: 'd952d25c4e8272a6dff69245dbddf983dc886521e2623464e476922fc95f43af', categoryIds: [0], }, // 营销能力
{ name: 'MaketingV2', token: 'f6d5cee2383ca203dfa2882b84dfa02a1d79de3c3ad892b42f030437fdc5ea21', categoryIds: [0] }, // 营销活动v2
{ name: 'AfterServiceV2', token: '58748fc89dcdb33ec5cac520c00293ba92abca362a8ddb979df589effd0db9bd', 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