Compare commits

..

13 Commits

Author SHA1 Message Date
ningyv 3217ad2bba Merge pull request #380 from APIParkLab/feature/1.9-OAuth
fix: Fix department selection issue
2025-08-12 10:44:59 +08:00
lcx 1485b31226 fix: Fix department selection issue 2025-08-12 10:43:17 +08:00
ningyv 8968e1f961 Merge pull request #379 from APIParkLab/feature/1.9-OAuth
fix: Fix department selection issue.
2025-08-12 10:23:42 +08:00
lcx 4b8fa43c36 fix: Fix department selection issue. 2025-08-12 10:23:14 +08:00
ningyv c21d783c52 Merge pull request #378 from APIParkLab/feature/1.9-OAuth
fix: issue with adding user permissions
2025-08-11 19:00:31 +08:00
lcx e928cd84d7 fix: issue with adding user permissions 2025-08-11 18:59:39 +08:00
FreyLoong 412cb75bf0 Update readme-zh-cn.md 2025-08-08 18:42:46 +08:00
FreyLoong a13b2a8afe Update README.md 2025-08-08 18:40:14 +08:00
Dot.L c0472c8539 Merge pull request #375 from APIParkLab/feature/liujian-1.9
Feature/liujian 1.9
2025-08-08 12:06:44 +08:00
Liujian 5f40d5092c update qiniu rput param 2025-08-08 12:05:46 +08:00
Liujian b949939816 Fix: The issue where the upstream forwarding header is not effective 2025-08-08 12:04:40 +08:00
Dot.L 55f09f7542 Merge pull request #374 from APIParkLab/feature/liujian-1.9
fix: fail to delete model
2025-08-08 11:31:25 +08:00
Liujian ef1ccb81a9 fix: fail to delete model 2025-08-08 11:29:26 +08:00
9 changed files with 106 additions and 50 deletions
+17
View File
@@ -156,6 +156,10 @@ curl -sSO https://download.apipark.com/install/quick-start.sh ; bash quick-sta
<br>
<br>
# 🚀 Use Cases
## Simplify AI Integration Costs
- Connect to 100+ major models from all mainstream AI vendors, with standardized API calls requiring no additional adaptation work.
@@ -199,11 +203,20 @@ To achieve this goal, we plan to add new features to APIPark, including:
# 📕 Documentation
Visit [APIPark Documentation](https://docs.apipark.com/docs/deploy) for detailed installation guides, API references, and usage instructions.
# 🧑‍🤝‍🧑Friendly Links
<a href="https://xroute.ai/">
<img width="1248" height="158" alt="新建 PPTX 演示文稿 (2)_03" src="https://github.com/user-attachments/assets/0ebd694c-410a-4e3f-a793-90f1140d15df" />
</a>
<br>
<br>
# 🧾 License
APIPark uses the Apache 2.0 License. For more details, please refer to the LICENSE file.
<br>
# 💌 Contact Us
@@ -215,3 +228,7 @@ For enterprise-level features and professional technical support, contact our pr
<br>
🙏 A big thanks to everyone who helped shape APIPark. We are thrilled to hear the communitys thoughts! Lets make the world of APIs and AI stronger and more fun together. 🎉
@@ -19,7 +19,7 @@ export type MemberTableListItem = {
enable:boolean
departmentId:string
roles:EntityItem[]
form: string
from: string
};
export type AddToDepartmentProps = {
@@ -41,7 +41,7 @@ export type MemberDropdownModalFieldType = {
export type MemberDropdownModalProps = {
type:'addDep'|'addChild'|'addMember'|'editMember'|'rename'
entity?:(MemberTableListItem & {departmentIds:string[]}) | ({id?:string, departmentIds?:string[],name?:string,form?:string})
entity?:(MemberTableListItem & {departmentIds:string[]}) | ({id?:string, departmentIds?:string[],name?:string,from?:string})
selectedMemberGroupId?:string
}
@@ -14,8 +14,7 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
const {fetchData} = useFetch()
const [departmentList, setDepartmentList] = useState<DepartmentListItem[]>([])
const { state } = useGlobalContext()
const [disableEditMemberData] = useState<boolean>(entity?.form !== 'self-build')
const [disableEditMemberData] = useState<boolean>(entity?.from === 'feishu')
const save:()=>Promise<boolean | string> = ()=>{
let url:string
let method:string
@@ -95,14 +95,15 @@ const AddToDepartment = forwardRef<AddToDepartmentHandle, AddToDepartmentProps>(
treeData?.map((x: DataNode) => ({
...x,
name: $t((x as unknown as { name: string }).name),
checkable: false,
children: x.children?.map(y => ({ ...y, checkable: false }))
checkable: false, // 根节点不可选中
children: x.children?.map(y => ({ ...y, checkable: true })) // 子节点可以选中
})),
[state.language, treeData]
)
const onCheck: TreeProps['onCheck'] = (checkedKeys: string[]) => {
setSelectedKeys(checkedKeys.checked)
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
const selectedIds = Array.isArray(checkedKeys) ? checkedKeys : checkedKeys.checked || []
setSelectedKeys(selectedIds)
}
useEffect(() => {
@@ -153,11 +154,12 @@ const MemberList = () => {
const [tableHttpReload, setTableHttpReload] = useState(true)
const [tableListDataSource, setTableListDataSource] = useState<MemberTableListItem[]>([])
const pageListRef = useRef<ActionType>(null)
const { topGroupId, selectedDepartmentIds, refreshGroup } = useOutletContext<{
const { topGroupId, selectedDepartmentIds, refreshGroup, refreshTableCount } = useOutletContext<{
topGroupId: string
departmentList: DepartmentListItem[]
selectedDepartmentIds: string[]
refreshGroup: () => void
refreshTableCount: number
}>()
const AddMemberRef = useRef<MemberDropdownModalHandle>(null)
const EditMemberRef = useRef<MemberDropdownModalHandle>(null)
@@ -396,7 +398,7 @@ const MemberList = () => {
width: 600,
okText: $t('确认'),
okButtonProps: {
disabled: isActionAllowed(type) || (type === 'editMember' && entity?.form !== 'self-build')
disabled: isActionAllowed(type) || (type === 'editMember' && entity?.from === 'feishu')
},
cancelText: $t('取消'),
closable: true,
@@ -415,6 +417,13 @@ const MemberList = () => {
getDepartmentList()
}, [])
// 监听外部刷新触发器
useEffect(() => {
if (refreshTableCount > 0) {
manualReloadTable()
}
}, [refreshTableCount])
const getDepartmentList = async () => {
setDepartmentValueEnum([])
const { code, data, msg } = await fetchData<BasicResponse<{ department: DepartmentListItem }>>(
@@ -36,6 +36,11 @@ const MemberPage = ()=>{
const [selectedDepartmentId, setSelectedDepartmentId] = useState<string>('-1')
const {accessData,state} = useGlobalContext()
const [refreshMemberCount, setRefreshMemberCount] = useState<number>(0)
const [refreshTableCount, setRefreshTableCount] = useState<number>(0)
const refreshMemberTable = () => {
setRefreshTableCount(prev => prev + 1)
}
const onSearchWordChange = (e:string)=>{
setSearchWord(e || '')
}
@@ -90,7 +95,7 @@ const MemberPage = ()=>{
case 'addChild':
return AddChildRef.current?.save().then((res)=>{if(res === true)getDepartmentList()})
case 'addMember':
return AddMemberRef.current?.save().then((res)=>{if(res === true){getDepartmentList();setRefreshMemberCount(pre=>pre+1)}})
return AddMemberRef.current?.save().then((res)=>{if(res === true){getDepartmentList();setRefreshMemberCount(pre=>pre+1);refreshMemberTable()}})
case 'rename':
return RenameRef.current?.save().then((res)=>{if(res === true)getDepartmentList()})
case 'delete':
@@ -262,7 +267,7 @@ const MemberPage = ()=>{
</div>
</div>
<div className="flex-1 p-btnbase pr-PAGE_INSIDE_X overflow-x-hidden">
<Outlet context={{refreshMemberCount, selectedDepartmentIds,refreshGroup:()=>getDepartmentList()}}/>
<Outlet context={{refreshMemberCount, selectedDepartmentIds,refreshGroup:()=>getDepartmentList(), refreshTableCount}}/>
</div>
</div>
</InsidePage>);
+15 -11
View File
@@ -128,17 +128,19 @@ func (i *imlProviderModelModule) DeleteProviderModel(ctx *gin.Context, provider
if err := i.providerModelService.Delete(ctx, id); err != nil {
return err
}
err = i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{
{
BasicItem: &gateway.BasicItem{
ID: fmt.Sprintf("%s#%s", provider, modelInfo.Name),
Resource: "ai-model",
if p.GetModelConfig().AccessConfigurationStatus {
err = i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{
{
BasicItem: &gateway.BasicItem{
ID: fmt.Sprintf("%s$%s", provider, modelInfo.Name),
Resource: "ai-model",
},
Attr: nil,
},
Attr: nil,
},
}, false)
if err != nil {
return err
}, false)
if err != nil {
return err
}
}
p.RemoveModel(id)
@@ -200,7 +202,9 @@ func (i *imlProviderModelModule) AddProviderModel(ctx *gin.Context, provider str
}
func newModel(provider string, model string, config string) *gateway.DynamicRelease {
if config == "" {
config = "{}"
}
return &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: fmt.Sprintf("%s$%s", provider, model),
+38 -26
View File
@@ -185,6 +185,41 @@ func (i *imlPublishModule) getProjectRelease(ctx context.Context, projectID stri
Id: projectID,
Version: version,
}
upstreamProxyHeaders := make([]*gateway.ProxyHeader, 0)
var upstreamRelease *gateway.UpstreamRelease
if len(upstreamCommitIds) > 0 {
upstreamCommits, err := i.upstreamService.ListCommit(ctx, upstreamCommitIds...)
if err != nil {
return nil, err
}
for _, c := range upstreamCommits {
upstreamRelease = &gateway.UpstreamRelease{
BasicItem: &gateway.BasicItem{
ID: c.Target,
Version: version,
MatchLabels: map[string]string{
"serviceId": projectID,
},
},
PassHost: c.Data.PassHost,
Scheme: c.Data.Scheme,
Balance: c.Data.Balance,
Timeout: c.Data.Timeout,
Nodes: utils.SliceToSlice(c.Data.Nodes, func(n *upstream.NodeConfig) string {
return fmt.Sprintf("%s weight=%d", n.Address, n.Weight)
}),
}
upstreamProxyHeaders = utils.SliceToSlice(c.Data.ProxyHeaders, func(n *upstream.ProxyHeader) *gateway.ProxyHeader {
return &gateway.ProxyHeader{
Key: n.Key,
Value: n.Value,
Opt: n.OptType,
}
})
}
r.Upstream = upstreamRelease
}
apis := make([]*gateway.ApiRelease, 0, len(apiInfos))
hasUpstream := len(upstreamCommitIds) > 0
for _, a := range apiInfos {
@@ -221,38 +256,15 @@ func (i *imlPublishModule) getProjectRelease(ctx context.Context, projectID stri
Opt: h.OptType,
}
})
apiInfo.ProxyHeaders = append(apiInfo.ProxyHeaders, upstreamProxyHeaders...)
apiInfo.Retry = proxy.Retry
apiInfo.Timeout = proxy.Timeout
}
apis = append(apis, apiInfo)
}
r.Apis = apis
var upstreamRelease *gateway.UpstreamRelease
if len(upstreamCommitIds) > 0 {
upstreamCommits, err := i.upstreamService.ListCommit(ctx, upstreamCommitIds...)
if err != nil {
return nil, err
}
for _, c := range upstreamCommits {
upstreamRelease = &gateway.UpstreamRelease{
BasicItem: &gateway.BasicItem{
ID: c.Target,
Version: version,
MatchLabels: map[string]string{
"serviceId": projectID,
},
},
PassHost: c.Data.PassHost,
Scheme: c.Data.Scheme,
Balance: c.Data.Balance,
Timeout: c.Data.Timeout,
Nodes: utils.SliceToSlice(c.Data.Nodes, func(n *upstream.NodeConfig) string {
return fmt.Sprintf("%s weight=%d", n.Address, n.Weight)
}),
}
}
r.Upstream = upstreamRelease
}
if len(strategyCommitIds) > 0 {
strategyCommits, err := i.strategyService.ListStrategyCommit(ctx, strategyCommitIds...)
if err != nil {
+10
View File
@@ -202,6 +202,16 @@ curl -sSO https://download.apipark.com/install/quick-start.sh; bash quick-start.
# 📕文档
访问 [APIPark文档](https://docs.apipark.com/docs/deploy) 获取详细的安装指南、API 参考和使用说明。
<br>
友情链接
<a href="https://xroute.ai/">
<img width="1248" height="158" alt="新建 PPTX 演示文稿 (2)_02(1)" src="https://github.com/user-attachments/assets/3e1cd0c1-c4c3-4f0c-8649-810d76f3166b" />
</a>
<br>
+1 -1
View File
@@ -22,7 +22,7 @@ echo "login qiniu..."
qshell account ${AccessKey} ${SecretKey} ${QINIU_NAME}
echo "qshell rput ${QINIU_BUCKET} \"${APP}/images/${Tar}\" ${Tar}"
qshell rput ${QINIU_BUCKET} "${APP}/images/${Tar}" ${Tar}
qshell rput --overwrite ${QINIU_BUCKET} "${APP}/images/${Tar}" ${Tar}
rm -f ${Tar}
docker rmi -f ${ImageName}:${Version}