shenwu há 8 meses atrás
pai
commit
b5534d836e

+ 14 - 45
config/routes.tsx

@@ -14,7 +14,7 @@ const newMenu = [
   // 分销商页面
   {
     path: '/distributor',
-    redirect: '/distributor/account',
+    redirect: '/distributor/miniApp',
   },
   {
     name: 'distributor.account',
@@ -39,7 +39,7 @@ const newMenu = [
   {
     path: '/miniApp/book',
     name: 'miniApp.book',
-    icon: 'icon-xiaoshuo',
+    icon: 'icon-xiaoshuo-wx',
     access: 'isShow',
     routes: [
       {
@@ -58,50 +58,11 @@ const newMenu = [
       },
     ],
   },
-  // 小程序端管理
-  {
-    name: 'miniApp.appManage',
-    icon: 'icon-xiaochengxu',
-    path: '/miniApp/appManage',
-    access: "isShow",
-    routes: [
-      {//小程序组件配置
-        path: '/miniApp/appManage/moduleConfig',
-        name: "moduleConfig",
-        component: './Admin',
-      },
-      {//小程序组件信息
-        path: '/miniApp/appManage/moduleInfo',
-        name: "moduleInfo",
-        component: './Admin',
-      },
-      {//短篇小说书架管理
-        path: '/miniApp/appManage/shortBookShelf',
-        name: "shortBookShelf",
-        component: './Admin',
-      },
-      {//短篇小说管理
-        path: '/miniApp/appManage/shortBook',
-        name: "shortBook",
-        component: './Admin',
-      },
-      {//长篇篇小说管理
-        path: '/miniApp/appManage/longtBook',
-        name: "longBook",
-        component: './Admin',
-      },
-      {//分类管理
-        path: '/miniApp/appManage/classify',
-        name: "classify",
-        component: './Admin',
-      },
-    ],
-  },
   // 阅读记录
   {
     path: '/miniApp/readLog',
     name: 'miniApp.readLog',
-    icon: 'icon-yuedu-2',
+    icon: 'icon-yuedu-2-wx',
     access: 'isShow',
     routes: [
       {
@@ -124,7 +85,7 @@ const newMenu = [
   {
     path: '/miniApp/payLog',
     name: 'miniApp.payLog',
-    icon: 'icon-chongzhi01',
+    icon: 'icon-chongzhi01-wx',
     access: 'isShow',
     routes: [
       {
@@ -146,15 +107,23 @@ const newMenu = [
   // 消费订单管理
   {
     name: 'miniApp.consume',
-    icon: 'icon-xiaofei',
+    icon: 'icon-xiaofei-wx',
     path: '/miniApp/consume',
     access: "isShow",
     component: './MiniApp/Consume',
   },
+  // 小程序端管理
+  {
+    name: 'miniApp.appManage',
+    icon: 'icon-xiaochengxu-wx',
+    path: '/miniApp/moduleConfig',
+    access: "isShow",
+    component: './Admin',
+  },
   // 书币充值模板
   {
     name: 'miniApp.payModuleConfig',
-    icon: 'icon-shubi',
+    icon: 'icon-taojinbi-wx',
     path: '/miniApp/payModuleConfig',
     access: "isShow",
     component: './MiniApp/ModuleConfig',

BIN
public/jb.png


BIN
public/top-r1.png


BIN
public/vip.png


+ 37 - 18
src/app.tsx

@@ -1,9 +1,8 @@
 import { Footer, Question, AvatarDropdown, AvatarName } from '@/components';
-// import { HomeOutlined, LinkOutlined } from '@ant-design/icons';
 import type { Settings as LayoutSettings } from '@ant-design/pro-components';
 import { SettingDrawer } from '@ant-design/pro-components';
 import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max';
-import { history } from '@umijs/max';
+import { history, useModel } from '@umijs/max';
 import defaultSettings from '../config/defaultSettings';
 import { errorConfig, ResponseStructure } from './requestErrorConfig';
 import React from 'react';
@@ -23,7 +22,7 @@ export async function getInitialState(): Promise<{
   loading?: boolean;
   menuType: "distributor" | "miniApp",
   navTheme?: "2" | "3",
-  selectApp?: { appId: string, id: string, appName: string } | null,
+  selectApp?: { appId: string, id: string, appName: string, appType: number } | null,
   token: any,
 }> {
   // 如果不是登录页面,执行
@@ -31,7 +30,7 @@ export async function getInitialState(): Promise<{
   let selectApp = sessionStorage.getItem("selectApp");
   let menuType = sessionStorage.getItem("menuType") as ("distributor" | "miniApp") || 'distributor';
   let navTheme: any = localStorage.getItem("navTheme") || '2';//主题色 2白 3黑
-  if (location.pathname !== loginPath) {
+  if (location.pathname !== loginPath && localStorage.getItem("Token")) {
     const res = await getUserInfo();
     // console.log(res)
     if (res.data) {
@@ -57,18 +56,30 @@ export async function getInitialState(): Promise<{
 export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
   return {
     // 动态管理菜单
-    // menu: {
-    //   // 每当 initialState?.currentUser?.userid 发生修改时重新执行 request
-    //   params: {
-    //     userId: initialState?.menuType,
-    //   },
-    //   request: async (params, defaultMenuData) => {
-    //     // initialState.currentUser 中包含了所有用户信息
-    //     // const menuData = 
-    //     console.log(defaultMenuData,initialState)
-    //     return defaultMenuData;
-    //   },
-    // },
+    menu: {
+      // 每当 initialState?.currentUser?.userid 发生修改时重新执行 request
+      params: {
+        appType: initialState?.selectApp?.appType,
+      },
+      request: async (params, defaultMenuData) => {
+        let newMenu = defaultMenuData?.map(menu=>{
+          // 替换图标给微信
+          if(initialState?.selectApp?.appType === 1 && menu.icon && menu.icon.includes("-dy")){
+            console.log(menu.icon)
+            let icon = menu.icon.replace("-dy",'-wx')
+            return {...menu,icon}
+          }
+          // 替换图标为抖音
+          if(initialState?.selectApp?.appType === 2 && menu.icon && menu.icon.includes("-wx")){
+            let icon = menu.icon.replace("-wx",'-dy')
+            return {...menu,icon}
+          }
+          return menu
+        })
+        console.log("newMenu",newMenu)
+        return newMenu;
+      },
+    },
     iconfontUrl: scriptUrl,
     actionsRender: () => [<Question key="doc" />],
     avatarProps: {
@@ -116,7 +127,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
         return false
       } else if (initialState?.selectApp) {
         return <Space>
-          <MyIcon type='icon-xiaochengxu' style={{ fontSize: 30 }} />
+          <MyIcon type={initialState?.selectApp?.appType === 1 ? "icon-weixin" : "icon-douyinzhanghao"} style={{ fontSize: 30 }} />
           <strong style={{ fontSize: 20 }}>{initialState?.selectApp?.appName}</strong>
         </Space>
       } else {
@@ -128,6 +139,14 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
     // 增加一个 loading 的状态
     childrenRender: (children) => {
       // if (initialState?.loading) return <PageLoading />;
+      const { init, state } = useModel('global', (ret) => ({
+        init: ret.init,
+        state: ret.state
+      }));
+      if (!state?.enumList && localStorage.getItem("Token")) {
+        init()//初始全局
+      }
+
       return (
         <>
           {children}
@@ -150,7 +169,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
       );
     },
     ...initialState?.settings,
-    navTheme: initialState?.navTheme === '2' ? "light" : "realDark"
+    navTheme: initialState?.navTheme === '2' ? "light" : "realDark",
     // title:initialState?.selectApp ? defaultSettings?.title + '--'+initialState?.selectApp?.appName : defaultSettings?.title //标题修改
   };
 };

+ 1 - 1
src/components/MenuChange.tsx

@@ -1,5 +1,5 @@
 import { useModel, history } from "@umijs/max"
-type Props = { menuType: "distributor" | "miniApp", children: any, data: { appId: string, id: string, appName: string } | null}
+type Props = { menuType: "distributor" | "miniApp", children: any, data: { appId: string, id: string, appName: string,appType:number } | null}
 //切换菜单展示
 const MenuChange: React.FC<Props> = (props) => {
     let { menuType, children, data } = props

+ 5 - 5
src/components/RightContent/AvatarDropdown.tsx

@@ -1,6 +1,6 @@
 import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
 import { history, useModel } from '@umijs/max';
-import {  Space, Spin } from 'antd';
+import { Space, Spin } from 'antd';
 import { createStyles } from 'antd-style';
 import type { MenuInfo } from 'rc-menu/lib/interface';
 import React, { useCallback } from 'react';
@@ -43,15 +43,15 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu, childre
    */
   const loginOut = async () => {
     // await outLogin();
-    const { search, pathname } = window.location;
+    let { search, pathname, origin, href } = window.location;
     const urlParams = new URL(window.location.href).searchParams;
     /** 此方法会跳转到 redirect 参数所在的位置 */
-    await logOut()
+    // await logOut()
     localStorage.removeItem("Token")
     sessionStorage.removeItem("menuType");
     sessionStorage.removeItem("selectApp");
-    const redirect = urlParams.get('redirect');
-    history.push('/user/login')
+    // history.push('/user/login')
+    window.location.href = origin
   };
   const { styles } = useStyles();
 

+ 1 - 0
src/global.less

@@ -28,6 +28,7 @@ body {
   text-rendering: optimizeLegibility;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
+
 }
 
 ul,

+ 1 - 1
src/global.tsx

@@ -5,7 +5,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
 
 const { pwa } = defaultSettings;
 const isHttps = document.location.protocol === 'https:';
-export let scriptUrl = "//at.alicdn.com/t/c/font_4644725_fo58yieucbw.js"
+export let scriptUrl = "//at.alicdn.com/t/c/font_4644725_sif6l9wwae.js"
 
 export const MyIcon = createFromIconfontCN({
   scriptUrl// 在 iconfont.cn 上生成

+ 2 - 8
src/locales/zh-CN/menu.ts

@@ -51,18 +51,12 @@ export default {
   'menu.editor.koni': '拓扑编辑器',
   // 新增
   // 分销商页面
-  "menu.distributor.miniApp":"小程序管理",
+  "menu.distributor.miniApp":"微信小程序管理",
   "menu.distributor.account":"账号管理",
   // 小程序页面
   "menu.miniApp.consume":"消费订单管理",
   "menu.miniApp.payModuleConfig":"书币充值模板管理",
-  "menu.miniApp.appManage":"小程序端管理",
-  "menu.miniApp.appManage.moduleConfig":"组件配置",
-  "menu.miniApp.appManage.moduleInfo":"组件信息",
-  "menu.miniApp.appManage.shortBookShelf":"短篇小说书架管理",
-  "menu.miniApp.appManage.shortBook":"短篇小说管理",
-  "menu.miniApp.appManage.longBook":"长篇小说管理",
-  "menu.miniApp.appManage.classify":"分类管理",
+  "menu.miniApp.appManage":"小程序组件管理",
   "menu.miniApp.book":"小说管理",
   "menu.miniApp.book.short":"短篇小说",
   "menu.miniApp.book.long":"长篇小说",

+ 57 - 0
src/models/global.tsx

@@ -0,0 +1,57 @@
+import { enumDictList, queryLabelList, queryCategoryList, queryAuthList } from "@/services/global"
+import { useReducer, useState } from "react"
+
+type State = {
+    enumList?: { [key: string]: any[] },//枚举
+    labelList?: any[],//标签列表
+    categoryList?: any[],//分类列表
+    authList?: any[],//作者列表
+}
+type Action = {
+    params?: any,
+    type: 'setEnum' | 'setLabelList' | 'setCategoryList' | 'setAuthList' | "setAll",
+}
+export function reducer(state: State, action: Action) {
+    let { type, params } = action
+    switch (type) {
+        case 'setEnum':
+            return { ...state, enumList: params?.enumList }
+        case 'setLabelList':
+            return { ...state, labelList: params?.labelList }
+        case 'setCategoryList':
+            return { ...state, categoryList: params?.categoryList }
+        case 'setAuthList':
+            return { ...state, authList: params?.authList }
+        case 'setAll':
+            return { ...state, ...params }
+        default:
+            return state;
+    }
+}
+export default (): { state: State, init: () => void } => {
+    const [state, dispatch] = useReducer(reducer, {})
+    let isLoding = false
+    const init = async () => {
+        if (isLoding) {
+            return
+        }
+        console.log("初始化")
+        isLoding = true
+        let enumData: any = await enumDictList().then((res) => res.data).catch((err) => { console.log(err) })
+        let labelList = await queryLabelList().then((res) => res.data).catch((err) => { console.log(err) })
+        let categoryList = await queryCategoryList().then((res) => res.data).catch((err) => { console.log(err) })
+        let authList = await queryAuthList().then((res) => res.data).catch((err) => { console.log(err) })
+        let enumList: { [key: string]: any[] } = {}
+        if (enumData) {
+            Object.values(enumData.enums).map((item: any) => {
+                enumList[item.name] = item
+            })
+        }
+        dispatch({ type: "setAll", params: { enumList, labelList, categoryList, authList } })
+        isLoding = false
+    }
+    return {
+        state,
+        init
+    }
+}

+ 2 - 2
src/pages/Distributor/MiniApp/index.tsx

@@ -7,8 +7,8 @@ import { useAjax } from "@/Hook/useAjax"
 const Page: React.FC = () => {
     let getList = useAjax((params) => miniAppList(params), { type: 'table' })
     return <PageContainer>
-        <ProTable<any, API.PageParams>
-            headerTitle={"小程序列表"}
+        <ProTable<any, any>
+            headerTitle={"微信小程序列表"}
             rowKey={(r) => r.id}
             search={{
                 labelWidth: 120,

+ 2 - 2
src/pages/Distributor/MiniApp/tableConfig.tsx

@@ -24,7 +24,7 @@ export const columns = (): ProColumns<any>[] => {
             hideInSearch: true,
             align: "center",
         },
-      
+
         {
             title: "运营载体状态",
             dataIndex: 'status',
@@ -41,7 +41,7 @@ export const columns = (): ProColumns<any>[] => {
             valueType: 'option',
             align: "center",
             render: (_, record) => {
-               return <MenuChange menuType="miniApp" data={record}><a type='primary'>管理</a></MenuChange>
+                return <MenuChange menuType="miniApp" data={{ ...record, appType: record.status ? 1 : 2 }}><a type='primary'>管理</a></MenuChange>
             },
         },
     ];

+ 8 - 20
src/pages/MiniApp/BookManage/Long/index.tsx

@@ -2,34 +2,22 @@ import { PageContainer, ProTable } from "@ant-design/pro-components"
 import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
 import { useModel } from "@umijs/max"
-import { longBookOrderList } from "@/services/miniApp/payLog"
-import { useState } from "react"
+import { longBookInfoList } from "@/services/miniApp/bookManage"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType, setAppType] = useState("1")
-    let getList = useAjax((params) => longBookOrderList(params), { type: 'table' })
+    let {enumList} = useModel("global",(res)=>({
+        enumList:res.state.enumList
+    }))
+    let getList = useAjax((params) => longBookInfoList(params), { type: 'table' })
     return <PageContainer title={false}
         tabProps={{ type: 'card' }}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key) => {
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+        >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+                appType:initialState?.selectApp?.appType || ""
             }}
             headerTitle={"长篇小说充值记录列表"}
             rowKey={(r) => r.id}

+ 3 - 18
src/pages/MiniApp/BookManage/Short/index.tsx

@@ -3,33 +3,18 @@ import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
 import { useModel } from "@umijs/max"
 import { shortBookOrderList } from "@/services/miniApp/payLog"
-import { useState } from "react"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType, setAppType] = useState("1")
     let getList = useAjax((params) => shortBookOrderList(params), { type: 'table' })
     return <PageContainer title={false}
         tabProps={{ type: 'card'}}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key) => {
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+        >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+             appType:initialState?.selectApp?.appType || ""
             }}
             headerTitle={"短篇小说充值记录列表"}
             rowKey={(r) => r.id}

+ 5 - 20
src/pages/MiniApp/Consume/index.tsx

@@ -1,35 +1,20 @@
 import { PageContainer, ProTable } from "@ant-design/pro-components"
 import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
-import { bookCoinList, Params } from "@/services/miniApp/consume"
+import { bookCoinList } from "@/services/miniApp/consume"
 import { useModel } from "@umijs/max"
-import { useState } from "react"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType,setAppType]=useState("1")
     let getList = useAjax((params) => bookCoinList(params), { type: 'table' })
     return <PageContainer
-        tabProps={{type:'card'}}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key)=>{
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+        tabProps={{ type: 'card' }}
+    >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+                appType: initialState?.selectApp?.appType || ""
             }}
             headerTitle={"消费订单列表"}
             rowKey={(r) => r.id}

+ 112 - 0
src/pages/MiniApp/ModuleConfig/formConfig.tsx

@@ -0,0 +1,112 @@
+import { ProFormColumnsType } from "@ant-design/pro-components";
+
+function formConfig(): ProFormColumnsType<{
+    name: string;
+    state: string;
+}>[] {
+    return [
+        {
+            title: '模板名称',
+            dataIndex: 'templateName',
+            formItemProps: {
+                rules: [
+                    {
+                        required: true,
+                        message: '此项为必填项',
+                    },
+                ],
+            }
+        },
+        {
+            title: '充值模板类型',
+            dataIndex: 'templateType',
+            valueType: 'select',
+            valueEnum: { '0': "书币充值", '1': "vip充值" },
+            formItemProps: {
+                rules: [
+                    {
+                        required: true,
+                        message: '此项为必填项',
+                    },
+                ],
+            }
+        },
+        {
+            title: '充值模板描述',
+            dataIndex: 'templateDescription',
+            valueType: 'textarea',
+        },
+        {
+            title: '备注',
+            dataIndex: 'remark',
+            valueType: 'textarea',
+        },
+        {
+            title: '充值档位配置',
+            dataIndex: 'rechargeConfigList',
+            valueType: 'formList',
+            fieldProps: {
+                // min:4,
+                // max:4,
+                creatorButtonProps: {
+                    creatorButtonText:"添加一个配置"
+                }
+            },
+            colProps: {
+                span: 24
+            },
+            columns: [
+                {
+                    valueType: 'group',
+                    colProps: {
+                        span: 24
+                    },
+                    columns: [{
+                        title: '价格',
+                        dataIndex: 'price',
+                        valueType: 'money',
+                        width: "100%",
+                        colProps: {
+                            span: 6
+                        }
+                    },
+                    {
+                        title: '赠送',
+                        dataIndex: 'gift',
+                        valueType: 'digit',
+                        width: "100%",
+                        colProps: {
+                            span: 6
+                        }
+                    },
+                    {
+                        title: '额外赠送',
+                        dataIndex: 'extra',
+                        valueType: 'digit',
+                        width: "100%",
+                        colProps: {
+                            span: 6
+                        }
+                    },
+                    {
+                        title: '额外描述',
+                        dataIndex: 'description',
+                        width: "100%",
+                        colProps: {
+                            span: 6
+                        }
+                    },]
+                }
+            ]
+        },
+        {
+            title: '激活当前模板',
+            dataIndex: 'activateTemplate',
+            valueType: 'switch',
+            formItemProps: { layout: 'horizontal' },
+            colProps: { offset: 19 }
+        },
+    ]
+}
+
+export default formConfig

+ 203 - 2
src/pages/MiniApp/ModuleConfig/index.tsx

@@ -1,6 +1,207 @@
+import { BetaSchemaForm, PageContainer, ProFormInstance, useToken } from "@ant-design/pro-components"
+import { useAjax } from "@/Hook/useAjax"
+import { useModel } from "@umijs/max"
+import { JSXElementConstructor, Key, ReactElement, ReactNode, ReactPortal, useEffect, useMemo, useRef, useState } from "react"
+import { appRechargeTemplateList, appRechargeTemplateSave, appRechargeTemplateSwitch, appRechargeTemplateRemove, appRechargeTemplateUpdate, appRechargeTemplateInfo } from "@/services/miniApp/moduleConfig"
+import { Button, Card, Col, Empty, message, Modal, Row, Space } from "antd"
+import { DeleteOutlined, EditOutlined, ExclamationCircleFilled, PlusOutlined } from "@ant-design/icons"
+import formConfig from "./formConfig"
+import { Template } from "./template"
+import { createStyles } from "antd-style";
+const useStyles = createStyles(({ token }) => {
+    return {
+        active: {
+            position: 'relative',
+            "&::after": {
+                content: '""', // 修正了这里的拼写错误
+                display: "block",
+                opacity: 1,
+                border: '15px solid #1890ff',
+                borderBlockEnd: '15px solid transparent',
+                borderInlineStart: '15px solid transparent', // 修正了多余的分号
+                borderStartEndRadius: '6px',
+                position: 'absolute',
+                top: 0,
+                right: 0
+            }
+        }
+    }
+})
+type DataItem = {
+    name: string;
+    state: string;
+};
+const Page: React.FC = () => {
+    let { token } = useToken()
+    let { initialState } = useModel("@@initialState")
+    let [open, setOpen] = useState<any>(null)
+    let [editValues, setEditValues] = useState<any>({})
+    let [activeT, setActiveT] = useState<any>()
+    let { styles } = useStyles()
+    let getList = useAjax((params) => appRechargeTemplateList(params))//获取模板列表
+    let add = useAjax((params) => appRechargeTemplateSave(params))//新增模板
+    let switchT = useAjax((params) => appRechargeTemplateSwitch(params))//切换模板
+    let editT = useAjax((params) => appRechargeTemplateUpdate(params))//编辑模板
+    let delT = useAjax((params) => appRechargeTemplateRemove(params))//删除模板
+    let infoT = useAjax((id) => appRechargeTemplateInfo(id))//模板详情
+    const formRef = useRef<ProFormInstance>();
+    let publicData = useMemo(() => {
+        return {
+            miniappId: initialState?.selectApp?.id || "",
+            distributorId: initialState?.currentUser?.distributorId,
+            appType: initialState?.selectApp?.appType || ""
+        }
+    }, [initialState?.selectApp, initialState?.currentUser?.distributorId])
+    // 获取表单数据
+    useEffect(() => {
+        getList.run(publicData).then(res => {
+            if (res.data) {
+                let activeObj = res?.data?.find((item: { activateTemplate: any }) => item.activateTemplate)
+                activeObj && setActiveT(activeObj.id)
+            }
+        })
+    }, [publicData])
+    // 提交表单
+    const submit = async (values: any) => {
+        let api = editValues?.id ? editT : add
+        if (!values.activateTemplate) {
+            values.activateTemplate = false
+        }
+        if (editValues?.id) {
+            values.id = editValues?.id
+        }
+        api.run({ ...values, ...publicData }).then(res => {
+            if (res.code === 200) {
+                getList.refresh()
+                message.success(values.id ? "编辑模板成功" : "新建模板成功!")
+                closeForm(false)
+            }
+        })
+    }
+    // 关闭表单弹窗和重置表单内容
+    const closeForm = (b: boolean, values?: any) => {
+        if (!b) {
+            setEditValues({})
+            formRef?.current?.resetFields?.()
+            setOpen(b)
+        } else {
+            setOpen(b)
+            if (values) {
+                infoT.run(values.id).then(res => {
+                    if (res.code === 200) {
+                        let data = { ...res.data, templateType: values.templateType + "" }
+                        setEditValues(data)
+                        formRef?.current?.setFieldsValue(data)
+                    }
+                })
+            }
+        }
+    }
+    // 模板切换
+    const switchTemplate = (id: any) => {
+        let params = { ...publicData, id }
+        Modal.confirm({
+            title: '切换充值模板',
+            content: '是否要切换为当前充值模板?',
+            icon: <ExclamationCircleFilled />,
+            okText: "切换",
+            onOk: () => {
+                switchT.run(params).then(res => {
+                    if (res.code === 200) {
+                        setActiveT(id)
+                        getList.refresh()
+                        message.success("切换成功")
+                    }
+                })
+            }
+        });
+    }
+    // 模板删除
+    const delTemplate = (id: any) => {
+        Modal.confirm({
+            title: '删除充值模板',
+            content: '是否要删除当前充值模板?',
+            icon: <ExclamationCircleFilled />,
+            okType: 'danger',
+            okText: "删除",
+            onOk: () => {
+                delT.run(id).then(res => {
+                    if (res.code === 200) {
+                        getList.refresh()
+                        message.success("删除成功")
+                    }
+                })
+            }
+        });
+    }
+    // 获取模板详情
+    const getTemplateInfo = (id: any) => {
 
+    }
+    // 模板编辑
+    const editTemplate = (values: any) => {
+        console.log(values)
+
+        // Modal.confirm({
+        //     title: '切换充值模板',
+        //     content: '是否要切换为当前充值模板?',
+        //     icon: <ExclamationCircleFilled />,
+        //     onOk: () => {
+        //         delT.run(id).then(res => {
+        //             if (res.code === 200) {
+        //                 getList.refresh()
+        //                 message.success("删除成功")
+        //             }
+        //         })
+        //     }
+        // });
+    }
+
+    return <PageContainer
+        extra={getList?.data?.data?.length > 0 && <Button type="primary" onClick={() => { closeForm(true) }}><PlusOutlined />新增模板</Button>}
+    >
+        {/* 模板列表 */}
+        <Row gutter={[20, 20]}>
+            {
+                getList?.data?.data?.map((item: { id: Key | null | undefined; templateName: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | null | undefined; rechargeConfigList: any[]; templateType: any; templateDescription: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | null | undefined }) => {
+                    return <Col key={item.id} style={{ cursor: 'pointer' }} onClick={() => { switchTemplate(item.id) }}>
+                        <Card className={activeT === item.id ? styles.active : ""} style={{ background: activeT === item.id ? token.colorPrimaryBgHover : token.colorFillAlter }} hoverable>
+                            <h3 style={{ fontSize: 16, fontWeight: 500, color: token.colorText, fontFamily: 'PingFang SC' }}>{item.templateName}</h3>
+                            <Template list={item.rechargeConfigList} isVip={!!item.templateType} />
+                            <p style={{ marginTop: 20, color: token.colorTextSecondary, fontSize: 12 }}>{item.templateDescription}</p>
+                            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'end' }}>
+                                <Space>
+                                    <Button size='small' type='primary' onClick={(e) => { e.stopPropagation(); closeForm(true, item) }}><EditOutlined /></Button>
+                                    <Button size='small' type="primary" danger onClick={(e) => { e.stopPropagation(); delTemplate(item.id) }}><DeleteOutlined /></Button>
+                                </Space>
+                            </div>
+                        </Card>
+                    </Col>
+                })
+            }
+            {
+                getList?.data?.data?.length === 0 && <div style={{ width: "100%", height: "100%", marginTop: "10%" }}><Empty description={<Space direction='vertical'><div>暂无模板数据</div><Button type="primary" onClick={() => { closeForm(true) }}><PlusOutlined />新增模板</Button></Space>} /></div>
+            }
+        </Row>
+        {/* 模板弹窗 */}
+        <BetaSchemaForm<DataItem>
+            title={editValues?.id ? "编辑模板" : '新建模板'}
+            formRef={formRef}
+            open={open}
+            onOpenChange={(b) => { !b && closeForm(b) }}
+            layoutType={"ModalForm"}
+            rowProps={{
+                gutter: [16, 16],
+            }}
+            colProps={{
+                span: 12,
+            }}
+            grid={true}
+            onFinish={submit}
+            columns={formConfig()}
+            loading={add?.loading}
+        />
+    </PageContainer>
 
-const Page:React.FC=()=>{
-    return <>模块管理</>
 }
 export default Page

+ 68 - 0
src/pages/MiniApp/ModuleConfig/template.tsx

@@ -0,0 +1,68 @@
+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";
+
+const useStyles = (isVip: any) => createStyles((props) => {
+    let { token } = props
+    return {
+        cardBox: {
+            position: 'relative'
+        },
+        isOne: {
+            backgroundImage: isVip ? "linear-gradient(180deg, #fff1dc 60%, #fffdfa 100%)" : 'linear-gradient(180deg, #ffeced 60%, #fffafa 100%)',
+        },
+        topRight: {
+            lineHeight: '20px',
+            background: isVip ? "#ffd89d" : "#ff2441",
+            position: 'absolute',
+            top: 0,
+            right: 0,
+            fontSize: 12,
+            borderRadius: isVip ? '0 8px 0 8px' : "8px 8px 0 8px",
+            padding: isVip ? '0 5px' : 0,
+        },
+        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', transform: 'translateX(-4px)' },
+        del:{ fontSize: 14, textDecoration: 'line-through',marginLeft:7,color:token.colorTextTertiary,fontWeight:"500" }
+    }
+});
+
+export function Template(params: { list: any[], isVip: boolean }) {
+    let { list, isVip } = params
+    let { styles } = useStyles(isVip)()
+    return <Card bordered={false} style={{ width: 420 }}>
+        <Row gutter={[0, 15]}>
+            {
+                list?.map((item, index) => {
+                    let isOne = index === 0
+                    return <Col key={index} span={11} offset={index % 2 === 0 ? 0 : 1} >
+                        <Card className={`${styles.cardBox} ${isOne ? styles.isOne : ""}`} styles={{ body:{maxHeight: 90, padding: '20px 15px'} }}>
+                            <div className={styles.topRight}>
+                                {
+                                    isVip ? <> <span>{item.description}</span></> : <>
+                                        <span className={styles.topRightSpan1}>{isOne ? "首充" : "超值"}</span>
+                                        <span className={styles.topRightSpan2}>{item.description}</span>
+                                    </>
+                                }
+                            </div>
+                            <div style={{ display: 'flex', flexFlow: 'column' }}>
+                                <strong >
+                                    <span style={{ fontSize: '20px', marginRight: 3 }}>¥</span>
+                                    <span style={{ fontSize: 22, fontFamily: 'Yuewen Font' }}>{item.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>
+                })
+            }
+        </Row>
+    </Card>
+}

+ 3 - 19
src/pages/MiniApp/PayLog/Long/index.tsx

@@ -3,33 +3,17 @@ import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
 import { useModel } from "@umijs/max"
 import { longBookOrderList } from "@/services/miniApp/payLog"
-import { useState } from "react"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType, setAppType] = useState("1")
     let getList = useAjax((params) => longBookOrderList(params), { type: 'table' })
     return <PageContainer title={false}
-        tabProps={{ type: 'card' }}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key) => {
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+    >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+                appType: initialState?.selectApp?.appType || ""
             }}
             headerTitle={"长篇小说充值记录列表"}
             rowKey={(r) => r.id}

+ 3 - 19
src/pages/MiniApp/PayLog/Short/index.tsx

@@ -3,33 +3,17 @@ import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
 import { useModel } from "@umijs/max"
 import { shortBookOrderList } from "@/services/miniApp/payLog"
-import { useState } from "react"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType, setAppType] = useState("1")
     let getList = useAjax((params) => shortBookOrderList(params), { type: 'table' })
     return <PageContainer title={false}
-        tabProps={{ type: 'card'}}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key) => {
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+    >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+             appType:initialState?.selectApp?.appType || ""
             }}
             headerTitle={"短篇小说充值记录列表"}
             rowKey={(r) => r.id}

+ 3 - 19
src/pages/MiniApp/ReadLog/Long/index.tsx

@@ -3,33 +3,17 @@ import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
 import { useModel } from "@umijs/max"
 import { longBookReadLogList } from "@/services/miniApp/readLog"
-import { useState } from "react"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType, setAppType] = useState("1")
     let getList = useAjax((params) => longBookReadLogList(params), { type: 'table' })
     return <PageContainer title={false}
-        tabProps={{ type: 'card' }}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key) => {
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+    >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+                appType: initialState?.selectApp?.appType || ""
             }}
             headerTitle={"长篇小说阅读记录列表"}
             rowKey={(r) => r.id}

+ 3 - 19
src/pages/MiniApp/ReadLog/Short/index.tsx

@@ -3,34 +3,18 @@ import { columns } from "./tableConfig"
 import { useAjax } from "@/Hook/useAjax"
 import { useModel } from "@umijs/max"
 import { shortBookReadLogList } from "@/services/miniApp/readLog"
-import { useState } from "react"
 
 const Page: React.FC = () => {
     let { initialState } = useModel("@@initialState")
-    let [appType, setAppType] = useState("1")
     let getList = useAjax((params) => shortBookReadLogList(params), { type: 'table' })
     return <PageContainer
         title={false}
-        tabProps={{ type: 'card' }}
-        header={{style:{paddingBottom:0}}}
-        onTabChange={(key) => {
-            setAppType(key)
-        }}
-        tabList={[
-            {
-                tab: '微信小程序',
-                key: '1',
-            },
-            {
-                tab: '抖音小程序',
-                key: '2',
-            },
-        ]}>
+    >
         <ProTable<any, any>
             params={{
                 miniappId: initialState?.selectApp?.id || "",
-                distributorId: initialState?.currentUser.distributorId,
-                appType
+                distributorId: initialState?.currentUser?.distributorId,
+                appType: initialState?.selectApp?.appType || ""
             }}
             headerTitle={"短篇小说阅读记录列表"}
             rowKey={(r) => r.id}

+ 2 - 8
src/pages/User/Login/index.tsx

@@ -1,21 +1,15 @@
-import { Footer } from '@/components';
-import { login } from '@/services/ant-design-pro/api';
-import { getFakeCaptcha } from '@/services/ant-design-pro/login';
+
 import {
-  AlipayCircleOutlined,
   LockOutlined,
   MobileOutlined,
-  TaobaoCircleOutlined,
   UserOutlined,
-  WeiboCircleOutlined,
 } from '@ant-design/icons';
 import {
   LoginForm,
   ProFormCaptcha,
-  ProFormCheckbox,
   ProFormText,
 } from '@ant-design/pro-components';
-import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max';
+import { FormattedMessage, history, useIntl, useModel, Helmet } from '@umijs/max';
 import { Alert, message, Tabs } from 'antd';
 import Settings from '../../../../config/defaultSettings';
 import React, { useState } from 'react';

+ 26 - 0
src/services/global.ts

@@ -0,0 +1,26 @@
+import { api } from '@/services/api';
+import { request } from '@umijs/max';
+/**标签列表 */
+export async function queryLabelList() {
+  return request(api+'/admin/query/labelList', {
+    method: 'GET',
+  });
+}
+/**分类列表 */
+export async function queryCategoryList() {
+  return request(api+'/admin/query/categoryList', {
+    method: 'GET',
+  });
+}
+/**作者列表 */
+export async function queryAuthList() {
+  return request(api+'/admin/query/authList', {
+    method: 'GET',
+  });
+}
+/**枚举列表 */
+export async function enumDictList() {
+  return request(api+'/admin/enumDict/list', {
+    method: 'GET',
+  });
+}

+ 2 - 2
src/services/miniApp/bookManage/index.tsx

@@ -33,8 +33,8 @@ export async function longBookInfoList(params:Params) {
 
 
 // ======================================短篇================================
-export async function shortBookOrderList(params:Params) {
-    return request(api+'/admin/shortBookOrder/list', {
+export async function shortBookInfoList(params:Params) {
+    return request(api+'/admin/shortBookInfo/list', {
       method: 'GET',
       params
     })

+ 70 - 0
src/services/miniApp/moduleConfig/index.tsx

@@ -0,0 +1,70 @@
+import { api } from '@/services/api';
+import { request } from '@umijs/max';
+type Page = {
+    pageSize: number | string,
+    pageNum: number | string
+}
+interface PublicParams{
+    miniappId: string,//微信小程序组件ID
+    distributorId: string,//分销商ID
+    appType: string,//小程序类型 1:微信小程序、2:抖音小程序
+}
+export interface Params extends Page,PublicParams{}
+/**书币充值模板列表 */
+export async function appRechargeTemplateList(params: Params) {
+    return request(api + '/admin/appRechargeTemplate/list', {
+        method: 'GET',
+        params
+    });
+}
+/**书币充值模板详情 */
+export async function appRechargeTemplateInfo(id: string) {
+    return request(api + `/admin/appRechargeTemplate/getInfo/${id}`, {
+        method: 'GET',
+    });
+}
+/**书币充值模板删除 */
+export async function appRechargeTemplateRemove(id: string) {
+    return request(api + `/admin/appRechargeTemplate/remove/${id}`, {
+        method: 'DELETE',
+    });
+}
+interface RechargeConfig {
+    price: string,//价格
+    gift: string,//赠送
+    extra: string,//额外赠送
+    description: string,//额外描述
+}
+interface Data extends PublicParams {
+    id?: string,//编辑时的ID
+    templateName: string,//模板名称
+    templateDescription: string,//充值模板描述
+    rechargeConfigJson: RechargeConfig,//充值挡位配置
+    activateTemplate: boolean,//当前激活的充值模板;true :已激活 false :未激活
+    remark?: string,//备注
+}
+/**书币充值模板新增*/
+export async function appRechargeTemplateSave(data: Data) {
+    return request(api + `/admin/appRechargeTemplate/save`, {
+        method: 'POST',
+        data
+    });
+}
+/**书币充值模板修改*/
+export async function appRechargeTemplateUpdate(params: Data) {
+    let { id, ...data } = params
+    return request(api + `/admin/appRechargeTemplate/update/${id}`, {
+        method: 'PUT',
+        data
+    });
+}
+interface DataSwitch extends PublicParams{
+    id:string,//模板ID
+}
+/**书币充值模板修改*/
+export async function appRechargeTemplateSwitch(data: DataSwitch) {
+    return request(api + `/admin/appRechargeTemplate/updateTemplate`, {
+        method: 'PUT',
+        data
+    });
+}