wjx 4 недель назад
Родитель
Сommit
26982cc0ee

+ 3 - 1
src/pages/weComTask/API/logs/index.tsx

@@ -114,6 +114,7 @@ export interface GetSendUserListProps {
     startDay?: string,
     endDay?: string,
     projectGroupIds?: string[]
+    includeCreateBy?: boolean
 }
 
 /**
@@ -137,7 +138,8 @@ export interface GetSendUserLogListProps {
     taskId?: any,
     startDay?: string,
     endDay?: string,
-    projectGroupIds?: string[]
+    projectGroupIds?: string[],
+    includeCreateBy: boolean
 }
 
 /**

+ 84 - 0
src/pages/weComTask/API/weChatApiLicense/index.ts

@@ -53,4 +53,88 @@ export function updateCallUserAppApi(data: { corpIdList: string[], userIdList: n
         method: 'POST',
         data
     })
+}
+
+
+export interface GetLicenseOrderListProps {
+    pageNum: number,
+    pageSize: number,
+    corpName?: string,
+    orderId?: string,
+    orderType?: number,
+    orderStatus?: number
+}
+/**
+ * 企业订单列表
+ * @returns 
+ */
+export function getLicenseOrderListApi(data: GetLicenseOrderListProps) {
+    return request({
+        url: api + `/corpOperation/license/order/listOfPage`,
+        method: 'POST',
+        data
+    })
+}
+
+export interface GetLicenseCodeListProps {
+    pageNum: number,
+    pageSize: number,
+    corpName?: string,
+    activeCode?: string,
+    status?: number
+}
+/**
+ * 席位详情列表
+ * @returns 
+ */
+export function getLicenseCodeListApi(data: GetLicenseCodeListProps) {
+    return request({
+        url: api + `/corpOperation/license/code/listOfPage`,
+        method: 'POST',
+        data
+    })
+}
+
+export interface ActiveCodeProps {
+    corpId: string,
+    activeParam: {
+        active_code: string,
+        userid: string
+    }[]
+}
+
+
+/**
+ * 激活
+ * @param data 
+ * @returns 
+ */
+export function activeCodeApi(data: ActiveCodeProps) {
+    return request({
+        url: api + `/corpOperation/license/code/batch/active`,
+        method: 'POST',
+        data
+    })
+}
+
+
+export interface TransferCodeProps {
+    corpId: string,
+    transferParam: {
+        handover_userid: string,
+        takeover_userid: string
+    }[]
+}
+
+/**
+ * 继承
+ * @param data 
+ * @returns 
+ */
+export function transferCodeApi(data: TransferCodeProps) {
+    return request({
+        url: api + `/corpOperation/license/code/batch/transfer`,
+        method: 'POST',
+        data
+    })
 }

+ 209 - 0
src/pages/weComTask/page/corpUserManage/selectCorpUserAll.tsx

