shenwu hai 7 meses
pai
achega
aa044517b2

+ 31 - 9
config/routes.tsx

@@ -14,7 +14,7 @@ const newMenu = [
   // 分销商页面
   {
     path: '/distributor',
-    redirect: '/distributor/wxMiniApp',
+    redirect: '/distributor/account',
   },
   {
     name: 'distributor.account',
@@ -24,19 +24,41 @@ const newMenu = [
     component: './Distributor/Account',
   },
   {
-    name: 'distributor.wxMiniApp',
-    icon: 'icon-weixin',
-    path: '/distributor/wxMiniApp',
+    name: 'distributor.appManage',
+    icon: 'icon-yingyongguanliyuanguanli',
+    path: '/distributor/appManage',
+    access: "isShow",
+    component: './Distributor/AppManage',
+  },
+  {
+    name: 'distributor.appList',
+    icon: 'icon-yingyongguanli',
+    path: '/distributor/appList',
     access: "isShow",
-    component: './Distributor/WxMiniApp',
+    component: './Distributor/AppList',
   },
   {
-    name: 'distributor.dyMiniApp',
-    icon: 'icon-douyinzhanghao',
-    path: '/distributor/dyMiniApp',
+    name: 'distributor.corpManage',
+    icon: 'icon-qiwei_qiwei',
+    path: '/distributor/corpManage',
     access: "isShow",
-    component: './Distributor/DyMiniApp',
+    component: './Distributor/CorpManage',
   },
+  
+  // {
+  //   name: 'distributor.wxMiniApp',
+  //   icon: 'icon-weixin',
+  //   path: '/distributor/wxMiniApp',
+  //   access: "isShow",
+  //   component: './Distributor/WxMiniApp',
+  // },
+  // {
+  //   name: 'distributor.dyMiniApp',
+  //   icon: 'icon-douyinzhanghao',
+  //   path: '/distributor/dyMiniApp',
+  //   access: "isShow",
+  //   component: './Distributor/DyMiniApp',
+  // },
   // 小程序页面
   {
     path: '/miniApp',

+ 6 - 6
src/components/bookSelect/index.tsx

@@ -8,15 +8,15 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"
 const BookSelect = (props: { value?: any, onChange?: (value: any) => void }) => {
     let { value, onChange } = props
     let { initialState } = useModel("@@initialState")
-    let {state} = useModel("appPageConifg")
+    let { state } = useModel("appPageConifg")
     let publicData = useMemo(() => {
         return {
             appId: initialState?.selectApp?.id || "",
             distributorId: initialState?.currentUser?.distributorId,
             appType: initialState?.selectApp?.appType || "",
-            workDirection:state.tabs 
+            workDirection: state.tabs
         }
-    }, [initialState?.selectApp, initialState?.currentUser?.distributorId,state.index])
+    }, [initialState?.selectApp, initialState?.currentUser?.distributorId, state.index])
     let apiobj = useApi(initialState?.selectApp?.appCategory || 1)
     let getList = useAjax((params) => apiobj.getBookPageList(params))
     let api = useMemo(() => {
@@ -57,8 +57,8 @@ const BookSelect = (props: { value?: any, onChange?: (value: any) => void }) =>
             onSearch={(value) => {
                 debounce(() => { setParmas({ ...params, bookName: value }) }, 500)
             }}
-            onChange={(value,option) => {
-                onChange?.(option?.longBookInfo)
+            onChange={(value, option) => {
+                onChange?.(initialState?.selectApp?.appCategory === 1 ? option?.longBookInfo : option?.shortBookInfoVO)
             }}
             value={value?.id || value}
             dropdownRender={(menu) => {
@@ -79,7 +79,7 @@ const BookSelect = (props: { value?: any, onChange?: (value: any) => void }) =>
                     />
                 </>
             }}
-            options={data?.records?.map(item => ({ label: item.longBookInfo.bookName, value: item.bookId,...item }))}
+            options={data?.records?.map(item => ({ label: initialState?.selectApp?.appCategory === 1 ? item.longBookInfo.bookName : item.shortBookInfoVO.bookName, value: item.bookId, ...item }))}
         />
     </div>
 

+ 1 - 1
src/global.tsx

@@ -5,7 +5,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
 import nocover from '../public/nocover.jpg'
 const { pwa } = defaultSettings;
 const isHttps = document.location.protocol === 'https:';
-export let scriptUrl = "//at.alicdn.com/t/c/font_4644725_kdi2stcj9z.js"//线上icon
+export let scriptUrl = "//at.alicdn.com/t/c/font_4644725_joneow2nore.js"//线上icon
 // 自定义icon组件用于线上icon
 export const MyIcon = createFromIconfontCN({
   scriptUrl// 在 iconfont.cn 上生成

+ 3 - 0
src/locales/zh-CN/menu.ts

@@ -54,6 +54,9 @@ export default {
   "menu.distributor.wxMiniApp":"微信小程序管理",
   "menu.distributor.dyMiniApp":"抖音小程序管理",
   "menu.distributor.account":"账号管理",
+  "menu.distributor.appManage":"管理员应用管理",
+  "menu.distributor.appList":"应用管理",
+  "menu.distributor.corpManage":"企微管理",
   // 小程序页面
   "menu.miniApp.payModuleConfig":"书币充值模板管理",
   "menu.miniApp.appManage":"小程序组件管理",

+ 1 - 0
src/models/appPageConifg.tsx

@@ -14,6 +14,7 @@ type State = {
     compAc: string,//当前选中的组件,切换tabs请0
     index: number,//每次操作修改数据都递增,为了检测到数据变动
     activePage: string,//当前选中的页面
+    templateName:string,//模板名称
     pageConfigList: {
         pageUrl: string,//组件所在页面地址
         workDirectionListDTOS: {

+ 22 - 3
src/models/global.tsx

@@ -2,7 +2,7 @@ import { enumDictList, queryLabelList, queryCategoryList, queryAuthList } from "
 import { useReducer, useState } from "react"
 
 type State = {
-    enumList?: { [key: string]: any[] },//枚举
+    enumList?: { [key: string]: any },//枚举
     labelList?: any[],//标签列表
     categoryList?: any[],//分类列表
     authList?: any[],//作者列表
@@ -28,7 +28,7 @@ export function reducer(state: State, action: Action) {
             return state;
     }
 }
-export default (): { state: State, init: () => void, getLabelAndClassList: (params?: { workDirection: number | string }) => Promise<boolean> } => {
+export default (): { state: State, init: () => void, getEnum: (enumName: string, type: "map" | "arr" | "obj") => any, getLabelAndClassList: (params?: { workDirection: number | string }) => Promise<boolean> } => {
     const [state, dispatch] = useReducer(reducer, {})
     let isLoding = false
     const init = async () => {
@@ -55,12 +55,31 @@ export default (): { state: State, init: () => void, getLabelAndClassList: (para
             labelList = await queryLabelList(params).then((res) => res.data).catch((err) => { console.log(err) })
             categoryList = await queryCategoryList(params).then((res) => res.data).catch((err) => { console.log(err) })
         }
-        dispatch({ type: "setAll", params: { ...state, labelList,categoryList } })
+        dispatch({ type: "setAll", params: { ...state, labelList, categoryList } })
         return true
     }
+    const getEnum = (enumName: string, type: "map" | "arr" | "obj") => {
+        let arr = state?.enumList?.[enumName]?.values
+        // console.log("arr",enumName,arr)
+        switch (type) {
+            case "map":
+                return new Map(arr?.map(({ value, description }: any) => [value, description]))
+            case "arr":
+                return arr?.map(({ value, description }: any) => ({ value, key: value, label: description }))
+            case "obj":
+                let obj: any = {}
+                if (arr) {
+                    for (let item of arr) {
+                        obj[item?.value] = { text: item?.description }
+                    }
+                }
+                return obj
+        }
+    }
     return {
         state,
         init,
+        getEnum,
         getLabelAndClassList
     }
 }

+ 55 - 0
src/pages/Distributor/AppList/index.tsx

@@ -0,0 +1,55 @@
+import { PageContainer, ProTable } from "@ant-design/pro-components"
+import { Table } from "antd"
+import { columns, childrenColumns } from "./tableConfig"
+import { useAjax } from "@/Hook/useAjax"
+import { useMemo, useState } from "react"
+import { useModel } from "@umijs/max"
+import { appList } from "@/services/distributor/appList"
+
+const Page: React.FC = () => {
+    let { state, getEnum } = useModel("global")
+    let [key, setKey] = useState<any>(1)
+    let getList = useAjax((params) => appList(params), { type: 'table' })
+    return <PageContainer
+        tabList={getEnum("APP_TYPE", "arr")}
+        tabProps={{
+            type: 'card',
+            hideAdd: true,
+            onChange: (e) => setKey(e),
+        }}
+    >
+        <ProTable<any, any>
+            headerTitle={"抖音小程序列表"}
+            rowKey={(r) => r.id}
+            search={{
+                labelWidth: 120,
+            }}
+            scroll={{ x: "auto" }}
+            params={{
+                appType: key
+            }}
+            request={async (params) => {
+                if (params.appType) {
+                    return await getList.run(params)
+                }
+            }}
+            columns={columns({ appType: key })}
+            expandable={{
+                rowExpandable: (record) => record?.appCarrierList?.length > 0,
+                expandRowByClick: true,
+                expandedRowRender: (record) => {
+                    return <Table
+                        columns={childrenColumns}
+                        dataSource={record.appCarrierList}
+                        rowKey={(r) => r.id}
+                        pagination={false}
+                        size='small'
+                        bordered
+                    />
+                },
+            }}
+        />
+    </PageContainer>
+
+}
+export default Page

+ 161 - 0
src/pages/Distributor/AppList/tableConfig.tsx

@@ -0,0 +1,161 @@
+import MenuChange from "@/components/MenuChange";
+import { MyIcon } from "@/global";
+import { ProColumns } from "@ant-design/pro-components";
+import { useModel } from "@umijs/max";
+import { Badge, Button, Space, Switch, TableColumnsType, Tag, Tooltip } from "antd";
+
+export const columns = (props: { appType: any}): ProColumns<any>[] => {
+    let { getEnum } = useModel("global")
+    return [
+        {
+            title: "应用名称",
+            dataIndex: 'appName',
+            key: "appName",
+            align: "center",
+            render: (a: any, b: any) => {
+                return <Space size={[3, 0]}>
+                    <MyIcon type={props?.appType === 2 ? "icon-xiaochengxu-dy" : "icon-xiaochengxu-wx"} />
+                    {b.appName}
+                </Space>
+            }
+        },
+        {
+            title: "应用标识",
+            dataIndex: 'appKey',
+            key: "appKey",
+            align: "center",
+        },
+        {
+            title: "小程序类型",
+            dataIndex: 'appCategory',
+            key: "appCategory",
+            align: "center",
+            valueEnum: getEnum("APP_CATEGORY", 'map')
+        },
+        {
+            title: "允许投放渠道",
+            dataIndex: 'advertisingChannels',
+            valueType:'select',
+            key: "advertisingChannels",
+            align: "center",
+            valueEnum:getEnum("ADVERTISING_CHANNEL","map")
+        },
+        {
+            title: "首页地址",
+            dataIndex: 'homePage',
+            key: "homePage",
+            align: "center",
+            hideInSearch: true,
+        },
+        {
+            title: "应用版本",
+            dataIndex: 'appVersion',
+            key: "appVersion",
+            align: "center",
+            hideInSearch: true,
+        },
+        {
+            title: '小程序配置信息(json)',
+            dataIndex: 'configParamList',
+            key: 'configParamList',
+            align: 'center',
+            hideInSearch: true,
+            render: (a, b) => {
+                return (
+                    <Space size={[0, 0]} wrap>
+                        {b?.configParamList?.map((item: any, index: number) => {
+                            return (
+                                <Tooltip title={JSON.stringify(item['additionalProp' + (index + 1)])} key={index}>
+                                    <Button type="link" size="small">
+                                        配置{index + 1}
+                                    </Button>
+                                </Tooltip>
+                            );
+                        })}
+                    </Space>
+                );
+            },
+        },
+        {
+            title: 'ios支付版本号',
+            tooltip: "ios的特殊性,此版本号与IOS支付模块关联,小程序版本号<=此版本号IOS才会出现支付功能,(微信)小程序发布线上后必须设置",
+            dataIndex: 'iosPayment',
+            align: "center",
+            hideInSearch: true,
+            render: (_, d) => {
+                return d.iosPayment ? <Tag color="processing" bordered={false}>{d.iosPayment}</Tag> : <Tag color="error" bordered={false}>IOS无法支付</Tag>
+            }
+        },
+        {
+            title: '小程序页面模板信息',
+            dataIndex: 'templateName',
+            key: 'templateName',
+            align: "center",
+            ellipsis: true,
+            hideInSearch: true,
+        },
+        {
+            title: '状态',
+            dataIndex: 'enabled',
+            key: 'enabled',
+            align: 'center',
+            ellipsis: true,
+            hideInSearch: true,
+            render: (a: any, b: any) => {
+                return (
+                    <Switch
+                        checkedChildren="正常"
+                        unCheckedChildren="停用"
+                        checked={b?.enabled}
+                        disabled
+                    />
+                );
+            },
+        },
+        {
+            title: "运营载体状态",
+            dataIndex: 'appCarrierList',
+            key: "appCarrierList",
+            hideInSearch: true,
+            align: "center",
+            render: (a, b: any) => {
+                let isTrue = b?.appCarrierList?.length > 0
+                return <Badge status={isTrue ? "processing" : "error"} text={isTrue ? "有" : "无"} />
+            }
+        },
+        {
+            title: "操作",
+            dataIndex: 'option',
+            valueType: 'option',
+            align: "center",
+            render: (_, record) => {
+                return <Space>
+                    <MenuChange menuType="miniApp" data={{ ...record, appType: props.appType }}><a type='primary'>管理</a></MenuChange>
+                </Space>
+            },
+        },
+    ];
+}
+export const childrenColumns: TableColumnsType<any> = [
+    {
+        title: "载体名称",
+        dataIndex: 'carrierName',
+        key: "carrierName",
+        align: "center",
+    },
+    {
+        title: "载体类型",
+        dataIndex: 'carrierType',
+        key: "carrierType",
+        align: "center",
+        render: (a: string, b: any) => {
+            return { '1': '企业微信', "2": "公众号" }[a]
+        }
+    },
+    {
+        title: "绑定时间",
+        dataIndex: 'createTime',
+        key: "createTime",
+        align: "center",
+    }
+]

+ 166 - 0
src/pages/Distributor/AppManage/index.tsx

@@ -0,0 +1,166 @@
+import { ActionType, ModalForm, PageContainer, ProFormCheckbox, ProFormSelect, ProFormText, ProTable } from "@ant-design/pro-components"
+import { Button, Drawer, message, Table } from "antd"
+import { columns, childrenColumns, columnsOpen } from "./tableConfig"
+import { useAjax } from "@/Hook/useAjax"
+import { useMemo, useRef, useState } from "react"
+import { useModel } from "@umijs/max"
+import { accountConfig, accountConfigEnabled, accountConfigList, delAccountConfig, manageList } from "@/services/distributor/appManage"
+import { distributorAccountAll } from "@/services/distributor/account"
+
+const Page: React.FC = () => {
+    let { state, getEnum } = useModel("global")
+    let [key, setKey] = useState<any>(1)
+    let [openTable, setOpenTalbe] = useState<any>(null)
+    let [openMoadl, setOpenModal] = useState<any>(false)
+    let getList = useAjax((params) => manageList(params), { type: 'table' })
+    let AccountConfigList = useAjax((params) => accountConfigList(params), { type: 'noPage' })
+    let DelAccountConfig = useAjax((id) => delAccountConfig(id))
+    let add = useAjax((params) => accountConfig(params))
+    let AccountConfigEnabled = useAjax((params) => accountConfigEnabled(params))
+    let allList = useAjax(() => distributorAccountAll())
+    const actionRef = useRef<ActionType>();
+
+
+    let del = (id: any) => {
+        DelAccountConfig.run(id).then(res => {
+            if (res.code === 200) {
+                message.success("删除成功")
+                actionRef.current?.reload()
+            }
+        })
+    }
+    let edit = (configId: any, enabled: boolean) => {
+        AccountConfigEnabled.run({ configId, enabled }).then(res => {
+            if (res.code === 200) {
+                message.success("操作成功")
+                actionRef.current?.reload()
+            }
+        })
+    }
+    return <PageContainer
+        tabList={getEnum("APP_TYPE", "arr")}
+        tabProps={{
+            type: 'card',
+            hideAdd: true,
+            onChange: (e) => setKey(e),
+        }}
+    >
+        <ProTable<any, any>
+            headerTitle={"抖音小程序列表"}
+            rowKey={(r) => r.id}
+            search={{
+                labelWidth: 120,
+            }}
+            scroll={{ x: "auto" }}
+            params={{
+                appType: key
+            }}
+            request={async (params) => {
+                if (params.appType) {
+                    return await getList.run(params)
+                }
+            }}
+            columns={columns({ appType: key, setOpenTalbe })}
+            expandable={{
+                rowExpandable: (record) => record?.appCarrierList?.length > 0,
+                expandRowByClick: true,
+                expandedRowRender: (record) => {
+                    return <Table
+                        columns={childrenColumns}
+                        dataSource={record.appCarrierList}
+                        rowKey={(r) => r.id}
+                        pagination={false}
+                        size='small'
+                        bordered
+                    />
+                },
+            }}
+        />
+        <Drawer
+            open={!!openTable}
+            placement="right"
+            onClose={() => { setOpenTalbe(null) }}
+            footer={null}
+            width={'85%'}
+            destroyOnClose={true}
+            styles={{ body: { padding: 0 } }}
+            closeIcon={false}
+            title={<div style={{ fontSize: 20 }}>{openTable?.appName}</div>}
+            extra={<Button type="primary" onClick={() => {
+                allList.run().then(res => {
+                    setOpenModal(true)
+                })
+            }}>批量新增账号</Button>}
+        >
+            <ProTable
+                actionRef={actionRef}
+                search={false}
+                toolBarRender={false}
+                columns={columnsOpen({ del, edit })}
+                params={{
+                    appType: key,
+                    appId: openTable?.id
+                }}
+                request={async (params) => {
+                    if (params.appType && params.appId) {
+                        return await AccountConfigList.run(params)
+                    }
+                }}
+            />
+            <ModalForm
+                title={"批量新增账号"}
+                width="500px"
+                open={openMoadl}
+                onOpenChange={(b) => {
+                    if (!b) {
+                        setOpenModal(false)
+                    }
+                }}
+                onFinish={async (value) => {
+                    console.log(value)
+                    add.run({ ...value, appId: openTable?.id, appType: key }).then(res => {
+                        if (res.code === 200) {
+                            message.success("新增成功!")
+                            actionRef.current?.reload()
+                            setOpenModal(false)
+                        }
+                    })
+                }}
+                colProps={{ span: 24 }}
+                layout="horizontal"
+            >
+                <ProFormCheckbox.Group
+                    rules={[
+                        {
+                            required: true,
+                            message: '此项为必填项',
+                        },
+                    ]}
+                    width="md"
+                    name="advertisingChannels"
+                    label="投放渠道"
+                    options={getEnum("ADVERTISING_CHANNEL", "arr")}
+                />
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '此项为必填项',
+                        },
+                    ]}
+                    fieldProps={{
+                        showSearch: true,
+                        placeholder: '批量选择账号',
+                        mode: "multiple"
+                    }}
+                    width="md"
+                    name="distributorAccountIds"
+                    label="投放账号"
+                    options={allList?.data?.data?.map((item: { id: any; nickname: any }) => ({ value: item.id, label: item.nickname }))}
+                />
+            </ModalForm>
+        </Drawer>
+    </PageContainer>
+
+}
+export default Page

+ 236 - 0
src/pages/Distributor/AppManage/tableConfig.tsx

@@ -0,0 +1,236 @@
+import MenuChange from "@/components/MenuChange";
+import { MyIcon } from "@/global";
+import { ProColumns } from "@ant-design/pro-components";
+import { useModel } from "@umijs/max";
+import { Badge, Button, Popconfirm, Space, Switch, TableColumnsType, Tag, Tooltip } from "antd";
+
+export const columns = (props: { appType: any, setOpenTalbe: (v: any) => void }): ProColumns<any>[] => {
+    let { getEnum } = useModel("global")
+    return [
+        {
+            title: "应用名称",
+            dataIndex: 'appName',
+            key: "appName",
+            align: "center",
+            render: (a: any, b: any) => {
+                return <Space size={[3, 0]}>
+                    <MyIcon type={props?.appType === 2 ? "icon-xiaochengxu-dy" : "icon-xiaochengxu-wx"} />
+                    {b.appName}
+                </Space>
+            }
+        },
+        {
+            title: "应用标识",
+            dataIndex: 'appKey',
+            key: "appKey",
+            align: "center",
+        },
+        {
+            title: "小程序类型",
+            dataIndex: 'appCategory',
+            key: "appCategory",
+            align: "center",
+            valueEnum: getEnum("APP_CATEGORY", 'map')
+        },
+        {
+            title: "允许投放渠道",
+            dataIndex: 'advertisingChannels',
+            valueType: 'select',
+            key: "advertisingChannels",
+            align: "center",
+            valueEnum: getEnum("ADVERTISING_CHANNEL", "map")
+        },
+        {
+            title: "首页地址",
+            dataIndex: 'homePage',
+            key: "homePage",
+            align: "center",
+            hideInSearch: true,
+        },
+        {
+            title: "应用版本",
+            dataIndex: 'appVersion',
+            key: "appVersion",
+            align: "center",
+            hideInSearch: true,
+        },
+        {
+            title: '小程序配置信息(json)',
+            dataIndex: 'configParamList',
+            key: 'configParamList',
+            align: 'center',
+            hideInSearch: true,
+            render: (a, b) => {
+                return (
+                    <Space size={[0, 0]} wrap>
+                        {b?.configParamList?.map((item: any, index: number) => {
+                            return (
+                                <Tooltip title={JSON.stringify(item['additionalProp' + (index + 1)])} key={index}>
+                                    <Button type="link" size="small">
+                                        配置{index + 1}
+                                    </Button>
+                                </Tooltip>
+                            );
+                        })}
+                    </Space>
+                );
+            },
+        },
+        {
+            title: 'ios支付版本号',
+            tooltip: "ios的特殊性,此版本号与IOS支付模块关联,小程序版本号<=此版本号IOS才会出现支付功能,(微信)小程序发布线上后必须设置",
+            dataIndex: 'iosPayment',
+            align: "center",
+            hideInSearch: true,
+            render: (_, d) => {
+                return d.iosPayment ? <Tag color="processing" bordered={false}>{d.iosPayment}</Tag> : <Tag color="error" bordered={false}>IOS无法支付</Tag>
+            }
+        },
+        {
+            title: '小程序页面模板信息',
+            dataIndex: 'templateName',
+            key: 'templateName',
+            align: "center",
+            ellipsis: true,
+            hideInSearch: true,
+        },
+        {
+            title: '状态',
+            dataIndex: 'enabled',
+            key: 'enabled',
+            align: 'center',
+            ellipsis: true,
+            hideInSearch: true,
+            render: (a: any, b: any) => {
+                return (
+                    <Switch
+                        checkedChildren="正常"
+                        unCheckedChildren="停用"
+                        checked={b?.enabled}
+                        disabled
+                    />
+                );
+            },
+        },
+        {
+            title: "运营载体状态",
+            dataIndex: 'appCarrierList',
+            key: "appCarrierList",
+            hideInSearch: true,
+            align: "center",
+            render: (a, b: any) => {
+                let isTrue = b?.appCarrierList?.length > 0
+                return <Badge status={isTrue ? "processing" : "error"} text={isTrue ? "有" : "无"} />
+            }
+        },
+        {
+            title: "操作",
+            dataIndex: 'option',
+            valueType: 'option',
+            align: "center",
+            render: (_, record) => {
+                return <Space>
+                    <a onClick={() => { props?.setOpenTalbe(record) }}>指派账号</a>
+                    <MenuChange menuType="miniApp" data={{ ...record, appType: props.appType }}><a type='primary'>管理</a></MenuChange>
+                </Space>
+            },
+        },
+    ];
+}
+export const childrenColumns: TableColumnsType<any> = [
+    {
+        title: "载体名称",
+        dataIndex: 'carrierName',
+        key: "carrierName",
+        align: "center",
+    },
+    {
+        title: "载体类型",
+        dataIndex: 'carrierType',
+        key: "carrierType",
+        align: "center",
+        render: (a: string, b: any) => {
+            return { '1': '企业微信', "2": "公众号" }[a]
+        }
+    },
+    {
+        title: "绑定时间",
+        dataIndex: 'createTime',
+        key: "createTime",
+        align: "center",
+    }
+]
+
+export const columnsOpen = (props?: { del: (id: any) => void, edit: (id: any, ck: boolean) => void }): ProColumns<any>[] => {
+    let { getEnum } = useModel("global")
+    return [
+        {
+            title: "ID",
+            dataIndex: 'id',
+            key: "id",
+            align: "center",
+            hideInSearch: true,
+        },
+        {
+            title: "账号名称",
+            dataIndex: 'nickname',
+            key: "nickname",
+            align: "center",
+            hideInSearch: true,
+            render: (_, row) => {
+                return row?.distributorAccountInfo?.nickname
+            }
+        },
+        {
+            title: '状态',
+            dataIndex: 'enabled',
+            key: 'enabled',
+            align: 'center',
+            ellipsis: true,
+            hideInSearch: true,
+            render: (a: any, b: any) => {
+                return (
+                    <Switch
+                        checkedChildren="正常"
+                        unCheckedChildren="停用"
+                        checked={b?.enabled}
+                        onChange={(ck) => {
+                            props?.edit(b?.id, ck)
+                        }}
+                    />
+                );
+            },
+        },
+        {
+            title: "允许投放渠道",
+            dataIndex: 'advertisingChannels',
+            valueType: 'select',
+            key: "advertisingChannels",
+            align: "center",
+            valueEnum: getEnum("ADVERTISING_CHANNEL", "map")
+        },
+        {
+            title: "配置时间",
+            dataIndex: 'createTime',
+            key: "createTime",
+            align: "center",
+            hideInSearch: true,
+        },
+        {
+            title: "操作",
+            dataIndex: 'option',
+            valueType: 'option',
+            align: "center",
+            render: (_, record) => {
+                return <Space>
+                    <Popconfirm
+                        title="是否要删除此账号"
+                        onConfirm={() => { props?.del(record.id) }}
+                    >
+                        <a style={{ color: 'red' }}>删除</a>
+                    </Popconfirm>
+                </Space>
+            },
+        },
+    ];
+}

+ 43 - 0
src/pages/Distributor/CorpManage/index.tsx

@@ -0,0 +1,43 @@
+import { miniAppList } from "@/services/distributor/miniApp"
+import { PageContainer, ProTable } from "@ant-design/pro-components"
+import { Table } from "antd"
+import { columns, childrenColumns } from "./tableConfig"
+import { useAjax } from "@/Hook/useAjax"
+
+const Page: React.FC = () => {
+    let getList = useAjax((params) => miniAppList(params), { type: 'table' })
+    return <PageContainer>
+        <ProTable<any, any>
+            headerTitle={"抖音小程序列表"}
+            rowKey={(r) => r.id}
+            search={{
+                labelWidth: 120,
+            }}
+            scroll={{ x: "auto" }}
+            request={async (params) => {
+                return await getList.run(params)
+            }}
+            columns={columns()}
+            // showHeader={false}//隐藏标题
+            // options={false}//隐藏工具栏
+            // ghost={true}//幽灵模式
+            // bordered
+            expandable={{
+                rowExpandable: (record) => record?.appCarrierList?.length > 0,
+                expandRowByClick: true,
+                expandedRowRender: (record) => {
+                    return <Table
+                        columns={childrenColumns}
+                        dataSource={record.appCarrierList}
+                        rowKey={(r) => r.id}
+                        pagination={false}
+                        size='small'
+                        bordered
+                    />
+                },
+            }}
+        />
+    </PageContainer>
+
+}
+export default Page

+ 91 - 0
src/pages/Distributor/CorpManage/tableConfig.tsx

@@ -0,0 +1,91 @@
+import MenuChange from "@/components/MenuChange";
+import { MyIcon } from "@/global";
+import { ProColumns } from "@ant-design/pro-components";
+import { Badge, Space, TableColumnsType } from "antd";
+
+export const columns = (): ProColumns<any>[] => {
+    return [
+        {
+            title: "小程序名称",
+            dataIndex: 'appName',
+            key: "appName",
+            align: "left",
+            render: (a: any, b: any) => {
+                return <Space size={[3, 0]}>
+                    <MyIcon type="icon-xiaochengxu-dy" />
+                    {b.appName}
+                </Space>
+            }
+        },
+        {
+            title: "AppId",
+            dataIndex: 'appKey',
+            key: "appKey",
+            hideInSearch: true,
+            align: "left",
+        },
+        {
+            title: "小程序类型",
+            dataIndex: 'appCategory',
+            key: "appCategory",
+            hideInSearch: true,
+            align: "left",
+            render: (a: any, b: any) => {
+                return b.appCategory === 1 ? "长篇" : "短篇"
+            }
+        },
+        {
+            title: "允许投放渠道",
+            dataIndex: 'advertisingChannels',
+            key: "advertisingChannels",
+            hideInSearch: true,
+            align: "left",
+            render:(a:any,b:any)=>{
+                return "需后端提供枚举"
+            }
+        },
+        {
+            title: "运营载体状态",
+            dataIndex: 'appCarrierList',
+            key: "appCarrierList",
+            hideInSearch: true,
+            align: "center",
+            render: (a,b:any) => {
+                let isTrue = b?.appCarrierList?.length > 0 
+                return <Badge status={isTrue ? "processing" : "error"} text={isTrue ? "有" : "无"} />
+            }
+        },
+        {
+            title: "操作",
+            dataIndex: 'option',
+            valueType: 'option',
+            align: "center",
+            render: (_, record) => {
+                return <MenuChange menuType="miniApp" data={{ ...record, appType: 2 }}><a type='primary'>管理</a></MenuChange>
+            },
+        },
+    ];
+}
+export const childrenColumns: TableColumnsType<any> = [
+    {
+        title: "载体名称",
+        dataIndex: 'carrierName',
+        key: "carrierName",
+        align: "center",
+    },
+    {
+        title: "载体类型",
+        dataIndex: 'carrierType',
+        key: "carrierType",
+        align: "center",
+        render: (a: string, b: any) => {
+            return { '1': '企业微信', "2": "公众号" }[a]
+        }
+    },
+    {
+        title: "绑定时间",
+        dataIndex: 'createTime',
+        key: "createTime",
+        align: "center",
+    }
+]

+ 3 - 3
src/pages/MiniApp/BookManage/components/readBook/index.tsx

@@ -93,7 +93,7 @@ function ReadBook(props: { next: (listData: { id: number }) => Promise<any>, lis
                     destroyOnClose={true}
                     styles={{ body: { padding: 0 } }}
                     closeIcon={false}
-                title={<div style={{ fontSize: 20 }}>{content?.chapterName}</div>}
+                    title={<div style={{ fontSize: 20 }}>{content?.chapterName}</div>}
                 >
                     {
                         content && <>
@@ -103,10 +103,10 @@ function ReadBook(props: { next: (listData: { id: number }) => Promise<any>, lis
                             <div style={{ borderTop: '1px solid #efefef', display: 'flex', justifyContent: 'center' }}>
                                 <Space style={{ marginTop: 15 }}>
                                     {content?.chapterNo > 1 && <Button onClick={() => {
-                                       getBookContent({bookId:content?.bookId,chapterNo:content?.chapterNo - 1})
+                                        getBookContent({ bookId: content?.bookId, chapterNo: content?.chapterNo - 1 })
                                     }}>上一章</Button>}
                                     {content?.chapterNo < listData?.list?.length && <Button onClick={() => {
-                                        getBookContent({bookId:content?.bookId,chapterNo:content?.chapterNo + 1})
+                                        getBookContent({ bookId: content?.bookId, chapterNo: content?.chapterNo + 1 })
                                     }}>下一章</Button>}
                                 </Space>
                             </div>

+ 36 - 4
src/pages/MiniApp/CompConfig/DrawerBox/index.tsx

@@ -1,4 +1,4 @@
-import { Button, Col, Drawer, Row } from "antd";
+import { Button, Col, Drawer, Input, message, Row, Space } from "antd";
 import React, { useState, useImperativeHandle, forwardRef, useRef, useEffect, useMemo } from "react";
 import PageList from "./pageList";
 import Content from "./content";
@@ -7,9 +7,10 @@ import { useToken } from "@ant-design/pro-components";
 import { useSize } from "ahooks";
 import { useModel } from "@umijs/max";
 import { useAjax } from "@/Hook/useAjax";
-import { appComponentConfigGetAppPageList } from "@/services/miniApp/compConfig";
+import { appComponentConfigAddOrUpdate, appComponentConfigGetAppPageList } from "@/services/miniApp/compConfig";
 // 定义组件的 Props 类型
 interface Props {
+    listApi: any
 }
 
 // 使用 forwardRef 以支持传递 ref
@@ -22,8 +23,10 @@ const ModalForm = forwardRef((props: Props, ref) => {
     const PageListRef = useRef<any>(null);
     const ContentRef = useRef<any>(null);
     const SetDataRef = useRef<any>(null);
+    const [templateName, setTemplateName] = useState("")
     const AppComponentConfigGetAppPageList = useAjax((params) => appComponentConfigGetAppPageList(params))
-
+    const AppComponentConfigAddOrUpdate = useAjax((params) => appComponentConfigAddOrUpdate(params))//添加
+    console.log("props", props)
     // 接口公共参数
     let publicData = useMemo(() => {
         return {
@@ -41,17 +44,40 @@ const ModalForm = forwardRef((props: Props, ref) => {
 
     // close 方法,用于关闭 Drawer
     const close = () => {
+        dispatch({
+            type: 'setAll', params: {
+                tabs: 0,
+                isWorkDirection: false,
+                compAc: "",
+                index: 0,
+                activePage: "",
+                pageConfigList: []
+            }
+        })
         setOpen(false); // 将 open 设置为 false,关闭 Drawer
     };
 
     const openDrawer = () => {
         setOpen(true); // 将 open 设置为 true,打开 Drawer
     };
+    // 保存
+    const save = () => {
+        if (!templateName) {
+            return message.error("请填写模板名称!")
+        }
+        AppComponentConfigAddOrUpdate.run({ templateName, pageConfigList: state.pageConfigList, ...publicData }).then(res => {
+            if (res.code === 200) {
+                props?.listApi?.refresh()
+                close()
+            }
+        })
 
+    }
     // 使用 useImperativeHandle 暴露方法给父组件
     useImperativeHandle(ref, () => ({
         close,        // 暴露 close 方法
         openDrawer,   // 也可以暴露打开的方法
+        save
     }));
     return (
         <Drawer
@@ -60,7 +86,13 @@ const ModalForm = forwardRef((props: Props, ref) => {
             open={open}
             onClose={close}
             width={'85vw'}
-            extra={<Button type='primary'>保存配置</Button>}
+            extra={<Space>
+                <Input placeholder="请输入模板名称" value={templateName} allowClear onChange={(e) => {
+                    let value = e.target.value
+                    setTemplateName(value)
+                }} />
+                <Button type='primary' onClick={save}>保存配置</Button>
+            </Space>}
             maskClosable={false}
         >
             <Row wrap style={{ height: `calc(100vh - ${(headerSize?.height || 0) + 50}px)` }}>

+ 7 - 6
src/pages/MiniApp/CompConfig/components/hot_category.tsx

@@ -39,7 +39,6 @@ export function HotCategory(props: {
             setTag(configs?.[0]?.categoryId)
         }
         if (tag) {
-            console.log("tag", tag)
             getList.run({ ...publicData, categoryId: tag, pageNum: 1, pageSize: 8 }).then(res => {
                 if (res.code === 200) {
                     setBookData(res?.data?.records)
@@ -47,19 +46,21 @@ export function HotCategory(props: {
             })
         }
         if (configs) {
-            console.log("configs", configs)
             let isExist = configs?.find(i => i.categoryId == tag)
             if (!isExist) {
                 setTag(configs?.[0]?.categoryId)
+                getList.run({ ...publicData, categoryId: configs?.[0]?.categoryId, pageNum: 1, pageSize: 8 }).then(res => {
+                    if (res.code === 200) {
+                        setBookData(res?.data?.records)
+                    }
+                })
             }
             if (configs.length === 0) {
-                console.log("nullconfigs", configs)
                 setTag(null)
                 setBookData([])
             }
         }
     }, [tag, configs, publicData])
-    console.log("tag1", tag)
     return <div className={`${styles.hot_category}`}>
         <Header title={componentName || "热门分类"} btnText={"全部分类"} showBtn={showRightButton} />
         <div className={styles.tags}>
@@ -88,10 +89,10 @@ export function HotCategory(props: {
                     </div>
                 }) : bookData?.length > 0 ? bookData?.map((item: any) => {
                     return <div key={item} className={styles.box}>
-                        <img src={item?.longBookInfo?.picUrl || item?.shortBookInfo?.picUrl} onError={(e: any) => {
+                        <img src={item?.longBookInfo?.picUrl || item?.shortBookInfoVO?.picUrl} onError={(e: any) => {
                             e.target.src = localStorage.getItem("nocover")
                         }} />
-                        <span>{item?.longBookInfo?.bookName || item?.shortBookInfo?.bookName}</span>
+                        <span>{item?.longBookInfo?.bookName || item?.shortBookInfoVO?.bookName}</span>
                     </div>
                 }) : <div style={{justifyContent:'center',display:'flex',width:'100%'}}><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据请选中后设置"/></div>
             }

+ 1 - 2
src/pages/MiniApp/CompConfig/index.tsx

@@ -165,7 +165,6 @@ const Page: React.FC = () => {
             }
         });
     }
-    console.log(DrawerBoxRef)
     return <PageContainer
         extra={getList?.data?.data?.length > 0 && <Button type="primary" onClick={DrawerBoxRef?.current?.openDrawer}><PlusOutlined />新增配置</Button>}
     >
@@ -199,7 +198,7 @@ const Page: React.FC = () => {
             }
         </Row>
         {/* 模板弹窗 */}
-        <DrawerBox ref={DrawerBoxRef}/>
+        <DrawerBox ref={DrawerBoxRef} listApi={getList} />
     </PageContainer>
 
 }

+ 4 - 4
src/pages/MiniApp/ModuleConfig/formConfig.tsx

@@ -13,8 +13,8 @@ function formConfig(enumList?: any): ProFormColumnsType<{
         {
             title: '模板名称',
             dataIndex: 'templateName',
-            colProps:{
-                span:24
+            colProps: {
+                span: 24
             },
             formItemProps: {
                 rules: [
@@ -61,7 +61,7 @@ function formConfig(enumList?: any): ProFormColumnsType<{
                             dataIndex: 'gearType',
                             valueType: 'select',
                             width: "100%",
-                            initialValue:1,
+                            initialValue: 1,
                             fieldProps: { placeholder: "请选择档位类型" },
                             colProps: {
                                 span: 4
@@ -220,7 +220,7 @@ function formConfig(enumList?: any): ProFormColumnsType<{
                             dataIndex: 'gearType',
                             valueType: 'select',
                             width: "100%",
-                            initialValue:1,
+                            initialValue: 1,
                             fieldProps: { placeholder: "请选择档位类型" },
                             colProps: {
                                 span: 4

+ 5 - 0
src/services/distributor/account/index.tsx

@@ -16,4 +16,9 @@ export async function distributorAccountList(params:Params) {
     method: 'GET',
     params
   });
+}
+export async function distributorAccountAll() {
+  return request(api+'/admin/distributorAccount/all', {
+    method: 'GET',
+  });
 }

+ 17 - 0
src/services/distributor/appList/index.tsx

@@ -0,0 +1,17 @@
+import { api } from '@/services/api';
+import { request } from '@umijs/max';
+type Page = {
+  pageSize: number | string,
+  pageNum: number | string
+}
+
+interface Params extends Page {
+  appType: string,//应用类型
+}
+/**应用列表 */
+export async function appList(params: Params) {
+  return request(api + '/admin/app/list', {
+    method: 'GET',
+    params
+  });
+}

+ 52 - 0
src/services/distributor/appManage/index.tsx

@@ -0,0 +1,52 @@
+import { api } from '@/services/api';
+import { request } from '@umijs/max';
+type Page = {
+  pageSize: number | string,
+  pageNum: number | string
+}
+
+interface Params extends Page {
+  appType: string,//应用类型
+}
+/**管理应用列表 */
+export async function manageList(params: Params) {
+  return request(api + '/admin/manageApp/manageList', {
+    method: 'GET',
+    params
+  });
+}
+
+/**配置的子账号列表 */
+export async function accountConfigList(params: { appType: string, appId: string }) {
+  let { appType, appId } = params
+  return request(api + `/admin/manageApp/accountConfigList/${appType}/${appId}`, {
+    method: 'GET'
+  });
+}
+/**删除 */
+export async function delAccountConfig(configId: any) {
+  return request(api + `/admin/manageApp/delAccountConfig/${configId}`, {
+    method: 'DELETE'
+  });
+}
+
+/**指派账号 */
+export async function accountConfig(data: {
+  appId: string,
+  appType: number,//应用类型
+  advertisingChannels: number,//投放渠道
+  distributorAccountIds: string//投放账号
+}) {
+  return request(api + `/admin/manageApp/accountConfig`, {
+    method: 'PUT',
+    data
+  });
+}
+
+/**账号状态修改 */
+export async function accountConfigEnabled(data: { configId: any, enabled: any }) {
+  let { configId, enabled } = data
+  return request(api + `/admin/manageApp/accountConfigEnabled/${configId}/${enabled}`, {
+    method: 'PUT',
+  });
+}

+ 19 - 0
src/services/distributor/corpManage/index.tsx

@@ -0,0 +1,19 @@
+import { api } from '@/services/api';
+import { request } from '@umijs/max';
+type Page={
+    pageSize:number|string,
+    pageNum:number|string
+}
+
+interface Params extends Page{
+    distributorId?:string,//分销商ID
+    nickname?:string,//账号昵称
+    phoneNum?:string,//手机
+}
+/**获取分销商账号列表 */
+export async function distributorAccountList(params:Params) {
+  return request(api+'/admin/distributorAccount/list', {
+    method: 'GET',
+    params
+  });
+}