mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
feat: Add path match type before api path & Modify Login Page
This commit is contained in:
@@ -272,3 +272,16 @@ a{
|
||||
stroke: rgba(255, 255, 255, 0.1);
|
||||
mask-image: radial-gradient(100% 100% at top right, white, transparent);
|
||||
}
|
||||
|
||||
.login-block{
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
.login-input{
|
||||
color:#fff;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
&:hover, &:focus, &.ant-input-status-error, &.ant-input-status-error:hover, &.ant-input-status-error:focus-within{
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,11 @@ export const API_PROTOCOL = [
|
||||
{label:'HTTPS',value:'HTTPS'}
|
||||
]
|
||||
|
||||
export const API_PATH_MATCH_RULES = [
|
||||
{label:'前缀匹配',value:'prefix'},
|
||||
{label:'全等匹配',value:'full'}
|
||||
]
|
||||
|
||||
|
||||
export const ALGORITHM_ITEM = [
|
||||
{label:'HS256',value:'HS256'},
|
||||
|
||||
@@ -139,7 +139,7 @@ const Login:FC = ()=> {
|
||||
|
||||
</div>
|
||||
{/* <div className="w-full border-box text-right pr-[40px]"></div> */}
|
||||
<div className="w-[410px] mx-auto flex-1 flex flex-col items-center justify-center z-[3]" >
|
||||
<div className="mx-auto flex-1 flex flex-col items-center justify-center z-[3]" >
|
||||
<div className="mx-auto">
|
||||
<span className="flex items-center justify-center">
|
||||
<img
|
||||
@@ -149,14 +149,10 @@ const Login:FC = ()=> {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<section className="block w-[410px] mx-auto mt-[46px] bg-MAIN_BG p-[30px] box-border rounded-[10px] shadow-[0_5px_20px_0_rgba(0,0,0,5%)]">
|
||||
<section className="block w-[410px] mx-auto mt-[46px] p-[30px] box-border rounded-[10px] shadow-[0_5px_20px_0_rgba(0,0,0,5%)] login-block">
|
||||
<div className="h-full">
|
||||
<div>
|
||||
<div className="flex justify-center items-center">
|
||||
<span className="text-[24px] text-[#101010]">{$t('登录')}</span>
|
||||
</div>
|
||||
|
||||
<Form onFinish={login} className="w-[350px] pt-[28px]"
|
||||
<div className="">
|
||||
<Form onFinish={login} className="w-[350px]"
|
||||
ref={formRef}>
|
||||
<Form.Item
|
||||
className="p-0 bg-transparent rounded border-none"
|
||||
@@ -164,7 +160,7 @@ const Login:FC = ()=> {
|
||||
rules={[{ required: true, message: $t('请输入账号') ,whitespace:true }]}
|
||||
>
|
||||
<Input
|
||||
className="w-[350px] h-[40px]"
|
||||
className="w-[350px] h-[40px] login-input"
|
||||
placeholder={$t("账号")}
|
||||
autoComplete="on"
|
||||
autoFocus
|
||||
@@ -172,12 +168,12 @@ const Login:FC = ()=> {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
className="p-0 bg-transparent rounded border-none"
|
||||
className="p-0 bg-transparent rounded border-none "
|
||||
name="password"
|
||||
rules={[{ required: true, message: $t('请输入密码') }]}
|
||||
>
|
||||
<Input.Password
|
||||
className="w-[350px] h-[40px]"
|
||||
className="w-[350px] h-[40px] login-input"
|
||||
placeholder={$t("密码")}
|
||||
autoComplete="off"
|
||||
/>
|
||||
@@ -209,8 +205,9 @@ const Login:FC = ()=> {
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col items-center mt-[46px] text-SECOND_TEXT">
|
||||
<p className="leading-[28px]">{$t('Version (0)-(1)',[state.version,state.updateDate])}</p>
|
||||
<p className="leading-[28px]">{$t(state.powered)}</p>
|
||||
<p className="leading-[28px]">
|
||||
{$t('Version (0)-(1)',[state.version,state.updateDate])}, {$t(state.powered)}
|
||||
</p>
|
||||
<LanguageSetting mode="light"/>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {App, Button, Form, Input, InputNumber, Row, Spin, Tag} from "antd";
|
||||
import {App, Button, Form, Input, InputNumber, Row, Select, Space, Spin, Tag} from "antd";
|
||||
import { MutableRefObject, useEffect, useRef, useState} from "react";
|
||||
import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
@@ -17,6 +17,8 @@ import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter
|
||||
import AiServiceRouterModelConfig, { AiServiceRouterModelConfigHandle } from "./AiServiceInsideRouterModelConfig";
|
||||
import { AiProviderDefaultConfig, AiProviderLlmsItems } from "@core/pages/aiSetting/AiSettingList";
|
||||
import { EditableFormInstance } from "@ant-design/pro-components";
|
||||
import { validateUrlSlash } from "@common/utils/validate";
|
||||
import { API_PATH_MATCH_RULES } from "@core/const/system/const";
|
||||
|
||||
type AiServiceRouterField = {
|
||||
name:string
|
||||
@@ -62,8 +64,11 @@ const AiServiceInsideRouterCreate = () => {
|
||||
const onFinish = ()=>{
|
||||
return variablesTableRef?.current?.validateFields().then(()=>{
|
||||
return form.validateFields().then((formValue)=>{
|
||||
const {name, path, description, variables, prompt, timeout, retry} = formValue
|
||||
const body = {name, path: prefixForce ? `${apiPrefix}/${path}`:path , description,timeout, retry,aiPrompt:{variables:variables, prompt:prompt},aiModel:{id:defaultLlm?.id, provider:defaultLlm?.provider, config:defaultLlm?.config}}
|
||||
const {name, path, description, variables, prompt, timeout, retry,pathMatch} = formValue
|
||||
const body = {
|
||||
name,
|
||||
path: `${prefixForce ? apiPrefix + '/' : ''}${path.trim()}${pathMatch === 'prefix' ? '/*' : ''}`,
|
||||
description,timeout, retry,aiPrompt:{variables:variables, prompt:prompt},aiModel:{id:defaultLlm?.id, provider:defaultLlm?.provider, config:defaultLlm?.config}}
|
||||
return fetchData<BasicResponse<null>>('service/ai-router',{method: routeId ? 'PUT' : 'POST',eoBody:(body), eoParams: {service:serviceId,team:teamId, ...(routeId ? {router:routeId}: {})},eoTransformKeys:['aiPrompt','aiModel']}).then(response=>{
|
||||
const {code,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
@@ -92,7 +97,20 @@ const AiServiceInsideRouterCreate = () => {
|
||||
const {code,data,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
const {path, aiPrompt,aiModel} = data.api
|
||||
form.setFieldsValue({...data.api,...aiPrompt, path:prefixForce && path?.startsWith(apiPrefix + '/')? path.slice((apiPrefix?.length || 0) + 1) : path })
|
||||
let newPath = path
|
||||
let pathMatch = 'full'
|
||||
if(prefixForce && path?.startsWith(apiPrefix + '/')){
|
||||
newPath = path.slice((apiPrefix?.length || 0) + 1)
|
||||
}
|
||||
if(newPath.endsWith('/*')){
|
||||
newPath = newPath.slice(0,-2)
|
||||
pathMatch = 'prefix'
|
||||
}
|
||||
form.setFieldsValue({
|
||||
...data.api,
|
||||
...aiPrompt,
|
||||
path:newPath,
|
||||
pathMatch})
|
||||
setVariablesTable(aiPrompt.variables as VariableItems[])
|
||||
setDefaultLlm(prev => ({...prev, provider: aiModel?.provider, id:aiModel?.id, config:aiModel.config}) as (AiProviderDefaultConfig & { config: string; }))
|
||||
getDefaultModelConfig(aiModel?.provider)
|
||||
@@ -141,7 +159,8 @@ const AiServiceInsideRouterCreate = () => {
|
||||
variables:[{key:'Query',value:'',require:true}],
|
||||
prompt:'{{Query}}',
|
||||
retry:0,
|
||||
timeout:300000
|
||||
timeout:300000,
|
||||
pathMatch:'prefix'
|
||||
})
|
||||
}
|
||||
return (form.setFieldsValue({}))
|
||||
@@ -230,15 +249,38 @@ const AiServiceInsideRouterCreate = () => {
|
||||
<Input className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)}/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<AiServiceRouterField>
|
||||
className="flex-1"
|
||||
label={$t("请求路径")}
|
||||
name="path"
|
||||
rules={[{ required: true,whitespace:true }]}
|
||||
>
|
||||
<Input prefix={prefixForce ? `${apiPrefix}/` :"/"} className="w-INPUT_NORMAL"
|
||||
placeholder={$t(PLACEHOLDER.input)}/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={$t("请求路径")}>
|
||||
<Space.Compact block>
|
||||
<Form.Item
|
||||
name="pathMatch"
|
||||
rules={[{ required: true,whitespace:true },
|
||||
{
|
||||
validator: validateUrlSlash,
|
||||
}]}
|
||||
noStyle
|
||||
>
|
||||
<Select placeholder={$t(PLACEHOLDER.select)} options={API_PATH_MATCH_RULES} className="w-[30%] min-w-[100px]"/>
|
||||
</Form.Item>
|
||||
<Form.Item<AiServiceRouterField>
|
||||
name="path"
|
||||
rules={[{ required: true,whitespace:true },
|
||||
{
|
||||
validator: validateUrlSlash,
|
||||
}]}
|
||||
noStyle
|
||||
>
|
||||
<Input prefix={(prefixForce ? `${apiPrefix}/` :"/")} className="w-INPUT_NORMAL"
|
||||
placeholder={$t(PLACEHOLDER.input)} onChange={(e)=>{
|
||||
if((e.target.value as string).endsWith('/*')){
|
||||
form.setFieldValue('path',e.target.value.slice(0,-2))
|
||||
form.setFieldValue('pathMatch','prefix')
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Space.Compact>
|
||||
</Form.Item>
|
||||
|
||||
</Row>
|
||||
|
||||
<Form.Item<AiServiceRouterField>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {App, Button, Col, Form, Input, Row, Select, Spin, Switch} from "antd";
|
||||
import {App, Button, Col, Form, Input, Row, Select, Space, Spin, Switch} from "antd";
|
||||
import {forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
|
||||
import EditableTableWithModal from "@common/components/aoplatform/EditableTableWithModal.tsx";
|
||||
import styles from "./SystemInsideApi.module.css"
|
||||
import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import { API_PROTOCOL, HTTP_METHOD, MATCH_CONFIG, MatchPositionEnum, MatchTypeEnum } from "../../../const/system/const.tsx";
|
||||
import { API_PATH_MATCH_RULES, API_PROTOCOL, HTTP_METHOD, MATCH_CONFIG, MatchPositionEnum, MatchTypeEnum } from "../../../const/system/const.tsx";
|
||||
import { SystemInsideRouterCreateHandle, SystemInsideRouterCreateProps, SystemApiProxyFieldType, SystemInsideApiProxyHandle } from "../../../const/system/type.ts";
|
||||
import { MatchItem } from "@common/const/type.ts";
|
||||
import { validateUrlSlash } from "@common/utils/validate.ts";
|
||||
@@ -31,7 +31,7 @@ const SystemInsideRouterCreate = forwardRef<SystemInsideRouterCreateHandle,Syste
|
||||
const onFinish = ()=>{
|
||||
return Promise.all([proxyRef.current?.validate?.(), form.validateFields()]).then(([,formValue])=>{
|
||||
const body = {...formValue,
|
||||
path: prefixForce? `${apiPrefix}/${formValue.path.trim()}` : formValue.path.trim(),
|
||||
path: `${prefixForce ? apiPrefix + '/' : ''}${formValue.path.trim()}${formValue.pathMatch === 'prefix' ? '/*' : ''}`,
|
||||
proxy:{...formValue.proxy,path:formValue.proxy.path ? (formValue.proxy.path.startsWith('/')? formValue.proxy.path: '/'+ formValue.proxy.path) : undefined}}
|
||||
return fetchData<BasicResponse<null>>('service/router',{
|
||||
method: routeId ? 'PUT' :'POST' ,eoBody:(body), eoParams: {service:serviceId,team:teamId, router:routeId },eoTransformKeys:['matchType','disable']}).then(response=>{
|
||||
@@ -77,7 +77,24 @@ const SystemInsideRouterCreate = forwardRef<SystemInsideRouterCreateHandle,Syste
|
||||
const {code,data,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
const {disable, protocols, path, methods, description, match, proxy} = data.router
|
||||
form.setFieldsValue({disable, protocols, path:prefixForce && path?.startsWith(apiPrefix + '/')? path.slice((apiPrefix?.length || 0) + 1) : path, methods, description, match,proxy
|
||||
let newPath = path
|
||||
let pathMatch = 'full'
|
||||
if(prefixForce && path?.startsWith(apiPrefix + '/')){
|
||||
newPath = path.slice((apiPrefix?.length || 0) + 1)
|
||||
}
|
||||
if(newPath.endsWith('/*')){
|
||||
newPath = newPath.slice(0,-2)
|
||||
pathMatch = 'prefix'
|
||||
}
|
||||
form.setFieldsValue({
|
||||
disable,
|
||||
protocols,
|
||||
path:newPath,
|
||||
pathMatch,
|
||||
methods,
|
||||
description,
|
||||
match,
|
||||
proxy
|
||||
})
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
@@ -94,6 +111,7 @@ const SystemInsideRouterCreate = forwardRef<SystemInsideRouterCreateHandle,Syste
|
||||
form.setFieldValue(['proxy','timeout'],10000)
|
||||
form.setFieldValue(['proxy','retry'],0)
|
||||
form.setFieldValue('protocols',['HTTP','HTTPS'])
|
||||
form.setFieldValue('pathMatch','prefix')
|
||||
}
|
||||
return (form.setFieldsValue({}))
|
||||
}, []);
|
||||
@@ -157,18 +175,35 @@ const SystemInsideRouterCreate = forwardRef<SystemInsideRouterCreateHandle,Syste
|
||||
<Select className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.select)} mode="multiple" options={API_PROTOCOL}>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<SystemApiProxyFieldType>
|
||||
label={$t("请求路径")}
|
||||
name="path"
|
||||
rules={[{ required: true,whitespace:true },
|
||||
{
|
||||
validator: validateUrlSlash,
|
||||
}]}
|
||||
className={styles['form-input-group']}
|
||||
>
|
||||
<Input prefix={(prefixForce ? `${apiPrefix}/` :"/")} className="w-INPUT_NORMAL"
|
||||
placeholder={$t(PLACEHOLDER.input)}/>
|
||||
<Form.Item label={$t("请求路径")}>
|
||||
<Space.Compact block>
|
||||
<Form.Item
|
||||
name="pathMatch"
|
||||
rules={[{ required: true,whitespace:true },
|
||||
{
|
||||
validator: validateUrlSlash,
|
||||
}]}
|
||||
noStyle
|
||||
>
|
||||
<Select placeholder={$t(PLACEHOLDER.select)} options={API_PATH_MATCH_RULES} className="w-[30%] min-w-[100px]"/>
|
||||
</Form.Item>
|
||||
<Form.Item<SystemApiProxyFieldType>
|
||||
name="path"
|
||||
rules={[{ required: true,whitespace:true },
|
||||
{
|
||||
validator: validateUrlSlash,
|
||||
}]}
|
||||
noStyle
|
||||
>
|
||||
<Input prefix={(prefixForce ? `${apiPrefix}/` :"/")} className="w-INPUT_NORMAL"
|
||||
placeholder={$t(PLACEHOLDER.input)} onChange={(e)=>{
|
||||
if((e.target.value as string).endsWith('/*')){
|
||||
form.setFieldValue('path',e.target.value.slice(0,-2))
|
||||
form.setFieldValue('pathMatch','prefix')
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Space.Compact>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<SystemApiProxyFieldType>
|
||||
|
||||
Reference in New Issue
Block a user