@@ -0,0 +1,209 @@
+import useNewToken from '@/Hook/useNewToken';
+import { App, Button, Input, Modal, Table, Tag, Tooltip } from 'antd';
+import React, { useEffect, useState } from 'react';
+import './global.less'
+import { CloseCircleFilled, SearchOutlined } from '@ant-design/icons';
+import { useAjax } from '@/Hook/useAjax';
+import { WeTableSelectConfig } from './tableConfig';
+import { RowSelectionType } from 'antd/es/table/interface';
+import { CorpMailListProps, getCorpMailListApi } from '../../API/corpUserAssign';
+
+interface Props {
+    type?: RowSelectionType,
+    corpId?: string,
+    value?: { corpUserId: string, name: string, corpName: string, corpId: string }[];
+    onChange?: (value: { corpUserId: string, name: string, corpName: string, corpId: string }[]) => void;
+    placeholder?: React.ReactNode
+    width?: number | string
+}
+
+/**
+ * 选择企业微信用户
+ * @param param0 
+ * @returns 
+ */
+const SelectCorpUserAll: React.FC<Props> = ({ value = [], onChange, placeholder, width, ...itr }) => {
+
+    /************************************************************/
+    const { token } = useNewToken()
+    const [open, setOpen] = useState<boolean>(false);
+    /************************************************************/
+
+    return <>
+        <div
+            className='selectCorpUser'
+            style={{
+                border: `1px solid ${token.colorBorder}`,
+                padding: `0px ${token.paddingXS}px`,
+                borderRadius: token.borderRadius,
+                height: token.controlHeight,
+                width: width || '100%',
+            }}
+            onClick={() => setOpen(true)}
+        >
+            <div className='selectCorpUserContent'>
+                {(value && value?.length > 0) ? <>
+                    <Tag
+                        closable
+                        onClick={(e) => e.stopPropagation()}
+                        onClose={(e) => {
+                            e.preventDefault();
+                            onChange(value?.filter(item => item.corpUserId !== value?.[0]?.corpUserId))
+                        }}
+                    >
+                        {value?.[0]?.name || value?.[0]?.corpUserId}
+                    </Tag>
+                    {value?.length > 1 && <Tooltip
+                        color="#FFF"
+                        title={<span style={{ color: '#000' }}>
+                            {value?.filter((_, index) => index !== 0)?.map((item) => <Tag
+                                key={item.corpUserId}
+                                closable
+                                onClick={(e) => e.stopPropagation()}
+                                onClose={(e) => {
+                                    e.stopPropagation()
+                                    onChange(value?.filter(item1 => item1.corpUserId !== item.corpUserId))
+                                }}
+                            >{item.name || item?.corpUserId}</Tag>)}</span>
+                        }
+                    >
+                        <Tag>+{value.length - 1} ...</Tag>
+                    </Tooltip>}
+                </> : <span style={{ color: token.colorTextDisabled }}>{placeholder || '请选择客服号'}</span>}
+            </div>
+            {(value && value?.length > 0) && <div className='selectCorpUserIcon'>
+                <CloseCircleFilled
+                    className='selectCorpUserIconClear'
+                    style={{ fontSize: token.fontSizeIcon, color: token.colorTextSecondary }}
+                    onClick={(e) => {
+                        e.stopPropagation()
+                        onChange?.([])
+                    }}
+                />
+            </div>}
+        </div>
+
+        {open && <SelectCorpUserModal
+            {...itr}
+            value={value}
+            open={open}
+            placeholder={placeholder}
+            onClose={() => setOpen(false)}
+            onChange={(values) => {
+                onChange?.(values)
+                setOpen(false)
+            }}
+        />}
+    </>
+};
+
+interface SelectCorpUserModalProps extends Props {
+    open?: boolean
+    onClose?: () => void
+}
+
+const SelectCorpUserModal: React.FC<SelectCorpUserModalProps> = React.memo(({ open, type = 'checkbox', value, corpId, onClose, onChange, placeholder }) => {
+
+    /*******************************************/
+    const [queryForm, setQueryForm] = useState<CorpMailListProps>({ pageNum: 1, pageSize: 20 })
+    const [queryFormNew, setQueryFormNew] = useState<CorpMailListProps>({ pageNum: 1, pageSize: 20 })
+    const [editSelectedRow, setEditSelectedRow] = useState<any[]>([])
+    const { message } = App.useApp()
+
+    const getCorpMailList = useAjax((params) => getCorpMailListApi(params))
+    /*******************************************/
+
+    useEffect(() => {
+        if (corpId) {
+            setQueryFormNew({ ...queryFormNew, corpId })
+            setQueryForm({ ...queryForm, corpId })
+        }
+    }, [corpId])
+
+    useEffect(() => {
+        if (open) {
+            setEditSelectedRow(value?.length ? [...value] : [])
+        }
+    }, [open, value])
+
+    useEffect(() => {
+        if (queryForm?.corpId)
+            getCorpMailList.run(queryForm)
+    }, [queryForm])
+
+    const handleOk = () => {
+        if (editSelectedRow.length) {
+            onChange?.([...editSelectedRow])
+        } else {
+            message.error('请至少选择一条数据')
+        }
+    }
+
+    return <Modal
+        title={<strong>{placeholder}</strong>}
+        open={open}
+        width={1050}
+        onCancel={onClose}
+        onOk={handleOk}
+    >
+        <div className='selectCorpUserBody' style={{ width: '100%' }}>
+            <div className='selectCorpUserBody_search'>
+                <Input style={{ width: 150 }} disabled={!!corpId} onChange={(e) => setQueryFormNew({ ...queryFormNew, corpId: e.target.value as any })} value={queryFormNew?.corpId} placeholder="企微ID(多个,,空格换行)" allowClear />
+                <Input style={{ width: 150 }} onChange={(e) => setQueryFormNew({ ...queryFormNew, name: e.target.value as any })} value={queryFormNew?.name} placeholder="客服号名称" allowClear />
+                <Button type="primary" onClick={() => {
+                    setQueryForm({ ...queryFormNew, pageNum: 1 })
+                }} loading={getCorpMailList.loading} icon={<SearchOutlined />}>搜索</Button>
+            </div>
+            <div className='selectCorpUserBody_content'>
+                <Table
+                    columns={WeTableSelectConfig()}
+                    dataSource={getCorpMailList?.data?.data?.records}
+                    size='small'
+                    scroll={{ y: 250 }}
+                    rowKey={'corpUserId'}
+                    loading={getCorpMailList.loading}
+                    pagination={{
+                        current: getCorpMailList?.data?.data?.current || 1,
+                        pageSize: getCorpMailList?.data?.data?.size || 20,
+                        total: getCorpMailList?.data?.data?.total,
+                        showTotal: (total) => `共 ${total} 条数据`,
+                        showSizeChanger: true
+                    }}
+                    rowSelection={type === 'checkbox' ? {
+                        type: 'checkbox',
+                        selectedRowKeys: editSelectedRow?.map(item => item.corpUserId),
+                        getCheckboxProps: (record: any) => ({
+                            disabled: record.status !== 1
+                        }),
+                        onSelect: (record: { corpUserId: any; }, selected: any) => {
+                            if (selected) {
+                                setEditSelectedRow([...editSelectedRow, record])
+                            } else {
+                                setEditSelectedRow(editSelectedRow?.filter(item => item.corpUserId !== record.corpUserId))
+                            }
+                        },
+                        onSelectAll: (selected: any, rows: any, changeRows: any[]) => {
+                            if (selected) {
+                                setEditSelectedRow([...editSelectedRow, ...changeRows])
+                            } else {
+                                let newArr = editSelectedRow?.filter(item => changeRows.every(i => i?.corpUserId !== item?.corpUserId))
+                                setEditSelectedRow(newArr)
+                            }
+                        }
+                    } : {
+                        type: 'radio',
+                        selectedRowKeys: editSelectedRow?.map(item => item.corpUserId),
+                        onChange(_, selectedRows) {
+                            setEditSelectedRow(selectedRows)
+                        },
+                    }}
+                    onChange={(pagination) => {
+                        setQueryForm({ ...queryForm, pageNum: pagination.current || 1, pageSize: pagination.pageSize || 20 })
+                    }}
+                />
+            </div>
+        </div>
+    </Modal>
+});
+
+export default React.memo(SelectCorpUserAll);

