feat(api, web): интеграция Macloud и VDSina через унифицированный UserAPI
Docker / build (push) Has been cancelled
Docker / build (push) Has been cancelled
Один модуль userapi для идентичного API обоих хостеров: синк VPS, баланса, тарифов и пополнений. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -14,7 +14,7 @@ import { providerAccountSchema, type ProviderAccountFormValues } from '@/lib/sch
|
||||
import type { BillingMode, Provider } from '@/types/entities'
|
||||
import { billingModeLabel } from '@/lib/format'
|
||||
import { api, ApiError } from '@/lib/api-client'
|
||||
import { accountCredentialLabels } from '@/lib/provider-sync'
|
||||
import { accountCredentialLabels, isUserApiType } from '@/lib/provider-sync'
|
||||
|
||||
const EMPTY: ProviderAccountFormValues = {
|
||||
providerId: '',
|
||||
@@ -84,9 +84,11 @@ export function ProviderAccountEditSheet({
|
||||
onOpenChange={onOpenChange}
|
||||
title={isEdit ? 'Редактировать аккаунт' : 'Новый аккаунт'}
|
||||
description={
|
||||
initialProvider?.apiType === '4vps'
|
||||
? 'Panel ID и API Key хранятся на сервере и используются для синка с 4VPS'
|
||||
: 'API-креды хранятся на сервере и используются для синка с BILLmanager'
|
||||
isUserApiType(initialProvider?.apiType)
|
||||
? 'API Token хранится на сервере и используется для синка с UserAPI'
|
||||
: initialProvider?.apiType === '4vps'
|
||||
? 'Panel ID и API Key хранятся на сервере и используются для синка с 4VPS'
|
||||
: 'API-креды хранятся на сервере и используются для синка с BILLmanager'
|
||||
}
|
||||
schema={providerAccountSchema as unknown as ZodType<ProviderAccountFormValues>}
|
||||
defaultValues={defaultValues}
|
||||
@@ -103,6 +105,7 @@ export function ProviderAccountEditSheet({
|
||||
const apiCredentials = buildApiCredentials(apiLogin, apiPassword)
|
||||
const canTest = Boolean(apiBaseUrl && apiCredentials)
|
||||
const credLabels = accountCredentialLabels(provider?.apiType)
|
||||
const tokenOnly = isUserApiType(provider?.apiType)
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -118,14 +121,16 @@ export function ProviderAccountEditSheet({
|
||||
<FormField label="Название" htmlFor="acc-name" error={errors.name?.message} invalid={!!errors.name}>
|
||||
<Input id="acc-name" aria-invalid={!!errors.name} {...register('name')} />
|
||||
</FormField>
|
||||
<FormField label={credLabels.loginLabel} htmlFor="acc-login">
|
||||
<Input
|
||||
id="acc-login"
|
||||
autoComplete="off"
|
||||
placeholder={credLabels.loginPlaceholder || undefined}
|
||||
{...register('apiLogin')}
|
||||
/>
|
||||
</FormField>
|
||||
{!tokenOnly ? (
|
||||
<FormField label={credLabels.loginLabel} htmlFor="acc-login">
|
||||
<Input
|
||||
id="acc-login"
|
||||
autoComplete="off"
|
||||
placeholder={credLabels.loginPlaceholder || undefined}
|
||||
{...register('apiLogin')}
|
||||
/>
|
||||
</FormField>
|
||||
) : null}
|
||||
<FormField
|
||||
label={isEdit ? `${credLabels.passwordLabel} (необязательно)` : credLabels.passwordLabel}
|
||||
htmlFor="acc-password"
|
||||
|
||||
@@ -6,6 +6,7 @@ import { SelectField } from '@/components/select-field'
|
||||
import type { ZodType } from 'zod'
|
||||
import { providerSchema, type ProviderFormValues } from '@/lib/schemas'
|
||||
import type { ApiType } from '@/types/entities'
|
||||
import { isUserApiType, USER_API_DEFAULT_BASE_URL } from '@cfdm/shared/contracts/provider'
|
||||
|
||||
const EMPTY: ProviderFormValues = {
|
||||
name: '',
|
||||
@@ -53,6 +54,20 @@ export function ProviderEditSheet({
|
||||
>
|
||||
{(form) => {
|
||||
const { register, formState: { errors }, watch, setValue } = form
|
||||
const apiType = watch('apiType')
|
||||
const apiUrlHint =
|
||||
apiType === '4vps'
|
||||
? 'Базовый URL API, например https://4vps.su/api'
|
||||
: isUserApiType(apiType)
|
||||
? `Базовый URL UserAPI, например ${USER_API_DEFAULT_BASE_URL[apiType]}`
|
||||
: 'Один URL на хостера для BILLmanager'
|
||||
const apiUrlPlaceholder =
|
||||
apiType === '4vps'
|
||||
? 'https://4vps.su/api'
|
||||
: isUserApiType(apiType)
|
||||
? USER_API_DEFAULT_BASE_URL[apiType]
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormField label="Название" htmlFor="pr-name" error={errors.name?.message} invalid={!!errors.name}>
|
||||
@@ -69,24 +84,14 @@ export function ProviderEditSheet({
|
||||
options={[
|
||||
{ value: 'billmanager', label: 'BILLmanager' },
|
||||
{ value: '4vps', label: '4VPS.SU' },
|
||||
{ value: 'macloud', label: 'Маклауд' },
|
||||
{ value: 'vdsina', label: 'VDSina' },
|
||||
{ value: 'none', label: 'Нет' },
|
||||
]}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="API URL"
|
||||
htmlFor="pr-apiurl"
|
||||
description={
|
||||
watch('apiType') === '4vps'
|
||||
? 'Базовый URL API, например https://4vps.su/api'
|
||||
: 'Один URL на хостера для BILLmanager'
|
||||
}
|
||||
>
|
||||
<Input
|
||||
id="pr-apiurl"
|
||||
placeholder={watch('apiType') === '4vps' ? 'https://4vps.su/api' : undefined}
|
||||
{...register('apiBaseUrl')}
|
||||
/>
|
||||
<FormField label="API URL" htmlFor="pr-apiurl" description={apiUrlHint}>
|
||||
<Input id="pr-apiurl" placeholder={apiUrlPlaceholder} {...register('apiBaseUrl')} />
|
||||
</FormField>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<FormField label="Валюта" htmlFor="pr-cur">
|
||||
|
||||
Reference in New Issue
Block a user