diff --git a/packages/global/support/user/team/type.d.ts b/packages/global/support/user/team/type.d.ts index 80daa89ef..325e2e63b 100644 --- a/packages/global/support/user/team/type.d.ts +++ b/packages/global/support/user/team/type.d.ts @@ -90,3 +90,19 @@ export type LafAccountType = { appid: string; pat: string; }; + +export type TeamInvoiceHeaderType = { + teamName: string; + unifiedCreditCode: string; + companyAddress: string; + companyPhone: string; + bankName: string; + bankAccount: string; + needSpecialInvoice?: boolean; + emailAddress: string; +}; + +export type TeamInvoiceHeaderInfoSchemaType = TeamInvoiceHeaderType & { + _id: string; + teamId: string; +}; diff --git a/packages/global/support/wallet/bill/constants.ts b/packages/global/support/wallet/bill/constants.ts index fe04c7b50..1a02f59b4 100644 --- a/packages/global/support/wallet/bill/constants.ts +++ b/packages/global/support/wallet/bill/constants.ts @@ -44,6 +44,7 @@ export enum BillPayWayEnum { balance = 'balance', wx = 'wx' } + export const billPayWayMap = { [BillPayWayEnum.balance]: { label: 'support.wallet.bill.payWay.balance' diff --git a/packages/global/support/wallet/bill/invoice/constants.ts b/packages/global/support/wallet/bill/invoice/constants.ts new file mode 100644 index 000000000..794fc01d7 --- /dev/null +++ b/packages/global/support/wallet/bill/invoice/constants.ts @@ -0,0 +1,4 @@ +export enum InvoiceStatusEnum { + submitted = 1, + completed = 2 +} diff --git a/packages/global/support/wallet/bill/type.d.ts b/packages/global/support/wallet/bill/type.d.ts index e7b5c9364..7f38797a2 100644 --- a/packages/global/support/wallet/bill/type.d.ts +++ b/packages/global/support/wallet/bill/type.d.ts @@ -1,6 +1,6 @@ import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from '../sub/constants'; import { BillPayWayEnum, BillTypeEnum } from './constants'; - +import { TeamInvoiceHeaderType } from '../../user/team/type'; export type BillSchemaType = { _id: string; userId: string; @@ -29,3 +29,16 @@ export type ChatNodeUsageType = { moduleName: string; model?: string; }; + +export type InvoiceType = { + amount: number; + billIdList: string[]; +} & TeamInvoiceHeaderType; + +export type InvoiceSchemaType = { + teamId: string; + _id: string; + status: 1 | 2; + createTime: Date; + finishTime?: Date; +} & InvoiceType; diff --git a/packages/web/common/file/hooks/useSelectFile.tsx b/packages/web/common/file/hooks/useSelectFile.tsx new file mode 100644 index 000000000..82852681d --- /dev/null +++ b/packages/web/common/file/hooks/useSelectFile.tsx @@ -0,0 +1,56 @@ +import React, { useRef, useCallback } from 'react'; +import { Box } from '@chakra-ui/react'; +import { useToast } from '../../../hooks/useToast'; +import { useTranslation } from 'next-i18next'; +export const useSelectFile = (props?: { + fileType?: string; + multiple?: boolean; + maxCount?: number; +}) => { + const { t } = useTranslation(); + const { fileType = '*', multiple = false, maxCount = 10 } = props || {}; + const { toast } = useToast(); + const SelectFileDom = useRef(null); + const openSign = useRef(); + + const File = useCallback( + ({ onSelect }: { onSelect: (e: File[], sign?: any) => void }) => ( + + { + const files = e.target.files; + + if (!files || files?.length === 0) return; + + let fileList = Array.from(files); + if (fileList.length > maxCount) { + toast({ + status: 'warning', + title: t('file:select_file_amount_limit', { max: maxCount }) + }); + fileList = fileList.slice(0, maxCount); + } + onSelect(fileList, openSign.current); + + e.target.value = ''; + }} + /> + + ), + [fileType, maxCount, multiple, toast] + ); + + const onOpen = useCallback((sign?: any) => { + openSign.current = sign; + SelectFileDom.current && SelectFileDom.current.click(); + }, []); + + return { + File, + onOpen + }; +}; diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index 086199708..90dc9e790 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -226,7 +226,10 @@ export const iconPaths = { delete: () => import('./icons/delete.svg'), edit: () => import('./icons/edit.svg'), empty: () => import('./icons/empty.svg'), + paragraph: () => import('./icons/paragraph.svg'), export: () => import('./icons/export.svg'), + point: () => import('./icons/point.svg'), + infoRounded: () => import('./icons/infoRounded.svg'), 'file/csv': () => import('./icons/file/csv.svg'), 'file/fill/csv': () => import('./icons/file/fill/csv.svg'), 'file/fill/doc': () => import('./icons/file/fill/doc.svg'), diff --git a/packages/web/components/common/Icon/icons/infoRounded.svg b/packages/web/components/common/Icon/icons/infoRounded.svg new file mode 100644 index 000000000..5a823345b --- /dev/null +++ b/packages/web/components/common/Icon/icons/infoRounded.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/paragraph.svg b/packages/web/components/common/Icon/icons/paragraph.svg new file mode 100644 index 000000000..e209b9460 --- /dev/null +++ b/packages/web/components/common/Icon/icons/paragraph.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/web/components/common/Icon/icons/point.svg b/packages/web/components/common/Icon/icons/point.svg new file mode 100644 index 000000000..11c4f76b6 --- /dev/null +++ b/packages/web/components/common/Icon/icons/point.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/web/components/common/MyPopover/PopoverConfirm.tsx b/packages/web/components/common/MyPopover/PopoverConfirm.tsx index 622661e83..0be921592 100644 --- a/packages/web/components/common/MyPopover/PopoverConfirm.tsx +++ b/packages/web/components/common/MyPopover/PopoverConfirm.tsx @@ -21,7 +21,9 @@ const PopoverConfirm = ({ Trigger, placement = 'bottom-start', offset, - onConfirm + onConfirm, + confirmText, + cancelText }: { content: string; showCancel?: boolean; @@ -30,6 +32,8 @@ const PopoverConfirm = ({ placement?: PlacementWithLogical; offset?: [number, number]; onConfirm: () => any; + confirmText?: string; + cancelText?: string; }) => { const { t } = useTranslation(); @@ -82,11 +86,11 @@ const PopoverConfirm = ({ {showCancel && ( )} diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx index ac1c23c9f..53afa20ff 100644 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPickerPlugin/index.tsx @@ -8,7 +8,7 @@ import { Box, Flex } from '@chakra-ui/react'; import { useBasicTypeaheadTriggerMatch } from '../../utils'; import { EditorVariableLabelPickerType } from '../../type'; import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import Avatar from '../../../../Avatar'; interface EditorVariableItemType { diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/components/VariableLabel.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/components/VariableLabel.tsx index e73a23a3f..87be5af7b 100644 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/components/VariableLabel.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/plugins/VariableLabelPlugin/components/VariableLabel.tsx @@ -1,6 +1,6 @@ import { ChevronRightIcon } from '@chakra-ui/icons'; import { Box } from '@chakra-ui/react'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import Avatar from '../../../../../../../components/common/Avatar'; export default function VariableLabel({ diff --git a/packages/web/hooks/usePagination.tsx b/packages/web/hooks/usePagination.tsx index c2cb1828e..231bfcf87 100644 --- a/packages/web/hooks/usePagination.tsx +++ b/packages/web/hooks/usePagination.tsx @@ -2,7 +2,7 @@ import { useRef, useState, useCallback, useMemo, useEffect } from 'react'; import { IconButton, Flex, Box, Input } from '@chakra-ui/react'; import { ArrowBackIcon, ArrowForwardIcon } from '@chakra-ui/icons'; import { useMutation } from '@tanstack/react-query'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import { throttle } from 'lodash'; import { useToast } from './useToast'; import { getErrText } from '@fastgpt/global/common/error/utils'; diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index 4e378bbe4..f4bea3119 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -75,6 +75,7 @@ "unit": "Number" }, "move_app": "Move app", + "no": "no", "paste_config": "Paste Config", "plugin_cost_per_times": "{{cost}}/per time", "plugin_dispatch": "Plugins", @@ -84,6 +85,27 @@ "search_app": "Search app", "setting_app": "Settings", "setting_plugin": "Setting plugin", + "support": { + "wallet": { + "bill_tag": { + "bill": "billing records", + "default_header": "Default header", + "invoice": "Invoicing records" + }, + "invoice_data": { + "bank": "Bank of deposit", + "bank_account": "Account opening account", + "company_address": "company address", + "company_phone": "company phone", + "email": "email address", + "in_valid": "There are empty fields or incorrect email formats", + "need_special_invoice": "Do you need a special ticket?", + "organization_name": "name of association", + "unit_code": "same credit code" + }, + "invoicing": "Invoicing" + } + }, "template": { "simple_robot": "Simple Robot" }, @@ -95,6 +117,7 @@ "templateTags": { "Image_generation": "Image generation", "Office_services": "Office searvices", + "Recommendation": "recommend", "Roleplay": "Roleplay", "Web_search": "Web search", "Writing": "Writing" @@ -115,6 +138,7 @@ "Create plugin bot": "Create plugin bot", "Create simple bot": "Create simple bot", "Create simple bot tip": "Create simple AI applications in form form", + "Create template tip": "Explore more ways to play in the template market to help you understand and use various applications", "Create workflow bot": "Create workflow bot", "Create workflow tip": "Through the way of low code, build a logically complex multi-round dialogue AI application, recommended for advanced players", "Http plugin": "Http plugin", @@ -160,5 +184,6 @@ "user_file_input_desc": "Links to documents and images uploaded by users", "user_select": "User select", "user_select_tip": "The module can have multiple options that lead to different workflow branches" - } + }, + "yes": "yes" } diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index bb8d2ca19..9c8672259 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -29,6 +29,7 @@ "UnKnow": "Unknown", "Warning": "Warning", "add_new": "Add new", + "back": "return", "chose_condition": "Selection criteria", "chosen": "selected", "classification": "Classification", @@ -36,6 +37,8 @@ "code_editor": "Code edit", "code_error": { "app_error": { + "invalid_app_type": "Wrong application type", + "invalid_owner": "Illegal app owner", "not_exist": "App does not exist", "un_auth_app": "No permission to operate this application" }, @@ -237,6 +240,7 @@ "empty": "This directory has nothing selectable~", "open_dataset": "Open knowledge base" }, + "have_done": "Completed", "input": { "Repeat Value": "Duplicate value" }, @@ -258,6 +262,9 @@ "error tip": "Speech to text failed", "not support": "Your browser does not support speech input" }, + "submit_success": "Submitted successfully", + "submitted": "Submitted", + "submitting": "Submitting", "support": "support", "system": { "Commercial version function": "Commercial version feature", @@ -358,6 +365,14 @@ "logs": { "Source And Time": "Source & Time" }, + "more": "View more", + "navbar": { + "External": "external use", + "Flow mode": "Advanced orchestration", + "Publish": "release", + "Publish app": "Publish application", + "Simple mode": "Easy configuration" + }, "no_app": "There is no application yet, go and create one!", "not_published": "Unpublished", "outLink": { @@ -600,7 +615,8 @@ "success": "Start syncing" } }, - "training": {} + "training": { + } }, "data": { "Auxiliary Data": "Auxiliary data", @@ -1061,6 +1077,7 @@ "Tools": "Tools" }, "new_create": "Create New", + "no": "no", "no_data": "No data", "no_laf_env": "The system is not configured with Laf environment", "not_yet_introduced": "No introduction yet", @@ -1097,7 +1114,12 @@ "Resume InheritPermission Confirm": "Whether to resume to inherit the parent folder's permission?", "Resume InheritPermission Failed": "Resume Failed", "Resume InheritPermission Success": "Resume Success", - "change_owner_tip": "Your permissions will not be retained after transfer" + "change_owner": "transfer ownership", + "change_owner_failed": "Transfer ownership failed", + "change_owner_placeholder": "Enter username to find account", + "change_owner_success": "Successfully transferred ownership", + "change_owner_tip": "Your administrator rights will be retained after the transfer", + "change_owner_to": "transferred to" }, "plugin": { "App": "Select app", @@ -1225,6 +1247,7 @@ "Standard Plan Detail": "Plan details", "To read plan": "View plan", "amount_0": "The purchase quantity cannot be 0", + "apply_invoice": "Apply for making an invoice", "bill": { "Number": "Order number", "Status": "Status", @@ -1241,12 +1264,36 @@ "success": "Payment successful" } }, + "bill_detail": "Bill details", + "bill_tag": { + "bill": "billing records", + "default_header": "Default header", + "invoice": "Invoicing records" + }, + "billable_invoice": "Billable bills", "buy_resource": "Purchase resource pack", + "has_invoice": "Whether the invoice has been issued", + "invoice_amount": "Invoice amount", + "invoice_data": { + "bank": "Bank of deposit", + "bank_account": "Account opening account", + "company_address": "Company address", + "company_phone": "Company phone number", + "email": "Email address", + "in_valid": "There are empty fields or incorrect email formats", + "need_special_invoice": "Do you need a special ticket?", + "organization_name": "Organization name", + "unit_code": "same credit code" + }, + "invoice_detail": "Invoice details", + "invoice_info": "The invoice will be sent to your mailbox within 3-7 working days, please be patient.", + "invoicing": "Invoicing", "moduleName": { "index": "Index generation", "qa": "QA split" }, "noBill": "No bill records~", + "no_invoice": "No invoicing record yet", "subscription": { "AI points": "AI points", "AI points click to read tip": "Each call to the AI model will consume a certain amount of AI points (similar to Tokens). Click to view detailed calculation rules.", @@ -1322,7 +1369,8 @@ "Total points": "AI points consumed", "Usage Detail": "Usage details", "Whisper": "Voice input" - } + }, + "use_default": "Use default header" } }, "sync_link": "Sync Link", @@ -1442,5 +1490,6 @@ "type": "type" }, "verification": "verify", - "xx_search_result": "{{key}} Search results" + "xx_search_result": "{{key}} Search results", + "yes": "yes" } diff --git a/packages/web/i18n/en/publish.json b/packages/web/i18n/en/publish.json index f1de04ba5..11b25fe34 100644 --- a/packages/web/i18n/en/publish.json +++ b/packages/web/i18n/en/publish.json @@ -1,10 +1,16 @@ { "app_key_tips": "These keys have the current application identification, refer to the document for specific use ", + "basic_info": "Basic information", + "copy_link_hint": "Copy the link below to the specified location", "create_api_key": "Create new Key", "create_link": "Create link", "default_response": "Default Response", "edit_api_key": "Edit Key information", + "edit_feishu_bot": "Edit Feishu Robot", "edit_link": "Edit", + "feishu_api": "Feishu interface", + "feishu_bot": "Feishu Robot", + "feishu_bot_desc": "Directly access Feishu Robot through API", "feishu_name": "Lark", "key_alias": "key alias, for display only ", "key_tips": "You can use the API Key to access certain interfaces (you can't access the app, you need to use the API key within the app to access the app)", @@ -12,9 +18,21 @@ "official_account": { "params": "Wechat params" }, + "new_feishu_bot": "Added Feishu robot", + "publish_name": "name", "qpm_is_empty": "QPM cannot be empty", "qpm_tips": "How many times per minute can each IP ask at most", + "request_address": "Request address", + "show_share_link_modal_title": "Get started", "token_auth": "Token authentication", "token_auth_tips": "Identity verification server address, if this value is filled, a request will be sent to the specified server before each conversation to perform identity verification", - "token_auth_use_cases": "View usage instructions for identity verification" + "token_auth_use_cases": "View usage instructions for identity verification", + "wecom": { + "api": "Qiwei API", + "bot": "Enterprise WeChat robot", + "bot_desc": "Directly access enterprise WeChat robots through API", + "create_modal_title": "Create a Qiwei robot", + "edit_modal_title": "Edit Qiwei Robot", + "title": "Publish to enterprise WeChat robot" + } } diff --git a/packages/web/i18n/en/user.json b/packages/web/i18n/en/user.json index 71691e214..06c254a9e 100644 --- a/packages/web/i18n/en/user.json +++ b/packages/web/i18n/en/user.json @@ -1,6 +1,12 @@ { "bind_inform_account_error": "Abnormal binding notification account", "bind_inform_account_success": "Binding notification account successful", + "code_error": { + "app_error": { + "invalid_app_type": "Wrong application type", + "invalid_owner": "Illegal app owner" + } + }, "delete": { "admin_failed": "Failed to delete administrator", "admin_success": "Administrator deleted successfully" @@ -17,7 +23,8 @@ }, "name": "name", "notification": { - "Bind Notification Pipe Hint": "Bind the email address or mobile phone number for receiving notifications to ensure that you receive important system notifications in a timely manner." + "Bind Notification Pipe Hint": "Bind the email address or mobile phone number for receiving notifications to ensure that you receive important system notifications in a timely manner.", + "remind_owner_bind": "Please remind the creator to bind the notification account" }, "operations": "operate", "password": { @@ -48,6 +55,12 @@ "Read desc": "Members can only read related resources and cannot create new resources.", "Write": "Write", "Write tip": "In addition to readable resources, you can also create new resources", + "change_owner": "transfer ownership", + "change_owner_failed": "Transfer ownership failed", + "change_owner_placeholder": "Enter username to find account", + "change_owner_success": "Successfully transferred ownership", + "change_owner_tip": "Your administrator rights will be retained after the transfer", + "change_owner_to": "transferred to", "only_collaborators": "Collaborator access only", "team_read": "Team accessible", "team_write": "Team editable" diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index 83bd64fcc..ecb84b257 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -19,6 +19,9 @@ "package_overlay_a": "可以的。每次购买的资源包都是独立的,在其有效期内将会叠加使用。AI积分会优先扣除最先过期的资源包。", "package_overlay_q": "额外资源包可以叠加么?" }, + "yes": "是", + "no": "否", + "back": "返回", "Folder": "文件夹", "Login": "登录", "Move": "移动", @@ -135,6 +138,7 @@ "Detail": "详情", "Documents": "文档", "Done": "完成", + "have_done": "已完成", "Edit": "编辑", "Exit": "退出", "Expired Time": "过期时间", @@ -190,7 +194,11 @@ "Set Name": "取个名字", "Setting": "设置", "Status": "状态", + "submitting": "提交中", + "submit_success": "提交成功", "Submit failed": "提交失败", + "submitted": "已提交", + "Success": "成功", "Sync success": "同步成功", "Team": "团队", @@ -1233,8 +1241,17 @@ "wallet": { "Ai point every thousand tokens": "{{points}} 积分/1K tokens", "Amount": "金额", - "Bills": "账单", + "Bills": "账单与开票", + "invoicing": "开票", + "invoice_amount": "开票金额", + "bill_detail": "账单详情", + "billable_invoice": "可开票账单", + "apply_invoice": "申请开票", "Buy": "购买", + "invoice_detail": "发票详情", + "invoice_info": "发票将在 3-7 个工作日内发送至邮箱,请耐心等待", + "no_invoice": "暂无开票记录", + "has_invoice": "是否已开票", "Confirm pay": "支付确认", "Not sufficient": "您的 AI 积分不足,请先升级套餐或购买额外 AI 积分后继续使用。", "Plan expired time": "套餐到期时间", @@ -1242,6 +1259,23 @@ "Standard Plan Detail": "套餐详情", "To read plan": "查看套餐", "amount_0": "购买数量不能为0", + "use_default": "使用默认抬头", + "bill_tag": { + "bill": "账单记录", + "invoice": "开票记录", + "default_header": "默认抬头" + }, + "invoice_data": { + "organization_name": "组织名称", + "unit_code": "统一信用代码", + "company_address": "公司地址", + "company_phone": "公司电话", + "bank": "开户银行", + "bank_account": "开户账号", + "need_special_invoice": "是否需要专票", + "email": "邮箱地址", + "in_valid": "存在空字段或邮箱格式错误" + }, "bill": { "Number": "订单号", "Status": "状态", diff --git a/projects/app/public/imgs/modal/invoice.svg b/projects/app/public/imgs/modal/invoice.svg new file mode 100644 index 000000000..5d6987cea --- /dev/null +++ b/projects/app/public/imgs/modal/invoice.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx index 0b2fdef72..d950b4465 100644 --- a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useMemo } from 'react'; import { Controller } from 'react-hook-form'; import RenderPluginInput from './renderPluginInput'; import { Button, Flex } from '@chakra-ui/react'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import { useContextSelector } from 'use-context-selector'; import { PluginRunContext } from '../context'; import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; diff --git a/projects/app/src/components/support/permission/DefaultPerList/index.tsx b/projects/app/src/components/support/permission/DefaultPerList/index.tsx index 5eae667bc..c0c284229 100644 --- a/projects/app/src/components/support/permission/DefaultPerList/index.tsx +++ b/projects/app/src/components/support/permission/DefaultPerList/index.tsx @@ -5,7 +5,7 @@ import type { PermissionValueType } from '@fastgpt/global/support/permission/typ import { ReadPermissionVal, WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; export enum defaultPermissionEnum { private = 'private', diff --git a/projects/app/src/pages/account/components/Info.tsx b/projects/app/src/pages/account/components/Info.tsx index 7c8fbab83..a813007da 100644 --- a/projects/app/src/pages/account/components/Info.tsx +++ b/projects/app/src/pages/account/components/Info.tsx @@ -83,7 +83,7 @@ const Account = () => { ) : ( <> - {!!standardPlan && } + {standardPlan && } )} diff --git a/projects/app/src/pages/account/components/bill/ApplyInvoiceModal.tsx b/projects/app/src/pages/account/components/bill/ApplyInvoiceModal.tsx new file mode 100644 index 000000000..2d313e39f --- /dev/null +++ b/projects/app/src/pages/account/components/bill/ApplyInvoiceModal.tsx @@ -0,0 +1,300 @@ +import { + getInvoiceBillsList, + invoiceBillDataType, + submitInvoice +} from '@/web/support/wallet/bill/invoice/api'; +import { + Box, + Button, + Checkbox, + Flex, + Table, + TableContainer, + Tbody, + Td, + Th, + Thead, + Tr, + useDisclosure +} from '@chakra-ui/react'; +import { billTypeMap } from '@fastgpt/global/support/wallet/bill/constants'; +import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; +import MyModal from '@fastgpt/web/components/common/MyModal'; +import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; +import dayjs from 'dayjs'; +import { useTranslation } from 'next-i18next'; +import { useCallback, useState } from 'react'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import Divider from '@/pages/app/detail/components/WorkflowComponents/Flow/components/Divider'; +import { TeamInvoiceHeaderType } from '@fastgpt/global/support/user/team/type'; +import { InvoiceHeaderSingleForm } from './InvoiceHeaderForm'; +import MyBox from '@fastgpt/web/components/common/MyBox'; +import { getTeamInvoiceHeader } from '@/web/support/user/team/api'; +import { useToast } from '@fastgpt/web/hooks/useToast'; +type chosenBillDataType = { + _id: string; + price: number; +}; +const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => { + const { t } = useTranslation(); + const { toast } = useToast(); + const [chosenBillDataList, setChosenBillDataList] = useState([]); + const [totalPrice, setTotalPrice] = useState(0); + const [formData, setFormData] = useState({ + teamName: '', + unifiedCreditCode: '', + companyAddress: '', + companyPhone: '', + bankName: '', + bankAccount: '', + needSpecialInvoice: undefined, + emailAddress: '' + }); + const { + isOpen: isOpenSettleModal, + onOpen: onOpenSettleModal, + onClose: onCloseSettleModal + } = useDisclosure(); + + const handleChange = useCallback((e: any) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }, []); + + const handleRatiosChange = useCallback((v: string) => { + setFormData((prev) => ({ ...prev, needSpecialInvoice: v === 'true' })); + }, []); + + const isHeaderValid = useCallback((v: TeamInvoiceHeaderType) => { + const emailRegex = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; + for (const [key, value] of Object.entries(v)) { + if (typeof value === 'string' && value.trim() === '') { + return false; + } + } + return emailRegex.test(v.emailAddress); + }, []); + + const { + loading: isLoading, + data: billsList, + run: getInvoiceBills + } = useRequest2(() => getInvoiceBillsList(), { + manual: false + }); + + const { run: handleSubmitInvoice, loading: isSubmitting } = useRequest2( + () => + submitInvoice({ + amount: totalPrice, + billIdList: chosenBillDataList.map((item) => item._id), + ...formData + }), + { + manual: true, + successToast: t('common:common.submit_success'), + errorToast: t('common:common.Submit failed'), + onSuccess: () => onClose() + } + ); + + const { loading: isLoadingHeader } = useRequest2(() => getTeamInvoiceHeader(), { + manual: false, + onSuccess: (res) => setFormData(res) + }); + + const handleSubmit = useCallback(async () => { + if (!isHeaderValid(formData)) { + toast({ + title: t('common:support.wallet.invoice_data.in_valid'), + status: 'info' + }); + return; + } + handleSubmitInvoice(); + }, [formData, handleSubmitInvoice, isHeaderValid, t, toast]); + + const handleBack = useCallback(() => { + setChosenBillDataList([]); + getInvoiceBills(); + onCloseSettleModal(); + }, [getInvoiceBills, onCloseSettleModal]); + + const handleSingleCheck = useCallback( + (item: invoiceBillDataType) => { + if (chosenBillDataList.find((bill) => bill._id === item._id)) { + setChosenBillDataList(chosenBillDataList.filter((bill) => bill._id !== item._id)); + } else { + setChosenBillDataList([...chosenBillDataList, { _id: item._id, price: item.price }]); + } + }, + [chosenBillDataList] + ); + + return ( + + {!isOpenSettleModal ? ( + + + {t('common:support.wallet.billable_invoice')} + + + + + + + + + + + + + + {billsList?.map((item) => ( + { + if (e.target?.name && e.target.name === 'check') return; + handleSingleCheck(item); + }} + _hover={{ + bg: 'blue.50' + }} + > + + + + + + ))} + +
+ { + !e.target.checked + ? setChosenBillDataList([]) + : setChosenBillDataList( + billsList?.map((item) => ({ + _id: item._id, + price: item.price + })) || [] + ); + }} + /> + {t('common:user.type')}{t('common:user.Time')}{t('common:support.wallet.Amount')}
+ i._id === item._id)} + /> + {t(billTypeMap[item.type]?.label as any)} + {item.createTime + ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') + : '-'} + {t('common:pay.yuan', { amount: formatStorePrice2Read(item.price) })}
+ {!isLoading && billsList && billsList.length === 0 && ( + + + + {t('common:support.wallet.noBill')} + + + )} +
+
+ + + +
+ ) : ( + + + + {t('common:support.wallet.invoice_amount')} + {t('common:pay.yuan', { amount: formatStorePrice2Read(totalPrice) })} + + + + + + + + + + + + + + {t('common:support.wallet.invoice_info')} + + + + + + + + )} +
+ ); +}; + +export default ApplyInvoiceModal; diff --git a/projects/app/src/pages/account/components/bill/BillAndInvoice.tsx b/projects/app/src/pages/account/components/bill/BillAndInvoice.tsx new file mode 100644 index 000000000..7f0c2d58c --- /dev/null +++ b/projects/app/src/pages/account/components/bill/BillAndInvoice.tsx @@ -0,0 +1,58 @@ +import { Box, Button, Flex } from '@chakra-ui/react'; +import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs'; +import dynamic from 'next/dynamic'; +import { useState } from 'react'; +import { useTranslation } from 'next-i18next'; +import ApplyInvoiceModal from './ApplyInvoiceModal'; + +const TabEnum = { + bill: 'bill', + invoice: 'invoice', + invoiceHeader: 'voiceHeader' +}; +const BillTable = dynamic(() => import('./BillTable')); +const InvoiceHeaderForm = dynamic(() => import('./InvoiceHeaderForm')); +const InvoiceTable = dynamic(() => import('./InvoiceTable')); +const BillAndInvoice = () => { + const [currentTab, setCurrentTab] = useState(TabEnum.bill); + const [isOpenInvoiceModal, setIsOpenInvoiceModal] = useState(false); + + const { t } = useTranslation(); + return ( + <> + + + + {currentTab !== TabEnum.invoiceHeader && ( + + )} + + + {currentTab === TabEnum.bill && } + {currentTab === TabEnum.invoice && } + {currentTab === TabEnum.invoiceHeader && } + + {isOpenInvoiceModal && setIsOpenInvoiceModal(false)} />} + + + ); +}; + +export default BillAndInvoice; diff --git a/projects/app/src/pages/account/components/BillTable.tsx b/projects/app/src/pages/account/components/bill/BillTable.tsx similarity index 96% rename from projects/app/src/pages/account/components/BillTable.tsx rename to projects/app/src/pages/account/components/bill/BillTable.tsx index 94ac1aa50..c7931b3fb 100644 --- a/projects/app/src/pages/account/components/BillTable.tsx +++ b/projects/app/src/pages/account/components/bill/BillTable.tsx @@ -102,8 +102,6 @@ const BillTable = () => { position={'relative'} h={'100%'} overflow={'overlay'} - py={[0, 5]} - px={[3, 8]} > @@ -188,7 +186,7 @@ function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: () isOpen={true} onClose={onClose} iconSrc="/imgs/modal/bill.svg" - title={t('common:support.wallet.usage.Usage Detail')} + title={t('common:support.wallet.bill_detail')} maxW={['90vw', '700px']} > @@ -218,6 +216,10 @@ function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: () {t('common:support.wallet.bill.Type')}: {t(billTypeMap[bill.type]?.label as any)} + + {t('common:support.wallet.has_invoice')}: + {bill.hasInvoice ? t('common:yes') : t('common:no')} + {!!bill.metadata?.subMode && ( diff --git a/projects/app/src/pages/account/components/bill/InvoiceHeaderForm.tsx b/projects/app/src/pages/account/components/bill/InvoiceHeaderForm.tsx new file mode 100644 index 000000000..71982ffb5 --- /dev/null +++ b/projects/app/src/pages/account/components/bill/InvoiceHeaderForm.tsx @@ -0,0 +1,209 @@ +import Divider from '@/pages/app/detail/components/WorkflowComponents/Flow/components/Divider'; +import { getTeamInvoiceHeader, updateTeamInvoiceHeader } from '@/web/support/user/team/api'; +import { Box, Button, Flex, Input, Radio, RadioGroup, Stack } from '@chakra-ui/react'; +import { TeamInvoiceHeaderType } from '@fastgpt/global/support/user/team/type'; +import MyBox from '@fastgpt/web/components/common/MyBox'; +import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; +import { useCallback, useState } from 'react'; +import { useTranslation } from 'next-i18next'; +import { useToast } from '@fastgpt/web/hooks/useToast'; + +const InputItem = ({ + label, + value, + onChange, + name +}: { + label: string; + value: string; + onChange: (e: any) => void; + name: string; +}) => { + return ( + <> + + + {label} + + + + + ); +}; + +export const InvoiceHeaderSingleForm = ({ + formData, + handleChange, + handleRatiosChange +}: { + formData: TeamInvoiceHeaderType; + handleChange: (e: any) => void; + handleRatiosChange: (v: string) => void; +}) => { + const { t } = useTranslation(); + return ( + <> + + + + + + + + + + {t('common:support.wallet.invoice_data.need_special_invoice')} + + + + + {t('common:yes')} + + + {t('common:no')} + + + + + + + + + + + ); +}; + +const InvoiceHeaderForm = () => { + const [formData, setFormData] = useState({ + teamName: '', + unifiedCreditCode: '', + companyAddress: '', + companyPhone: '', + bankName: '', + bankAccount: '', + needSpecialInvoice: undefined, + emailAddress: '' + }); + const { loading: isLoading } = useRequest2(() => getTeamInvoiceHeader(), { + manual: false, + onSuccess: (data) => { + setFormData(data); + } + }); + const { t } = useTranslation(); + const { toast } = useToast(); + const handleChange = useCallback((e: any) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }, []); + const handleRatiosChange = useCallback((v: string) => { + setFormData((prev) => ({ ...prev, needSpecialInvoice: v === 'true' })); + }, []); + const isHeaderValid = useCallback((v: TeamInvoiceHeaderType) => { + const emailRegex = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; + return emailRegex.test(v.emailAddress); + }, []); + const { loading: isSubmitting, run: handleSubmit } = useRequest2( + () => updateTeamInvoiceHeader(formData), + { + manual: true, + successToast: t('common:common.Save Success'), + errorToast: t('common:common.Save Failed') + } + ); + const onSubmit = useCallback(() => { + if (!isHeaderValid(formData)) { + toast({ + title: t('common:support.wallet.invoice_data.in_valid'), + status: 'info' + }); + return; + } + handleSubmit(); + }, [handleSubmit, formData, isHeaderValid, toast, t]); + return ( + <> + + + + + + + + + + ); +}; + +export default InvoiceHeaderForm; diff --git a/projects/app/src/pages/account/components/bill/InvoiceTable.tsx b/projects/app/src/pages/account/components/bill/InvoiceTable.tsx new file mode 100644 index 000000000..a39dcbd2a --- /dev/null +++ b/projects/app/src/pages/account/components/bill/InvoiceTable.tsx @@ -0,0 +1,207 @@ +import { getInvoiceRecords } from '@/web/support/wallet/bill/invoice/api'; +import MyBox from '@fastgpt/web/components/common/MyBox'; +import { useTranslation } from 'next-i18next'; +import { useEffect, useState } from 'react'; +import { + Box, + Button, + Flex, + FormLabel, + ModalBody, + Table, + TableContainer, + Tbody, + Td, + Th, + Thead, + Tr +} from '@chakra-ui/react'; +import { usePagination } from '@fastgpt/web/hooks/usePagination'; +import { InvoiceSchemaType } from '@fastgpt/global/support/wallet/bill/type'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import dayjs from 'dayjs'; +import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; +import MyModal from '@fastgpt/web/components/common/MyModal'; +const InvoiceTable = () => { + const { t } = useTranslation(); + const [invoiceDetailData, setInvoiceDetailData] = useState(''); + const { + data: invoices, + isLoading, + Pagination, + getData, + total + } = usePagination({ + api: getInvoiceRecords, + pageSize: 20, + defaultRequest: false + }); + + useEffect(() => { + getData(1); + }, [getData]); + + return ( + + +
+ + + + + + + + + + + {invoices.map((item, i) => ( + + + + + + + + ))} + +
#{t('common:user.Time')}{t('common:support.wallet.Amount')}{t('common:support.wallet.bill.Status')}
{i + 1} + {item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} + {t('common:pay.yuan', { amount: formatStorePrice2Read(item.amount) })} + + + + {item.status === 1 + ? t('common:common.submitted') + : t('common:common.have_done')} + + + + +
+ {total >= 20 && ( + + + + )} + {!isLoading && invoices.length === 0 && ( + + + + {t('common:support.wallet.no_invoice')} + + + )} +
+ {!!invoiceDetailData && ( + setInvoiceDetailData('')} /> + )} + + ); +}; + +export default InvoiceTable; + +function InvoiceDetailModal({ + invoice, + onClose +}: { + invoice: InvoiceSchemaType; + onClose: () => void; +}) { + const { t } = useTranslation(); + return ( + + + {t('common:support.wallet.invoice_detail')} + + } + > + + + + + + + + + + + + + + + ); +} + +function LabelItem({ label, value }: { label: string; value: string }) { + return ( + + {label} + {value} + + ); +} diff --git a/projects/app/src/pages/account/index.tsx b/projects/app/src/pages/account/index.tsx index 950d26da1..ad67a7c4b 100644 --- a/projects/app/src/pages/account/index.tsx +++ b/projects/app/src/pages/account/index.tsx @@ -16,7 +16,7 @@ import { useSystem } from '@fastgpt/web/hooks/useSystem'; const Promotion = dynamic(() => import('./components/Promotion')); const UsageTable = dynamic(() => import('./components/UsageTable')); -const BillTable = dynamic(() => import('./components/BillTable')); +const BillAndInvoice = dynamic(() => import('./components/bill/BillAndInvoice')); const InformTable = dynamic(() => import('./components/InformTable')); const ApiKeyTable = dynamic(() => import('./components/ApiKeyTable')); const Individuation = dynamic(() => import('./components/Individuation')); @@ -53,7 +53,8 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { } ] : []), - ...(feConfigs?.show_pay && userInfo?.team?.permission.hasWritePer + // ...(feConfigs?.show_pay && userInfo?.team?.permission.hasWritePer + ...(feConfigs?.show_pay || userInfo?.team?.permission.hasWritePer ? [ { icon: 'support/bill/payRecordLight', @@ -176,7 +177,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => { {currentTab === TabEnum.info && } {currentTab === TabEnum.promotion && } {currentTab === TabEnum.usage && } - {currentTab === TabEnum.bill && } + {currentTab === TabEnum.bill && } {currentTab === TabEnum.individuation && } {currentTab === TabEnum.inform && } {currentTab === TabEnum.apikey && } diff --git a/projects/app/src/pages/api/common/file/upload.ts b/projects/app/src/pages/api/common/file/upload.ts index da2726184..7eb503103 100644 --- a/projects/app/src/pages/api/common/file/upload.ts +++ b/projects/app/src/pages/api/common/file/upload.ts @@ -29,7 +29,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { maxSize: (global.feConfigs?.uploadFileMaxSize || 500) * 1024 * 1024 }); const { file, bucketName, metadata } = await upload.doUpload(req, res); - + filePaths.push(file.path); const { teamId, tmbId, outLinkUid } = await authChatCert({ req, authToken: true }); await authUploadLimit(outLinkUid || tmbId); diff --git a/projects/app/src/pages/app/detail/components/Publish/components/BasicInfo.tsx b/projects/app/src/pages/app/detail/components/Publish/components/BasicInfo.tsx index ce0b387c3..4210fb0d0 100644 --- a/projects/app/src/pages/app/detail/components/Publish/components/BasicInfo.tsx +++ b/projects/app/src/pages/app/detail/components/Publish/components/BasicInfo.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Box, Flex, Input } from '@chakra-ui/react'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import dayjs from 'dayjs'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import { UseFormRegister, UseFormSetValue } from 'react-hook-form'; import { OutLinkEditType } from '@fastgpt/global/support/outLink/type'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; diff --git a/projects/app/src/pages/app/detail/components/Publish/components/showShareLinkModal.tsx b/projects/app/src/pages/app/detail/components/Publish/components/showShareLinkModal.tsx index 5acee34f8..01a7969d4 100644 --- a/projects/app/src/pages/app/detail/components/Publish/components/showShareLinkModal.tsx +++ b/projects/app/src/pages/app/detail/components/Publish/components/showShareLinkModal.tsx @@ -2,7 +2,7 @@ import { useCopyData } from '@/web/common/hooks/useCopyData'; import { Box, Image, Flex, ModalBody } from '@chakra-ui/react'; import MyModal from '@fastgpt/web/components/common/MyModal'; import MyIcon from '@fastgpt/web/components/common/Icon'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; export type ShowShareLinkModalProps = { shareLink: string; diff --git a/projects/app/src/pages/dataset/detail/components/CollectionCard/HeaderTagPopOver.tsx b/projects/app/src/pages/dataset/detail/components/CollectionCard/HeaderTagPopOver.tsx index def249a14..efe6acf84 100644 --- a/projects/app/src/pages/dataset/detail/components/CollectionCard/HeaderTagPopOver.tsx +++ b/projects/app/src/pages/dataset/detail/components/CollectionCard/HeaderTagPopOver.tsx @@ -5,7 +5,7 @@ import MyBox from '@fastgpt/web/components/common/MyBox'; import { postCreateDatasetCollectionTag } from '@/web/core/dataset/api'; import { useContextSelector } from 'use-context-selector'; import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import { useCallback, useEffect, useState } from 'react'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { CollectionPageContext } from './Context'; diff --git a/projects/app/src/pages/dataset/detail/components/CollectionCard/TagsPopOver.tsx b/projects/app/src/pages/dataset/detail/components/CollectionCard/TagsPopOver.tsx index d4f422323..97662481a 100644 --- a/projects/app/src/pages/dataset/detail/components/CollectionCard/TagsPopOver.tsx +++ b/projects/app/src/pages/dataset/detail/components/CollectionCard/TagsPopOver.tsx @@ -5,7 +5,7 @@ import MyBox from '@fastgpt/web/components/common/MyBox'; import { postCreateDatasetCollectionTag, putDatasetCollectionById } from '@/web/core/dataset/api'; import { useContextSelector } from 'use-context-selector'; import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; import { useEffect, useMemo, useRef, useState } from 'react'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useDeepCompareEffect } from 'ahooks'; diff --git a/projects/app/src/pages/dataset/list/component/List.tsx b/projects/app/src/pages/dataset/list/component/List.tsx index aaa4ce70e..4b1e26684 100644 --- a/projects/app/src/pages/dataset/list/component/List.tsx +++ b/projects/app/src/pages/dataset/list/component/List.tsx @@ -34,7 +34,7 @@ import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import { useFolderDrag } from '@/components/common/folder/useFolderDrag'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { useI18n } from '@/web/context/I18n'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; function List() { const { setLoading } = useSystemStore(); diff --git a/projects/app/src/pages/dataset/list/context.tsx b/projects/app/src/pages/dataset/list/context.tsx index b8f999ed3..53c909823 100644 --- a/projects/app/src/pages/dataset/list/context.tsx +++ b/projects/app/src/pages/dataset/list/context.tsx @@ -20,7 +20,7 @@ import dynamic from 'next/dynamic'; import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants'; import { DatasetItemType, DatasetListItemType } from '@fastgpt/global/core/dataset/type'; import { EditResourceInfoFormType } from '@/components/common/Modal/EditResourceModal'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'next-i18next'; const MoveModal = dynamic(() => import('@/components/common/folder/MoveModal')); diff --git a/projects/app/src/web/support/user/team/api.ts b/projects/app/src/web/support/user/team/api.ts index 282f3e7a1..9a7c99b6b 100644 --- a/projects/app/src/web/support/user/team/api.ts +++ b/projects/app/src/web/support/user/team/api.ts @@ -14,6 +14,7 @@ import { TeamMemberSchema } from '@fastgpt/global/support/user/team/type.d'; import { FeTeamPlanStatusType, TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type'; +import { TeamInvoiceHeaderType } from '@fastgpt/global/support/user/team/type'; /* --------------- team ---------------- */ export const getTeamList = (status: `${TeamMemberSchema['status']}`) => @@ -61,3 +62,9 @@ export const getTeamPlanStatus = () => GET(`/support/user/team/plan/getTeamPlanStatus`, { maxQuantity: 1 }); export const getTeamPlans = () => GET(`/proApi/support/user/team/plan/getTeamPlans`); + +export const getTeamInvoiceHeader = () => + GET(`/proApi/support/user/team/invoiceAccount/getTeamInvoiceHeader`); + +export const updateTeamInvoiceHeader = (data: TeamInvoiceHeaderType) => + POST(`/proApi/support/user/team/invoiceAccount/update`, data); diff --git a/projects/app/src/web/support/wallet/bill/invoice/api.ts b/projects/app/src/web/support/wallet/bill/invoice/api.ts new file mode 100644 index 000000000..74c0572be --- /dev/null +++ b/projects/app/src/web/support/wallet/bill/invoice/api.ts @@ -0,0 +1,20 @@ +import { RequestPaging } from '@/types'; +import { GET, POST } from '@/web/common/api/request'; +import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants'; +import { InvoiceType } from '@fastgpt/global/support/wallet/bill/type'; +import { InvoiceSchemaType } from '../../../../../../../../packages/global/support/wallet/bill/type'; +export type invoiceBillDataType = { + type: BillTypeEnum; + price: number; + createTime: Date; + _id: string; +}; + +export const getInvoiceBillsList = () => + GET(`/proApi/support/wallet/bill/invoice/unInvoiceList`); + +export const submitInvoice = (data: InvoiceType) => + POST(`/proApi/support/wallet/bill/invoice/submit`, data); + +export const getInvoiceRecords = (data: RequestPaging) => + POST(`/proApi/support/wallet/bill/invoice/records`, data);