+ 2 - 1
src/pages/weComTask/page/corpUserManage/tableConfig.tsx

@@ -150,7 +150,8 @@ export function WeTableSelectConfig(): ColumnsType<any> {
             key: 'corpName',
             align: 'center',
             width: 120,
-            ellipsis: true
+            ellipsis: true,
+            render: (text) => text || '--'
         },
         {
             title: '企业ID',

+ 10 - 7
src/pages/weComTask/page/home/groupItem.tsx

@@ -1,6 +1,6 @@
 import React, { useEffect, useState } from "react";
 import style from './index.less';
-import { Avatar, Badge, Button, Card, DatePicker, Drawer, Input, Modal, Select, Space, Table, Tabs, Tag, Tooltip } from "antd";
+import { Avatar, Badge, Button, Card, Checkbox, DatePicker, Drawer, Input, Modal, Select, Space, Table, Tabs, Tag, Tooltip } from "antd";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
 import { getProjectGroupsAllListApi } from "../../API/groupManage";
@@ -119,8 +119,8 @@ const GroupXfCorpTabls: React.FC<{ groupList: { label: string, value: number }[]
 
     /***********************************/
     const taskType = projectType === 1 ? 'TASK_STAT_GROUP_SEND_CHAT' : projectType === 2 ? 'TASK_STAT_GROUP_ROBOT' : 'TASK_STAT_GROUP_SEND'
-    const [queryParams, setQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20, startDay: dayJs().format('YYYY-MM-DD') })
-    const [oldQueryParams, setOldQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20, startDay: dayJs().format('YYYY-MM-DD') })
+    const [queryParams, setQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true, startDay: dayJs().format('YYYY-MM-DD') })
+    const [oldQueryParams, setOldQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true, startDay: dayJs().format('YYYY-MM-DD') })
     const { token } = useNewToken()
     const [modal, contextHolder] = Modal.useModal();
 
@@ -163,6 +163,7 @@ const GroupXfCorpTabls: React.FC<{ groupList: { label: string, value: number }[]
                     onChange={(e) => setOldQueryParams({ ...oldQueryParams, taskId: e.target.value })}
                     value={oldQueryParams?.taskId}
                 />
+                <Checkbox checked={oldQueryParams?.includeCreateBy} onChange={(e) => setOldQueryParams({ ...oldQueryParams, includeCreateBy: e.target.checked })}>是否包含创建人</Checkbox>
                 <Select
                     showSearch
                     style={{ minWidth: 100 }}
@@ -435,8 +436,8 @@ const GroupTaskNotes: React.FC<{ groupList: { label: string, value: number }[],
 
     /***********************************/
     const taskType = projectType === 1 ? 'TASK_STAT_GROUP_SEND_CHAT' : projectType === 2 ? 'TASK_STAT_GROUP_ROBOT' : 'TASK_STAT_GROUP_SEND'
-    const [queryParams, setQueryParams] = useState<GetSendUserLogListProps>({ pageNum: 1, pageSize: 20 })
-    const [oldQueryParams, setOldQueryParams] = useState<GetSendUserLogListProps>({ pageNum: 1, pageSize: 20 })
+    const [queryParams, setQueryParams] = useState<GetSendUserLogListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true })
+    const [oldQueryParams, setOldQueryParams] = useState<GetSendUserLogListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true })
     const { token } = useNewToken()
     const [modal, contextHolder] = Modal.useModal();
 
@@ -526,6 +527,7 @@ const GroupTaskNotes: React.FC<{ groupList: { label: string, value: number }[],
                     onChange={(e) => setOldQueryParams({ ...oldQueryParams, taskId: e.target.value })}
                     value={oldQueryParams?.taskId}
                 />
+                <Checkbox checked={oldQueryParams?.includeCreateBy} onChange={(e) => setOldQueryParams({ ...oldQueryParams, includeCreateBy: e.target.checked })}>是否包含创建人</Checkbox>
                 <Select
                     placeholder='请选择项目组'
                     allowClear
@@ -751,8 +753,8 @@ const ShareTabls: React.FC<{ groupList: { label: string, value: number }[], proj
 
     /***********************************/
     const taskType = projectType === 1 ? 'TASK_STAT_GROUP_SEND_CHAT' : projectType === 2 ? 'TASK_STAT_GROUP_ROBOT' : 'TASK_STAT_GROUP_SEND'
-    const [queryParams, setQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20 })
-    const [oldQueryParams, setOldQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20 })
+    const [queryParams, setQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true })
+    const [oldQueryParams, setOldQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true })
     const { token } = useNewToken()
     const [modal, contextHolder] = Modal.useModal();
 
