diff --git a/frontend/providers/applaunchpad/src/constants/app.ts b/frontend/providers/applaunchpad/src/constants/app.ts index b89d723a2..f0e820e5c 100644 --- a/frontend/providers/applaunchpad/src/constants/app.ts +++ b/frontend/providers/applaunchpad/src/constants/app.ts @@ -78,3 +78,8 @@ export const appDeployKey = 'cloud.sealos.io/app-deploy-manager'; export const domainKey = `cloud.sealos.io/app-deploy-manager-domain`; export const gpuNodeSelectorKey = 'nvidia.com/gpu.product'; export const gpuResourceKey = 'nvidia.com/gpu'; +export enum Coin { + cny = 'cny', + shellCoin = 'shellCoin', + usd = 'usd' +} diff --git a/frontend/providers/applaunchpad/src/pages/api/platform/getInitData.ts b/frontend/providers/applaunchpad/src/pages/api/platform/getInitData.ts index 8fb204ff5..ac853e040 100644 --- a/frontend/providers/applaunchpad/src/pages/api/platform/getInitData.ts +++ b/frontend/providers/applaunchpad/src/pages/api/platform/getInitData.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/services/backend/response'; import type { FormSliderListType } from '@/types'; import { readFileSync } from 'fs'; -import { noGpuSliderKey } from '@/constants/app'; +import { Coin, noGpuSliderKey } from '@/constants/app'; export type Response = { SEALOS_DOMAIN: string; @@ -10,6 +10,7 @@ export type Response = { INGRESS_SECRET: string; SHOW_EVENT_ANALYZE: boolean; FORM_SLIDER_LIST_CONFIG: FormSliderListType; + CURRENCY: Coin; }; export const defaultVal = { @@ -37,14 +38,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) global.FormSliderListConfig = defaultVal; } - jsonRes(res, { data: { SEALOS_DOMAIN: process.env.SEALOS_DOMAIN || 'cloud.sealos.io', DOMAIN_PORT: process.env.DOMAIN_PORT || '', INGRESS_SECRET: process.env.INGRESS_SECRET || 'wildcard-cert', SHOW_EVENT_ANALYZE: !!process.env.FASTGPT_KEY, - FORM_SLIDER_LIST_CONFIG: global.FormSliderListConfig + FORM_SLIDER_LIST_CONFIG: global.FormSliderListConfig, + CURRENCY: (process.env['CURRENCY'] || Coin.shellCoin) as Coin } }); } diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/components/PriceBox.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/components/PriceBox.tsx index 51ed5d4da..0e23ae923 100644 --- a/frontend/providers/applaunchpad/src/pages/app/edit/components/PriceBox.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/edit/components/PriceBox.tsx @@ -2,7 +2,29 @@ import React, { useMemo } from 'react'; import { Box, Flex } from '@chakra-ui/react'; import { useGlobalStore } from '@/store/global'; import { useTranslation } from 'next-i18next'; - +import { Text, Icon } from '@chakra-ui/react'; +import { CURRENCY } from '@/store/static'; +function Currencysymbol({ + type = 'shellCoin', + ...props +}: { + type?: 'shellCoin' | 'cny' | 'usd'; +} & Pick[0], 'w' | 'h' | 'color'>) { + return type === 'shellCoin' ? ( + + + + ) : type === 'cny' ? ( + ¥ + ) : ( + $ + ); +} const PriceBox = ({ cpu, memory, @@ -40,7 +62,12 @@ const PriceBox = ({ const podScale = (val: number) => { const min = (val * pods[0]).toFixed(2); const max = (val * pods[1]).toFixed(2); - return pods[0] === pods[1] ? `¥${min}` : `¥${min} ~ ${max}`; + return ( + + + {pods[0] === pods[1] ? `${min}` : `${min} ~ ${max}`} + + ); }; return [ diff --git a/frontend/providers/applaunchpad/src/store/static.ts b/frontend/providers/applaunchpad/src/store/static.ts index 7a87584e8..1db8f4065 100644 --- a/frontend/providers/applaunchpad/src/store/static.ts +++ b/frontend/providers/applaunchpad/src/store/static.ts @@ -1,10 +1,11 @@ import { getInitData } from '@/api/platform'; +import { Coin } from '@/constants/app'; export let SEALOS_DOMAIN = 'cloud.sealos.io'; export let DOMAIN_PORT = ''; export let INGRESS_SECRET = 'wildcard-cert'; export let SHOW_EVENT_ANALYZE = false; - +export let CURRENCY = Coin.shellCoin; export const loadInitData = async () => { try { const res = await getInitData(); @@ -12,11 +13,13 @@ export const loadInitData = async () => { DOMAIN_PORT = res.DOMAIN_PORT; INGRESS_SECRET = res.INGRESS_SECRET; SHOW_EVENT_ANALYZE = res.SHOW_EVENT_ANALYZE; + CURRENCY = res.CURRENCY; return { SEALOS_DOMAIN, DOMAIN_PORT, INGRESS_SECRET, + CURRENCY, FORM_SLIDER_LIST_CONFIG: res.FORM_SLIDER_LIST_CONFIG }; } catch (error) {} diff --git a/frontend/providers/costcenter/.env b/frontend/providers/costcenter/.env index a7766c4f3..14e689c6a 100644 --- a/frontend/providers/costcenter/.env +++ b/frontend/providers/costcenter/.env @@ -1,5 +1,7 @@ # for open transfer # TRANSFER_ENABLED="true" +# WECHAT_ENABLED="true" +# STRIPE_ENABLED="true" # for open transfer # RECHARGE_ENABLED="true" @@ -7,8 +9,10 @@ # for open GPU measure # GPU_ENABLED="true" + # for Stripe pay # STRIPE_PUB + # for open invoice # INVOICE_ENABLED="true" # MONGODB_URI diff --git a/frontend/providers/costcenter/public/locales/en/common.json b/frontend/providers/costcenter/public/locales/en/common.json index 7dc89993f..0d4f0f364 100644 --- a/frontend/providers/costcenter/public/locales/en/common.json +++ b/frontend/providers/costcenter/public/locales/en/common.json @@ -66,6 +66,8 @@ "he payee cannot be oneself": "The payee cannot be oneself", "True Amount": "True Amount", "Get Code": "verification", + "Stripe Success": "pay with Stripe successfully", + "Stripe Cancel": "cancel to pay with Stripe", "orders": { "list": "Order List", "invoiceAmount": "Invoice Amount", diff --git a/frontend/providers/costcenter/public/locales/zh/common.json b/frontend/providers/costcenter/public/locales/zh/common.json index 412246e83..0976689c3 100644 --- a/frontend/providers/costcenter/public/locales/zh/common.json +++ b/frontend/providers/costcenter/public/locales/zh/common.json @@ -66,6 +66,8 @@ "Transfer Success": "转账成功", "True Amount": "实际金额", "Get Code": "获取验证码", + "Stripe Success": "Stripe 支付完成", + "Stripe Cancel": "Stripe 支付取消", "orders": { "list": "订单列表", "invoiceAmount": "发票金额", diff --git a/frontend/providers/costcenter/src/components/CurrencySymbol.tsx b/frontend/providers/costcenter/src/components/CurrencySymbol.tsx new file mode 100644 index 000000000..090ffee84 --- /dev/null +++ b/frontend/providers/costcenter/src/components/CurrencySymbol.tsx @@ -0,0 +1,22 @@ +import { Text, Icon } from '@chakra-ui/react'; +export default function currencysymbol({ + type = 'shellCoin', + ...props +}: { + type?: 'shellCoin' | 'cny' | 'usd'; +} & Pick[0], 'w' | 'h' | 'color'>) { + return type === 'shellCoin' ? ( + + + + ) : type === 'cny' ? ( + ¥ + ) : ( + $ + ); +} diff --git a/frontend/providers/costcenter/src/components/billing/billingTable.tsx b/frontend/providers/costcenter/src/components/billing/billingTable.tsx index f5c7f346d..dbacd6f9b 100644 --- a/frontend/providers/costcenter/src/components/billing/billingTable.tsx +++ b/frontend/providers/costcenter/src/components/billing/billingTable.tsx @@ -5,12 +5,13 @@ import lineUp from '@/assert/lineUp.svg'; import { Flex, Img, Table, TableContainer, Tbody, Td, Text, Th, Thead, Tr } from '@chakra-ui/react'; import { format, parseISO } from 'date-fns'; import { formatMoney } from '@/utils/format'; -import shellCoin from '@/assert/shell_coin.svg'; import { useTranslation } from 'next-i18next'; import useEnvStore from '@/stores/env'; +import CurrencySymbol from '../CurrencySymbol'; export function BillingTable({ data }: { data: BillingItem[] }) { const { t } = useTranslation(); const gpuEnabled = useEnvStore((state) => state.gpuEnabled); + const currency = useEnvStore((s) => s.currency); return ( @@ -28,7 +29,12 @@ export function BillingTable({ data }: { data: BillingItem[] }) { background: '#F1F4F6' }} > - {t(item)} + + {t(item)} + {['CPU', 'Gpu', 'Memory', 'Storage', 'Total Amount'].includes(item) && ( + + )} + ))} @@ -80,57 +86,13 @@ export function BillingTable({ data }: { data: BillingItem[] }) { - - - - + + + {gpuEnabled && ( - + )} - + ); })} diff --git a/frontend/providers/costcenter/src/components/cost_overview/buget.tsx b/frontend/providers/costcenter/src/components/cost_overview/buget.tsx index 84035cbfe..387091e88 100644 --- a/frontend/providers/costcenter/src/components/cost_overview/buget.tsx +++ b/frontend/providers/costcenter/src/components/cost_overview/buget.tsx @@ -6,10 +6,12 @@ import { useMemo } from 'react'; import { formatMoney } from '@/utils/format'; import { useTranslation } from 'next-i18next'; import useBillingData from '@/hooks/useBillingData'; -import shellcoin from '@/assert/shell_coin.svg'; +import CurrencySymbol from '../CurrencySymbol'; +import useEnvStore from '@/stores/env'; export function Buget() { const { t } = useTranslation(); const { data } = useBillingData(); + const currency = useEnvStore((s) => s.currency); const [_out, _in] = useMemo( () => (data?.data?.status.item || []).reduce<[number, number]>( @@ -52,8 +54,8 @@ export function Buget() { {t(v.title)} - - + + {v.value} diff --git a/frontend/providers/costcenter/src/components/cost_overview/components/RechargeModal.tsx b/frontend/providers/costcenter/src/components/cost_overview/components/RechargeModal.tsx index 30ec2bc9f..68c5fb7eb 100644 --- a/frontend/providers/costcenter/src/components/cost_overview/components/RechargeModal.tsx +++ b/frontend/providers/costcenter/src/components/cost_overview/components/RechargeModal.tsx @@ -1,4 +1,3 @@ -import shellcoin from '@/assert/shell_coin.svg'; import { Box, Button, @@ -33,6 +32,8 @@ import stripe_icon from '@/assert/bi_stripe.svg'; import { Spinner } from '@chakra-ui/react'; import { Stripe } from '@stripe/stripe-js'; import type { AxiosInstance } from 'axios'; +import useEnvStore from '@/stores/env'; +import Currencysymbol from '@/components/CurrencySymbol'; const StripeForm = (props: { tradeNO?: string; complete: number; @@ -123,6 +124,7 @@ const BonusBox = (props: { amount: number; }) => { const { t } = useTranslation(); + const currency = useEnvStore((s) => s.currency); return ( - - + + {props.amount} @@ -308,7 +310,7 @@ const RechargeModal = forwardRef( }, [isSuccess, ratios, steps] ); - + const { stripeEnabled, wechatEnabled } = useEnvStore(); useEffect(() => { if (steps && steps.length > 0) { setAmount(steps[0]); @@ -322,10 +324,11 @@ const RechargeModal = forwardRef( }; const handleStripeConfirm = () => { - setComplete(1); setPayType('stripe'); + setComplete(1); createPaymentRes.mutate(); }; + const currency = useEnvStore((s) => s.currency); return ( @@ -352,8 +355,8 @@ const RechargeModal = forwardRef( {t('Balance')} - - + + {formatMoney(balance).toFixed(2)} @@ -399,7 +402,7 @@ const RechargeModal = forwardRef( variant={'unstyled'} onChange={(str, v) => (str.trim() ? setAmount(v) : setAmount(0))} > - + @@ -434,34 +437,38 @@ const RechargeModal = forwardRef( - - + {stripeEnabled && ( + + )} + {wechatEnabled && ( + + )} diff --git a/frontend/providers/costcenter/src/components/cost_overview/components/TransferModal.tsx b/frontend/providers/costcenter/src/components/cost_overview/components/TransferModal.tsx index fdd2eac95..105ecbdd1 100644 --- a/frontend/providers/costcenter/src/components/cost_overview/components/TransferModal.tsx +++ b/frontend/providers/costcenter/src/components/cost_overview/components/TransferModal.tsx @@ -1,5 +1,5 @@ import request from '@/service/request'; -import shellcoin from '@/assert/shell_coin.svg'; +import Currencysymbol from '@/components/CurrencySymbol'; import { Button, Flex, @@ -15,7 +15,6 @@ import { NumberInput, NumberInputField, NumberInputStepper, - Spinner, Text, useDisclosure, useToast @@ -27,6 +26,7 @@ import { deFormatMoney, formatMoney } from '@/utils/format'; import { useTranslation } from 'next-i18next'; import { ApiResp } from '@/types/api'; import { TransferState, transferStatus } from '@/types/Transfer'; +import useEnvStore from '@/stores/env'; const TransferModal = forwardRef( ( @@ -51,6 +51,7 @@ const TransferModal = forwardRef( }), [] ); + const currency = useEnvStore((s) => s.currency); const { t } = useTranslation(); const { isOpen, onOpen, onClose: _onClose } = useDisclosure(); const [to, setTo] = useState(''); @@ -216,8 +217,8 @@ const TransferModal = forwardRef( onChange={(str, v) => (str.trim() ? setAmount(v) : setAmount(0))} isDisabled={mutation.isLoading} > - - + + @@ -231,8 +232,8 @@ const TransferModal = forwardRef( {t('Balance')} - - + + {formatMoney(balance).toFixed(2)}
- {!item.type ? ( - - - {formatMoney(item.costs?.cpu || 0)} - - ) : ( - '-' - )} - - {!item.type ? ( - - - {formatMoney(item.costs?.memory || 0)}{' '} - - ) : ( - '-' - )} - - {!item.type ? ( - - - {formatMoney(item.costs?.storage || 0)}{' '} - - ) : ( - '-' - )} - {!item.type ? {formatMoney(item.costs?.cpu || 0)} : '-'}{!item.type ? {formatMoney(item.costs?.memory || 0)} : '-'}{!item.type ? {formatMoney(item.costs?.storage || 0)} : '-'} - {!item.type ? ( - - - {formatMoney(item.costs?.gpu || 0)}{' '} - - ) : ( - '-' - )} - {!item.type ? {formatMoney(item.costs?.gpu || 0)} : '-'} - { - - - {formatMoney(item.amount)} - - } - {{formatMoney(item.amount)}}
@@ -32,7 +35,10 @@ export function InvoiceTable({ background: '#F1F4F6' }} > - {t(item)} + + {t(item)} + {item !== 'Order Number' && } + ))} @@ -57,7 +63,7 @@ export function InvoiceTable({ - + ))} diff --git a/frontend/providers/costcenter/src/components/valuation/predictCard.tsx b/frontend/providers/costcenter/src/components/valuation/predictCard.tsx index b0d59c594..1c8e281da 100644 --- a/frontend/providers/costcenter/src/components/valuation/predictCard.tsx +++ b/frontend/providers/costcenter/src/components/valuation/predictCard.tsx @@ -1,14 +1,15 @@ import useBillingStore from '@/stores/billing'; import useEnvStore from '@/stores/env'; import { displayMoney } from '@/utils/format'; -import { Flex, Img } from '@chakra-ui/react'; +import { Flex, Img, Text } from '@chakra-ui/react'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import shellcoin from '@/assert/shell_coin.svg'; +import CurrencySymbol from '../CurrencySymbol'; export default function PredictCard() { const { t } = useTranslation(); const total = t('total'); const state = useBillingStore(); + const currency = useEnvStore((s) => s.currency); const gpuEnabled = useEnvStore((state) => state.gpuEnabled); const leastCost = useMemo(() => { const origin = [ @@ -45,8 +46,8 @@ export default function PredictCard() { {item.name} - - {item.cost} + + {item.cost} ))} diff --git a/frontend/providers/costcenter/src/pages/_app.tsx b/frontend/providers/costcenter/src/pages/_app.tsx index a72187194..270a1b68f 100644 --- a/frontend/providers/costcenter/src/pages/_app.tsx +++ b/frontend/providers/costcenter/src/pages/_app.tsx @@ -72,11 +72,15 @@ const App = ({ Component, pageProps }: AppProps) => { (async () => { try { const { data } = await request>('/api/enabled'); - state.setInvoiceEnabled(!!data?.invoiceEnabled); - state.setTransferEnabled(!!data?.transferEnabled); - state.setRechargeEnabled(!!data?.rechargeEnabled); - state.setGpuEnabled(!!data?.gpuEnabled); - state.setStripe(data?.stripePub || ''); + state.setEnv('invoiceEnabled', !!data?.invoiceEnabled); + state.setEnv('transferEnabled', !!data?.transferEnabled); + state.setEnv('rechargeEnabled', !!data?.rechargeEnabled); + state.setEnv('currency', data?.currency || 'shellCoin'); + state.setEnv('gpuEnabled', !!data?.gpuEnabled); + const stripeE = !!data?.stripeEnabled; + state.setEnv('stripeEnabled', stripeE); + stripeE && state.setStripe(data?.stripePub || ''); + state.setEnv('wechatEnabled', !!data?.wechatEnabled); } catch (error) { console.error('get env error'); } diff --git a/frontend/providers/costcenter/src/pages/api/enabled.ts b/frontend/providers/costcenter/src/pages/api/enabled.ts index 71f73f146..6aff7541d 100644 --- a/frontend/providers/costcenter/src/pages/api/enabled.ts +++ b/frontend/providers/costcenter/src/pages/api/enabled.ts @@ -1,4 +1,11 @@ -import { enabelGpu, enableInvoice, enableRecharge, enableTransfer } from '@/service/enabled'; +import { + enableGpu, + enableInvoice, + enableRecharge, + enableStripe, + enableTransfer, + enableWechat +} from '@/service/enabled'; import { jsonRes } from '@/service/backend/response'; import { NextApiRequest, NextApiResponse } from 'next'; import { EnvData } from '@/types/env'; @@ -10,8 +17,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) rechargeEnabled: enableRecharge(), transferEnabled: enableTransfer(), invoiceEnabled: enableInvoice(), - gpuEnabled: enabelGpu(), - stripePub: process.env['STRIPE_PUB'] || '' + gpuEnabled: enableGpu(), + stripePub: process.env['STRIPE_PUB'] || '', + stripeEnabled: enableStripe(), + wechatEnabled: enableWechat(), + currency: (process.env['CURRENCY'] as EnvData['currency']) || 'shellCoin' }, code: 200 }); diff --git a/frontend/providers/costcenter/src/pages/cost_overview/index.module.scss b/frontend/providers/costcenter/src/pages/cost_overview/index.module.scss deleted file mode 100644 index 15e0cb183..000000000 --- a/frontend/providers/costcenter/src/pages/cost_overview/index.module.scss +++ /dev/null @@ -1,17 +0,0 @@ -.container { - table thead tr { - background: #f8f8fa; - } - - td, - th { - border: none; - text-align: center; - &:first-child { - text-align: left; - } - &:last-child { - text-align: right; - } - } -} diff --git a/frontend/providers/costcenter/src/pages/cost_overview/index.tsx b/frontend/providers/costcenter/src/pages/cost_overview/index.tsx index 716b11e0a..a3c65e01b 100644 --- a/frontend/providers/costcenter/src/pages/cost_overview/index.tsx +++ b/frontend/providers/costcenter/src/pages/cost_overview/index.tsx @@ -2,7 +2,7 @@ import bar_icon from '@/assert/bar_chart_4_bars_black.svg'; import { BillingTable } from '@/components/billing/billingTable'; import SelectRange from '@/components/billing/selectDateRange'; import useNotEnough from '@/hooks/useNotEnough'; -import { Box, Flex, Heading, Img } from '@chakra-ui/react'; +import { Box, Flex, Heading, Img, useToast } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { useEffect, useMemo } from 'react'; @@ -17,6 +17,7 @@ import { QueryClient } from '@tanstack/react-query'; import request from '@/service/request'; import useBillingStore from '@/stores/billing'; import { isSameDay, isSameHour, parseISO } from 'date-fns'; +import { useRouter } from 'next/router'; function CostOverview() { const { t, i18n } = useTranslation(); const updateCPU = useBillingStore((state) => state.updateCpu); @@ -35,6 +36,29 @@ function CostOverview() { () => data?.data?.status.item.filter((v) => v.type === 0) || [], [data] ); + const totast = useToast(); + const router = useRouter(); + const { stripeState } = router.query; + useEffect(() => { + if (stripeState === 'success') { + totast({ + status: 'success', + duration: 3000, + title: t('Stripe Success'), + isClosable: true, + position: 'top' + }); + } else if (stripeState === 'error') { + totast({ + status: 'error', + duration: 3000, + title: t('Stripe Cancel'), + isClosable: true, + position: 'top' + }); + } + !!stripeState && router.replace(router.pathname); + }, [stripeState]); useEffect(() => { if (costBillingItems.length === 0) return; const time = parseISO(costBillingItems[0].time); diff --git a/frontend/providers/costcenter/src/pages/create_invoice/index.tsx b/frontend/providers/costcenter/src/pages/create_invoice/index.tsx index 0a1d7ec25..e3c2e4de8 100644 --- a/frontend/providers/costcenter/src/pages/create_invoice/index.tsx +++ b/frontend/providers/costcenter/src/pages/create_invoice/index.tsx @@ -1,4 +1,3 @@ -// import { MockBillingData } from '@/mock/billing'; import { InvoiceTable } from '@/components/invoice/invoiceTable'; import { Box, Button, Flex, Heading, Img, Input, Text } from '@chakra-ui/react'; import { useEffect, useRef, useState } from 'react'; diff --git a/frontend/providers/costcenter/src/pages/index.tsx b/frontend/providers/costcenter/src/pages/index.tsx index 6515a2bac..c212fc498 100644 --- a/frontend/providers/costcenter/src/pages/index.tsx +++ b/frontend/providers/costcenter/src/pages/index.tsx @@ -1,12 +1,11 @@ import { useRouter } from 'next/router'; -import { useEffect } from 'react'; export default function Index() { const router = useRouter(); - - useEffect(() => { - router.push('/cost_overview'); - }, [router]); + router.push({ + pathname: '/cost_overview', + query: router.query + }); return
; } diff --git a/frontend/providers/costcenter/src/pages/valuation/index.tsx b/frontend/providers/costcenter/src/pages/valuation/index.tsx index f893a587e..47e7c544a 100644 --- a/frontend/providers/costcenter/src/pages/valuation/index.tsx +++ b/frontend/providers/costcenter/src/pages/valuation/index.tsx @@ -15,7 +15,7 @@ import OuterLink from '@/components/outerLink'; import NotFound from '@/components/notFound'; import PredictCard from '@/components/valuation/predictCard'; import useEnvStore from '@/stores/env'; -import shellcoin from '@/assert/shell_coin.svg'; +import CurrencySymbol from '@/components/CurrencySymbol'; type CardItem = { title: string; price: number[]; @@ -46,6 +46,7 @@ function Valuation() { const { t, i18n } = useTranslation(); const cookie = getCookie('NEXT_LOCALE'); const gpuEnabled = useEnvStore((state) => state.gpuEnabled); + const currency = useEnvStore((s) => s.currency); useEffect(() => { i18n.changeLanguage(cookie); }, [cookie, i18n]); @@ -111,12 +112,14 @@ function Valuation() { justifyContent="center" alignContent={'center'} > - {item.price[0]} - - {item.unit} / {t('Hour')} - + + + + {item.unit} / {t('Hour')} + + {CYCLE.map((_item, idx) => ( {item.price[idx + 1]} - - {`${item.unit} / ${t(_item)}`} + + {`${item.unit} / ${t(_item)}`} ))} @@ -154,17 +157,14 @@ function Valuation() { pt="12px" px="24px" > - - - {`${item.price}`} - + {`${item.price}`} {item.name} - + {`${gpuProps.unit} / ${t('Hour')}`} diff --git a/frontend/providers/costcenter/src/service/enabled.ts b/frontend/providers/costcenter/src/service/enabled.ts index 3bf8caf75..8693fd74f 100644 --- a/frontend/providers/costcenter/src/service/enabled.ts +++ b/frontend/providers/costcenter/src/service/enabled.ts @@ -8,4 +8,7 @@ export const enableInvoice = () => !!process.env['ALI_SIGN_NAME'] && !!process.env['ALI_TEMPLATE_CODE'] && !!process.env['MONGODB_URI']; -export const enabelGpu = () => !!process.env['GPU_ENABLED']; +export const enableGpu = () => !!process.env['GPU_ENABLED']; +export const enableWechat = () => process.env['WECHAT_ENABLED'] === 'true'; +export const enableStripe = () => + process.env['STRIPE_ENABLED'] === 'true' && !!process.env['STRIPE_PUB']; diff --git a/frontend/providers/costcenter/src/stores/env.ts b/frontend/providers/costcenter/src/stores/env.ts index 5e837a026..47e76d4b8 100644 --- a/frontend/providers/costcenter/src/stores/env.ts +++ b/frontend/providers/costcenter/src/stores/env.ts @@ -1,30 +1,31 @@ -import { Stripe, loadStripe } from '@stripe/stripe-js'; +import { loadStripe } from '@stripe/stripe-js'; import { create } from 'zustand'; type EnvState = { rechargeEnabled: boolean; transferEnabled: boolean; invoiceEnabled: boolean; gpuEnabled: boolean; + wechatEnabled: boolean; + stripeEnabled: boolean; + currency: 'shellCoin' | 'cny' | 'usd'; stripePromise: ReturnType; - setRechargeEnabled: (enabled: boolean) => void; - setTransferEnabled: (enabled: boolean) => void; - setInvoiceEnabled: (enabled: boolean) => void; - setGpuEnabled: (enabled: boolean) => void; setStripe: (pub: string) => void; + setEnv: >( + key: T, + value: EnvState[T] + ) => void; }; const useEnvStore = create((set, get) => ({ rechargeEnabled: false, transferEnabled: false, invoiceEnabled: false, + wechatEnabled: false, + stripeEnabled: false, gpuEnabled: false, + currency: 'shellCoin', stripePromise: Promise.resolve(null), - setRechargeEnabled: (enabled: boolean) => set({ rechargeEnabled: enabled }), - setTransferEnabled: (enabled: boolean) => set({ transferEnabled: enabled }), - setInvoiceEnabled: (enabled: boolean) => set({ invoiceEnabled: enabled }), - setGpuEnabled(enabled) { - set({ gpuEnabled: enabled }); - }, - setStripe: (pub: string) => set({ stripePromise: loadStripe(pub) }) + setStripe: (pub: string) => set({ stripePromise: loadStripe(pub) }), + setEnv: (k, v) => set({ [k]: v }) })); export default useEnvStore; diff --git a/frontend/providers/costcenter/src/types/env.ts b/frontend/providers/costcenter/src/types/env.ts index ccfc12db7..fc1805e85 100644 --- a/frontend/providers/costcenter/src/types/env.ts +++ b/frontend/providers/costcenter/src/types/env.ts @@ -1,6 +1,9 @@ export type EnvData = { rechargeEnabled: boolean; transferEnabled: boolean; + stripeEnabled: boolean; + wechatEnabled: boolean; + currency: 'shellCoin' | 'cny' | 'usd'; invoiceEnabled: boolean; gpuEnabled: boolean; stripePub: string; diff --git a/frontend/providers/template/next-i18next.config.js b/frontend/providers/template/next-i18next.config.js index b39aac163..745f9f71e 100644 --- a/frontend/providers/template/next-i18next.config.js +++ b/frontend/providers/template/next-i18next.config.js @@ -7,6 +7,6 @@ module.exports = { i18n: { defaultLocale: 'en', locales: ['en', 'zh', 'zh-Hans'], - localeDetection: false, - }, -} + localeDetection: false + } +}; diff --git a/frontend/providers/template/next.config.js b/frontend/providers/template/next.config.js index 4d2553420..907c382a5 100644 --- a/frontend/providers/template/next.config.js +++ b/frontend/providers/template/next.config.js @@ -1,8 +1,8 @@ /** @type {import('next').NextConfig} */ -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin -const { i18n } = require('./next-i18next.config') -const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : [] -const path = require('path') +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const { i18n } = require('./next-i18next.config'); +const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : []; +const path = require('path'); const nextConfig = { i18n, output: 'standalone', @@ -15,14 +15,14 @@ const nextConfig = { issuer: /\.[jt]sx?$/, use: ['@svgr/webpack'] } - ]) - config.plugins = [...config.plugins, ...analyzer] - return config + ]); + config.plugins = [...config.plugins, ...analyzer]; + return config; }, experimental: { // this includes files from the monorepo base two directories up outputFileTracingRoot: path.join(__dirname, '../../') } -} +}; -module.exports = nextConfig +module.exports = nextConfig; diff --git a/frontend/providers/template/src/components/LangSelect/index.tsx b/frontend/providers/template/src/components/LangSelect/index.tsx index 838e8a2b4..3e1401a1d 100644 --- a/frontend/providers/template/src/components/LangSelect/index.tsx +++ b/frontend/providers/template/src/components/LangSelect/index.tsx @@ -9,7 +9,8 @@ const langIcon = ( width="1em" height="1em" fill="currentColor" - aria-hidden="true"> + aria-hidden="true" + > = (props) => { onClick={() => { setLangStore(key); i18n.changeLanguage(key); - }}> + }} + > {lang.label} ))} diff --git a/frontend/providers/template/src/pages/deploy/components/Form.tsx b/frontend/providers/template/src/pages/deploy/components/Form.tsx index 7662480e7..e57d60e0b 100644 --- a/frontend/providers/template/src/pages/deploy/components/Form.tsx +++ b/frontend/providers/template/src/pages/deploy/components/Form.tsx @@ -62,7 +62,8 @@ const Form = ({ w="200px" className="template-dynamic-label" color={'#333'} - userSelect={'none'}> + userSelect={'none'} + > {item?.label} {item?.required && ( @@ -92,14 +93,16 @@ const Form = ({ alignItems="center" h={'160px'} w={'100%'} - flexDirection="column"> + flexDirection="column" + > + alignItems={'center'} + > diff --git a/frontend/providers/template/src/pages/deploy/components/Header.tsx b/frontend/providers/template/src/pages/deploy/components/Header.tsx index b2dfcacf4..9de87780a 100644 --- a/frontend/providers/template/src/pages/deploy/components/Header.tsx +++ b/frontend/providers/template/src/pages/deploy/components/Header.tsx @@ -50,7 +50,8 @@ const Header = ({ h={'80px'} mt={'32px'} alignItems={'center'} - backgroundColor={'rgba(255, 255, 255, 0.90)'}> + backgroundColor={'rgba(255, 255, 255, 0.90)'} + > + border={' 1px solid #DEE0E2'} + > @@ -81,7 +83,8 @@ const Header = ({ mt={'8px'} fontSize={'12px'} color={'5A646E'} - fontWeight={400}> + fontWeight={400} + > {templateDetail?.spec?.description} @@ -95,7 +98,8 @@ const Header = ({ bg={'myWhite.600'} borderColor={'myGray.200'} variant={'base'} - onClick={handleExportYaml}> + onClick={handleExportYaml} + > {t('Export')} Yaml
{format(item.createdTime, 'MM-dd HH:mm')}{'¥' + item.amount}{item.amount}