|
@@ -1,142 +1,202 @@
|
|
|
-import { Card, Col, Row } from "antd";
|
|
|
-import jb from '../../../../public//jb.png';
|
|
|
-import vip from '../../../../public//vip.png';
|
|
|
-import top from '../../../../public//top-r1.png';
|
|
|
-import { createStyles } from "antd-style";
|
|
|
-
|
|
|
-
|
|
|
-export function Template(params: { data: any, enmuList: any }) {
|
|
|
- let { data, enmuList } = params
|
|
|
- let { firstRecharge, rechargeConfigList } = data
|
|
|
- const useStyles = createStyles((props) => {
|
|
|
- let { token } = props
|
|
|
- let navTheme = localStorage.getItem("navTheme")//全局 2亮色 3黑色
|
|
|
+import { useAjax } from "@/Hook/useAjax";
|
|
|
+import { appComponentConfigGetAppPageList, getHotCategory, getShortBookBanners, getShortBookHotBooks } from "@/services/miniApp/compConfig";
|
|
|
+import { Card, Col, Row, Space, Spin } from "antd";
|
|
|
+import styles from './DrawerBox/index.less'
|
|
|
+import { useEffect, useMemo, useReducer } from "react";
|
|
|
+import React from "react";
|
|
|
+import { Banners } from "./components/banners";
|
|
|
+import { HotBooks } from "./components/hot_books";
|
|
|
+import { HotCategory } from "./components/hot_category";
|
|
|
+import { useModel } from "@umijs/max";
|
|
|
+import { useToken } from "@ant-design/pro-components";
|
|
|
+type Config = {
|
|
|
+ bannerType?: number,//banner类型; 0:小说 1:页面路径 banners组件使用
|
|
|
+ activityPagePath?: string,//banner类型 1的时候使用页面路径
|
|
|
+ bannerImage?: string,//banner图片
|
|
|
+ bookId?: string,//小说ID
|
|
|
+ categoryId?: string,//分类ID
|
|
|
+ bookIds?: any[],//用于分类自义定书籍的参数
|
|
|
+}
|
|
|
+type State = {
|
|
|
+ tabs: 0 | 1,//男生女生选项
|
|
|
+ isWorkDirection: boolean,//当前页面是否存在男频女频
|
|
|
+ compAc: string,//当前选中的组件,切换tabs请0
|
|
|
+ index: number,//每次操作修改数据都递增,为了检测到数据变动
|
|
|
+ activePage: string,//当前选中的页面
|
|
|
+ templateName: string,//模板名称
|
|
|
+ pageList: any[],//页面表
|
|
|
+ pageConfigList: {
|
|
|
+ pageUrl: string,//组件所在页面地址
|
|
|
+ workDirectionList: {
|
|
|
+ workDirection?: 0 | 1,//作品方向;0-男频 1-女频
|
|
|
+ componentConfigList: {
|
|
|
+ appComponentId: number | string,//组件ID
|
|
|
+ componentType: string,//组件类型
|
|
|
+ showRightButton?: boolean,//是否展示左侧按钮
|
|
|
+ componentName?: string,//组件名称
|
|
|
+ remark?: string,//备注
|
|
|
+ configs?: Config[],//组件内的配置
|
|
|
+ }[]
|
|
|
+ }[]
|
|
|
+ }[],
|
|
|
+}
|
|
|
+type Action = {
|
|
|
+ params?: any,
|
|
|
+ type: "setAll",
|
|
|
+}
|
|
|
+export function reducer(state: State, action: Action) {
|
|
|
+ let { type, params } = action
|
|
|
+ switch (type) {
|
|
|
+ case 'setAll':
|
|
|
+ return { ...state, ...params }
|
|
|
+ default:
|
|
|
+ return state;
|
|
|
+ }
|
|
|
+}
|
|
|
+export function Template(params: { data: any }) {
|
|
|
+ let { data } = params
|
|
|
+ let { token } = useToken()
|
|
|
+ let { initialState } = useModel("@@initialState")
|
|
|
+ // 接口公共参数
|
|
|
+ let publicData = useMemo(() => {
|
|
|
return {
|
|
|
- cardBox: {
|
|
|
- position: 'relative'
|
|
|
- },
|
|
|
- bgVip: {
|
|
|
- backgroundImage: "linear-gradient(180deg, #fff1dc 60%, #fffdfa 100%)",
|
|
|
- color: navTheme == "3" ? "#000" : "unset"
|
|
|
- },
|
|
|
- bg: {
|
|
|
- backgroundImage: 'linear-gradient(180deg, #ffeced 60%, #fffafa 100%)',
|
|
|
- color: navTheme == "3" ? "#000" : "unset"
|
|
|
- },
|
|
|
- topRight: {
|
|
|
- lineHeight: '20px',
|
|
|
- background: "#ff2441",
|
|
|
- position: 'absolute',
|
|
|
- top: 0,
|
|
|
- right: 0,
|
|
|
- fontSize: 12,
|
|
|
- borderRadius: "0px 8px 0 8px",
|
|
|
- },
|
|
|
- topRightVip: {
|
|
|
- background: "#ffd89d !important",
|
|
|
- },
|
|
|
- //
|
|
|
- topRightSpan1: { display: 'inline-block', background: `url(${top}) no-repeat`, minWidth: 40, height: 20, padding: "0 10px 0 6px", backgroundSize: "100% 100%", color: "#fff" },
|
|
|
- topRightSpan2: { color: "#fff", display: 'inline-block', padding: "0 5px" },
|
|
|
- del: { fontSize: 14, textDecoration: 'line-through', marginLeft: 7, color: token.colorTextTertiary, fontWeight: "500" }
|
|
|
+ appId: initialState?.selectApp?.id || "",
|
|
|
+ appType: initialState?.selectApp?.appType || ""
|
|
|
}
|
|
|
- });
|
|
|
- let { styles } = useStyles()
|
|
|
-
|
|
|
- return <Card bordered={false} >
|
|
|
- <Row gutter={[0, 15]}>
|
|
|
- {
|
|
|
- rechargeConfigList?.map((item: any, index: any) => {
|
|
|
- let {
|
|
|
- color,//背景色
|
|
|
- description,//整数购买文案
|
|
|
- extra,//右上角描述值
|
|
|
- gearType,//充值类型
|
|
|
- gift,//赠送
|
|
|
- obtain,//获得书币/vip每天价格
|
|
|
- price,//价格
|
|
|
- subscript,//右上角文案 首充|超值等
|
|
|
- vipDays,//vip天数
|
|
|
- } = item
|
|
|
- switch (gearType) {
|
|
|
- case 1://充值
|
|
|
- return <Col key={index} span={11} offset={index % 2 === 0 ? 0 : 1} >
|
|
|
- <Card className={`${styles.cardBox} ${color && styles.bg}`} styles={{ body: { maxHeight: 90, padding: '20px 15px' } }}>
|
|
|
- {/* 右上角 */}
|
|
|
- <div className={`${styles.topRight}`} style={subscript ? { borderRadius: "8px 8px 0 8px", } : {}} >
|
|
|
- {
|
|
|
- <>
|
|
|
- {subscript && <span className={styles.topRightSpan1}>{subscript}</span>}
|
|
|
- <span className={styles.topRightSpan2} style={subscript ? { transform: 'translateX(-4px)' } : {}}>多送{extra}元</span>
|
|
|
- </>
|
|
|
- }
|
|
|
- </div>
|
|
|
- <div style={{ display: 'flex', flexFlow: 'column' }}>
|
|
|
- <strong >
|
|
|
- <span style={{ fontSize: '20px', marginRight: 3 }} >¥</span>
|
|
|
- <span style={{ fontSize: 22, fontFamily: 'Yuewen Font' }}>{price}</span>
|
|
|
- </strong>
|
|
|
- <span style={{ fontSize: 12, marginTop: 2, color: "#777", display: 'block' }}>{obtain}书币 送{gift}书券</span>
|
|
|
- </div>
|
|
|
- {color && <img src={jb} style={{ position: 'absolute', right: 0, bottom: 0, width: 50 }} />}
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- case 2://vip
|
|
|
- let vipEnum = enmuList?.VIP_DAYS?.values;
|
|
|
- let vipStr = vipEnum?.find((i: { value: any; }) => i.value === vipDays)?.description || ""
|
|
|
- return <Col key={index} span={11} offset={index % 2 === 0 ? 0 : 1} >
|
|
|
- <Card className={`${styles.cardBox} ${color && styles.bgVip}`} styles={{ body: { maxHeight: 90, padding: '20px 15px' } }}>
|
|
|
- {/* 右上角 */}
|
|
|
- <div className={`${styles.topRight} ${styles.topRightVip}`} style={subscript ? { borderRadius: "8px 8px 0 8px", } : {}}>
|
|
|
- {
|
|
|
- <>
|
|
|
- {subscript && <span className={styles.topRightSpan1}>{subscript}</span>}
|
|
|
- <span className={styles.topRightSpan2}>{vipStr}</span>
|
|
|
- </>
|
|
|
- }
|
|
|
- </div>
|
|
|
- <div style={{ display: 'flex', flexFlow: 'column' }}>
|
|
|
- <strong >
|
|
|
- <span style={{ fontSize: '20px', marginRight: 3 }} >¥</span>
|
|
|
- <span style={{ fontSize: 22, fontFamily: 'Yuewen Font' }}>{price}</span>
|
|
|
- </strong>
|
|
|
- <span style={{ fontSize: 12, marginTop: 2, color: "#777", display: 'block' }}>¥{obtain}元/天</span>
|
|
|
- </div>
|
|
|
- {color && <img src={vip} style={{ position: 'absolute', right: 0, bottom: 0, width: 30 }} />}
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- case 3://整本
|
|
|
- return <Col key={index} span={11} offset={index % 2 === 0 ? 0 : 1} >
|
|
|
- <Card className={`${styles.cardBox} `} styles={{ body: { maxHeight: 90, padding: '20px 15px' } }}>
|
|
|
- {/* 右上角 */}
|
|
|
- <div className={styles.topRight}>
|
|
|
- {
|
|
|
- subscript ? <> <span>{item.description}</span></> : <>
|
|
|
- <span className={styles.topRightSpan1}>{subscript}</span>
|
|
|
- <span className={styles.topRightSpan2}>{item.description}</span>
|
|
|
- </>
|
|
|
+ }, [initialState?.selectApp])
|
|
|
+ const [state, dispatch] = useReducer(reducer, {
|
|
|
+ tabs: 0,
|
|
|
+ isWorkDirection: false,
|
|
|
+ compAc: "",
|
|
|
+ index: 0,
|
|
|
+ activePage: "",
|
|
|
+ pageConfigList: data?.pageConfigList
|
|
|
+ })
|
|
|
+ const list = useMemo(() => {
|
|
|
+ let pageConfig = state?.pageConfigList?.find((page: { pageUrl: any; }) => page.pageUrl === state.activePage)
|
|
|
+ let list: {
|
|
|
+ appComponentId: number | string;
|
|
|
+ componentType: string;
|
|
|
+ showRightButton?: boolean;
|
|
|
+ componentName?: string;
|
|
|
+ remark?: string;
|
|
|
+ configs?: Config[];
|
|
|
+ }[] = []
|
|
|
+ if (state?.isWorkDirection) {
|
|
|
+ let thePage = pageConfig?.workDirectionList?.find((page: { workDirection: any; }) => page.workDirection == state.tabs)
|
|
|
+ list = thePage?.componentConfigList || []
|
|
|
+ } else {
|
|
|
+ list = pageConfig?.workDirectionList?.[0].componentConfigList || []
|
|
|
+ }
|
|
|
+ return list
|
|
|
+ }, [state])
|
|
|
+ // 获取全部页面并且处理当前模板有哪些页面
|
|
|
+ useEffect(() => {
|
|
|
+ AppComponentConfigGetAppPageList.run(publicData).then(res => {
|
|
|
+ if (res.code === 200 && data?.pageConfigList?.length > 0) {
|
|
|
+ let pages: any = []
|
|
|
+ for (let item of data?.pageConfigList) {
|
|
|
+ let thatPage = res?.data?.find((page: { pagePath: any; }) => page.pagePath === item.pageUrl)
|
|
|
+ if (thatPage) {
|
|
|
+ pages.push(thatPage)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pages?.length > 0 && dispatch({ type: "setAll", params: { activePage: pages[0].pagePath, isWorkDirection: true, pageList: pages } })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }, [data])
|
|
|
+ //api
|
|
|
+ const GetShortBookHotBooks = useAjax((params) => getShortBookHotBooks(params))
|
|
|
+ const GetShortBookBanners = useAjax((params) => getShortBookBanners(params))
|
|
|
+ const GetHotCategory = useAjax((params) => getHotCategory(params))
|
|
|
+ const AppComponentConfigGetAppPageList = useAjax((params) => appComponentConfigGetAppPageList(params))
|
|
|
+ // 获取对应组件数据
|
|
|
+ useEffect(() => {
|
|
|
+ async function getData() {
|
|
|
+ if (state.pageConfigList) {
|
|
|
+ for (let page of state?.pageConfigList) {
|
|
|
+ for (let wd of page?.workDirectionList) {
|
|
|
+ for (let comp of wd?.componentConfigList) {
|
|
|
+ switch (comp?.componentType) {
|
|
|
+ case "banners":
|
|
|
+ await GetShortBookBanners.run({ templateName: data?.templateName, workDirection: wd?.workDirection, ...publicData }).then(res => {
|
|
|
+ comp.configs = res.data
|
|
|
+ })
|
|
|
+ break;
|
|
|
+ case "hot_books":
|
|
|
+ // await GetShortBookHotBooks.run({ templateName: data?.templateName, workDirection: wd?.workDirection, ...publicData }).then(res => {
|
|
|
+ // comp.configs = res.data
|
|
|
+ // })
|
|
|
+ break;
|
|
|
+ case "hot_category":
|
|
|
+ await GetHotCategory.run({ templateName: data?.templateName, workDirection: wd?.workDirection, ...publicData }).then(res => {
|
|
|
+ if(res.data){
|
|
|
+ comp.configs = res.data?.bookCategoryList?.map((item: { id: any; }) => {
|
|
|
+ return { categoryId: item.id, categoryInfo: item }
|
|
|
+ })
|
|
|
}
|
|
|
- </div>
|
|
|
- <div style={{ display: 'flex', flexFlow: 'column' }}>
|
|
|
- <strong >
|
|
|
- <span style={{ fontSize: '20px', marginRight: 3 }} >¥</span>
|
|
|
- <span style={{ fontSize: 22, fontFamily: 'Yuewen Font' }}>{price}</span>
|
|
|
- {/* {isVip && item.gift && <span className={styles.del}>¥{item.gift}</span>} */}
|
|
|
- </strong>
|
|
|
- {/* {isVip ?
|
|
|
- <span style={{ fontSize: 12, marginTop: 2, color: "#777", display: 'block' }}>{isOne ? "仅" : "¥"}{item.extra}元/天</span>
|
|
|
- :
|
|
|
- <span style={{ fontSize: 12, marginTop: 2, color: "#777", display: 'block' }}>{item.gift}书币 送{item.extra}书券</span>} */}
|
|
|
- </div>
|
|
|
- {/* {isOne && <img src={isVip ? vip : jb} style={{ position: 'absolute', right: 0, bottom: 0, width: isVip ? 30 : 50 }} />} */}
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- default:
|
|
|
- break;
|
|
|
+ })
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- })
|
|
|
+ }
|
|
|
}
|
|
|
- </Row>
|
|
|
- </Card >
|
|
|
+ }
|
|
|
+ getData()
|
|
|
+ }, [])
|
|
|
+ // 获取配置页面的列表
|
|
|
+ return <Spin spinning={GetShortBookHotBooks?.loading || GetShortBookBanners?.loading || GetHotCategory?.loading || AppComponentConfigGetAppPageList?.loading}>
|
|
|
+ <div className={styles.phone} onClick={(e) => {
|
|
|
+ e.stopPropagation()
|
|
|
+ }}>
|
|
|
+ <div className={styles.content} >
|
|
|
+ {/* 头部男女tabs */}
|
|
|
+ <Space className={styles.tabs} size={[20, 20]}>
|
|
|
+ {
|
|
|
+ ["男生", "女生"].map((s, i) => {
|
|
|
+ return <strong
|
|
|
+ key={i}
|
|
|
+ className={`${styles.tabs_text} ${state?.tabs === i ? styles.tabs_ac : ""}`}
|
|
|
+ onClick={() => {
|
|
|
+ dispatch({ type: "setAll", params: { tabs: i, compAc: 0 } })
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {s}
|
|
|
+ </strong>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </Space>
|
|
|
+ <div className={styles.content_box}>
|
|
|
+ {/* 内容 */}
|
|
|
+ {
|
|
|
+ list?.map(item => {
|
|
|
+ // console.log("item", item)
|
|
|
+ return <React.Fragment key={item.appComponentId}>
|
|
|
+ <div
|
|
|
+ // className={`${styles.comp} `}
|
|
|
+ onClick={() => { dispatch({ type: "setAll", params: { compAc: item.componentType } }) }}
|
|
|
+ >
|
|
|
+ {/* banners */}
|
|
|
+ {item.componentType === 'banners' && <Banners data={item.configs || []} />}
|
|
|
+ {/* 热门书籍*/}
|
|
|
+ {item.componentType === "hot_books" && <HotBooks data={item} />}
|
|
|
+ {/* 热门分类 */}
|
|
|
+ {item.componentType === "hot_category" && <HotCategory data={item} />}
|
|
|
+ </div>
|
|
|
+ <div className={styles.compBoxM} />
|
|
|
+ </React.Fragment>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ <div className={styles.phone_footer}>
|
|
|
+ {
|
|
|
+ state?.pageList?.map((item: { pagePath: React.Key | null | undefined; pageName: string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | null | undefined; }) => {
|
|
|
+ return <div key={item.pagePath} className={state.activePage === item.pagePath && styles.footer_ac}>{item.pageName}</div>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Spin>
|
|
|
}
|