@@ -788,6 +790,7 @@ const ShareTabls: React.FC<{ groupList: { label: string, value: number }[], proj
                     onChange={(e) => setOldQueryParams({ ...oldQueryParams, taskId: e.target.value })}
                     value={oldQueryParams?.taskId}
                 />
+                <Checkbox checked={oldQueryParams?.includeCreateBy} onChange={(e) => setOldQueryParams({ ...oldQueryParams, includeCreateBy: e.target.checked })}>是否包含创建人</Checkbox>
                 <Select
                     showSearch
                     style={{ minWidth: 100 }}

+ 212 - 0
src/pages/weComTask/page/weChatApiLicense/enterpriseOrder/index.tsx

@@ -0,0 +1,212 @@
+import React, { useState, useEffect } from 'react';
+import { useAjax } from "@/Hook/useAjax";
+import { Button, Card, Select, Input, Badge, Table, Tag } from "antd";
+import { SearchOutlined } from "@ant-design/icons";
+import SearchBox from "@/pages/weComTask/components/searchBox";
+import { getLicenseOrderListApi, GetLicenseOrderListProps } from "@/pages/weComTask/API/weChatApiLicense";
+import { copy } from "@/utils/utils";
+
+const orderTypeEnum = {
+    1: <Tag color="#f50">购买账号</Tag>,
+    2: <Tag color="#2db7f5">续期账号</Tag>,
+    5: <Tag color="#87d068">应用版本付费迁移订单</Tag>,
+    6: <Tag color="#108ee9">历史合同迁移订单</Tag>
+}
+
+const orderStatusEnum = {
+    0: <Badge status="processing" text="待支付" />,
+    1: <Badge status="success" text="已支付" />,
+    2: <Badge status="default" text="已取消(未支付,订单已关闭)" />,
+    3: <Badge status="default" text="未支付,订单已过期" />,
+    4: <Badge status="warning" text="申请退款中" />,
+    5: <Badge status="error" text="退款成功" />,
+    6: <Badge status="error" text="退款被拒绝" />,
+    7: <Badge status="warning" text="订单已失效" />,
+}
+
+
+const EnterpriseOrder: React.FC = () => {
+
+    /***********************************/
+    const [queryParams, setQueryParams] = useState<GetLicenseOrderListProps>({ pageNum: 1, pageSize: 20 })
+    const [oldQueryParams, setOldQueryParams] = useState<GetLicenseOrderListProps>({ pageNum: 1, pageSize: 20 })
+
+    const getLicenseOrderList = useAjax((params) => getLicenseOrderListApi(params))
+    /***********************************/
+
+    useEffect(() => {
+        getLicenseOrderList.run(queryParams)
+    }, [queryParams])
+
+    return <Card>
+        <SearchBox
+            bodyPadding={`0 0 10px`}
+            buttons={<>
+                <Button type="primary" onClick={() => {
+                    setQueryParams({ ...oldQueryParams, pageNum: 1, pageSize: queryParams.pageSize })
+                }} loading={getLicenseOrderList.loading} icon={<SearchOutlined />}>搜索</Button>
+            </>}
+        >
+            <>
+                <Input
+                    placeholder="企业名称"
+                    style={{ width: 120 }}
+                    allowClear
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, corpName: e.target.value })}
+                    value={oldQueryParams?.corpName}
+                />
+                <Input
+                    placeholder="订单号"
+                    style={{ width: 120 }}
+                    allowClear
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, orderId: e.target.value })}
+                    value={oldQueryParams?.orderId}
+                />
+                <Select
+                    allowClear
+                    placeholder="订单类型"
+                    showSearch
+                    options={Object.keys(orderTypeEnum).map(key => ({ label: orderTypeEnum[key], value: key }))}
+                    filterOption={(input, option) =>
+                        ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                    }
+                    style={{ width: 160 }}
+                    value={oldQueryParams?.orderType}
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, orderType: e })}
+                />
+                <Select
+                    allowClear
+                    placeholder="订单状态"
+                    showSearch
+                    options={Object.keys(orderStatusEnum).map(key => ({ label: orderStatusEnum[key], value: key }))}
+                    filterOption={(input, option) =>
+                        ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                    }
+                    style={{ width: 160 }}
+                    value={oldQueryParams?.orderStatus}
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, orderStatus: e })}
+                />
+            </>
+        </SearchBox>
+
+        {/* 表 */}
+        <Table
+            style={{ marginTop: 10 }}
+            dataSource={getLicenseOrderList?.data?.data?.records}
+            loading={getLicenseOrderList?.loading}
+            bordered
+            columns={[
+                {
+                    title: '企业名称',
+                    dataIndex: 'corpName',
+                    key: 'corpName',
+                    width: 200,
+                    ellipsis: true,
+                    render: (text) => <a onClick={() => copy(text)}>{text}</a>
+                },
+                {
+                    title: '企业ID',
+                    dataIndex: 'corpId',
+                    key: 'corpId',
+                    width: 280,
+                    ellipsis: true,
+                },
+                {
+                    title: '订单号',
+                    dataIndex: 'orderId',
+                    key: 'orderId',
+                    width: 280,
+                    ellipsis: true,
+                },
+                {
+                    title: '订单类型',
+                    dataIndex: 'orderType',
+                    key: 'orderType',
+                    width: 120,
+                    align: 'center',
+                    render: (text) => orderTypeEnum[text]
+                },
+                {
+                    title: '订单状态',
+                    dataIndex: 'orderStatus',
+                    key: 'orderStatus',
+                    width: 120,
+                    align: 'center',
+                    render: (text) => orderStatusEnum[text]
+                },
+                {
+                    title: '订单金额',
+                    dataIndex: 'price',
+                    key: 'price',
+                    width: 60,
+                    align: 'right'
+                },
+                {
+                    title: '席位数量',
+                    dataIndex: 'accountCount',
+                    key: 'accountCount',
+                    width: 70,
+                    align: 'center'
+                },
+                {
+                    title: '下单时间',
+                    dataIndex: 'createTime',
+                    key: 'createTime',
+                    width: 135,
+                    align: 'center',
+                    ellipsis: true,
+                    render: (text) => text || '--'
+                },
+                {
+                    title: '支付时间',
+                    dataIndex: 'payTime',
+                    key: 'payTime',
+                    width: 135,
+                    align: 'center',
+                    ellipsis: true,
+                    render: (text) => text || '--'
+                },
+                {
+                    title: '更新时间',
+                    dataIndex: 'updateTime',
+                    key: 'updateTime',
+                    width: 135,
+                    align: 'center',
+                    ellipsis: true,
+                    render: (text) => text || '--'
+                }
+            ]}
+            scroll={{ x: 1000 }}
+            rowKey={'orderId'}
+            size='small'
+            pagination={{
+                total: getLicenseOrderList?.data?.data?.total,
+                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
+                showSizeChanger: true,
+                showLessItems: true,
+                defaultCurrent: 1,
+                defaultPageSize: 20,//默认初始的每页条数
+                current: getLicenseOrderList?.data?.data?.current || 1,
+                pageSize: getLicenseOrderList?.data?.data?.size || 20,
+            }}
+            onChange={(pagination, _, sortData: any) => {
+                let { current, pageSize } = pagination
+                let newQueryForm = JSON.parse(JSON.stringify(queryParams))
+                let newOldQueryParams = JSON.parse(JSON.stringify(oldQueryParams))
+                if (sortData && sortData?.order) {
+                    newQueryForm['sortAsc'] = sortData?.order === 'ascend' ? true : false
+                    newQueryForm['sortFiled'] = sortData?.field
+                } else {
+                    delete newQueryForm['sortAsc']
+                    delete newQueryForm['sortFiled']
+                }
+                newQueryForm.pageNum = current || newQueryForm.pageNum
+                newQueryForm.pageSize = pageSize || newQueryForm.pageSize
+                setQueryParams({ ...newQueryForm })
+                setOldQueryParams({ ...newOldQueryParams })
+            }}
+        />
+    </Card>
+};
+
+export default EnterpriseOrder;

+ 99 - 0
src/pages/weComTask/page/weChatApiLicense/seatDetails/activeCode.tsx

@@ -0,0 +1,99 @@
+import { Card, Form, message, Modal } from "antd"
+import React, { useEffect } from "react"
+import SelectCorpUserAll from "../../corpUserManage/selectCorpUserAll"
+import { useAjax } from "@/Hook/useAjax"
+import { activeCodeApi } from "@/pages/weComTask/API/weChatApiLicense"
+
+interface Props {
+    selectedRows: any[]
+    visible?: boolean
+    onChange?: () => void
+    onClose?: () => void
+}
+const ActiveCode: React.FC<Props> = ({ visible, selectedRows, onChange, onClose }) => {
+
+    /***********************************/
+    const corpId = selectedRows[0].corpId
+    const [form] = Form.useForm();
+    const activeParam = Form.useWatch('activeParam', form)
+
+    const activeCode = useAjax((params) => activeCodeApi(params))
+    /***********************************/
+
+    useEffect(() => {
+        form.setFieldsValue({
+            activeParam: selectedRows.map(item => {
+                return {
+                    active_code: item.activeCode,
+                    user: undefined
+                }
+            })
+        })
+    }, [selectedRows])
+
+    const handleOk = () => {
+        form.validateFields().then((values) => {
+            const activeParam = values?.activeParam.map(item => {
+                return {
+                    active_code: item.active_code,
+                    userid: item.user?.[0]?.corpUserId
+                }
+            })
+            activeCode.run({
+                corpId,
+                activeParam
+            }).then(res => {
+                if (res?.data) {
+                    message.success('激活成功')
+                    onChange?.()
+                }
+            })
+        }).catch(err => console.log('校验失败', err))
+    }
+
+    return <Modal
+        title="激活码激活"
+        open={visible}
+        onCancel={onClose}
+        width={650}
+        onOk={handleOk}
+        confirmLoading={activeCode.loading}
+    >
+        <Form
+            form={form}
+            name={'active-code'}
+            labelAlign='left'
+            labelCol={{ span: 5 }}
+            colon={false}
+            preserve={true}
+        >
+            <Form.List name="activeParam">
+                {(fields) => (
+                    <>
+                        {fields.map(({ key, name, ...restField }, index) => {
+                            const activeP = activeParam?.[index]
+                            return <Card
+                                key={key}
+                                title={<strong>激活码:{activeP?.active_code}</strong>}
+                                style={{ background: '#fff', marginBottom: 10 }}
+                            >
+                                <Form.Item
+                                    {...restField}
+                                    label={<strong>企业成员</strong>}
+                                    name={[name, 'user']}
+                                    rules={[
+                                        { required: true, message: '请选择企业成员!' }
+                                    ]}
+                                >
+                                    <SelectCorpUserAll type='radio' corpId={corpId} placeholder="请选择企业成员" />
+                                </Form.Item>
+                            </Card>
+                        })}
+                    </>
+                )}
+            </Form.List>
+        </Form>
+    </Modal>
+}
+
+export default React.memo(ActiveCode)

+ 284 - 0
src/pages/weComTask/page/weChatApiLicense/seatDetails/index.tsx

@@ -0,0 +1,284 @@
+import React, { useState, useEffect } from 'react';
+import { useAjax } from "@/Hook/useAjax";
+import { Button, Card, Table, Input, Badge, Select, Tag, Space, Tooltip } from "antd";
+import { QuestionCircleOutlined, SearchOutlined } from "@ant-design/icons";
+import SearchBox from "@/pages/weComTask/components/searchBox";
+import { getLicenseCodeListApi, GetLicenseCodeListProps } from "@/pages/weComTask/API/weChatApiLicense";
+import { copy } from '@/utils/utils';
+import ActiveCode from './activeCode';
+import TransferCode from './transferCode';
+
+const typeEnum = {
+    1: <Tag color="#f50">基础账号</Tag>,
+    2: <Tag color="#2db7f5">互通账号</Tag>
+}
+
+const statusEnum = {
+    1: <Badge status="default" text="未绑定" />,
+    2: <Badge status="success" text="已绑定且有效" />,
+    3: <Badge status="error" text="已过期" />,
+    4: <Badge status="processing" text="待转移" />,
+    5: <Badge color='gold' text="已合并" />,
+    6: <Badge color="lime" text="已分配给下游" />,
+}
+
+const SeatDetails: React.FC = () => {
+    /***********************************/
+    const [queryParams, setQueryParams] = useState<GetLicenseCodeListProps>({ pageNum: 1, pageSize: 20 })
+    const [oldQueryParams, setOldQueryParams] = useState<GetLicenseCodeListProps>({ pageNum: 1, pageSize: 20 })
+    const [selectedRows, setselectedRows] = useState<any[]>([])
+    const [visible, setVisible] = useState<boolean>(false)
+    const [visibleTr, setVisibleTr] = useState<boolean>(false)
+
+    const getLicenseCodeList = useAjax((params) => getLicenseCodeListApi(params))
+    /***********************************/
+
+    useEffect(() => {
+        getLicenseCodeList.run(queryParams)
+    }, [queryParams])
+
+    return <Card>
+        <SearchBox
+            bodyPadding={`0 0 10px`}
+            buttons={<>
+                <Button type="primary" onClick={() => {
+                    setQueryParams({ ...oldQueryParams, pageNum: 1, pageSize: queryParams.pageSize })
+                }} loading={getLicenseCodeList.loading} icon={<SearchOutlined />}>搜索</Button>
+                <Button type="primary" disabled={selectedRows?.length === 0} onClick={() => setVisible(true)}>激活码激活</Button>
+                <Button type="primary" disabled={selectedRows?.length === 0} onClick={() => setVisibleTr(true)}>激活码继承</Button>
+            </>}
+        >
+            <>
+                <Input
+                    placeholder="企业名称"
+                    style={{ width: 120 }}
+                    allowClear
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, corpName: e.target.value })}
+                    value={oldQueryParams?.corpName}
+                />
+                <Input
+                    placeholder="账号激活码"
+                    style={{ width: 120 }}
+                    allowClear
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, activeCode: e.target.value })}
+                    value={oldQueryParams?.activeCode}
+                />
+                <Select
+                    allowClear
+                    placeholder="账号状态"
+                    showSearch
+                    options={Object.keys(statusEnum).map(key => ({ label: statusEnum[key], value: key }))}
+                    filterOption={(input, option) =>
+                        ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                    }
+                    style={{ width: 160 }}
+                    value={oldQueryParams?.status}
+                    onChange={(e) => setOldQueryParams({ ...oldQueryParams, status: e })}
+                />
+            </>
+        </SearchBox>
+
+        {/* 表 */}
+        <Table
+            style={{ marginTop: 10 }}
+            dataSource={getLicenseCodeList?.data?.data?.records}
+            loading={getLicenseCodeList?.loading}
+            bordered
+            columns={[
+                {
+                    title: '企业名称',
+                    dataIndex: 'corpName',
+                    key: 'corpName',
+                    width: 200,
+                    ellipsis: true,
+                    render: (text) => <a onClick={() => copy(text)}>{text}</a>
+                },
+                {
+                    title: '企业ID',
+                    dataIndex: 'corpId',
+                    key: 'corpId',
+                    width: 250,
+                    ellipsis: true,
+                },
+                {
+                    title: '账号激活码',
+                    dataIndex: 'activeCode',
+                    key: 'activeCode',
+                    width: 190,
+                    ellipsis: true,
+                },
+                {
+                    title: '账号类型',
+                    dataIndex: 'type',
+                    key: 'type',
+                    width: 100,
+                    align: 'center',
+                    render: (text) => typeEnum[text]
+                },
+                {
+                    title: '账号状态',
+                    dataIndex: 'status',
+                    key: 'status',
+                    width: 120,
+                    align: 'center',
+                    render: (text) => statusEnum[text]
+                },
+                {
+                    title: '账号绑定激活的企业成员名称',
+                    dataIndex: 'userName',
+                    key: 'userName',
+                    width: 260,
+                    align: 'center',
+                    ellipsis: true,
+                    render: (text, re: any) => text + `(${re?.userId})`
+                },
+                {
+                    title: <Space>
+                        <span>创建时间</span>
+                        <Tooltip title="订单支付成功后立即创建">
+                            <QuestionCircleOutlined />
+                        </Tooltip>
+                    </Space>,
+                    dataIndex: 'createTime',
+                    key: 'createTime',
+                    width: 135,
+                    align: 'center',
+                    ellipsis: true,
+                    render: (text) => text || '--'
+                },
+                {
+                    title: <Space>
+                        <span>首次激活绑定用户的时间</span>
+                        <Tooltip title="未激活则不返回该字段">
+                            <QuestionCircleOutlined />
+                        </Tooltip>
+                    </Space>,
+                    dataIndex: 'activeTime',
+                    key: 'activeTime',
+                    width: 155,
+                    align: 'center',
+                    ellipsis: true,
+                    render: (text) => text || '--'
+                },
+                {
+                    title: <Space>
+                        <span>过期时间</span>
+                        <Tooltip title="为首次激活绑定的时间加上购买时长。未激活则不返回该字段">
+                            <QuestionCircleOutlined />
+                        </Tooltip>
+                    </Space>,
+                    dataIndex: 'expireTime',
+                    key: 'expireTime',
+                    width: 155,
+                    align: 'center',
+                    render: (text) => text || '--'
+                },
+                {
+                    title: '数据更新时间',
+                    dataIndex: 'updateTime',
+                    key: 'updateTime',
+                    width: 135,
+                    align: 'center',
+                    ellipsis: true,
+                    sorter: true,
+                    render: (text) => text || '--'
+                }
+            ]}
+            scroll={{ x: 1000 }}
+            rowKey={'activeCode'}
+            size='small'
+            pagination={{
+                total: getLicenseCodeList?.data?.data?.total,
+                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
+                showSizeChanger: true,
+                showLessItems: true,
+                defaultCurrent: 1,
+                defaultPageSize: 20,//默认初始的每页条数
+                current: getLicenseCodeList?.data?.data?.current || 1,
+                pageSize: getLicenseCodeList?.data?.data?.size || 20,
+            }}
+            onChange={(pagination, _, sortData: any) => {
+                let { current, pageSize } = pagination
+                let newQueryForm = JSON.parse(JSON.stringify(queryParams))
+                let newOldQueryParams = JSON.parse(JSON.stringify(oldQueryParams))
+                if (sortData && sortData?.order) {
+                    newQueryForm['sortAsc'] = sortData?.order === 'ascend' ? true : false
+                    newQueryForm['sortFiled'] = sortData?.field
+                } else {
+                    delete newQueryForm['sortAsc']
+                    delete newQueryForm['sortFiled']
+                }
+                newQueryForm.pageNum = current || newQueryForm.pageNum
+                newQueryForm.pageSize = pageSize || newQueryForm.pageSize
+                setQueryParams({ ...newQueryForm })
+                setOldQueryParams({ ...newOldQueryParams })
+            }}
+            rowSelection={{
+                selectedRowKeys: selectedRows?.map((item: any) => item?.activeCode),
+                getCheckboxProps: (record: any) => ({
+                    disabled: selectedRows.length > 0 ? record.corpId !== selectedRows[0].corpId : false
+                }),
+                onSelect: (record: { activeCode: string }, selected: boolean) => {
+                    let newData = JSON.parse(JSON.stringify(selectedRows))
+                    if (selected) {
+                        newData.push({ ...record })
+                    } else {
+                        newData = newData.filter((item: { activeCode: string }) => item.activeCode !== record.activeCode)
+                    }
+                    setselectedRows(newData)
+                },
+                onSelectAll: (selected: boolean, _: { activeCode: string }[], changeRows: { activeCode: string, corpId: string }[]) => {
+                    let newData = JSON.parse(JSON.stringify(selectedRows || '[]'))
+                    if (selected) {
+                        const firstCorpId = newData?.length > 0 ? newData?.[0].corpId : changeRows?.[0]?.corpId
+                        changeRows.forEach((item: { activeCode: string, corpId: string }) => {
+                            const index = newData.findIndex((ite: { activeCode: string }) => ite.activeCode === item.activeCode)
+                            if (index === -1 && item.corpId === firstCorpId) {
+                                newData.push(item)
+                            }
+                        })
+                    } else {
+                        const newSelectAccData = newData.filter((item: { activeCode: string }) => {
+                            const index = changeRows.findIndex((ite: { activeCode: string }) => ite.activeCode === item.activeCode)
+                            if (index !== -1) {
+                                return false
+                            } else {
+                                return true
+                            }
+                        })
+                        newData = newSelectAccData
+                    }
+                    setselectedRows(newData)
+                }
+            }}
+        />
+
+        {/* 激活激活码 */}
+        {visible && <ActiveCode
+            visible={visible}
+            onChange={() => {
+                setVisible(false)
+                setselectedRows([])
+            }}
+            selectedRows={selectedRows}
+            onClose={() => {
+                setVisible(false)
+            }}
+        />}
+
+        {/* 激活码继承 */}
+        {visibleTr && <TransferCode
+            visible={visibleTr}
+            onChange={() => {
+                setVisibleTr(false)
+                setselectedRows([])
+            }}
+            selectedRows={selectedRows}
+            onClose={() => {
+                setVisibleTr(false)
+            }}
+        />}
+    </Card>
+};
+
+export default SeatDetails;

+ 100 - 0
src/pages/weComTask/page/weChatApiLicense/seatDetails/transferCode.tsx

@@ -0,0 +1,100 @@
+import { Card, Form, message, Modal } from "antd"
+import React, { useEffect } from "react"
+import SelectCorpUserAll from "../../corpUserManage/selectCorpUserAll"
+import { useAjax } from "@/Hook/useAjax"
+import { transferCodeApi } from "@/pages/weComTask/API/weChatApiLicense"
+
+interface Props {
+    selectedRows: any[]
+    visible?: boolean
+    onChange?: () => void
+    onClose?: () => void
+}
+const TransferCode: React.FC<Props> = ({ visible, selectedRows, onChange, onClose }) => {
+
+    /***********************************/
+    const corpId = selectedRows[0].corpId
+    const [form] = Form.useForm();
+    const transferParam = Form.useWatch('transferParam', form)
+
+    const transferCode = useAjax((params) => transferCodeApi(params))
+    /***********************************/
+
+    useEffect(() => {
+        form.setFieldsValue({
+            transferParam: selectedRows.map(item => {
+                return {
+                    handover_user_name: item.userName,
+                    handover_userid: item.userId,
+                    takeoverUser: undefined
+                }
+            })
+        })
+    }, [selectedRows])
+
+    const handleOk = () => {
+        form.validateFields().then((values) => {
+            const transferParam = values?.transferParam.map(item => {
+                return {
+                    handover_userid: item.handover_userid,
+                    takeover_userid: item.takeoverUser?.[0]?.corpUserId
+                }
+            })
+            transferCode.run({
+                corpId,
+                transferParam
+            }).then(res => {
+                if (res?.data) {
+                    message.success('继承成功')
+                    onChange?.()
+                }
+            })
+        }).catch(err => console.log('校验失败', err))
+    }
+
+    return <Modal
+        title="激活码继承"
+        open={visible}
+        onCancel={onClose}
+        width={650}
+        onOk={handleOk}
+        confirmLoading={transferCode.loading}
+    >
+        <Form
+            form={form}
+            name={'transfer-code'}
+            labelAlign='left'
+            labelCol={{ span: 5 }}
+            colon={false}
+            preserve={true}
+        >
+            <Form.List name="transferParam">
+                {(fields) => (
+                    <>
+                        {fields.map(({ key, name, ...restField }, index) => {
+                            const transferP = transferParam?.[index]
+                            return <Card
+                                key={key}
+                                title={<strong>转移人员:{transferP.handover_user_name}({transferP?.handover_userid})</strong>}
+                                style={{ background: '#fff', marginBottom: 10 }}
+                            >
+                                <Form.Item
+                                    {...restField}
+                                    label={<strong>接收人员</strong>}
+                                    name={[name, 'takeoverUser']}
+                                    rules={[
+                                        { required: true, message: '请选择接收人员!' }
+                                    ]}
+                                >
+                                    <SelectCorpUserAll type='radio' corpId={corpId} placeholder="请选择接收人员" />
+                                </Form.Item>
+                            </Card>
+                        })}
+                    </>
+                )}
+            </Form.List>
+        </Form>
+    </Modal>
+}
+
+export default React.memo(TransferCode)