mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
Compare commits
298 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1aca2099de | |||
| a93e5b4ff8 | |||
| 85d25bebe2 | |||
| 9fa43ccc00 | |||
| c2a11050dd | |||
| 080bfc3a44 | |||
| f6956ddeca | |||
| 9f56fa5e14 | |||
| ccc39b95de | |||
| 9a2782e54b | |||
| 22455e2301 | |||
| 8ed2c84b68 | |||
| ccd2a209e2 | |||
| baf8ed4830 | |||
| dedb586daf | |||
| 21cd823791 | |||
| c8ab65ef1b | |||
| f1c16fd992 | |||
| 52035341f6 | |||
| aa62d44717 | |||
| a072d1fc8d | |||
| 38a00570d0 | |||
| 43283b9da3 | |||
| ef82cdbed6 | |||
| 2bafe6f31f | |||
| 3eb4f98fd8 | |||
| bb5acad033 | |||
| b8308a446b | |||
| c86f99ce45 | |||
| 952c519e45 | |||
| 07d97fa0bf | |||
| b0defedf04 | |||
| edc2fccdeb | |||
| a75b8a3f13 | |||
| 5aab5f7913 | |||
| 9ab7989c8b | |||
| e3e11d740a | |||
| 4bae2edc49 | |||
| 4eaa47ca25 | |||
| e01f596525 | |||
| 912e8d0d04 | |||
| 570c80af91 | |||
| 7aa0ec0d67 | |||
| 2fea6cb622 | |||
| 2195ff900f | |||
| 836c7699b8 | |||
| 72ed6c814e | |||
| c33b070509 | |||
| de12d5686c | |||
| c55a8ac805 | |||
| df3626f3f0 | |||
| 28bef97faa | |||
| 9897b6e9dc | |||
| 9af6963901 | |||
| c2d3ebecda | |||
| ba543311fc | |||
| 87b8dda97b | |||
| e7facf5686 | |||
| 4dd57837c5 | |||
| d4ebc68e30 | |||
| 1f8e089e51 | |||
| ce6f463fe8 | |||
| a37fe1d794 | |||
| 818d1ec6bf | |||
| fc4a5f7e28 | |||
| 0e3568b584 | |||
| 3617e4fe29 | |||
| f2fddc1727 | |||
| 3b7204f1a6 | |||
| 6646bb1e56 | |||
| c27533f802 | |||
| 613a47c181 | |||
| 90138a142b | |||
| 4bf8db4898 | |||
| 4f887f7204 | |||
| 14e17ccf2c | |||
| 5975670b8c | |||
| dbc4bc3343 | |||
| ada7635703 | |||
| 943a77f718 | |||
| ef02c11efa | |||
| 8c166dae9b | |||
| b23da78c26 | |||
| 93ac7310e8 | |||
| 9376acc456 | |||
| b70a1f9a51 | |||
| ac90a134b4 | |||
| 96bd1cf9f6 | |||
| 960e37a81a | |||
| 044bd550c9 | |||
| 0a9a903d1b | |||
| 84d7606e12 | |||
| febb64b8bb | |||
| 932e433c46 | |||
| b7307cd36d | |||
| 7a0f3efd83 | |||
| 28af1f691c | |||
| 796bc7bc15 | |||
| 8f06073783 | |||
| 7d6251b191 | |||
| e13fff633e | |||
| d984be4b85 | |||
| 213bdbd9d5 | |||
| 6a59d27b84 | |||
| ad45ab2e82 | |||
| 8982a63283 | |||
| 1b1515a8bd | |||
| df50e13db0 | |||
| 89d91c14c9 | |||
| 3a57c609f7 | |||
| 2cd331ec50 | |||
| 3fa02ec65c | |||
| f33f1965b4 | |||
| a70ecea02b | |||
| 8e68eb35f3 | |||
| 2893331ff5 | |||
| 1a3d14cdd6 | |||
| dce9a7addb | |||
| f3e7487482 | |||
| 86c39237dc | |||
| b5ad739b93 | |||
| 0b7f0405d5 | |||
| 1ab56708a5 | |||
| 522489c9e9 | |||
| a9eb2a790f | |||
| a092ed1108 | |||
| 503515281d | |||
| 2326d4dfb5 | |||
| 42e8030cf7 | |||
| 17b4ede566 | |||
| bbc3fea848 | |||
| 82e46b872b | |||
| 0f6a091c73 | |||
| 4e87adb4b3 | |||
| 320a2b6cf8 | |||
| b216556867 | |||
| 7fbb98a2a9 | |||
| 461a8edbea | |||
| cdef179bed | |||
| a067388d79 | |||
| 2d5e541593 | |||
| be40186ad3 | |||
| c9ae05b22e | |||
| 2b874fe59f | |||
| 9da5e5d6c0 | |||
| a6bfce2a5f | |||
| 8cbeabe917 | |||
| 1db354077f | |||
| e31d41a276 | |||
| 21d2abf716 | |||
| 3a86a88870 | |||
| 6117a840e1 | |||
| 0e20987fb8 | |||
| 65e7cab772 | |||
| 935f2ac766 | |||
| 3e12d7eb9c | |||
| d6095269b7 | |||
| 0c415b4e32 | |||
| bc1819b368 | |||
| a9be016c87 | |||
| 11da5e9d26 | |||
| 2c6c194821 | |||
| aedd8b4cc6 | |||
| fa2607e9b8 | |||
| 3783e5ee5d | |||
| fd56b8ffed | |||
| 07e288be16 | |||
| 46143c3fe0 | |||
| 83e3cc85f2 | |||
| a4b50ae60a | |||
| a30d0c37eb | |||
| 64fdf59905 | |||
| 1aa3f2fb05 | |||
| 68e8cb72d3 | |||
| a86d3cd65a | |||
| a4b4cbf60f | |||
| 2dcb7ebd74 | |||
| ad6b64ca74 | |||
| d27a2b8cf3 | |||
| 8fa1985feb | |||
| 451efb8d3e | |||
| d6bf3139ff | |||
| 309b9ea937 | |||
| 554bff38c6 | |||
| d5e6062ec9 | |||
| bcb68d552f | |||
| 3de87723ae | |||
| 535d70ac5a | |||
| d588d43aa1 | |||
| f455cecb54 | |||
| b88c0a9305 | |||
| 9030cff8ba | |||
| 98f73f799a | |||
| d2e428ada8 | |||
| 74156ec84c | |||
| f9e6bc92d7 | |||
| 9884586cc9 | |||
| ac717a6efb | |||
| 2b7c1ded15 | |||
| daac27712d | |||
| 1080f33282 | |||
| cc5c0a0a89 | |||
| 85971447e1 | |||
| 256e8ef275 | |||
| c07e54ec03 | |||
| 70f834e1cf | |||
| c320c6f2a2 | |||
| 256eb60df8 | |||
| 5f03973bf2 | |||
| ab2a0d8ae2 | |||
| 7e48402591 | |||
| aa85f6fcd1 | |||
| cd441ccfe7 | |||
| 47f6519006 | |||
| 9679376cb2 | |||
| efa97c3bbc | |||
| 087e598be0 | |||
| 31aa8243ee | |||
| d3d05ef539 | |||
| d6062ea4e7 | |||
| 7949748951 | |||
| 94f7392060 | |||
| 0d737bad57 | |||
| 1225db50c9 | |||
| e5d85bb3df | |||
| 0f09e5c236 | |||
| 0f0204b647 | |||
| 94421d2622 | |||
| 44f0b70461 | |||
| f58768237b | |||
| 588cf839e3 | |||
| 76872b3a97 | |||
| d253d68a12 | |||
| 4de0d29f30 | |||
| 0f0480db63 | |||
| aa40b62e0a | |||
| 68309ac582 | |||
| 522183eb4d | |||
| 4f6fee4d73 | |||
| c5fecf73c8 | |||
| ee8e93d1e8 | |||
| 9d0fa5ea4a | |||
| b0b9affbe7 | |||
| 1d1c7c78e8 | |||
| d7f5b87e70 | |||
| 1048666972 | |||
| 217f5d61c7 | |||
| 2f1677f581 | |||
| afd7ea6a1c | |||
| 7155e14e64 | |||
| 68e5b49f46 | |||
| c01e95c716 | |||
| ffa7e5130e | |||
| 7ce33bfd4c | |||
| 0c64fa9986 | |||
| 07e8b347e1 | |||
| 38a402adef | |||
| 7ab2e29101 | |||
| b96796793b | |||
| baa073b05d | |||
| c944f9de52 | |||
| 5567a65e4b | |||
| c6c775f436 | |||
| c0c43be6b9 | |||
| 9b6074318a | |||
| ada121015d | |||
| 9d7b6c4bc6 | |||
| c262fc4f4d | |||
| 335317bd86 | |||
| 396464c573 | |||
| d93c76ca36 | |||
| 60ad6007e5 | |||
| ceee520102 | |||
| a053557000 | |||
| e7c14b0817 | |||
| 727fd0bd36 | |||
| 885cec57db | |||
| 4ba2b0c9ab | |||
| b3672b8c66 | |||
| b33dda4a32 | |||
| 450e565718 | |||
| 00bd72c1e4 | |||
| 81da1f45f1 | |||
| 24c24c1307 | |||
| 2bcee5e362 | |||
| 74d402a330 | |||
| 08bd8a9942 | |||
| 6944260767 | |||
| 3ada2d1d9d | |||
| 4a48255be1 | |||
| 25f8712a9f | |||
| f83b8c74ca | |||
| 7a4f3dc4c5 | |||
| 26b52b1ab0 | |||
| bf2aefe2da | |||
| 540a31f237 | |||
| 0505045c81 | |||
| 1a18d79d94 |
@@ -45,19 +45,18 @@ body:
|
||||
label: Steps to Reproduce
|
||||
description: Share the steps you took so that we can reproduce the issue. Reports without proper steps details will likely be closed.
|
||||
placeholder: |
|
||||
1. Run apinto via the Docker image.
|
||||
2. Create a Route with the Admin API.
|
||||
3. Try configuring ...
|
||||
4. ...
|
||||
1. Run APIPark via the Docker image.
|
||||
2. Try configuring ...
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: Share your environment details. Reports without proper environment details will likely be closed.
|
||||
value: |
|
||||
- APINTO Dashboard version (run `apinto dashboard version`):
|
||||
- APINTO Dashboard version:
|
||||
- Operating system (run `uname -a`):
|
||||
validations:
|
||||
required: true
|
||||
@@ -25,7 +25,7 @@ body:
|
||||
label: Environment
|
||||
description: Share your environment details. Reports without proper environment details will likely be closed.
|
||||
value: |
|
||||
- APIPark version (run `apinto dashboard version`):
|
||||
- APIPark version:
|
||||
- Operating system (run `uname -a`):
|
||||
validations:
|
||||
required: true
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
echo "Build frontend..."
|
||||
cd ./frontend && pnpm run build
|
||||
- name: upload frontend release
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: frontend-package
|
||||
path: frontend/dist
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
- name: Checkout #Checkout代码
|
||||
uses: actions/checkout@v3
|
||||
- name: download frontend release
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: frontend-package
|
||||
path: frontend/dist
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: download frontend release
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: frontend-package
|
||||
path: frontend/dist
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
/config.yml
|
||||
/build/
|
||||
/apipark
|
||||
/aoplatform
|
||||
.gitlab-ci.yml
|
||||
@@ -1,98 +0,0 @@
|
||||
variables:
|
||||
PATH: /opt/go-1.21/go/bin/:/opt/node/node/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
|
||||
GOROOT: /opt/go-1.21/go
|
||||
GOPROXY: https://goproxy.cn
|
||||
VERSION: $CI_COMMIT_SHORT_SHA
|
||||
APP: apipark
|
||||
APP_PRE: ${APP}_${VERSION}
|
||||
BUILD_DIR: ${APP}-build
|
||||
DEPLOY_DESC: "DEV 环境"
|
||||
VIEW_ADDR: http://172.18.166.219:8288
|
||||
SAVE_DIR: /opt/${APP}
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
|
||||
stages:
|
||||
- notice
|
||||
- prefix
|
||||
- build
|
||||
- deploy
|
||||
- webhook
|
||||
|
||||
feishu-informer: # 飞书回调
|
||||
stage: notice
|
||||
variables:
|
||||
DIFF_URL: "$CI_MERGE_REQUEST_PROJECT_URL/-/merge_requests/$CI_MERGE_REQUEST_IID/diffs"
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE=="merge_request_event" && $CI_COMMIT_BRANCH =~ "main"
|
||||
script:
|
||||
- echo "merge request"
|
||||
- |
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"项目:${CI_PROJECT_NAME}\\n提交人:${GITLAB_USER_NAME}\\n提交信息:${CI_MERGE_REQUEST_TITLE}\\n合并分支信息:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} -> ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}\\n差异性地址:${DIFF_URL}\\n请及时review代码\"}}" \
|
||||
https://open.feishu.cn/open-apis/bot/v2/hook/1c334752-2874-41a1-8f1b-3060f2d46b6c
|
||||
|
||||
prebuild:
|
||||
stage: prefix
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
script:
|
||||
- echo "prebuild"
|
||||
- chmod +x ./scripts/prefix.sh
|
||||
- ./scripts/prefix.sh
|
||||
|
||||
builder:
|
||||
stage: build
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
script:
|
||||
- set -e
|
||||
- |
|
||||
if [ ! -d "../artifacts" ]; then
|
||||
mkdir -p ../artifacts
|
||||
fi
|
||||
if [ -d "../artifacts/dist" ]; then
|
||||
cp -r ../artifacts/dist frontend/dist
|
||||
fi
|
||||
- |
|
||||
if [ -n "$(git diff --name-status HEAD~1 HEAD -- frontend)" ]; then
|
||||
./scripts/build.sh $BUILD_DIR ${VERSION} all ""
|
||||
else
|
||||
./scripts/build.sh $BUILD_DIR ${VERSION}
|
||||
fi
|
||||
if [ -d "frontend/dist" ]; then
|
||||
echo "copy frontend/dist to artifacts/dist"
|
||||
rm -fr ../artifacts/dist
|
||||
cp -r frontend/dist ../artifacts/dist
|
||||
fi
|
||||
cp $BUILD_DIR/${APP_PRE}_linux_amd64.tar.gz ${SAVE_DIR}
|
||||
|
||||
deployer:
|
||||
stage: deploy
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
variables:
|
||||
APIPARK_GUEST_MODE: allow
|
||||
APIPARK_GUEST_ID: dklejrfbhjqwdh
|
||||
script:
|
||||
- cd ${SAVE_DIR};mkdir -p ${APP_PRE};tar -zxvf ${APP_PRE}_linux_amd64.tar.gz -C ${APP_PRE};cd ${APP_PRE};./install.sh ${SAVE_DIR};./run.sh restart;cd ${SAVE_DIR} && ./clean.sh ${APP_PRE}
|
||||
when: on_success
|
||||
success:
|
||||
stage: webhook
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
script:
|
||||
- |
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"最近一次提交:${CI_COMMIT_TITLE}\\n提交人:${GITLAB_USER_NAME}\\n项目:${CI_PROJECT_NAME}\\n环境:${DEPLOY_DESC}\\n更新部署完成.\\n访问地址:${VIEW_ADDR}\\n工作流地址:${CI_PIPELINE_URL}\"}}" \
|
||||
https://open.feishu.cn/open-apis/bot/v2/hook/c3672932-4dfa-4989-8023-0128bae59338
|
||||
when: on_success
|
||||
failure:
|
||||
stage: webhook
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
script:
|
||||
- |
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"最近一次提交:${CI_COMMIT_TITLE}\\n提交人:${GITLAB_USER_NAME}\\n项目:${CI_PROJECT_NAME}\\n环境:${DEPLOY_DESC}\\n更新部署失败,请及时到gitlab上查看\\n工作流地址:${CI_PIPELINE_URL}\"}}" \
|
||||
https://open.feishu.cn/open-apis/bot/v2/hook/c3672932-4dfa-4989-8023-0128bae59338
|
||||
when: on_failure
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"Antd",
|
||||
"apinto",
|
||||
"Apipark",
|
||||
"logsettings",
|
||||
"resourcesettings"
|
||||
]
|
||||
}
|
||||
@@ -197,7 +197,7 @@ To achieve this goal, we plan to add new features to APIPark, including:
|
||||
<br>
|
||||
|
||||
# 📕 Documentation
|
||||
Visit [APIPark Documentation](https://docs.apipark.com/docs/install) for detailed installation guides, API references, and usage instructions.
|
||||
Visit [APIPark Documentation](https://docs.apipark.com/docs/deploy) for detailed installation guides, API references, and usage instructions.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
@@ -69,15 +69,6 @@ provider_credential_schema:
|
||||
placeholder:
|
||||
zh_Hans: 在此输入您的 API Key
|
||||
en_US: Enter your API Key
|
||||
- variable: openai_organization
|
||||
label:
|
||||
zh_Hans: 组织 ID
|
||||
en_US: Organization
|
||||
type: text-input
|
||||
required: false
|
||||
placeholder:
|
||||
zh_Hans: 在此输入您的组织 ID
|
||||
en_US: Enter your Organization ID
|
||||
- variable: openai_api_base
|
||||
label:
|
||||
zh_Hans: API Base
|
||||
|
||||
@@ -30,4 +30,4 @@ provider_credential_schema:
|
||||
placeholder:
|
||||
zh_Hans: 在此输入您的 API Key
|
||||
en_US: Enter your API Key
|
||||
address: https://api.openai.com
|
||||
address: https://api.360.cn
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// These should be set via go build -ldflags -X 'xxxx'.
|
||||
@@ -20,7 +20,7 @@ var profileInfo []byte
|
||||
|
||||
func init() {
|
||||
buffer := &bytes.Buffer{}
|
||||
fmt.Fprintf(buffer, "Apinto version: %s\n", Version)
|
||||
fmt.Fprintf(buffer, "APIPark version: %s\n", Version)
|
||||
fmt.Fprintf(buffer, "Golang version: %s\n", goVersion)
|
||||
fmt.Fprintf(buffer, "Git commit hash: %s\n", gitCommit)
|
||||
fmt.Fprintf(buffer, "Built on: %s\n", BuildTime)
|
||||
|
||||
@@ -27,7 +27,7 @@ type imlAPIController struct {
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error) {
|
||||
info, err := i.serviceModule.Get(ctx, serviceId)
|
||||
_, err := i.serviceModule.Get(ctx, serviceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_
|
||||
plugins["ai_formatter"] = api.PluginSetting{
|
||||
Config: plugin_model.ConfigType{
|
||||
"model": input.AiModel.Id,
|
||||
"provider": fmt.Sprintf("%s@ai-provider", info.Provider.Id),
|
||||
"provider": fmt.Sprintf("%s@ai-provider", input.AiModel.Provider),
|
||||
"config": input.AiModel.Config,
|
||||
},
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_
|
||||
Retry: input.Retry,
|
||||
Plugins: plugins,
|
||||
},
|
||||
Upstream: info.Provider.Id,
|
||||
Upstream: input.AiModel.Provider,
|
||||
Disable: false,
|
||||
})
|
||||
|
||||
@@ -86,7 +86,7 @@ func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) (*ai_api_dto.API, error) {
|
||||
info, err := i.serviceModule.Get(ctx, serviceId)
|
||||
_, err := i.serviceModule.Get(ctx, serviceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -106,11 +106,11 @@ func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string
|
||||
proxy.Plugins["ai_formatter"] = api.PluginSetting{
|
||||
Config: plugin_model.ConfigType{
|
||||
"model": input.AiModel.Id,
|
||||
"provider": fmt.Sprintf("%s@ai-provider", info.Provider.Id),
|
||||
"provider": fmt.Sprintf("%s@ai-provider", input.AiModel.Provider),
|
||||
"config": input.AiModel.Config,
|
||||
},
|
||||
}
|
||||
upstream = &info.Provider.Id
|
||||
upstream = &input.AiModel.Provider
|
||||
}
|
||||
|
||||
if input.AiPrompt != nil {
|
||||
|
||||
@@ -45,8 +45,8 @@ func (p *imlCluster) Check(ctx *gin.Context, input *cluster_dto.CheckCluster) ([
|
||||
// return id, nil
|
||||
//}
|
||||
//
|
||||
//func (p *imlCluster) Search(ctx *gin.Context, keyword string) ([]*parition_dto.Item, error) {
|
||||
// return p.module.Search(ctx, keyword)
|
||||
//func (p *imlCluster) SearchByDriver(ctx *gin.Context, keyword string) ([]*parition_dto.Item, error) {
|
||||
// return p.module.SearchByDriver(ctx, keyword)
|
||||
//}
|
||||
//
|
||||
//func (p *imlCluster) Simple(ctx *gin.Context) ([]*parition_dto.Simple, error) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
log_dto "github.com/APIParkLab/APIPark/module/log/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ILogController interface {
|
||||
Save(ctx *gin.Context, driver string, input *log_dto.Save) error
|
||||
Get(ctx *gin.Context, driver string) (*log_dto.LogSource, error)
|
||||
}
|
||||
|
||||
func init() {
|
||||
logController := &imlLogController{}
|
||||
autowire.Auto[ILogController](func() reflect.Value {
|
||||
return reflect.ValueOf(logController)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/APIParkLab/APIPark/module/log"
|
||||
log_dto "github.com/APIParkLab/APIPark/module/log/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type imlLogController struct {
|
||||
module log.ILogModule `autowired:""`
|
||||
}
|
||||
|
||||
func (c *imlLogController) Save(ctx *gin.Context, driver string, input *log_dto.Save) error {
|
||||
return c.module.Save(ctx, driver, input)
|
||||
}
|
||||
|
||||
func (c *imlLogController) Get(ctx *gin.Context, driver string) (*log_dto.LogSource, error) {
|
||||
return c.module.Get(ctx, driver)
|
||||
}
|
||||
@@ -17,6 +17,70 @@ type imlMonitorStatisticController struct {
|
||||
module monitor.IMonitorStatisticModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error) {
|
||||
switch dataType {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.ApiStatistics(ctx, input)
|
||||
case monitor_dto.DataTypeProvider:
|
||||
return i.module.ProviderStatistics(ctx, input)
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
return i.module.SubscriberStatistics(ctx, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported data type: %s", dataType)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) InvokeTrend(ctx *gin.Context, dataType string, id string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
|
||||
switch dataType {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.APITrend(ctx, id, input)
|
||||
case monitor_dto.DataTypeProvider:
|
||||
return i.module.ProviderTrend(ctx, id, input)
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
return i.module.SubscriberTrend(ctx, id, input)
|
||||
default:
|
||||
return nil, "", fmt.Errorf("unsupported data type: %s", dataType)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) InvokeTrendInner(ctx *gin.Context, dataType string, typ string, api string, provider string, subscriber string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
|
||||
if dataType == monitor_dto.DataTypeApi && typ == monitor_dto.DataTypeSubscriber || dataType == monitor_dto.DataTypeSubscriber && typ == monitor_dto.DataTypeApi {
|
||||
return i.module.InvokeTrendWithSubscriberAndApi(ctx, api, subscriber, input)
|
||||
} else if dataType == monitor_dto.DataTypeApi && typ == monitor_dto.DataTypeProvider || dataType == monitor_dto.DataTypeProvider && typ == monitor_dto.DataTypeApi {
|
||||
return i.module.InvokeTrendWithProviderAndApi(ctx, provider, api, input)
|
||||
}
|
||||
return nil, "", fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) StatisticsInner(ctx *gin.Context, dataType string, typ string, id string, input *monitor_dto.StatisticInput) (interface{}, error) {
|
||||
switch dataType {
|
||||
case monitor_dto.DataTypeApi:
|
||||
switch typ {
|
||||
case monitor_dto.DataTypeProvider:
|
||||
return i.module.ProviderStatisticsOnApi(ctx, id, input)
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
return i.module.SubscriberStatisticsOnApi(ctx, id, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
case monitor_dto.DataTypeProvider:
|
||||
switch typ {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.ApiStatisticsOnProvider(ctx, id, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
case monitor_dto.DataTypeSubscriber:
|
||||
switch typ {
|
||||
case monitor_dto.DataTypeApi:
|
||||
return i.module.ApiStatisticsOnSubscriber(ctx, id, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported data type: %s", dataType)
|
||||
}
|
||||
|
||||
func (i *imlMonitorStatisticController) OverviewMessageTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []float64, []float64, string, error) {
|
||||
trend, timeInterval, err := i.module.MessageTrend(ctx, input)
|
||||
if err != nil {
|
||||
|
||||
@@ -16,7 +16,12 @@ type IMonitorStatisticController interface {
|
||||
OverviewInvokeTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []int64, []int64, []int64, []int64, []float64, []float64, string, error)
|
||||
OverviewMessageTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []float64, []float64, string, error)
|
||||
|
||||
//Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error)
|
||||
Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error)
|
||||
|
||||
InvokeTrend(ctx *gin.Context, dataType string, id string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
|
||||
|
||||
InvokeTrendInner(ctx *gin.Context, dataType string, typ string, api string, provider string, subscriber string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
|
||||
StatisticsInner(ctx *gin.Context, dataType string, typ string, id string, input *monitor_dto.StatisticInput) (interface{}, error)
|
||||
}
|
||||
|
||||
type IMonitorConfigController interface {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
api_doc "github.com/APIParkLab/APIPark/module/api-doc"
|
||||
api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto"
|
||||
"github.com/APIParkLab/APIPark/module/router"
|
||||
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
)
|
||||
|
||||
var _ IRouterController = (*imlAPIController)(nil)
|
||||
@@ -15,6 +16,10 @@ type imlAPIController struct {
|
||||
module router.IRouterModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Simple(ctx *gin.Context, input *router_dto.InputSimpleAPI) ([]*router_dto.SimpleItem, error) {
|
||||
return i.module.SimpleAPIs(ctx, input)
|
||||
}
|
||||
|
||||
func (i *imlAPIController) Detail(ctx *gin.Context, serviceId string, apiId string) (*router_dto.Detail, error) {
|
||||
return i.module.Detail(ctx, serviceId, apiId)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto"
|
||||
"reflect"
|
||||
|
||||
api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
@@ -24,6 +25,7 @@ type IRouterController interface {
|
||||
Delete(ctx *gin.Context, serviceId string, apiId string) error
|
||||
// Prefix 获取API前缀
|
||||
Prefix(ctx *gin.Context, serviceId string) (string, bool, error)
|
||||
Simple(ctx *gin.Context, input *router_dto.InputSimpleAPI) ([]*router_dto.SimpleItem, error)
|
||||
}
|
||||
|
||||
type IAPIDocController interface {
|
||||
|
||||
+135
-32
@@ -5,6 +5,19 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/eolinker/go-common/pm3"
|
||||
|
||||
"github.com/APIParkLab/APIPark/module/system"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
api_doc "github.com/APIParkLab/APIPark/module/api-doc"
|
||||
|
||||
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
|
||||
|
||||
"github.com/eolinker/eosc/log"
|
||||
|
||||
application_authorization "github.com/APIParkLab/APIPark/module/application-authorization"
|
||||
application_authorization_dto "github.com/APIParkLab/APIPark/module/application-authorization/dto"
|
||||
@@ -22,7 +35,6 @@ import (
|
||||
"github.com/APIParkLab/APIPark/module/service"
|
||||
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
|
||||
"github.com/APIParkLab/APIPark/module/upstream"
|
||||
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
|
||||
"github.com/eolinker/go-common/store"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
@@ -39,29 +51,102 @@ type imlServiceController struct {
|
||||
docModule service.IServiceDocModule `autowired:""`
|
||||
aiAPIModule ai_api.IAPIModule `autowired:""`
|
||||
routerModule router.IRouterModule `autowired:""`
|
||||
apiDocModule api_doc.IAPIDocModule `autowired:""`
|
||||
providerModule ai.IProviderModule `autowired:""`
|
||||
upstreamModule upstream.IUpstreamModule `autowired:""`
|
||||
settingModule system.ISettingModule `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
}
|
||||
|
||||
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
|
||||
return &upstream_dto.Upstream{
|
||||
Type: "http",
|
||||
Balance: "round-robin",
|
||||
Timeout: 300000,
|
||||
Retry: 0,
|
||||
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
|
||||
LimitPeerSecond: 0,
|
||||
ProxyHeaders: nil,
|
||||
Scheme: uri.Scheme(),
|
||||
PassHost: "node",
|
||||
Nodes: []*upstream_dto.NodeConfig{
|
||||
{
|
||||
Address: uri.Host(),
|
||||
Weight: 100,
|
||||
},
|
||||
},
|
||||
var (
|
||||
loader = openapi3.NewLoader()
|
||||
)
|
||||
|
||||
func (i *imlServiceController) swagger(ctx *gin.Context, id string) (*openapi3.T, error) {
|
||||
doc, err := i.apiDocModule.GetDoc(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmp, err := loader.LoadFromData([]byte(doc.Content))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := i.settingModule.Get(ctx)
|
||||
|
||||
tmp.AddServer(&openapi3.Server{
|
||||
URL: cfg.InvokeAddress,
|
||||
})
|
||||
return tmp, nil
|
||||
}
|
||||
|
||||
func (i *imlServiceController) ExportSwagger(ctx *gin.Context) {
|
||||
id, has := ctx.Params.Get("id")
|
||||
if !has {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: fmt.Sprintf("id is required"),
|
||||
})
|
||||
return
|
||||
}
|
||||
s, err := i.module.Get(ctx, id)
|
||||
if err != nil {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
tmp, err := i.swagger(ctx, id)
|
||||
if err != nil {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
data, _ := tmp.MarshalJSON()
|
||||
ctx.Status(200)
|
||||
// 设置响应头
|
||||
ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.json", strings.Replace(s.Name, " ", "_", -1)))
|
||||
ctx.Header("Content-Type", "application/octet-stream")
|
||||
ctx.Header("Content-Transfer-Encoding", "binary")
|
||||
ctx.Writer.Write(data)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *imlServiceController) Swagger(ctx *gin.Context) {
|
||||
id, has := ctx.Params.Get("id")
|
||||
if !has {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: fmt.Sprintf("id is required"),
|
||||
})
|
||||
return
|
||||
}
|
||||
tmp, err := i.swagger(ctx, id)
|
||||
if err != nil {
|
||||
ctx.JSON(200, &pm3.Response{
|
||||
Code: -1,
|
||||
Success: "fail",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.JSON(200, tmp)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *imlServiceController) Simple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error) {
|
||||
return i.module.Simple(ctx)
|
||||
}
|
||||
|
||||
func (i *imlServiceController) MySimple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error) {
|
||||
return i.module.MySimple(ctx)
|
||||
}
|
||||
|
||||
func (i *imlServiceController) editAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error) {
|
||||
@@ -151,8 +236,9 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
|
||||
Prompt: "You need to translate {{source_lang}} into {{target_lang}}, and the following is the content that needs to be translated.\n---\n{{text}}",
|
||||
}
|
||||
aiModel := &ai_api_dto.AiModel{
|
||||
Id: m.ID(),
|
||||
Config: m.DefaultConfig(),
|
||||
Id: m.ID(),
|
||||
Config: m.DefaultConfig(),
|
||||
Provider: *input.Provider,
|
||||
}
|
||||
name := "Demo Translation API"
|
||||
description := "A demo that shows you how to use a prompt to create a Translation API."
|
||||
@@ -211,10 +297,7 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//_, err = i.upstreamModule.Save(ctx, info.Id, newAIUpstream(info.Id, *input.Provider, p.URI()))
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
return i.docModule.SaveServiceDoc(ctx, info.Id, &service_dto.SaveServiceDoc{
|
||||
Doc: "The Translation API allows developers to translate text from one language to another. It supports multiple languages and enables easy integration of high-quality translation features into applications. With simple API requests, you can quickly translate content into different target languages.",
|
||||
})
|
||||
@@ -227,15 +310,11 @@ func (i *imlServiceController) SearchMyServices(ctx *gin.Context, teamId string,
|
||||
return i.module.SearchMyServices(ctx, teamId, keyword)
|
||||
}
|
||||
|
||||
//func (i *imlServiceController) Simple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
|
||||
// return i.module.Simple(ctx, keyword)
|
||||
//}
|
||||
//
|
||||
//func (i *imlServiceController) MySimple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
|
||||
// return i.module.MySimple(ctx, keyword)
|
||||
//}
|
||||
|
||||
func (i *imlServiceController) Get(ctx *gin.Context, id string) (*service_dto.Service, error) {
|
||||
now := time.Now()
|
||||
defer func() {
|
||||
log.Infof("get service %s cost %d ms", id, time.Since(now).Milliseconds())
|
||||
}()
|
||||
return i.module.Get(ctx, id)
|
||||
}
|
||||
|
||||
@@ -278,6 +357,10 @@ type imlAppController struct {
|
||||
authModule application_authorization.IAuthorizationModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAppController) SearchCanSubscribe(ctx *gin.Context, serviceId string) ([]*service_dto.SimpleAppItem, error) {
|
||||
return i.module.SearchCanSubscribe(ctx, serviceId)
|
||||
}
|
||||
|
||||
func (i *imlAppController) Search(ctx *gin.Context, teamId string, keyword string) ([]*service_dto.AppItem, error) {
|
||||
return i.module.Search(ctx, teamId, keyword)
|
||||
}
|
||||
@@ -326,3 +409,23 @@ func (i *imlAppController) GetApp(ctx *gin.Context, appId string) (*service_dto.
|
||||
func (i *imlAppController) DeleteApp(ctx *gin.Context, appId string) error {
|
||||
return i.module.DeleteApp(ctx, appId)
|
||||
}
|
||||
|
||||
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
|
||||
return &upstream_dto.Upstream{
|
||||
Type: "http",
|
||||
Balance: "round-robin",
|
||||
Timeout: 300000,
|
||||
Retry: 0,
|
||||
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
|
||||
LimitPeerSecond: 0,
|
||||
ProxyHeaders: nil,
|
||||
Scheme: uri.Scheme(),
|
||||
PassHost: "node",
|
||||
Nodes: []*upstream_dto.NodeConfig{
|
||||
{
|
||||
Address: uri.Host(),
|
||||
Weight: 100,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ type IServiceController interface {
|
||||
Delete(ctx *gin.Context, id string) error
|
||||
ServiceDoc(ctx *gin.Context, id string) (*service_dto.ServiceDoc, error)
|
||||
SaveServiceDoc(ctx *gin.Context, id string, input *service_dto.SaveServiceDoc) error
|
||||
Simple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error)
|
||||
MySimple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error)
|
||||
|
||||
//createAIService(ctx *gin.Context, teamID string, input *service_dto.CreateService) (*service_dto.Service, error)
|
||||
//editAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error)
|
||||
//DeleteAIService(ctx *gin.Context, id string) error
|
||||
//SearchMyAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
|
||||
//SearchAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
|
||||
Swagger(ctx *gin.Context)
|
||||
ExportSwagger(ctx *gin.Context)
|
||||
}
|
||||
|
||||
type IAppController interface {
|
||||
@@ -42,6 +41,7 @@ type IAppController interface {
|
||||
// SimpleApps 获取简易项目列表
|
||||
SimpleApps(ctx *gin.Context, keyword string) ([]*service_dto.SimpleAppItem, error)
|
||||
MySimpleApps(ctx *gin.Context, keyword string) ([]*service_dto.SimpleAppItem, error)
|
||||
SearchCanSubscribe(ctx *gin.Context, keyword string) ([]*service_dto.SimpleAppItem, error)
|
||||
GetApp(ctx *gin.Context, appId string) (*service_dto.App, error)
|
||||
DeleteApp(ctx *gin.Context, appId string) error
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
package strategy
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/eolinker/go-common/utils"
|
||||
|
||||
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
|
||||
|
||||
"github.com/APIParkLab/APIPark/module/service"
|
||||
"github.com/APIParkLab/APIPark/module/strategy"
|
||||
strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var _ IStrategyController = (*imlStrategyController)(nil)
|
||||
|
||||
type imlStrategyController struct {
|
||||
strategyModule strategy.IStrategyModule `autowired:""`
|
||||
serviceModule service.IServiceModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) Restore(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Restore(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) DeleteServiceStrategy(ctx *gin.Context, serviceId string, id string) error {
|
||||
return i.strategyModule.DeleteServiceStrategy(ctx, serviceId, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) ToPublish(ctx *gin.Context, driver string) ([]*strategy_dto.ToPublishItem, string, string, bool, error) {
|
||||
list, err := i.strategyModule.ToPublish(ctx, driver)
|
||||
if err != nil {
|
||||
return nil, "", "", false, err
|
||||
}
|
||||
data, _ := json.Marshal(list)
|
||||
source := base64.StdEncoding.EncodeToString(data)
|
||||
return list, source, time.Now().Format("20060102150405") + "-release", len(list) > 0, nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterGlobalRemote(ctx *gin.Context, name string) ([]*strategy_dto.Title, []any, int64, string, string, error) {
|
||||
f, has := strategy_filter.RemoteFilter(name)
|
||||
if !has {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("filter not found: %s", name)
|
||||
}
|
||||
scopeAllow := false
|
||||
for _, s := range f.Scopes() {
|
||||
if s == strategy_filter.ScopeGlobal {
|
||||
scopeAllow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !scopeAllow {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("scope not allowed: %s", name)
|
||||
}
|
||||
|
||||
list, total, err := f.RemoteList(ctx, "", nil, -1, -1)
|
||||
if err != nil {
|
||||
return nil, nil, 0, "", "", err
|
||||
}
|
||||
return utils.SliceToSlice(f.Titles(), func(l strategy_filter.OptionTitle) *strategy_dto.Title {
|
||||
return &strategy_dto.Title{
|
||||
Field: l.Field,
|
||||
Title: l.Title,
|
||||
}
|
||||
}), list, total, f.Key(), f.Key(), nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterServiceRemote(ctx *gin.Context, serviceId string, name string) ([]*strategy_dto.Title, []any, int64, string, string, error) {
|
||||
f, has := strategy_filter.RemoteFilter(name)
|
||||
if !has {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("filter not found: %s", name)
|
||||
}
|
||||
scopeAllow := false
|
||||
for _, s := range f.Scopes() {
|
||||
if s == strategy_filter.ScopeService {
|
||||
scopeAllow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !scopeAllow {
|
||||
return nil, nil, 0, "", "", fmt.Errorf("scope not allowed: %s", name)
|
||||
}
|
||||
list, total, err := f.RemoteList(ctx, "", map[string]interface{}{"service": serviceId}, -1, -1)
|
||||
if err != nil {
|
||||
return nil, nil, 0, "", "", err
|
||||
}
|
||||
return utils.SliceToSlice(f.Titles(), func(l strategy_filter.OptionTitle) *strategy_dto.Title {
|
||||
return &strategy_dto.Title{
|
||||
Field: l.Field,
|
||||
Title: l.Title,
|
||||
}
|
||||
}), list, total, f.Key(), "list", nil
|
||||
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) filterOptions(ctx *gin.Context, scope string) ([]*strategy_dto.FilterOption, error) {
|
||||
m, has := strategy_filter.Options(scope)
|
||||
if !has {
|
||||
return nil, fmt.Errorf("scope not found: %s", scope)
|
||||
}
|
||||
|
||||
list := utils.MapToSlice(m, func(key string, value *strategy_filter.Option) *strategy_dto.FilterOption {
|
||||
pattern := ""
|
||||
if value.Pattern != nil {
|
||||
pattern = value.Pattern.String()
|
||||
}
|
||||
return &strategy_dto.FilterOption{
|
||||
Name: value.Name,
|
||||
Title: value.Title,
|
||||
Type: value.Type,
|
||||
Pattern: pattern,
|
||||
Options: value.Options,
|
||||
}
|
||||
})
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return list[i].Name < list[j].Name
|
||||
})
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterServiceOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error) {
|
||||
return i.filterOptions(ctx, strategy_filter.ScopeService)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) FilterGlobalOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error) {
|
||||
return i.filterOptions(ctx, strategy_filter.ScopeGlobal)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) GetStrategy(ctx *gin.Context, id string) (*strategy_dto.Strategy, error) {
|
||||
return i.strategyModule.Get(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) search(ctx *gin.Context, keyword string, scope strategy_dto.Scope, target string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) {
|
||||
p, err := strconv.Atoi(page)
|
||||
if err != nil {
|
||||
if page != "" {
|
||||
return nil, 0, fmt.Errorf("page error: %s", err)
|
||||
}
|
||||
p = 1
|
||||
}
|
||||
ps, err := strconv.Atoi(pageSize)
|
||||
if err != nil {
|
||||
if pageSize != "" {
|
||||
return nil, 0, fmt.Errorf("page size error: %s", err)
|
||||
}
|
||||
ps = 20
|
||||
}
|
||||
ss := make([]string, 0)
|
||||
json.Unmarshal([]byte(sort), &ss)
|
||||
fs := make([]string, 0)
|
||||
json.Unmarshal([]byte(filters), &fs)
|
||||
list, total, err := i.strategyModule.Search(ctx, keyword, driver, scope, target, p, ps, fs, ss...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) GlobalStrategyList(ctx *gin.Context, keyword string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) {
|
||||
|
||||
return i.search(ctx, keyword, strategy_dto.ToScope(strategy_dto.ScopeGlobal), "", driver, page, pageSize, order, sort, filters)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) CreateGlobalStrategy(ctx *gin.Context, driver string, input *strategy_dto.Create) error {
|
||||
input.Driver = driver
|
||||
input.Scope = strategy_dto.ToScope(strategy_dto.ScopeGlobal)
|
||||
|
||||
return i.strategyModule.Create(ctx, input)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) PublishGlobalStrategy(ctx *gin.Context, driver string) error {
|
||||
return i.strategyModule.Publish(ctx, driver, strategy_dto.ScopeGlobal, "")
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) ServiceStrategyList(ctx *gin.Context, keyword string, serviceId string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) {
|
||||
|
||||
return i.search(ctx, keyword, strategy_dto.ToScope(strategy_dto.ScopeService), serviceId, driver, page, pageSize, order, sort, filters)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) CreateServiceStrategy(ctx *gin.Context, serviceId string, driver string, input *strategy_dto.Create) error {
|
||||
_, err := i.serviceModule.Get(ctx, serviceId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create service strategy error: %s", err)
|
||||
}
|
||||
input.Driver = driver
|
||||
input.Scope = strategy_dto.ToScope(strategy_dto.ScopeService)
|
||||
input.Target = serviceId
|
||||
|
||||
return i.strategyModule.Create(ctx, input)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) EditStrategy(ctx *gin.Context, id string, input *strategy_dto.Edit) error {
|
||||
return i.strategyModule.Edit(ctx, id, input)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) EnableStrategy(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Enable(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) DisableStrategy(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Disable(ctx, id)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) DeleteStrategy(ctx *gin.Context, id string) error {
|
||||
return i.strategyModule.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func genTime(t string, defaultValue time.Time) (time.Time, error) {
|
||||
if t == "" {
|
||||
return defaultValue, nil
|
||||
}
|
||||
|
||||
s, err := strconv.ParseInt(t, 10, 64)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Unix(s, 0), nil
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) GetStrategyLogs(ctx *gin.Context, keyword string, strategyId string, start string, end string, limit string, offset string) ([]*strategy_dto.LogItem, int64, error) {
|
||||
now := time.Now()
|
||||
|
||||
s, err := genTime(start, now.Add(-time.Hour*24*30))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("start time error: %s", err)
|
||||
}
|
||||
e, err := genTime(end, now)
|
||||
if err != nil {
|
||||
|
||||
return nil, 0, fmt.Errorf("end time error: %s", err)
|
||||
}
|
||||
if s.After(e) {
|
||||
return nil, 0, fmt.Errorf("start time must be less than end time")
|
||||
}
|
||||
l, err := strconv.ParseInt(limit, 10, 64)
|
||||
if err != nil && limit != "" {
|
||||
|
||||
return nil, 0, err
|
||||
}
|
||||
o, err := strconv.ParseInt(offset, 10, 64)
|
||||
if err != nil && offset != "" {
|
||||
return nil, 0, err
|
||||
}
|
||||
if l < 1 {
|
||||
l = 15
|
||||
}
|
||||
if o < 1 {
|
||||
o = 1
|
||||
}
|
||||
return i.strategyModule.GetStrategyLogs(ctx, keyword, strategyId, s, e, l, o)
|
||||
}
|
||||
|
||||
func (i *imlStrategyController) LogInfo(ctx *gin.Context, id string) (*strategy_dto.LogInfo, error) {
|
||||
|
||||
return i.strategyModule.StrategyLogInfo(ctx, id)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package strategy
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type IStrategyController interface {
|
||||
GlobalStrategyList(ctx *gin.Context, keyword string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error)
|
||||
CreateGlobalStrategy(ctx *gin.Context, driver string, input *strategy_dto.Create) error
|
||||
PublishGlobalStrategy(ctx *gin.Context, driver string) error
|
||||
|
||||
ServiceStrategyList(ctx *gin.Context, keyword string, serviceId string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error)
|
||||
CreateServiceStrategy(ctx *gin.Context, serviceId string, driver string, input *strategy_dto.Create) error
|
||||
|
||||
EditStrategy(ctx *gin.Context, id string, input *strategy_dto.Edit) error
|
||||
GetStrategy(ctx *gin.Context, id string) (*strategy_dto.Strategy, error)
|
||||
EnableStrategy(ctx *gin.Context, id string) error
|
||||
DisableStrategy(ctx *gin.Context, id string) error
|
||||
|
||||
DeleteStrategy(ctx *gin.Context, id string) error
|
||||
DeleteServiceStrategy(ctx *gin.Context, serviceId string, id string) error
|
||||
|
||||
Restore(ctx *gin.Context, id string) error
|
||||
|
||||
FilterGlobalOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error)
|
||||
FilterServiceOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error)
|
||||
|
||||
FilterGlobalRemote(ctx *gin.Context, name string) ([]*strategy_dto.Title, []any, int64, string, string, error)
|
||||
FilterServiceRemote(ctx *gin.Context, serviceId string, name string) ([]*strategy_dto.Title, []any, int64, string, string, error)
|
||||
|
||||
ToPublish(ctx *gin.Context, driver string) ([]*strategy_dto.ToPublishItem, string, string, bool, error)
|
||||
|
||||
GetStrategyLogs(ctx *gin.Context, keyword string, strategyId string, start string, end string, limit string, offset string) ([]*strategy_dto.LogItem, int64, error)
|
||||
LogInfo(ctx *gin.Context, id string) (*strategy_dto.LogInfo, error)
|
||||
}
|
||||
|
||||
type IStrategyCommonController interface {
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[IStrategyController](func() reflect.Value {
|
||||
return reflect.ValueOf(&imlStrategyController{})
|
||||
})
|
||||
}
|
||||
@@ -381,8 +381,9 @@ func (i *imlInitController) createAIService(ctx context.Context, teamID string,
|
||||
Prompt: "You need to translate {{source_lang}} into {{target_lang}}, and the following is the content that needs to be translated.\n---\n{{text}}",
|
||||
}
|
||||
aiModel := &ai_api_dto.AiModel{
|
||||
Id: m.ID(),
|
||||
Config: m.DefaultConfig(),
|
||||
Id: m.ID(),
|
||||
Config: m.DefaultConfig(),
|
||||
Provider: providerId,
|
||||
}
|
||||
name := "Demo Translation API"
|
||||
description := "A demo that shows you how to use a prompt to create a Translation API."
|
||||
|
||||
@@ -27,4 +27,5 @@ packages/core/public/tinymce/
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
|
||||
/pnpm-lock.yaml
|
||||
|
||||
+12
-5
@@ -1,10 +1,17 @@
|
||||
# 部署
|
||||
|
||||
## 安装依赖
|
||||
建议使用pnpm
|
||||
`npm install -g pnpm`
|
||||
使用pnpm安装依赖
|
||||
`pnpm install`
|
||||
建议使用 pnpm
|
||||
```
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
使用pnpm安装依赖
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## 编译
|
||||
`pnpm run build`
|
||||
```
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# 部署
|
||||
|
||||
## 代码同步
|
||||
packages目录下,部分子项目为企业版独有,不要同步到开源版:
|
||||
packages/businessEntry, packages/openApi, packages/systemRunning, README.pro.md
|
||||
|
||||
## 安装依赖
|
||||
建议使用pnpm
|
||||
`npm install -g pnpm`
|
||||
使用pnpm安装依赖
|
||||
`pnpm install`
|
||||
|
||||
## 编译
|
||||
### 开源版本
|
||||
`pnpm run build`
|
||||
### 企业版本
|
||||
`pnpm run build:pro`
|
||||
@@ -1,10 +1,3 @@
|
||||
/*
|
||||
* @Date: 2024-05-10 14:19:56
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-05-10 15:55:29
|
||||
* @FilePath: \frontend\jest.config.js
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
roots: ['<rootDir>/packages'],
|
||||
testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'],
|
||||
@@ -15,4 +8,4 @@ module.exports = {
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
||||
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
/*
|
||||
* @Date: 2024-05-10 14:22:41
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-05-10 15:49:31
|
||||
* @FilePath: \frontend\jest.setup.js
|
||||
*/
|
||||
// import '@testing-library/jest-dom/extend-expect';
|
||||
// import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
"packages/*"
|
||||
],
|
||||
"version": "independent"
|
||||
|
||||
}
|
||||
@@ -9,11 +9,9 @@
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"build": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=core --stream --verbose ",
|
||||
"build:pro": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=business-entry --stream --verbose ",
|
||||
"serve": "lerna run preview --parallel",
|
||||
"serve:remotes": "lerna run serve --scope=remote --parallel",
|
||||
"dev": "lerna run dev --scope=core --stream",
|
||||
"dev:pro": "lerna run dev --scope=business-entry --stream",
|
||||
"stop": "kill-port --port 5000",
|
||||
"scan": "i18next-scanner --config i18next-scanner.config.js"
|
||||
},
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
// .env.pro
|
||||
VITE_APP_MODE=pro
|
||||
VITE_APP_TITLE=My Production App
|
||||
VITE_API_BASE_URL=https://api.production.example.com
|
||||
@@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs','public','code-snippet','ace-editor'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
public/tinymce
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# `businessEntry`
|
||||
|
||||
> TODO: description
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
const businessEntry = require('businessEntry');
|
||||
|
||||
// TODO: DEMONSTRATE API
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const businessEntry = require('..');
|
||||
const assert = require('assert').strict;
|
||||
|
||||
assert.strictEqual(businessEntry(), 'Hello from businessEntry');
|
||||
console.info('businessEntry tests passed');
|
||||
@@ -1,15 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/frontend/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>APIPark - 企业API数据开放平台</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script src="/frontend/iconpark_eolink.js"></script>
|
||||
<script src="/frontend/iconpark_apinto.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "business-entry",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": " vite --port 5000 --strictPort",
|
||||
"build": "vite build ",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview --port 5000 --strictPort",
|
||||
"serve": "vite preview --port 5000 --strictPort"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* @Date: 2023-11-27 17:31:54
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-06-05 10:42:18
|
||||
* @FilePath: \frontend\packages\core\postcss.config.js
|
||||
*/
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
},
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,158 +0,0 @@
|
||||
import '@core/App.css'
|
||||
import { ConfigProvider } from 'antd';
|
||||
import RenderRoutes from '@businessEntry/components/aoplatform/RenderRoutes';
|
||||
import {BreadcrumbProvider} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import useInitializeMonaco from "@common/hooks/useInitializeMonaco";
|
||||
import ThemeSwitcher from '@common/components/aoplatform/ThemeSwitcher'
|
||||
|
||||
const antdComponentThemeToken = {
|
||||
token: {
|
||||
// Seed Token,影响范围大
|
||||
colorPrimary: '#3D46F2',
|
||||
colorLink:'#3D46F2',
|
||||
colorBorder:'#ededed',
|
||||
colorText:'#333',
|
||||
borderRadius: 4,
|
||||
// 派生变量,影响范围小
|
||||
colorBgContainer: '#fff',
|
||||
colorPrimaryBg:'#EBEEF2',
|
||||
colorTextQuaternary:'#BBB',
|
||||
colorTextTertiary:'#999'
|
||||
},
|
||||
components:{
|
||||
// 派生变量,影响范围小
|
||||
Input:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Select:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Checkbox:{
|
||||
activeShadow:'none'
|
||||
},
|
||||
Cascader:{
|
||||
activeShadow:'none',
|
||||
optionSelectedBg:'#EBEEF2',
|
||||
optionHoverBg:'#EBEEF2'
|
||||
},
|
||||
Layout: {
|
||||
bodyBg: '#17163E',
|
||||
headerBg: 'transparent',
|
||||
headerColor: '#333',
|
||||
headerPadding: '10 20px',
|
||||
lightSiderBg: 'transparent',
|
||||
siderBg: 'transparent',
|
||||
},
|
||||
Breadcrumb:{
|
||||
itemColor:'#666',
|
||||
linkColor:'#666',
|
||||
lastItemColor:'#333',
|
||||
},
|
||||
Table:{
|
||||
headerBorderRadius:0,
|
||||
headerSplitColor:'#ededed',
|
||||
borderColor:'#ededed',
|
||||
cellPaddingBlockMD:'10px',
|
||||
cellPaddingInlineMD:'12px',
|
||||
cellPaddingBlockSM:'8px',
|
||||
cellPaddingInlineSM:'12px',
|
||||
headerFilterHoverBg:'#EBEEF2',
|
||||
headerSortActiveBg:'#F7F8FA',
|
||||
headerSortHoverBg:'#F7F8FA',
|
||||
fixedHeaderSortActiveBg:'#F7F8FA',
|
||||
headerBg:'#F7F8FA',
|
||||
rowHoverBg:'#EBEEF2'
|
||||
|
||||
},
|
||||
Segmented:{
|
||||
itemColor:'#333',
|
||||
itemSelectedColor:'#333',
|
||||
trackBg:'#f7f8fa',
|
||||
trackPadding:0,
|
||||
// itemHoverColor:'#EBEEF2',
|
||||
itemActiveBg:'#EBEEF2',
|
||||
itemHoverBg:'#EBEEF2',
|
||||
itemSelectedBg:'#EBEEF2',
|
||||
},
|
||||
Tree:{
|
||||
// titleHeight:30,
|
||||
// fontSize:12,
|
||||
directoryNodeSelectedBg:'#EBEEF2',
|
||||
directoryNodeSelectedColor:'#333',
|
||||
nodeSelectedBg:'#EBEEF2',
|
||||
nodeHoverBg:'#EBEEF2'
|
||||
},
|
||||
Collapse:{
|
||||
headerBg:'#f7f8fa',
|
||||
headerPadding:"12px",
|
||||
contentPadding:"0 10px 12px 10px"
|
||||
},
|
||||
Button:{
|
||||
// paddingInline:8,
|
||||
dangerShadow:'none',
|
||||
defaultShadow:'none',
|
||||
primaryShadow:'none'
|
||||
},
|
||||
Tabs:{
|
||||
cardBg:'#EBEEF2',
|
||||
cardHeight:42,
|
||||
horizontalItemGutter:8,
|
||||
horizontalItemPaddingSM:'12px 8px 8px 8px',
|
||||
horizontalItemPadding:'12px 8px 8px 8px',
|
||||
},
|
||||
Menu:{
|
||||
// itemBg:'#F7F8FA',
|
||||
// subMenuItemBg:'#F7F8FA',
|
||||
// itemMarginBlock:0,
|
||||
// activeBarBorderWidth:0,
|
||||
// itemSelectedColor:'#333',
|
||||
// itemSelectedBg:'#EBEEF2',
|
||||
// itemHoverBg:'#EBEEF2'
|
||||
// itemHeight:'72px',
|
||||
// darkItemBg:'transparent',
|
||||
// itemBg:'transparent',
|
||||
// itemSelectedBg:'transparent',
|
||||
// darkItemSelectedBg:'transparent',
|
||||
// subMenuItemBg:'transparent',
|
||||
// itemActiveBg:'transparent',
|
||||
// darkSubMenuItemBg:'transparent',
|
||||
// activeBarHeight:'2px',
|
||||
// activeBarBorderWidth:2
|
||||
},
|
||||
List:{
|
||||
itemPadding:'8px 0'
|
||||
},
|
||||
Form:{
|
||||
itemMarginBottom:10,
|
||||
|
||||
},
|
||||
Alert:{
|
||||
defaultPadding:'12px 16px'
|
||||
},
|
||||
Tag:{
|
||||
defaultBg:"#f7f8fa"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
useInitializeMonaco()
|
||||
|
||||
return (
|
||||
<StyleProvider hashPriority={"high"}>
|
||||
<ConfigProvider
|
||||
locale={zhCN}
|
||||
wave={{disabled:true}}
|
||||
theme={antdComponentThemeToken}>
|
||||
<ThemeSwitcher />
|
||||
<BreadcrumbProvider>
|
||||
<RenderRoutes />
|
||||
</BreadcrumbProvider>
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -1,484 +0,0 @@
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from 'react-router-dom';
|
||||
import Login from "@core/pages/Login.tsx"
|
||||
import BasicLayout from '@common/components/aoplatform/BasicLayout';
|
||||
import {createElement, ReactElement,ReactNode,Suspense} from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {App, Skeleton} from "antd";
|
||||
import ApprovalPage from "@core/pages/approval/ApprovalPage.tsx";
|
||||
import {SystemProvider} from "@core/contexts/SystemContext.tsx";
|
||||
import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx";
|
||||
import {FC,lazy} from 'react';
|
||||
import { TeamProvider } from '@core/contexts/TeamContext.tsx';
|
||||
import SystemOutlet from '@core/pages/system/SystemOutlet.tsx';
|
||||
import { DashboardProvider } from '@core/contexts/DashboardContext.tsx';
|
||||
import { TenantManagementProvider } from '@market/contexts/TenantManagementContext.tsx';
|
||||
|
||||
type RouteConfig = {
|
||||
path:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
}
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
}
|
||||
|
||||
const PUBLIC_ROUTES:RouteConfig[] = [
|
||||
{
|
||||
path:'/',
|
||||
component:<Login/>,
|
||||
key: uuidv4(),
|
||||
},
|
||||
{
|
||||
path:'/login',
|
||||
component:<Login/>,
|
||||
key: uuidv4()
|
||||
},
|
||||
{
|
||||
path:'/',
|
||||
component:<ProtectedRoute/>,
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'approval/*',
|
||||
component:<ApprovalPage />,
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'team',
|
||||
component:<Outlet/>,
|
||||
key: uuidv4(),
|
||||
provider: TeamProvider,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamList.tsx'))
|
||||
},
|
||||
{
|
||||
path:'inside/:teamId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsidePage.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'member',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamInsideMember.tsx')),
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/team/TeamConfig.tsx')),
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'service',
|
||||
component:<SystemOutlet />,
|
||||
key: uuidv4(),
|
||||
provider: SystemProvider,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:uuidv4(),
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:teamId',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemList.tsx')),
|
||||
},
|
||||
{
|
||||
path:':teamId',
|
||||
component:<Outlet/>,
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'inside/:serviceId',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'api',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideApiDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path:'router',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/api/SystemInsideRouterList')),
|
||||
},
|
||||
{
|
||||
path:'upstream',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/upstream/SystemInsideUpstreamContent.tsx')),
|
||||
},
|
||||
{
|
||||
path:'document',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideDocument.tsx')),
|
||||
},
|
||||
{
|
||||
path:'subscriber',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemInsideSubscriber.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'approval',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApproval.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/approval/SystemInsideApprovalList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'topology',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemTopology.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'publish',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublish.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'*',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/publish/SystemInsidePublishList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/system/SystemConfig.tsx')),
|
||||
children:[
|
||||
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},{
|
||||
path:'datasourcing',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideDashboardSetting.tsx')),
|
||||
},
|
||||
{
|
||||
path:'cluster',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCluster.tsx')),
|
||||
},
|
||||
{
|
||||
path:'cert',
|
||||
key: uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/partitions/PartitionInsideCert.tsx')),
|
||||
},
|
||||
{
|
||||
path:'serviceHub',
|
||||
component:<Outlet />,
|
||||
key:uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'detail/:serviceId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/ServiceHubDetail.tsx')),
|
||||
}]
|
||||
},
|
||||
{
|
||||
path:'commonsetting',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/common/CommonPage.tsx')),
|
||||
key:uuidv4(),
|
||||
},
|
||||
{
|
||||
path:'consumer',
|
||||
component:<Outlet />,
|
||||
provider:TenantManagementProvider,
|
||||
key:uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:uuidv4(),
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:':teamId/inside/:appId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsidePage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'service',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideService.tsx')),
|
||||
},
|
||||
{
|
||||
path:'authorization',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementInsideAuth.tsx')),
|
||||
},
|
||||
{
|
||||
path:'setting',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ManagementAppSetting.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:teamId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@market/pages/serviceHub/management/ServiceHubManagement.tsx')),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'member',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberPage.tsx')),
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
key:uuidv4(),
|
||||
component:<Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
},
|
||||
{
|
||||
path:'list/:memberGroupId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/member/MemberList.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'role',
|
||||
key:uuidv4(),
|
||||
component:<Outlet></Outlet>,
|
||||
children:[
|
||||
{
|
||||
path: '',
|
||||
key: uuidv4(),
|
||||
component: <Navigate to="list" />
|
||||
},
|
||||
{
|
||||
path:'list',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleList.tsx')),
|
||||
},
|
||||
{
|
||||
path:':roleType/config',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
},
|
||||
{
|
||||
path:':roleType/config/:roleId',
|
||||
key:uuidv4(),
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/role/RoleConfig.tsx')),
|
||||
}
|
||||
]
|
||||
},
|
||||
APP_MODE === 'pro' &&{
|
||||
path:'openapi',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@openApi/pages/OpenApiList.tsx')),
|
||||
key:uuidv4(),
|
||||
},
|
||||
{
|
||||
path:'assets',
|
||||
component:<p>设计中</p>,
|
||||
key:uuidv4()
|
||||
},
|
||||
APP_MODE === 'pro' &&{
|
||||
path:'analytics',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/Dashboard.tsx')),
|
||||
key:uuidv4(),
|
||||
children:[
|
||||
{
|
||||
path:':dashboardType',
|
||||
component:<Outlet/>,
|
||||
key:uuidv4(),
|
||||
provider:DashboardProvider,
|
||||
children:[
|
||||
{
|
||||
path:'list',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardList.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'detail/:dashboardDetailId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@dashboard/pages/DashboardDetail.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path:'systemrunning',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@systemRunning/pages/SystemRunning.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '../../../../common/src/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:uuidv4()
|
||||
},
|
||||
{
|
||||
path:'logsettings/*',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/logsettings/LogSettings.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:uuidv4()
|
||||
}]
|
||||
|
||||
},
|
||||
APP_MODE ==='pro' && {
|
||||
path:'resourcesettings/*',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/resourcesettings/ResourceSettings.tsx')),
|
||||
key: uuidv4(),
|
||||
children:[{
|
||||
path:'template/:moduleId',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@common/components/aoplatform/intelligent-plugin/IntelligentPluginList.tsx')),
|
||||
key:uuidv4()
|
||||
}]
|
||||
|
||||
},
|
||||
{
|
||||
path:'userProfile/*',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')),
|
||||
key:uuidv4(),
|
||||
children:[{
|
||||
path:'changepsw',
|
||||
lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')),
|
||||
key:uuidv4()
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
const RenderRoutes = ()=> {
|
||||
return (
|
||||
<App className="h-full" message={{ maxCount: 1 }}>
|
||||
<Router>
|
||||
<Routes>
|
||||
{generateRoutes(PUBLIC_ROUTES)}
|
||||
</Routes>
|
||||
</Router>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
const generateRoutes = (routerConfig: RouteConfig[]) => {
|
||||
return routerConfig?.map((route: RouteConfig) => {
|
||||
let routeElement;
|
||||
if (route.lazy) {
|
||||
const LazyComponent = route.lazy as React.ExoticComponent<unknown>;
|
||||
|
||||
routeElement = (
|
||||
<Suspense fallback={ <div className=''><Skeleton className='m-btnbase w-calc-100vw-minus-padding-r' active /></div>}>
|
||||
{route.provider ? (
|
||||
createElement(route.provider, {}, <LazyComponent />)
|
||||
) : (
|
||||
<LazyComponent />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
} else {
|
||||
routeElement = route.provider ? (
|
||||
createElement(route.provider, {}, route.component)
|
||||
) : (
|
||||
route.component
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Route
|
||||
key={route.key}
|
||||
path={route.path}
|
||||
element={routeElement}
|
||||
>
|
||||
{route.children && generateRoutes(route.children as RouteConfig[])}
|
||||
</Route>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 保护的路由组件
|
||||
function ProtectedRoute() {
|
||||
const {state} = useGlobalContext()
|
||||
return state.isAuthenticated? <BasicLayout project="core" /> : <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
export default RenderRoutes
|
||||
@@ -1,27 +0,0 @@
|
||||
import {StrictMode} from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import '@core/index.css'
|
||||
import {GlobalProvider} from "@common/contexts/GlobalStateContext.tsx";
|
||||
|
||||
async function initializeApp() {
|
||||
try {
|
||||
// 初始化行为
|
||||
// await fetchInitialConfig(); // 示例:获取初始配置
|
||||
|
||||
// 异步操作完成后,渲染React应用
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<GlobalProvider>
|
||||
<App />
|
||||
</GlobalProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Initialization failed:', error);
|
||||
// 处理初始化失败的情况,比如渲染一个错误界面
|
||||
}
|
||||
}
|
||||
|
||||
// 执行初始化
|
||||
initializeApp();
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* @Date: 2024-06-05 09:35:25
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-06-05 10:50:12
|
||||
* @FilePath: \frontend\packages\core\start-vite.js
|
||||
*/
|
||||
// start-vite.js// start-vite.js
|
||||
import { exec } from 'child_process';
|
||||
|
||||
const viteProcess = exec('pnpm run build');
|
||||
|
||||
viteProcess.stdout.on('data', (data) => {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
viteProcess.stderr.on('data', (data) => {
|
||||
console.error(data.toString());
|
||||
});
|
||||
|
||||
viteProcess.on('close', (code) => {
|
||||
console.log(`Vite process exited with code ${code}`);
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@core/*": ["../core/src/*"],
|
||||
"@common/*": ["../common/src/*"],
|
||||
"@market/*": ["../market/src/*"],
|
||||
"@dashboard/*": ["../dashboard/src/*"],
|
||||
"@openApi/*": ["../openApi/src/*"],
|
||||
"@systemRunning/*": ["../systemRunning/src/*"],
|
||||
"@businessEntry/*": ["./src/*"],
|
||||
},
|
||||
},
|
||||
"include": ["src", "public/iconpark_eolink.js", "public/iconpark_apinto.js", "../common/src/component/aoplatform/EditableTableWithModal.tsx", "../common/src/components/aoplatform/TreeWithMore.tsx", "../common/src/components/aoplatform/DatePicker.tsx", "../common/src/components/aoplatform/TimeRangeSelector.tsx", "../common/src/components/aoplatform/TimePicker.tsx", "../common/src/components/aoplatform/MemberTransfer.tsx", "../common/src/components/aoplatform/Navigation.tsx", "../common/src/components/aoplatform/PageList.tsx", "../common/src/components/aoplatform/ErrorBoundary.tsx", "../common/src/components/aoplatform/ScrollableSection.tsx", "../common/src/utils/postcat.tsx", "../common/src/utils/curl.ts", "../common/src/components/aoplatform/ResetPsw.tsx", "../common/src/components/aoplatform/SubscribeApprovalModalContent.tsx", "src/components/aoplatform/RenderRoutes.tsx", "../common/src/components/aoplatform/PublishApprovalModalContent.tsx", "../common/src/components/aoplatform/InsidePage.tsx", "../common/src/const/type.ts", "../common/src/components/aoplatform/intelligent-plugin", "../common/src/const/domain"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import path from 'path'
|
||||
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: './node_modules/.vite',
|
||||
build:{
|
||||
outDir:'../../dist',
|
||||
sourcemap: false,
|
||||
chunkSizeWarningLimit: 50000,
|
||||
cacheDir: './node_modules/.vite',
|
||||
output: {
|
||||
manualChunks(id) {
|
||||
if (id.includes('node_modules')) {
|
||||
return id.toString().split('node_modules/')[1].split('/')[0].toString();
|
||||
}
|
||||
// 针对 pnpm 和 Monorepo 特殊处理
|
||||
if (id.includes('.pnpm')) {
|
||||
const segments = id.split(path.sep);
|
||||
const packageName = segments[segments.indexOf('.pnpm') + 1].split('@')[0];
|
||||
return packageName;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
tailwindcss(path.resolve(__dirname, '../common/tailwind.config.js')),
|
||||
autoprefixer
|
||||
],
|
||||
},
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
modules:{
|
||||
localsConvention:"camelCase",
|
||||
generateScopedName:"[local]_[hash:base64:2]"
|
||||
}
|
||||
},
|
||||
plugins: [react(),
|
||||
dynamicImportVars({
|
||||
include:["src"],
|
||||
exclude:[],
|
||||
warnOnError:false
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
{ find: /^~/, replacement: '' },
|
||||
{ find: '@common', replacement: path.resolve(__dirname, '../common/src') },
|
||||
{ find: '@market', replacement: path.resolve(__dirname, '../market/src') },
|
||||
{ find: '@core', replacement: path.resolve(__dirname, '../core/src') },
|
||||
{ find: '@dashboard', replacement: path.resolve(__dirname, '../dashboard/src') },
|
||||
{ find: '@openApi', replacement: path.resolve(__dirname, '../openApi/src') },
|
||||
{ find: '@systemRunning', replacement: path.resolve(__dirname, '../systemRunning/src') },
|
||||
{ find: '@businessEntry', replacement: path.resolve(__dirname, './src') },
|
||||
]
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api/v1': {
|
||||
// target: 'http://uat.apikit.com:11204/mockApi/aoplatform/',
|
||||
target: 'http://172.18.166.219:8288/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/api2/v1': {
|
||||
// target: 'http://uat.apikit.com:11204/mockApi/aoplatform/',
|
||||
target: 'http://172.18.166.219:8288/',
|
||||
changeOrigin: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
logLevel:'info'
|
||||
})
|
||||
-85
File diff suppressed because one or more lines are too long
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @Date: 2023-11-27 17:31:54
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2023-11-29 15:49:05
|
||||
* @FilePath: \applatform\frontend\packages\core\postcss.config.js
|
||||
*/
|
||||
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
|
||||
@@ -1,185 +1,162 @@
|
||||
import {
|
||||
ConfigProvider,
|
||||
Dropdown,
|
||||
MenuProps,
|
||||
App,
|
||||
Button} from 'antd';
|
||||
import {
|
||||
MenuProps,
|
||||
App,
|
||||
Button,
|
||||
ConfigProvider,
|
||||
Dropdown
|
||||
} from 'antd';
|
||||
import { Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import Logo from '@common/assets/layout-logo.png';
|
||||
import AvatarPic from '@common/assets/default-avatar.png'
|
||||
import {Outlet, useLocation, useNavigate} from "react-router-dom";
|
||||
import { useEffect, useMemo, useState} from "react";
|
||||
import { useCallback, useEffect, useMemo, useState} from "react";
|
||||
import { useGlobalContext } from '@common/contexts/GlobalStateContext.tsx';
|
||||
import { PERMISSION_DEFINITION } from '@common/const/permissions.ts';
|
||||
import {
|
||||
ProConfigProvider,
|
||||
ProLayout,
|
||||
} from '@ant-design/pro-components';
|
||||
import { BasicResponse, RESPONSE_TIPS, routerKeyMap, STATUS_CODE } from '@common/const/const.tsx';
|
||||
import { UserInfoType } from '@common/const/type.ts';
|
||||
import { useFetch } from '@common/hooks/http.ts';
|
||||
import { ProjectFilled } from '@ant-design/icons';
|
||||
import { getNavItem } from '@common/utils/navigation';
|
||||
import { getNavItem, transformMenuData } from '@common/utils/navigation';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { $t } from '@common/locales';
|
||||
import { ProConfigProvider, ProLayout } from '@ant-design/pro-components';
|
||||
import LanguageSetting from './LanguageSetting';
|
||||
import { usePluginSlotHub } from '@common/contexts/PluginSlotHubContext';
|
||||
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
export type MenuItem = Required<MenuProps>['items'][number];
|
||||
|
||||
const themeToken = {
|
||||
bgLayout:'#17163E;',
|
||||
header: {
|
||||
heightLayoutHeader:72
|
||||
},
|
||||
pageContainer:{
|
||||
paddingBlockPageContainerContent:0,
|
||||
paddingInlinePageContainerContent:0,
|
||||
}
|
||||
bgLayout: '#17163E;',
|
||||
header: {
|
||||
heightLayoutHeader: 72
|
||||
},
|
||||
pageContainer: {
|
||||
paddingBlockPageContainerContent: 0,
|
||||
paddingInlinePageContainerContent: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function BasicLayout({project = 'core'}:{project:string}){
|
||||
const navigator = useNavigate()
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const { state,accessData,checkPermission,accessInit} = useGlobalContext()
|
||||
const [pathname, setPathname] = useState(currentUrl);
|
||||
const mainPage = project === 'core' ?'/service/list':'/serviceHub/list'
|
||||
const navigator = useNavigate()
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const { state,accessData,checkPermission,accessInit,dispatch,resetAccess,getGlobalAccessData, menuList} = useGlobalContext()
|
||||
const [pathname, setPathname] = useState(currentUrl);
|
||||
const mainPage = project === 'core' ?'/service/list':'/serviceHub/list'
|
||||
const [menuItems, setMenuItems] = useState<MenuProps['items']>();
|
||||
const pluginSlotHub = usePluginSlotHub()
|
||||
|
||||
const TOTAL_MENU_ITEMS:MenuProps['items'] = useMemo(() => [
|
||||
getNavItem($t('工作空间'), 'workspace','/guide/page',<Icon icon="ic:baseline-space-dashboard" width="18" height="18"/>, [
|
||||
getNavItem(<a>{$t('首页')}</a>, 'guide','/guide/page',<Icon icon="ic:baseline-home" width="18" height="18"/>,undefined,undefined,'all'),
|
||||
getNavItem(<a>{$t('服务')}</a>, 'service','/service',<Icon icon="ic:baseline-blinds-closed" width="18" height="18"/>,undefined,undefined,'all'),
|
||||
getNavItem(<a>{$t('消费者')}</a>, 'consumer','/consumer',<Icon icon="ic:baseline-apps" width="18" height="18"/>,undefined,undefined,'all'),
|
||||
getNavItem(<a>{$t('团队')}</a>, 'team','/team',<Icon icon="ic:baseline-people-alt" width="18" height="18"/>,undefined,undefined,'all'),
|
||||
]),
|
||||
getNavItem($t('API 市场'), 'serviceHub','/serviceHub',<Icon icon="ic:baseline-hub" width="18" height="18"/>,undefined,undefined,'system.workspace.api_market.view'),
|
||||
useEffect(()=>{
|
||||
const newMenu = transformMenuData(menuList)
|
||||
setMenuItems(newMenu);
|
||||
},[menuList, state.language,accessInit])
|
||||
|
||||
getNavItem($t('仪表盘'), 'mainPage', APP_MODE === 'pro' ? '/analytics' : '/analytics/total',<Icon icon="ic:baseline-bar-chart" width="18" height="18"/>,[
|
||||
getNavItem(<a >{$t('运行视图')}</a>, 'analytics',APP_MODE === 'pro' ? '/analytics' : '/analytics/total' ,<ProjectFilled />,undefined,undefined,'system.dashboard.run_view.view'),
|
||||
APP_MODE === 'pro' ? getNavItem(<a >{$t('系统拓扑图')}</a>, 'systemrunning','/systemrunning',<ProjectFilled />,undefined,undefined,'system.dashboard.systemrunning.view') : null,
|
||||
],undefined,'system.dashboard.run_view.view'),
|
||||
|
||||
getNavItem($t('系统设置'), 'operationCenter','/commonsetting',<Icon icon="ic:baseline-settings" width="18" height="18"/>, [
|
||||
getNavItem($t('系统'), 'serviceHubSetting','/commonsetting',null,[
|
||||
getNavItem(<a>{$t('常规')}</a>, 'commonsetting','/commonsetting',<Icon icon="ic:baseline-hub" width="18" height="18"/>,undefined,undefined,'system.api_market.service_classification.view'),
|
||||
getNavItem(<a>{$t('API 网关')}</a>, 'cluster','/cluster',<Icon icon="ic:baseline-device-hub" width="18" height="18"/>,undefined,undefined,'system.devops.cluster.view'),
|
||||
getNavItem(<a>{$t('AI 模型')}</a>, 'aisetting','/aisetting',<Icon icon="hugeicons:ai-network" width="18" height="18"/>,undefined,undefined,'system.devops.cluster.view'),
|
||||
],undefined,'system.api_market.service_classification.view'),
|
||||
getNavItem($t('用户'), 'organization','/member',null,[
|
||||
getNavItem(<a>{$t('账号')}</a>, 'member','/member',<Icon icon="ic:baseline-people-alt" width="18" height="18"/>,undefined,undefined,'system.organization.member.view'),
|
||||
getNavItem(<a>{$t('角色')}</a>, 'role','/role',<Icon icon="ic:baseline-verified-user" width="18" height="18"/>,undefined,undefined,'system.organization.role.view'),
|
||||
],undefined,''),
|
||||
getNavItem($t('集成'), 'maintenanceCenter','/datasourcing', null, [
|
||||
getNavItem(<a>{$t('数据源')}</a>, 'datasourcing','/datasourcing',<Icon icon="ic:baseline-monitor-heart" width="18" height="18"/>,undefined,undefined,'system.devops.data_source.view'),
|
||||
getNavItem(<a>{$t('证书')}</a>, 'cert','/cert',<Icon icon="ic:baseline-security" width="18" height="18"/>,undefined,undefined,'system.devops.ssl_certificate.view'),
|
||||
getNavItem(<a>{$t('日志')}</a>, 'logsettings','/logsettings',<Icon icon="ic:baseline-sticky-note-2" width="18" height="18"/>,undefined,undefined,'system.devops.log_configuration.view'),
|
||||
APP_MODE === 'pro' ? getNavItem(<a>{$t('资源')}</a>, 'resourcesettings','/resourcesettings',null,undefined,undefined,'system.partition.self.view'):null,
|
||||
APP_MODE === 'pro' ? getNavItem(<a>{$t('Open API')}</a>, 'openapi','/openapi',null,undefined,undefined,'system.openapi.self.view'):null,
|
||||
]),
|
||||
]),
|
||||
],[state.language,accessInit])
|
||||
useEffect(() => {
|
||||
if (currentUrl === '/') {
|
||||
navigator(mainPage)
|
||||
}
|
||||
|
||||
}, [currentUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
if(currentUrl === '/'){
|
||||
navigator(mainPage)
|
||||
}
|
||||
|
||||
}, [currentUrl]);
|
||||
const headerMenuData = useMemo(() => {
|
||||
// 判断权限
|
||||
const hasAccess = (access: unknown) => checkPermission(access as keyof typeof PERMISSION_DEFINITION[0]);
|
||||
|
||||
const headerMenuData = useMemo(() => {
|
||||
// 判断权限
|
||||
const hasAccess = (access: unknown) => checkPermission(access as keyof typeof PERMISSION_DEFINITION[0]);
|
||||
|
||||
// 过滤菜单项
|
||||
const filterMenu = (menu: Array<{ [k: string]: unknown }>) => {
|
||||
return [...menu]
|
||||
.filter(x => x) // 过滤掉空数据
|
||||
.map((item: any) => {
|
||||
if (item.routes && item.routes.length > 0) {
|
||||
// 递归处理子菜单
|
||||
const filteredRoutes: Array<{ [k: string]: unknown }> = filterMenu(item.routes);
|
||||
|
||||
if(filteredRoutes.length === 0){
|
||||
return false
|
||||
}
|
||||
return {...item, routes: filteredRoutes};
|
||||
}
|
||||
// 处理没有 routes 的菜单项
|
||||
if (item.access) {
|
||||
return (item.access === 'all' || hasAccess(item.access)) ? item : null;
|
||||
}
|
||||
// 过滤菜单项
|
||||
const filterMenu = (menu: Array<{ [k: string]: unknown }>) => {
|
||||
return [...menu]
|
||||
.filter(x => x) // 过滤掉空数据
|
||||
.map((item: any) => {
|
||||
if (item.routes && item.routes.length > 0) {
|
||||
// 递归处理子菜单
|
||||
const filteredRoutes: Array<{ [k: string]: unknown }> = filterMenu(item.routes);
|
||||
|
||||
if (filteredRoutes.length === 0) {
|
||||
return false
|
||||
}
|
||||
return { ...item,routes: filteredRoutes,name:$t(item.name) };
|
||||
}
|
||||
// 处理没有 routes 的菜单项
|
||||
if (item.access) {
|
||||
return (item.access === 'all' || hasAccess(item.access)) ? {...item,name:$t(item.name)} : null;
|
||||
}
|
||||
// 如果没有 access 和 routes,则保留
|
||||
return item;
|
||||
return {...item,name:$t(item.name) };
|
||||
})
|
||||
.filter(x => x); // 过滤掉处理后为 null 的项
|
||||
};
|
||||
|
||||
// 初始过滤操作
|
||||
const res = [...TOTAL_MENU_ITEMS]!.filter(x => x).map((x: any) => (x.routes ? { ...x, routes: filterMenu(x.routes) } : x));
|
||||
const res = [...(menuItems || [])]!.filter(x => x).map((x: any) => (x.routes ? { ...x,name:$t(x.name), routes: filterMenu(x.routes) } : {...x,name:$t(x.name)}));
|
||||
// 返回处理后的数据
|
||||
return { path: '/', routes: res.map(x=> ({...x, routes: x.routes?.filter(x=> (x.access || x.routes?.length > 0))})).filter(x=> (x.access || x.routes?.length > 0)) };
|
||||
}, [accessData, state.language]);
|
||||
|
||||
|
||||
|
||||
}, [accessData, state.language,menuItems]);
|
||||
|
||||
const { message } = App.useApp()
|
||||
const { dispatch,resetAccess,getGlobalAccessData} = useGlobalContext()
|
||||
const [userInfo,setUserInfo] = useState<UserInfoType>()
|
||||
const {fetchData} = useFetch()
|
||||
const navigate = useNavigate();
|
||||
|
||||
const getUserInfo = ()=>{
|
||||
fetchData<BasicResponse<{profile:UserInfoType}>>('account/profile',{method:'GET'})
|
||||
.then(response=>{
|
||||
const {code,data,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
setUserInfo(data.profile)
|
||||
dispatch({type:'UPDATE_USERDATA',userData:data.profile})
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
const getUserInfo = () => {
|
||||
fetchData<BasicResponse<{ profile: UserInfoType }>>('account/profile', { method: 'GET' })
|
||||
.then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setUserInfo(data.profile)
|
||||
dispatch({ type: 'UPDATE_USERDATA', userData: data.profile })
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getUserInfo()
|
||||
getGlobalAccessData()
|
||||
}, []);
|
||||
|
||||
const logOut = ()=>{
|
||||
fetchData<BasicResponse<null>>('account/logout',{method:'GET'}).then(response=>{
|
||||
const {code,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
dispatch({type:'LOGOUT'})
|
||||
resetAccess()
|
||||
// message.success(msg || $t(RESPONSE_TIPS.logoutSuccess))
|
||||
navigate('/login')
|
||||
}else{
|
||||
message.error(msg ||$t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
getUserInfo()
|
||||
getGlobalAccessData()
|
||||
}, []);
|
||||
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
key: '2',
|
||||
label: (
|
||||
<Button key="changePsw" type="text" className="flex items-center p-0 bg-transparent border-none " onClick={()=>navigator('/userProfile/changepsw')}>
|
||||
{$t('账号设置')}
|
||||
</Button>)
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: (
|
||||
<Button key="logout" type="text" className="flex items-center p-0 bg-transparent border-none " onClick={logOut}>
|
||||
{$t('退出登录')}
|
||||
</Button>)
|
||||
},
|
||||
];
|
||||
const logOut = () => {
|
||||
fetchData<BasicResponse<null>>('account/logout', { method: 'GET' }).then(response => {
|
||||
const { code, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
dispatch({ type: 'LOGOUT' })
|
||||
resetAccess()
|
||||
// message.success(msg || $t(RESPONSE_TIPS.logoutSuccess))
|
||||
navigate('/login')
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const items: MenuProps['items'] = useMemo(() => [
|
||||
userInfo?.type !== 'guest' && {
|
||||
key: '2',
|
||||
label: (
|
||||
<Button key="changePsw" type="text" className="flex items-center p-0 bg-transparent border-none " onClick={() => navigator('/userProfile/changepsw')}>
|
||||
{$t('账号设置')}
|
||||
</Button>)
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: (
|
||||
<Button key="logout" type="text" className="flex items-center p-0 bg-transparent border-none " onClick={logOut}>
|
||||
{$t('退出登录')}
|
||||
</Button>)
|
||||
},
|
||||
].filter(Boolean), [userInfo]);
|
||||
|
||||
|
||||
const actionRender =useMemo( ()=>{
|
||||
return [
|
||||
<LanguageSetting />,
|
||||
<Button className=" text-[#ffffffb3] hover:text-[#fff] border-none" type="default" ghost onClick={()=>{window.open('https://docs.apipark.com','_blank')}}>
|
||||
<span className='flex items-center gap-[8px]'> <Icon icon="ic:baseline-help" width="14" height="14"/>{$t('文档')}</span>
|
||||
</Button> ,
|
||||
...((pluginSlotHub.getSlot('basicLayoutAfterBtns') as unknown[] )||[] )
|
||||
]
|
||||
},[pluginSlotHub.getSlot('basicLayoutAfterBtns') ])
|
||||
|
||||
|
||||
return(
|
||||
@@ -231,12 +208,7 @@ const themeToken = {
|
||||
actionsRender={(props) => {
|
||||
if (props.isMobile) return [];
|
||||
if (typeof window === 'undefined') return [];
|
||||
return [
|
||||
<LanguageSetting />,
|
||||
<Button className=" text-[#ffffffb3] hover:text-[#fff] border-none" type="default" ghost onClick={()=>{window.open('https://docs.apipark.com','_blank')}}>
|
||||
<span className='flex items-center gap-[8px]'> <Icon icon="ic:baseline-help" width="14" height="14"/>{$t('文档')}</span>
|
||||
</Button>
|
||||
];
|
||||
return actionRender;
|
||||
}}
|
||||
headerTitleRender={() => (
|
||||
<div className="w-[192px] flex items-center">
|
||||
@@ -248,7 +220,7 @@ const themeToken = {
|
||||
</div>
|
||||
)}
|
||||
logo={Logo}
|
||||
pageTitleRender={()=>$t('APIPark - 企业API数据开放平台')}
|
||||
pageTitleRender={()=>$t('APIPark')}
|
||||
menuFooterRender={(props) => {
|
||||
if (props?.collapsed) return undefined;
|
||||
}}
|
||||
|
||||
@@ -37,13 +37,13 @@ const InsidePage:FC<InsidePageProps> = ({showBanner=true,pageTitle,tagList,showB
|
||||
// <div className="h-full flex flex-col flex-1 overflow-hidden bg-[#f7f8fa]">
|
||||
<div className={`h-full flex flex-col flex-1 overflow-hidden ${className}`}>
|
||||
{ showBanner && <div className={`border-[0px] mr-PAGE_INSIDE_X ${showBorder ? 'border-b-[1px] border-solid border-BORDER' : ''} ${headerClassName}`}>
|
||||
<div className="mb-[30px]">
|
||||
{!pageTitle && !description && !backUrl &&!customBtn ? <></>: <div className="mb-[30px]">
|
||||
{backUrl &&<div className="text-[18px] leading-[25px] mb-[12px]">
|
||||
<Button type="text" onClick={goBack}><ArrowLeftOutlined className="max-h-[14px]" />{$t('返回')}</Button>
|
||||
</div>}
|
||||
<div className="flex justify-between mb-[20px] items-center ">
|
||||
<div className="flex items-center gap-TAG_LEFT ">
|
||||
<p className="text-theme text-[26px] ">{pageTitle}</p>
|
||||
<div className="text-theme text-[26px] ">{pageTitle}</div>
|
||||
{tagList && tagList?.length > 0 && tagList?.map((tag)=>{
|
||||
return ( <Tag key={tag.label as string} bordered={false} >{tag.label}</Tag>)
|
||||
})}
|
||||
@@ -53,10 +53,10 @@ const InsidePage:FC<InsidePageProps> = ({showBanner=true,pageTitle,tagList,showB
|
||||
}}>{btnTitle}</Button></WithPermission>}
|
||||
{customBtn}
|
||||
</div>
|
||||
<p >
|
||||
<div >
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
</div>}
|
||||
<div className={`h-full ${scrollPage ? 'overflow-hidden' : 'overflow-auto'} ${contentClassName || ''}`}>{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
|
||||
import { GetProp, TransferProps, TreeDataNode, theme, Transfer, Tree, Spin } from "antd";
|
||||
import { DataNode, TreeProps } from "antd/es/tree";
|
||||
import { TransferProps, TreeDataNode, Tree, Spin, Input, Empty } from "antd";
|
||||
import { DataNode } from "antd/es/tree";
|
||||
import { Ref, forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
||||
import { ApartmentOutlined, LoadingOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { cloneDeep, debounce } from "lodash-es";
|
||||
import { ColumnsType } from "antd/es/table";
|
||||
import { $t } from "@common/locales";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
|
||||
type TransferItem = GetProp<TransferProps, 'dataSource'>[number];
|
||||
|
||||
export type TransferTableProps<T> = {
|
||||
request?:(k?:string)=>Promise<{data:T[],success:boolean}>
|
||||
columns: ColumnsType<T>
|
||||
primaryKey:string
|
||||
onSelect:(selectedData:T[])=>void
|
||||
onSelect:(selectedData:string[])=>void
|
||||
tableType?:'member'|'api'
|
||||
disabledData:string[]
|
||||
searchPlaceholder?:string
|
||||
}
|
||||
|
||||
export type TransferTableHandle<T> = {
|
||||
selectedData: () => T[];
|
||||
selectedRowKeys: () => React.Key[];
|
||||
}
|
||||
|
||||
@@ -31,10 +27,6 @@ interface TreeTransferProps {
|
||||
onChange: TransferProps['onChange'];
|
||||
}
|
||||
|
||||
// Customize Table Transfer
|
||||
const isChecked = (selectedKeys: React.Key[], eventKey: React.Key) =>
|
||||
selectedKeys.includes(eventKey);
|
||||
|
||||
const generateTree = (
|
||||
treeNodes: TreeDataNode[] = [],
|
||||
checkedKeys: TreeTransferProps['targetKeys'] = [],
|
||||
@@ -73,200 +65,104 @@ const generateTree = (
|
||||
)
|
||||
};
|
||||
|
||||
const TransferTree = (props)=>{
|
||||
const { direction, token, tableHeight, dataSource, targetKeys, onItemSelect, onItemSelectAll,checkedKey,selectedKeys, filteredItems ,disabledData} = props;
|
||||
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
|
||||
|
||||
const getExpandedKeys = (newData:TreeDataNode[], expandedSet:Set<string> = new Set())=>{
|
||||
newData.forEach((item)=>{
|
||||
if(item.children && item.children.length > 0){
|
||||
expandedSet.add(item.key)
|
||||
getExpandedKeys(item.children,expandedSet)
|
||||
}
|
||||
})
|
||||
return expandedSet
|
||||
}
|
||||
|
||||
const treeData:TreeDataNode[] = useMemo(()=>{
|
||||
const filteredSet = filteredItems && filteredItems.length > 0 ? new Set(filteredItems.map((x)=>x.id)) : new Set()
|
||||
const res = dataSource && dataSource.length > 0 ? generateTree(dataSource, targetKeys,direction === 'right',disabledData,filteredSet) : []
|
||||
setExpandedKeys(Array.from(getExpandedKeys(res)))
|
||||
return res
|
||||
},[
|
||||
dataSource, targetKeys,direction ,disabledData,filteredItems
|
||||
])
|
||||
|
||||
const onExpand: TreeProps['onExpand'] = (expandedKeysValue) => {
|
||||
setExpandedKeys(expandedKeysValue as string[]);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<div style={{ padding: token.paddingXS }}>
|
||||
<Tree
|
||||
className="icon-tree"
|
||||
blockNode
|
||||
checkable
|
||||
showIcon
|
||||
checkedKeys={direction === 'left' ? Array.from(new Set([...checkedKey,...disabledData])) : selectedKeys }
|
||||
defaultExpandAll
|
||||
expandedKeys={expandedKeys}
|
||||
onExpand={onExpand}
|
||||
height={tableHeight}
|
||||
icon={(props)=> { return (props.type === 'member' ? <UserOutlined /> :<ApartmentOutlined /> )} }
|
||||
treeData={treeData}
|
||||
onCheck={(_checkedKeys, e:{checked: boolean, checkedNodes, node, event, halfCheckedKeys}) => {
|
||||
if(e.checked){
|
||||
onItemSelectAll( _checkedKeys, e.checked);
|
||||
}else{
|
||||
const checkedKeyArrFromTree = e.checkedNodes.map(node => node.key)
|
||||
onItemSelectAll((checkedKey as string[]).filter(key => checkedKeyArrFromTree.indexOf(key) === -1),e.checked)
|
||||
}
|
||||
}}
|
||||
onSelect={(_, { node: { key } }) => {
|
||||
onItemSelect(key as string, !isChecked(checkedKey, key));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const MemberTransfer= forwardRef<TransferTableHandle<{[k:string]:unknown}>, TransferTableProps<{[k:string]:unknown}>>(
|
||||
<T extends {[k:string]:unknown}>(props: TransferTableProps<T>, ref:Ref<TransferTableHandle<T>>) => {
|
||||
const {request,columns,primaryKey,onSelect,tableType,disabledData = [],searchPlaceholder} = props
|
||||
const [tableHeight, setTableHeight] = useState(window.innerHeight * 80 / 100 - 64 - 72 - 56 - 16 -3);
|
||||
const [targetKeys, setTargetKeys] = useState<TreeTransferProps['targetKeys']>([]);
|
||||
const [dataSource, setDataSource] = useState<DataNode[] >([])
|
||||
const parentRef = useRef<HTMLDivElement>(null);
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const {state} = useGlobalContext()
|
||||
|
||||
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
|
||||
const [searchWord, setSearchWord] = useState<string>('')
|
||||
useEffect(()=>{
|
||||
setTargetKeys(disabledData)
|
||||
},[disabledData])
|
||||
|
||||
useImperativeHandle(ref, () =>({
|
||||
selectedData: () => dataSource,
|
||||
selectedRowKeys: () => targetKeys,}))
|
||||
|
||||
const onChange: TreeTransferProps['onChange'] = (keys) => {
|
||||
onSelect?.(new Set(keys))
|
||||
setTargetKeys(Array.from(new Set(keys)));
|
||||
};
|
||||
const translatedDataSource = useMemo(()=>{
|
||||
|
||||
const loop = (data: DataNode[]): DataNode[] =>
|
||||
data?.map((item) => {
|
||||
const strTitle:string = item.name === '所有成员' ? $t(item.name) as string : item.name as string;
|
||||
const index = strTitle.indexOf(searchWord);
|
||||
const beforeStr = strTitle.substring(0, index);
|
||||
const afterStr = strTitle.slice(index + searchWord.length);
|
||||
const title =
|
||||
index > -1 ? (
|
||||
<span className='w-[calc(100%-16px)] truncate' title={strTitle}>
|
||||
{beforeStr}
|
||||
<span className="text-theme">{searchWord}</span>
|
||||
{afterStr}
|
||||
</span>
|
||||
) : (
|
||||
<span className='w-[calc(100%-16px)] truncate' title={`${strTitle}`}>{strTitle}</span>
|
||||
)
|
||||
if (item.children) {
|
||||
return {
|
||||
...item,
|
||||
title,
|
||||
disableCheckbox:disabledData.indexOf(item.key as string) !== -1,
|
||||
icon:<ApartmentOutlined />,
|
||||
children: loop(item.children as T[]) };
|
||||
}
|
||||
|
||||
const { token } = theme.useToken();
|
||||
|
||||
const transferDataSource: TransferItem[] = useMemo(()=>{
|
||||
function flatten(list: TreeDataNode[] = [], res:TransferItem[]) {
|
||||
list.forEach((item) => {
|
||||
res.push({...item, title:item.title === '所有成员' ? $t((item as unknown as {title:string}).title):item.title }as TransferItem);
|
||||
flatten(item.children,res);
|
||||
});
|
||||
}
|
||||
const res:TransferItem[] =[]
|
||||
flatten(dataSource,res);
|
||||
return res
|
||||
},[
|
||||
dataSource, state.language
|
||||
])
|
||||
|
||||
|
||||
const translatedDataSource = useMemo(()=>dataSource.map((item)=>({
|
||||
...item,
|
||||
name:item.name === '所有成员' ? $t((item as unknown as {name:string}).name):item.name,
|
||||
})),[dataSource, state.language])
|
||||
|
||||
|
||||
|
||||
let memo: Record<string, boolean> = {};
|
||||
|
||||
const handlerFilterOption = (inputValue: string, item: any, parentResult: boolean = false, childrenSet: Set<string> = new Set()): boolean => {
|
||||
const cacheKey = `${inputValue}_${item.key}`;
|
||||
if (memo[cacheKey]) {
|
||||
return memo[cacheKey];
|
||||
}
|
||||
|
||||
childrenSet.add(item.key);
|
||||
let result = item.title.includes(inputValue) || parentResult
|
||||
if (item.children) {
|
||||
for (const child of item.children) {
|
||||
if (handlerFilterOption(inputValue, child, result,childrenSet)) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
memo[cacheKey] = result;
|
||||
childrenSet.forEach((key) => {
|
||||
memo[`${inputValue}_${key}`] = result;
|
||||
return {
|
||||
...item,
|
||||
title,
|
||||
icon:<UserOutlined />,
|
||||
isLeaf:true,
|
||||
disableCheckbox:disabledData.indexOf(item.key as string) !== -1
|
||||
};
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
return loop(dataSource);
|
||||
},[dataSource, state.language, searchWord])
|
||||
|
||||
|
||||
const getInitExpandKeys = (data:T[], expandKeys:string[] = [])=>{
|
||||
data.forEach((item)=>{
|
||||
if(item.children?.length){
|
||||
expandKeys.push(item.key as string)
|
||||
getInitExpandKeys(item.children,expandKeys)
|
||||
}
|
||||
})
|
||||
return expandKeys
|
||||
}
|
||||
|
||||
const getDataSource = ()=>{
|
||||
setLoading(true)
|
||||
request && request().then((res)=>{
|
||||
const {data,success} = res
|
||||
setDataSource(success? data : [])
|
||||
setExpandedKeys(getInitExpandKeys(success? data:[]))
|
||||
}).finally(()=>{setLoading(false)})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getDataSource()
|
||||
const handleResize = () => {
|
||||
setTableHeight(window.innerHeight * 80 / 100 - 64 - 72 - 56 - 16 -3)
|
||||
};
|
||||
|
||||
const debouncedHandleResize = debounce(handleResize, 200);
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', debouncedHandleResize);
|
||||
handleResize();
|
||||
return () => {
|
||||
window.removeEventListener('resize', debouncedHandleResize);
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
getDataSource()
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={parentRef}>
|
||||
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={loading} className=''>
|
||||
<Transfer
|
||||
showSearch
|
||||
onSearch={(dir)=>{
|
||||
memo = {};
|
||||
}}
|
||||
listStyle={{width:'408px'}}
|
||||
disabledData={disabledData}
|
||||
filterOption={(inputValue: string, item: any) => handlerFilterOption(inputValue, item)}
|
||||
targetKeys={targetKeys}
|
||||
dataSource={transferDataSource}
|
||||
className="tree-transfer"
|
||||
render={(item) => item.title!}
|
||||
showSelectAll={false}
|
||||
onChange={onChange}
|
||||
titles={['','']}
|
||||
>
|
||||
{({ direction, onItemSelect, selectedKeys,onItemSelectAll ,filteredItems}) => {
|
||||
const treeProps = {
|
||||
dataSource:translatedDataSource, direction, onItemSelect, selectedKeys,onItemSelectAll ,filteredItems,token,tableHeight,targetKeys,disabledData
|
||||
}
|
||||
if (direction === 'left') {
|
||||
const checkedKey = [...selectedKeys, ...targetKeys as string[]];
|
||||
return (
|
||||
<TransferTree {...treeProps} checkedKey={checkedKey} />
|
||||
);
|
||||
}
|
||||
if(direction === 'right'){
|
||||
const checkedKey = [...selectedKeys,...targetKeys as string[]];
|
||||
return (
|
||||
<TransferTree {...treeProps} checkedKey={checkedKey} />
|
||||
);
|
||||
}
|
||||
}}
|
||||
</Transfer>
|
||||
<Input className="mb-[10px]" placeholder={searchPlaceholder} onChange={(e)=>setSearchWord(e.target.value)} value={searchWord} />
|
||||
<>{ translatedDataSource && translatedDataSource.length > 0 ? <Tree
|
||||
checkable
|
||||
expandedKeys={expandedKeys}
|
||||
checkedKeys={targetKeys}
|
||||
selectable={false}
|
||||
onCheck={(e)=>{setTargetKeys(e);
|
||||
onSelect(((e as string[])?.filter(x=>disabledData.indexOf(x as string) === -1))||[])}}
|
||||
onExpand={setExpandedKeys}
|
||||
treeData={translatedDataSource}
|
||||
blockNode
|
||||
showIcon
|
||||
/>
|
||||
: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/> }</>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Result, Skeleton } from 'antd';
|
||||
|
||||
const NotFound: React.FC = () => {
|
||||
const [showPage, setShowPage] = useState<boolean>(false)
|
||||
|
||||
useEffect(()=>{
|
||||
setTimeout(()=>setShowPage(true), 1000)
|
||||
},[])
|
||||
|
||||
return (
|
||||
<div className={`h-full w-full flex flex-1 align-middle ${showPage ? 'items-center' : ''}`}>
|
||||
{ showPage ? <Result
|
||||
className='w-full'
|
||||
status="404"
|
||||
title="404"
|
||||
subTitle="Sorry, the page you visited does not exist."
|
||||
/> : <Skeleton active /> }
|
||||
</div>
|
||||
)}
|
||||
|
||||
export default NotFound;
|
||||
@@ -0,0 +1,95 @@
|
||||
import {App, Form, Input, Row, Table} from "antd";
|
||||
import {forwardRef, useEffect, useImperativeHandle, useMemo} from "react";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import {BasicResponse, PLACEHOLDER, PolicyPublishColumns, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { $t } from "@common/locales";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { PolicyPublishModalHandle, PolicyPublishModalProps } from "@common/const/type";
|
||||
|
||||
|
||||
export const PolicyPublishModalContent = forwardRef<PolicyPublishModalHandle,PolicyPublishModalProps>((props, ref) => {
|
||||
const { message } = App.useApp()
|
||||
const { data} = props
|
||||
const [form] = Form.useForm();
|
||||
const {fetchData} = useFetch()
|
||||
const {state} = useGlobalContext()
|
||||
|
||||
const publish:()=>Promise<boolean | string | Record<string, unknown>> = ()=>{
|
||||
return new Promise((resolve, reject)=>{
|
||||
form.validateFields().then((value)=>{
|
||||
const body = {...value, source:data.source}
|
||||
fetchData<BasicResponse<null>>('strategy/global/data-masking/publish',{method: 'POST',eoBody:body,eoTransformKeys:['versionName']}).then(response=>{
|
||||
const {code,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
message.success(msg || $t(RESPONSE_TIPS.success))
|
||||
resolve(response)
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
reject(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).catch((errorInfo)=> reject(errorInfo))
|
||||
}).catch((errorInfo)=> reject(errorInfo))
|
||||
})
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, ()=>({
|
||||
publish,
|
||||
})
|
||||
)
|
||||
|
||||
useEffect(()=>{
|
||||
form.setFieldsValue(data)
|
||||
},[data])
|
||||
|
||||
const translatedPolicyColumns = useMemo(()=>PolicyPublishColumns.map((x)=>({
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title) : x.title,
|
||||
})),[state.language])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<WithPermission access=""><Form
|
||||
className=" mx-auto"
|
||||
form={form}
|
||||
labelAlign='left'
|
||||
layout='vertical'
|
||||
scrollToFirstError
|
||||
name="publishApprovalModalContent"
|
||||
// labelCol={{span: 3}}
|
||||
// wrapperCol={{span: 21}}
|
||||
autoComplete="off"
|
||||
>
|
||||
|
||||
<Form.Item
|
||||
label={$t("发布名称")}
|
||||
name='versionName'
|
||||
rules={[{required: true,whitespace:true }]}
|
||||
>
|
||||
<Input className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={$t("描述")}
|
||||
name="desc"
|
||||
>
|
||||
<Input.TextArea className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)} />
|
||||
</Form.Item>
|
||||
<Row className="mt-mbase pb-[8px] h-[32px] font-bold" ><span >{$t('策略列表')}:</span></Row>
|
||||
<Row className="mb-mbase ">
|
||||
<Table
|
||||
columns={translatedPolicyColumns}
|
||||
bordered={true}
|
||||
rowKey="name"
|
||||
size="small"
|
||||
dataSource={data.strategies || []}
|
||||
pagination={false}
|
||||
/>
|
||||
{!data?.isPublish&& data?.unpublishMsg&& <p className="text-status_fail mt-[4px]">{data.unpublishMsg}</p>}
|
||||
</Row>
|
||||
|
||||
</Form>
|
||||
</WithPermission>
|
||||
</>)
|
||||
})
|
||||
@@ -6,7 +6,7 @@ import {BasicResponse, FORM_ERROR_TIPS, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE,
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { SYSTEM_PUBLISH_ONLINE_COLUMNS } from "@core/const/system/const.tsx";
|
||||
import { $t } from "@common/locales";
|
||||
import { ApprovalRouteColumns, ApprovalStatusColorClass, ApprovalUpstreamColumns, ChangeTypeEnum } from "@common/const/approval/const";
|
||||
import { ApprovalPolicyColumns, ApprovalRouteColumns, ApprovalStatusColorClass, ApprovalUpstreamColumns, ChangeTypeEnum } from "@common/const/approval/const";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import { SystemInsidePublishOnlineItems } from "@core/pages/system/publish/SystemInsidePublishOnline";
|
||||
@@ -140,6 +140,31 @@ export const PublishApprovalModalContent = forwardRef<PublishApprovalModalHandle
|
||||
}
|
||||
}),[state.language])
|
||||
|
||||
|
||||
const translatedPolicyColumns = useMemo(()=>ApprovalPolicyColumns.map((x)=>{
|
||||
return {
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title) : x.title,
|
||||
...(x.dataIndex === 'status' ? {
|
||||
render:(_,entity)=> {
|
||||
switch(entity.change){
|
||||
case 'none':
|
||||
return '-'
|
||||
case 'new':
|
||||
return $t('新建')
|
||||
case 'update':
|
||||
return $t('更新')
|
||||
case 'delete':
|
||||
return $t('删除')
|
||||
default:
|
||||
return '-'
|
||||
}
|
||||
}
|
||||
}:{})
|
||||
}
|
||||
}),[state.language])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{!insidePage && <>
|
||||
@@ -219,12 +244,22 @@ export const PublishApprovalModalContent = forwardRef<PublishApprovalModalHandle
|
||||
/></Row>
|
||||
</>
|
||||
}
|
||||
<Form.Item
|
||||
<Row className="mt-mbase pb-[8px] h-[32px] font-bold" ><span >{$t('策略列表')}:</span></Row>
|
||||
<Row className="mb-mbase ">
|
||||
<Table
|
||||
bordered={true}
|
||||
columns={translatedPolicyColumns}
|
||||
size="small"
|
||||
rowKey="id"
|
||||
dataSource={data.diffs?.strategies || []}
|
||||
pagination={false}
|
||||
/></Row>
|
||||
{/* <Form.Item
|
||||
label={$t("备注")}
|
||||
name="remark"
|
||||
>
|
||||
<Input.TextArea className="w-INPUT_NORMAL" disabled={type !== 'add' && type !== 'publish'} placeholder={$t(PLACEHOLDER.input)} />
|
||||
</Form.Item>
|
||||
</Form.Item> */}
|
||||
{/*
|
||||
{type !== 'add' && type !== 'publish' && <Form.Item
|
||||
label={$t("审核意见"
|
||||
|
||||
@@ -8,64 +8,78 @@ import { Icon } from "@iconify/react/dist/iconify.js"
|
||||
import { $t } from "@common/locales"
|
||||
|
||||
type TableBtnWithPermissionProps = {
|
||||
btnTitle:string
|
||||
access?:keyof typeof PERMISSION_DEFINITION[0],
|
||||
tooltip?:string,
|
||||
disabled?:boolean,
|
||||
navigateTo?:string,
|
||||
onClick?:(args?:unknown)=>void
|
||||
className?:string
|
||||
btnType:string
|
||||
btnTitle: string
|
||||
access?: keyof typeof PERMISSION_DEFINITION[0],
|
||||
tooltip?: string,
|
||||
disabled?: boolean,
|
||||
navigateTo?: string,
|
||||
onClick?: (args?: unknown) => void
|
||||
className?: string
|
||||
btnType: string
|
||||
}
|
||||
|
||||
const TableIconName={
|
||||
'add':'ic:baseline-add',
|
||||
'edit':'ic:baseline-edit',
|
||||
'delete':'ic:baseline-delete',
|
||||
'remove':'ic:baseline-minus',
|
||||
'copy':'ic:baseline-file-copy',
|
||||
'view':'ic:baseline-remove-red-eye',
|
||||
'publish':'ic:baseline-publish',
|
||||
'approval':'ic:baseline-approval',
|
||||
'stop':'ic:baseline-stop-circle',
|
||||
'online':'ic:baseline-check-circle',
|
||||
'cancel':'ic:baseline-cancel-schedule-send',
|
||||
'refresh':'ic:baseline-refresh'
|
||||
const TableIconName = {
|
||||
'add': 'ic:baseline-add',
|
||||
'edit': 'ic:baseline-edit',
|
||||
'delete': 'ic:baseline-delete',
|
||||
'remove': 'ic:baseline-minus',
|
||||
'copy': 'ic:baseline-file-copy',
|
||||
'view': 'ic:baseline-remove-red-eye',
|
||||
'publish': 'ic:baseline-publish',
|
||||
'approval': 'ic:baseline-approval',
|
||||
'stop': 'ic:baseline-stop-circle',
|
||||
'online': 'ic:baseline-check-circle',
|
||||
'cancel': 'ic:baseline-cancel-schedule-send',
|
||||
'refresh': 'ic:baseline-refresh',
|
||||
'logs': 'hugeicons:google-doc'
|
||||
}
|
||||
// 表格操作栏按钮,受权限控制
|
||||
const TableBtnWithPermission = ({btnTitle, access, tooltip, disabled, navigateTo, onClick,className,btnType}:TableBtnWithPermissionProps) => {
|
||||
|
||||
const [btnAccess, setBtnAccess] = useState<boolean>(false)
|
||||
const {accessData,checkPermission,accessInit} = useGlobalContext()
|
||||
const navigate = useNavigate()
|
||||
const lastAccess = useMemo(()=>{
|
||||
if(!accessInit) return false
|
||||
if(!access) return true
|
||||
return checkPermission(access)
|
||||
},[access, accessData,checkPermission,accessInit])
|
||||
const TableBtnWithPermission = ({ btnTitle, access, tooltip, disabled, navigateTo, onClick, className, btnType }: TableBtnWithPermissionProps) => {
|
||||
|
||||
useEffect(()=>{
|
||||
access ? setBtnAccess(lastAccess) : setBtnAccess(true)
|
||||
},[access, lastAccess])
|
||||
const [btnAccess, setBtnAccess] = useState<boolean>(false)
|
||||
const [btnStatus, setBtnStatus] = useState<boolean>(false)
|
||||
const [closeToolTip, setCloseToolTip] = useState<boolean>(false)
|
||||
const { accessData, checkPermission, accessInit } = useGlobalContext()
|
||||
const navigate = useNavigate()
|
||||
const lastAccess = useMemo(() => {
|
||||
if (!accessInit) return false
|
||||
if (!access) return true
|
||||
return checkPermission(access)
|
||||
}, [access, accessData, checkPermission, accessInit])
|
||||
|
||||
useEffect(() => {
|
||||
access ? setBtnAccess(lastAccess) : setBtnAccess(true)
|
||||
}, [access, lastAccess])
|
||||
|
||||
|
||||
const handleClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
setTimeout(() => {
|
||||
setBtnStatus(false)
|
||||
setCloseToolTip(true)
|
||||
})
|
||||
|
||||
const handleClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
navigateTo ? navigate(navigateTo) : onClick?.()
|
||||
}, [navigateTo, navigate, onClick])
|
||||
|
||||
return (<>{
|
||||
!btnAccess || (disabled&&tooltip) ?
|
||||
<Tooltip placement="top" title={tooltip ?? $t('暂无(0)权限,请联系管理员分配。',[$t(btnTitle).toLowerCase()])}>
|
||||
<Button type="text" disabled={true} className={`h-[22px] border-none p-0 flex items-center bg-transparent ${className}`} key={btnType} icon={<Icon icon={TableIconName[btnType as keyof typeof TableIconName]} width="18" height="18"/>} >{}</Button>
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip placement="top" title={$t(btnTitle)}>
|
||||
<Button type="text" disabled={disabled} className={`h-[22px] border-none p-0 flex items-center bg-transparent ${className} `} key={btnType} icon={<Icon icon={TableIconName[btnType as keyof typeof TableIconName]} width="18" height="18"/>} onClick={handleClick}>{}</Button>
|
||||
</Tooltip>
|
||||
|
||||
}</>
|
||||
);
|
||||
navigateTo ? navigate(navigateTo) : onClick?.()
|
||||
}, [navigateTo, navigate, onClick])
|
||||
const changeTooltipStatus = (open: boolean) => {
|
||||
setBtnStatus(open)
|
||||
if (closeToolTip) {
|
||||
setBtnStatus(false)
|
||||
setCloseToolTip(false)
|
||||
}
|
||||
|
||||
}
|
||||
return (<>{
|
||||
!btnAccess || (disabled && tooltip) ?
|
||||
<Tooltip placement="top" title={tooltip ?? $t('暂无(0)权限,请联系管理员分配。', [$t(btnTitle).toLowerCase()])}>
|
||||
<Button type="text" disabled={true} className={`h-[22px] border-none p-0 flex items-center bg-transparent ${className}`} key={btnType} icon={<Icon icon={TableIconName[btnType as keyof typeof TableIconName]} width="18" height="18" />} >{ }</Button>
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip placement="top" title={$t(btnTitle)} trigger='hover' open={btnStatus} onOpenChange={changeTooltipStatus}>
|
||||
<Button type="text" disabled={disabled} className={`h-[22px] border-none p-0 flex items-center bg-transparent ${className} `} key={btnType} icon={<Icon icon={TableIconName[btnType as keyof typeof TableIconName]} width="18" height="18" />} onClick={handleClick}>{ }</Button>
|
||||
</Tooltip>
|
||||
|
||||
}</>
|
||||
);
|
||||
}
|
||||
|
||||
export default TableBtnWithPermission
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Radio, DatePicker, GetProps, RadioChangeEvent } from 'antd';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
@@ -12,69 +12,80 @@ export type RangeValue = [Dayjs | null, Dayjs | null] | null;
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
export type TimeRange = {
|
||||
start:number|null
|
||||
end:number|null
|
||||
start: number | null
|
||||
end: number | null
|
||||
}
|
||||
|
||||
export type TimeRangeButton = ''| 'hour' | 'day' | 'threeDays' | 'sevenDays';
|
||||
export type TimeRangeButton = '' | 'hour' | 'day' | 'threeDays' | 'sevenDays';
|
||||
|
||||
type TimeRangeSelectorProps = {
|
||||
initialTimeButton?:TimeRangeButton,
|
||||
initialDatePickerValue?:RangeValue
|
||||
onTimeRangeChange?:(timeRange:TimeRange) =>void
|
||||
hideTitle?:boolean
|
||||
onTimeButtonChange:(time:TimeRangeButton) =>void
|
||||
labelSize?:'small'|'default'
|
||||
}
|
||||
const TimeRangeSelector = (props:TimeRangeSelectorProps) => {
|
||||
const {initialTimeButton,initialDatePickerValue,onTimeRangeChange,hideTitle,onTimeButtonChange,labelSize='default'} = props
|
||||
initialTimeButton?: TimeRangeButton,
|
||||
initialDatePickerValue?: RangeValue
|
||||
onTimeRangeChange?: (timeRange: TimeRange) => void
|
||||
hideTitle?: boolean
|
||||
onTimeButtonChange: (time: TimeRangeButton) => void
|
||||
labelSize?: 'small' | 'default'
|
||||
bindRef?: any
|
||||
hideBtns?: TimeRangeButton[]
|
||||
defaultTimeButton?: TimeRangeButton
|
||||
}
|
||||
const TimeRangeSelector = (props: TimeRangeSelectorProps) => {
|
||||
const { initialTimeButton, initialDatePickerValue, onTimeRangeChange, hideTitle, onTimeButtonChange, labelSize = 'default', bindRef, hideBtns = [], defaultTimeButton = 'hour' } = props
|
||||
const [timeButton, setTimeButton] = useState(initialTimeButton || '');
|
||||
const [datePickerValue, setDatePickerValue] = useState<RangeValue>(initialDatePickerValue || [null,null]);
|
||||
|
||||
const [datePickerValue, setDatePickerValue] = useState<RangeValue>(initialDatePickerValue || [null, null]);
|
||||
useEffect(() => {
|
||||
if (bindRef) {
|
||||
bindRef({ reset });
|
||||
}
|
||||
}, [bindRef])
|
||||
// 根据选择的时间范围计算开始和结束时间
|
||||
const calculateTimeRange = (curBtn:'hour'|'day'|'threeDays'|'sevenDays') => {
|
||||
const currentSecond = new Date().getTime() // 当前毫秒数时间戳
|
||||
const currentMin = currentSecond - (currentSecond % (60 * 1000)) // 当前分钟数时间戳
|
||||
let startMin = currentMin - 60 * 60 * 1000
|
||||
const calculateTimeRange = (curBtn: TimeRangeButton) => {
|
||||
const currentSecond = Math.floor(Date.now() / 1000); // 当前秒级时间戳
|
||||
let startMin = currentSecond - 60 * 60
|
||||
switch (curBtn) {
|
||||
case 'hour': {
|
||||
startMin = currentMin - 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'day': {
|
||||
startMin = currentMin - 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'threeDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
2 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'sevenDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
6 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'hour': {
|
||||
startMin = currentSecond - 60 * 60
|
||||
break
|
||||
}
|
||||
case 'day': {
|
||||
startMin = currentSecond - 24 * 60 * 60
|
||||
break
|
||||
}
|
||||
case 'threeDays': {
|
||||
startMin =
|
||||
Math.floor(new Date().setHours(0, 0, 0, 0) / 1000) -
|
||||
2 * 24 * 60 * 60
|
||||
break
|
||||
}
|
||||
case 'sevenDays': {
|
||||
startMin =
|
||||
Math.floor(new Date().setHours(0, 0, 0, 0) / 1000) -
|
||||
6 * 24 * 60 * 60
|
||||
break
|
||||
}
|
||||
}
|
||||
if (onTimeRangeChange) {
|
||||
onTimeRangeChange({ start: startMin / 1000, end: currentMin / 1000 });
|
||||
onTimeRangeChange({ start: startMin, end: currentSecond });
|
||||
}
|
||||
};
|
||||
|
||||
// 处理单选按钮的变化
|
||||
const handleRadioChange = (e:RadioChangeEvent) => {
|
||||
const handleRadioChange = (e: RadioChangeEvent) => {
|
||||
setTimeButton(e.target.value);
|
||||
onTimeButtonChange?.(e.target.value)
|
||||
setDatePickerValue(null)
|
||||
calculateTimeRange(e.target.value);
|
||||
};
|
||||
const reset = () => {
|
||||
setTimeButton(defaultTimeButton)
|
||||
calculateTimeRange(defaultTimeButton)
|
||||
setDatePickerValue(null)
|
||||
}
|
||||
|
||||
// 处理日期选择器的变化
|
||||
const handleDatePickerChange = (dates: RangeValue) => {
|
||||
setTimeButton(dates ? '' : 'hour')
|
||||
onTimeButtonChange?.(dates ? '' : 'hour')
|
||||
setTimeButton(dates ? '' : defaultTimeButton)
|
||||
onTimeButtonChange?.(dates ? '' : defaultTimeButton)
|
||||
setDatePickerValue(dates);
|
||||
if (dates && Array.isArray(dates) && dates.length === 2) {
|
||||
const [startDate, endDate] = dates;
|
||||
@@ -84,34 +95,37 @@ const TimeRangeSelector = (props:TimeRangeSelectorProps) => {
|
||||
onTimeRangeChange({ start, end });
|
||||
}
|
||||
}
|
||||
if (!dates) {
|
||||
calculateTimeRange(defaultTimeButton)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
||||
// Can not select days before today and today
|
||||
|
||||
|
||||
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
||||
// Can not select days before today and today
|
||||
return current && current.valueOf() > dayjs().startOf('day').valueOf();
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-nowrap items-center pt-btnybase mr-btnybase">
|
||||
{!hideTitle && <label className={`whitespace-nowrap `}>{$t('时间')}:</label>}
|
||||
<Radio.Group className="whitespace-nowrap" value={timeButton} onChange={handleRadioChange} buttonStyle="solid">
|
||||
<Radio.Button value="hour">{$t('近1小时')}</Radio.Button>
|
||||
<Radio.Button value="day">{$t('近24小时')}</Radio.Button>
|
||||
<Radio.Button value="threeDays">{$t('近3天')}</Radio.Button>
|
||||
<Radio.Button className="rounded-e-none" value="sevenDays">{$t('近7天')}</Radio.Button>
|
||||
</Radio.Group>
|
||||
{!hideTitle && <label className={`whitespace-nowrap `}>{$t('时间')}:</label>}
|
||||
<Radio.Group className="whitespace-nowrap" value={timeButton} onChange={handleRadioChange} buttonStyle="solid">
|
||||
{hideBtns?.length && hideBtns.includes('hour') ? null : <Radio.Button value="hour">{$t('近1小时')}</Radio.Button>}
|
||||
{hideBtns?.length && hideBtns.includes('day') ? null : <Radio.Button value="day">{$t('近24小时')}</Radio.Button>}
|
||||
{hideBtns?.length && hideBtns.includes('threeDays') ? null : <Radio.Button value="threeDays">{$t('近3天')}</Radio.Button>}
|
||||
{hideBtns?.length && hideBtns.includes('sevenDays') ? null : <Radio.Button className="rounded-e-none" value="sevenDays">{$t('近7天')}</Radio.Button>}
|
||||
</Radio.Group>
|
||||
<DatePicker.RangePicker
|
||||
value={datePickerValue}
|
||||
className="rounded-s-none ml-[-1px]"
|
||||
className="rounded-s-none ml-[-1px]"
|
||||
disabledDate={disabledDate}
|
||||
onChange={handleDatePickerChange}
|
||||
onOpenChange={(open)=>{
|
||||
if(!open && datePickerValue && datePickerValue.length > 2){
|
||||
setTimeButton('')
|
||||
onTimeButtonChange?.('')
|
||||
}
|
||||
onOpenChange={(open) => {
|
||||
if (!open && datePickerValue && datePickerValue.length > 2) {
|
||||
setTimeButton('')
|
||||
onTimeButtonChange?.('')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -132,7 +132,59 @@ export const TranslateWord = ()=>{
|
||||
{$t('每小时')}
|
||||
{$t('每天')}
|
||||
{$t('每周')}
|
||||
|
||||
{$t('上线结果')}
|
||||
{$t('订阅服务数量')}
|
||||
{$t('鉴权数量')}
|
||||
{$t('列表')}
|
||||
{$t('块')}
|
||||
{$t('HTTP 请求头')}
|
||||
{$t('全等匹配')}
|
||||
{$t('前缀匹配')}
|
||||
{$t('后缀匹配')}
|
||||
{$t('子串匹配')}
|
||||
{$t('非等匹配')}
|
||||
{$t('空值匹配')}
|
||||
{$t('存在匹配')}
|
||||
{$t('不存在匹配')}
|
||||
{$t('区分大小写的正则匹配')}
|
||||
{$t('不区分大小写的正则匹配')}
|
||||
{$t('任意匹配')}
|
||||
{$t('驳回')}
|
||||
{$t('已订阅')}
|
||||
{$t('取消申请')}
|
||||
{$t('透传客户端请求 Host')}
|
||||
{$t('使用上游服务 Host')}
|
||||
{$t('重写 Host')}
|
||||
{$t('动态服务发现')}
|
||||
{$t('地址')}
|
||||
{$t('新增')}
|
||||
{$t('申请方消费者')}
|
||||
{$t('策略名称')}
|
||||
{$t('优先级')}
|
||||
{$t('筛选条件')}
|
||||
{$t('处理数')}
|
||||
{$t('数据格式')}
|
||||
{$t('关键字')}
|
||||
{$t('正则表达式')}
|
||||
{$t('手机号')}
|
||||
{$t('身份证号')}
|
||||
{$t('银行卡号')}
|
||||
{$t('金额')}
|
||||
{$t('日期')}
|
||||
{$t('局部显示')}
|
||||
{$t('局部遮蔽')}
|
||||
{$t('截取')}
|
||||
{$t('替换')}
|
||||
{$t('乱序')}
|
||||
{$t('随机字符串')}
|
||||
{$t('自定义字符串')}
|
||||
{$t('请输入IP地址或CIDR范围,每条以换行分割')}
|
||||
{$t('待更新')}
|
||||
{$t('待删除')}
|
||||
{$t('内容')}
|
||||
{$t('调用地址')}
|
||||
{$t('消费者 IP')}
|
||||
{$t('鉴权名称')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -39,7 +39,7 @@ const WithPermission = ({access, tooltip, children,disabled, showDisabled = true
|
||||
{ cloneElement(children, {disabled:true})}
|
||||
</Tooltip>}
|
||||
{!editAccess && (children?.type !== Button && children?.type !== Upload && showDisabled) && <Tooltip title={tooltip ?? $t("暂无操作权限,请联系管理员分配。")}>
|
||||
{ cloneElement(children, {disabled:true,okButtonProps:{disabled:true}})}
|
||||
{ cloneElement(children, {disabled:true, onClick:(e)=>e.preventDefault(),okButtonProps:{disabled:true}})}
|
||||
</Tooltip>}
|
||||
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { set } from 'lodash-es';
|
||||
import { ExoticComponent, JSXElementConstructor, ReactElement, useEffect, useState } from 'react';
|
||||
import { useBlocker, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { JSX } from 'react/jsx-runtime';
|
||||
|
||||
const withRouteGuard = (WrappedComponent: ExoticComponent<any> | JSXElementConstructor<any>, {
|
||||
canActivate,
|
||||
canLoad ,
|
||||
canDeactivate,
|
||||
deactivated,
|
||||
pathPrefix
|
||||
}: { pathPrefix?:string, canActivate?: () => Promise<boolean>; canLoad?: () => Promise<boolean>; canDeactivate?: () => Promise<boolean>; deactivated?: () => Promise<void>; } = {}) => {
|
||||
return function RouteGuard(props: JSX.IntrinsicAttributes) {
|
||||
const [isActivated, setIsActivated] = useState<boolean>(false);
|
||||
const location = useLocation();
|
||||
// check canActivate
|
||||
const startLifecycle = async ()=>{
|
||||
if(canActivate){
|
||||
const activateRes = await canActivate();
|
||||
setIsActivated(activateRes);
|
||||
}else{
|
||||
setIsActivated(true);
|
||||
}
|
||||
}
|
||||
|
||||
// check canDeactivate
|
||||
const handleBeforeUnload =async (event: { preventDefault: () => void; returnValue: string; }) => {
|
||||
const deactivateRes = canDeactivate? await canDeactivate():true;
|
||||
if (!deactivateRes) {
|
||||
event.preventDefault();
|
||||
event.returnValue = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 激活组件时的检查
|
||||
useEffect(() => {
|
||||
startLifecycle();
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
deactivated?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
const blocker = useBlocker((tx) => {
|
||||
const currentPath = location.pathname;
|
||||
const targetPath = tx.nextLocation.pathname;
|
||||
|
||||
if (pathPrefix && currentPath.startsWith(pathPrefix) && !targetPath.startsWith(pathPrefix) && canDeactivate) {
|
||||
canDeactivate().then((res) => {
|
||||
if(res){
|
||||
return false;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const checkCanLoad = async()=>{
|
||||
const loadRes = await canLoad!();
|
||||
!loadRes && setIsActivated(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (isActivated && canLoad) {
|
||||
checkCanLoad()
|
||||
}
|
||||
}, [isActivated]);
|
||||
|
||||
return isActivated ? <WrappedComponent {...props}/> : null;
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouteGuard;
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
UPDATE_DATASETS_EVENT_EMITTER,
|
||||
UPDATE_HISTORY_EVENT_EMITTER,
|
||||
} from './constants'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
export type PromptEditorProps = {
|
||||
instanceId?: string
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import { $splitNodeContainingQuery } from '../../utils'
|
||||
import { useOptions } from './hooks'
|
||||
import type { PickerBlockMenuOption } from './menu'
|
||||
// import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
type ComponentPickerProps = {
|
||||
triggerString: string
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { DELETE_CONTEXT_BLOCK_COMMAND } from './index'
|
||||
// PortalToFollowElemContent,
|
||||
// PortalToFollowElemTrigger,
|
||||
// } from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
import { $t } from '@common/locales'
|
||||
|
||||
type ContextBlockComponentProps = {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import { DELETE_HISTORY_BLOCK_COMMAND } from './index'
|
||||
// PortalToFollowElemContent,
|
||||
// PortalToFollowElemTrigger,
|
||||
// } from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
import { $t } from '@common/locales'
|
||||
|
||||
type HistoryBlockComponentProps = {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
||||
import { textToEditorState } from '../utils'
|
||||
import { CustomTextNode } from './custom-text/node'
|
||||
import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/event-emitter'
|
||||
import { useEventEmitterContextContext } from '@common/contexts/EventEmitterContext'
|
||||
|
||||
export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'
|
||||
export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface CodeboxApiRef {
|
||||
formatCode: () => void
|
||||
}
|
||||
|
||||
export type codeBoxLanguagesType = 'html' | 'json' | 'xml' | 'javascript' | 'css' | 'plaintext'|'yaml'
|
||||
interface CodeboxProps {
|
||||
options?: MonacoEditor.IStandaloneEditorConstructionOptions
|
||||
value?: string
|
||||
@@ -22,7 +23,7 @@ interface CodeboxProps {
|
||||
height?: string | null
|
||||
readOnly?: boolean
|
||||
apiRef?: RefObject<CodeboxApiRef>
|
||||
language?: 'html' | 'json' | 'xml' | 'javascript' | 'css' | 'plaintext'|'yaml'
|
||||
language?: codeBoxLanguagesType
|
||||
extraContent?:React.ReactNode
|
||||
sx?:Record<string,unknown>
|
||||
editorTheme?:'vs' | 'vs-dark' | 'hc-black'
|
||||
|
||||
@@ -295,7 +295,7 @@ export interface IconParkIconElement extends HTMLElement {
|
||||
| 'apispace'
|
||||
| 'auto-generate-api'
|
||||
| 'compare-api'
|
||||
| 'multi-protocal'
|
||||
| 'multi-protocol'
|
||||
| 'read-good'
|
||||
| 'richdoc'
|
||||
| 'mockapi'
|
||||
|
||||
@@ -241,6 +241,26 @@ export const ApprovalRouteColumns = [
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
export const ApprovalPolicyColumns = [
|
||||
{
|
||||
title:('名称'),
|
||||
dataIndex:'name',
|
||||
ellipsis:true,
|
||||
},
|
||||
{
|
||||
title:('优先级'),
|
||||
dataIndex:'priority',
|
||||
ellipsis:true
|
||||
},
|
||||
{
|
||||
title:('状态'),
|
||||
dataIndex:'status',
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
export const ApprovalUpstreamColumns = [
|
||||
{
|
||||
title:('上游类型'),
|
||||
@@ -343,11 +363,6 @@ export const PUBLISH_APPROVAL_RECORD_INNER_TABLE_COLUMN : PageProColumns<Publish
|
||||
dataIndex: 'status',
|
||||
ellipsis:true,
|
||||
},
|
||||
{
|
||||
title:('备注'),
|
||||
dataIndex: 'comments',
|
||||
ellipsis:true
|
||||
},
|
||||
{
|
||||
title:('申请人'),
|
||||
dataIndex: ['applicant','name'],
|
||||
|
||||
@@ -67,6 +67,7 @@ export type PublishApprovalInfoType = {
|
||||
diffs:{
|
||||
apis:PublishApprovalApiItem[]
|
||||
upstreams:PublishApprovalUpstreamItem[]
|
||||
strategies:Array<{name:string, priority:number,statues:0|1}>
|
||||
}
|
||||
clusterPublishStatus?:SystemInsidePublishOnlineItems[],
|
||||
error:string
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { $t } from '@common/locales'
|
||||
import { StrategyStatusColorClass, StrategyStatusEnum } from './policy/consts'
|
||||
|
||||
export type BasicResponse<T> = {
|
||||
code:number
|
||||
@@ -5,7 +7,6 @@ export type BasicResponse<T> = {
|
||||
msg:string
|
||||
}
|
||||
|
||||
|
||||
export const STATUS_CODE = {
|
||||
SUCCESS:0,
|
||||
UNANTHORIZED:401,
|
||||
@@ -18,7 +19,7 @@ export const STATUS_COLOR = {
|
||||
}
|
||||
|
||||
|
||||
// avoid changing route within ths same category
|
||||
// TODO should be generated dynamically
|
||||
export const routerKeyMap = new Map<string, string[]|string>([
|
||||
['workspace',['consumer','service','team','guide']],
|
||||
['my',['consumer','service','team']],
|
||||
@@ -29,6 +30,7 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
['maintenanceCenter',['aisetting','datasourcing','cluster','cert','logsettings','resourcesettings','openapi']
|
||||
]])
|
||||
|
||||
|
||||
|
||||
export const COLUMNS_TITLE = {
|
||||
operate : ''
|
||||
@@ -45,6 +47,7 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
startWithAlphabet:('英文数字下划线任意一种,首字母必须为英文'),
|
||||
specialStartWithAlphabet:('支持字母开头、英文数字中横线下划线组合'),
|
||||
onlyAlphabet:('字符非法,仅支持英文'),
|
||||
ipAndCidr:'请输入IP地址或CIDR范围,每条以换行分割'
|
||||
}
|
||||
|
||||
export const FORM_ERROR_TIPS = {
|
||||
@@ -73,4 +76,33 @@ export const routerKeyMap = new Map<string, string[]|string>([
|
||||
export const DATA_SHOW_TYPE_OPTIONS = [
|
||||
{label:'列表', value:'list'},
|
||||
{label:'块', value:'block'},
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
export const PolicyPublishColumns = [
|
||||
|
||||
{
|
||||
title: ('策略名称'),
|
||||
dataIndex: 'name',
|
||||
ellipsis: true,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: ('优先级'),
|
||||
dataIndex: 'priority',
|
||||
width: 140,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('状态'),
|
||||
dataIndex: 'status',
|
||||
width: 140,
|
||||
render:(text:string)=> <span className={StrategyStatusColorClass[text as keyof typeof StrategyStatusColorClass]}>{$t(StrategyStatusEnum[text as keyof typeof StrategyStatusEnum])}</span>,
|
||||
},
|
||||
{
|
||||
title: ('更新时间'),
|
||||
dataIndex: 'optTime',
|
||||
width: 182,
|
||||
ellipsis: true,
|
||||
},
|
||||
]
|
||||
@@ -4,84 +4,84 @@
|
||||
|
||||
export const PERMISSION_DEFINITION = [
|
||||
{
|
||||
"system.organization.member.view": {
|
||||
"system.settings.account.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.view"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.view"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.remove": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.block": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.department.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.department.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.member.department.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.account.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.team.view": {
|
||||
"system.workspace.team.view_all": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.team.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.view_all"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.team.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.team.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.create"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.team.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.team.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.team.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.team.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.team.running": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.team.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.role.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.role.view_system_role","system.organization.role.view_team_role"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.role.view"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.role.system.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.role.view_system_role"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.role.view"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.role.system.add": {
|
||||
@@ -101,7 +101,7 @@ export const PERMISSION_DEFINITION = [
|
||||
},
|
||||
"system.organization.role.team.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.organization.role.view_team_role"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.role.view"] }]
|
||||
}
|
||||
},
|
||||
"system.organization.role.team.add": {
|
||||
@@ -121,22 +121,22 @@ export const PERMISSION_DEFINITION = [
|
||||
},
|
||||
"system.api_market.service_classification.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.service_classification.view"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.general.view"] }]
|
||||
}
|
||||
},
|
||||
"system.api_market.service_classification.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.service_classification.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.general.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.api_market.service_classification.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.service_classification.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.general.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.api_market.service_classification.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.service_classification.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.general.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.system_setting.view": {
|
||||
@@ -149,94 +149,119 @@ export const PERMISSION_DEFINITION = [
|
||||
"anyOf": [{ "backend": ["system.settings.general.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.dashboard.run_view.view":{
|
||||
"system.analysis.run_view.view":{
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ['system.dashboard.run_view.view'] }]
|
||||
"anyOf": [{ "backend": ['system.analysis.run_view.view'] }]
|
||||
}
|
||||
},
|
||||
"system.devops.data_source.view":{
|
||||
"system.settings.data_source.view":{
|
||||
"granted":{
|
||||
"anyOf":[{"backend":['system.devops.data_source.view']}]
|
||||
"anyOf":[{"backend":['system.settings.data_source.view']}]
|
||||
}
|
||||
},
|
||||
"system.devops.data_source.edit":{
|
||||
"granted":{
|
||||
"anyOf":[{"backend":['system.devops.data_source.manager']}]
|
||||
"anyOf":[{"backend":['system.settings.data_source.manager']}]
|
||||
}
|
||||
},
|
||||
"system.devops.cluster.view": {
|
||||
"system.settings.api_gateway.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.cluster.view"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.api_gateway.view"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.cluster.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.cluster.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.api_gateway.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.cluster.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.cluster.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.api_gateway.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.cluster.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.cluster.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.api_gateway.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.ai_provider.view": {
|
||||
"system.settings.ai_provider.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.ai_provider.view"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.ai_provider.view"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.ai_provider.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.ai_provider.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.ai_provider.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.ssl_certificate.view": {
|
||||
"system.settings.ssl_certificate.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.ssl_certificate.view"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.ssl_certificate.view"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.ssl_certificate.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.ssl_certificate.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.ssl_certificate.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.ssl_certificate.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.ssl_certificate.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.ssl_certificate.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.ssl_certificate.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.ssl_certificate.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.ssl_certificate.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.log_configuration.view": {
|
||||
"system.settings.log_configuration.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.log_configuration.view"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.log_configuration.view"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.log_configuration.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.log_configuration.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.log_configuration.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.log_configuration.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.log_configuration.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.log_configuration.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.log_configuration.publish": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.log_configuration.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.log_configuration.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.log_configuration.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.devops.log_configuration.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.settings.log_configuration.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.view"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.publish": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.devops.policy.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.settings.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"system.workspace.application.view_all": {
|
||||
@@ -244,19 +269,24 @@ export const PERMISSION_DEFINITION = [
|
||||
"anyOf": [{ "backend": ["system.workspace.application.view_all"] }]
|
||||
}
|
||||
},
|
||||
"system.workspace.application.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_all"] }]
|
||||
}
|
||||
},
|
||||
"system.workspace.service.view_all": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all"] }]
|
||||
}
|
||||
},
|
||||
"system.workspace.team.view_all": {
|
||||
"system.workspace.service.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.team.view_all"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all"] }]
|
||||
}
|
||||
},
|
||||
"system.workspace.api_market.view": {
|
||||
"system.api_portal.api_portal.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.api_market.view"] }]
|
||||
"anyOf": [{ "backend": ["system.api_portal.api_portal.view"] }]
|
||||
}
|
||||
},
|
||||
"system.dashboard.dashboard.view": {
|
||||
@@ -271,237 +301,277 @@ export const PERMISSION_DEFINITION = [
|
||||
},
|
||||
"team.service.api_doc.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.api_doc.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all","team.service.api_doc.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.api_doc.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.api_doc.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.api_doc.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.api_doc.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.api_doc.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.api_doc.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service_intro.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all","team.service.service_intro.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service_intro.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.service_intro.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service_intro.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.service_intro.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.api_doc.import": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.api_doc.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.api_doc.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.router.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.router.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all","team.service.api.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.router.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.router.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.api.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.router.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.router.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.api.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.router.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.router.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.api.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.upstream.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.upstream.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all","team.service.upstream.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.upstream.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.upstream.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.upstream.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.upstream.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.upstream.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.upstream.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.upstream.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.upstream.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.upstream.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all","team.service.release.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.online": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.stop": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.cancel": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.rollback": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.release.approval": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.release.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.release.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.subscription.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.subscription.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.view_all","team.service.subscription.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.subscription.approval": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.subscription.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.subscription.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.subscription.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.subscription.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.subscription.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.subscription.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.subscription.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.service.subscription.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": [""] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","system.workspace.service.view_all","team.team.service.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.service.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.team.service.manager","team.service.service.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.service.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.team.service.manager","team.service.service.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.service.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.service.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.service.manager_all","team.team.service.manager","team.service.service.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.view"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.publish": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.service.policy.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.service.strategy.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.subscription.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.view_all","team.consumer.subscription.view_subscribed_service"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.subscription.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.subscription.subscribe"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.subscription.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.subscription.manager_subscribed_services"] }]
|
||||
}
|
||||
},
|
||||
"team.application.subscription.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.subscription.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.team.consumer.subscription.manager_subscribed_services"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.application.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.view_all","team.team.consumer.view"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.application.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.application.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.application.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.application.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al",'team.team.consumer.manager',"team.consumer.application.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.view": {
|
||||
"team.consumer.authorization.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.authorization.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","system.workspace.application.view_all","team.consumer.authorization.view"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.delete": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.cancelSubApply": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.application.authorization.cancelSub": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.application.authorization.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.application.manager_al","team.consumer.authorization.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.team.team.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.team.team.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.view_all","team.team.team.view"] }]
|
||||
}
|
||||
},
|
||||
"team.team.team.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.team.team.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.manager","team.team.team.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.team.member.view": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.team.member.view"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.view_all","team.team.member.view"] }]
|
||||
}
|
||||
},
|
||||
"team.team.member.add": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.team.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.manager","team.team.member.manager"] }]
|
||||
}
|
||||
},
|
||||
"team.team.member.edit": {
|
||||
"granted": {
|
||||
"anyOf": [{ "backend": ["team.team.member.manager"] }]
|
||||
"anyOf": [{ "backend": ["system.workspace.team.manager","team.team.member.manager"] }]
|
||||
}
|
||||
},
|
||||
"project.mySystem.topology.view": {
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
system:
|
||||
- name: organization
|
||||
cname: '组织管理'
|
||||
value: 'organization'
|
||||
children:
|
||||
- name: member
|
||||
cname: '成员'
|
||||
value: 'member'
|
||||
access:
|
||||
- system.organization.member.view
|
||||
- system.organization.member.add
|
||||
- system.organization.member.edit
|
||||
- system.organization.member.delete
|
||||
- system.organization.member.block
|
||||
- system.organization.member.department.add
|
||||
- system.organization.member.department.edit
|
||||
- system.organization.member.department.delete
|
||||
- name: team_manager
|
||||
cname: '团队管理'
|
||||
desc: '团队管理'
|
||||
- system.organization.team.view
|
||||
- system.organization.team.add
|
||||
- system.organization.team.edit
|
||||
- system.organization.team.delete
|
||||
- system.organization.team.running
|
||||
- name: role_manager
|
||||
cname: '角色管理'
|
||||
desc: '角色管理'
|
||||
- system.organization.role.view
|
||||
- system.organization.role.system.view
|
||||
- system.organization.role.system.add
|
||||
- system.organization.role.system.edit
|
||||
- system.organization.role.system.delete
|
||||
- system.organization.role.team.view
|
||||
- system.organization.role.team.add
|
||||
- system.organization.role.team.edit
|
||||
- system.organization.role.team.delete
|
||||
- name: API Market
|
||||
cname: 'API市场'
|
||||
value: 'api_market'
|
||||
children:
|
||||
- name: service classification
|
||||
cname: '服务分类'
|
||||
value: 'service_classification'
|
||||
children:
|
||||
- system.api_market.service_classification.view
|
||||
- system.api_market.service_classification.add
|
||||
- system.api_market.service_classification.edit
|
||||
- system.api_market.service_classification.delete
|
||||
- name: devops
|
||||
cname: 运维
|
||||
value: 'devops'
|
||||
children:
|
||||
- name: cluster
|
||||
cname: 集群
|
||||
value: 'cluster'
|
||||
children:
|
||||
- system.devops.cluster.view
|
||||
- system.devops.cluster.add
|
||||
- system.devops.cluster.edit
|
||||
- system.devops.cluster.delete
|
||||
- name: ssl certificate
|
||||
cname: 证书
|
||||
value: 'ssl_certificate'
|
||||
children:
|
||||
- system.devops.ssl_certificate.view
|
||||
- system.devops.ssl_certificate.add
|
||||
- system.devops.ssl_certificate.edit
|
||||
- system.devops.ssl_certificate.delete
|
||||
- name: log configuration
|
||||
cname: 日志
|
||||
value: 'log_configuration'
|
||||
children:
|
||||
- system.devops.log_configuration.view
|
||||
- system.devops.log_configuration.add
|
||||
- system.devops.log_configuration.edit
|
||||
- system.devops.log_configuration.publish
|
||||
- system.devops.log_configuration.delete
|
||||
- name: workspace
|
||||
cname: 工作空间
|
||||
value: 'workspace'
|
||||
children:
|
||||
- name: application
|
||||
cname: 应用
|
||||
value: 'application'
|
||||
children:
|
||||
- system.workspace.application.view_all
|
||||
- name: service
|
||||
cname: 服务
|
||||
value: 'service'
|
||||
children:
|
||||
- system.workspace.service.view_all
|
||||
- name: team
|
||||
cname: 团队
|
||||
value: 'team'
|
||||
children:
|
||||
- system.workspace.team.view_all
|
||||
- name: api market
|
||||
cname: API市场
|
||||
value: 'api_market'
|
||||
children:
|
||||
- system.workspace.api_market.view
|
||||
team:
|
||||
- name: service
|
||||
cname: 服务
|
||||
value: 'service'
|
||||
children:
|
||||
- name: api
|
||||
cname: API
|
||||
value: 'api'
|
||||
children:
|
||||
- team.service.api_doc.view
|
||||
- team.service.api_doc.add
|
||||
- team.service.api_doc.edit
|
||||
- name: route
|
||||
cname: route
|
||||
value: 'route'
|
||||
children:
|
||||
- team.service.router.view
|
||||
- team.service.router.add
|
||||
- team.service.router.edit
|
||||
- team.service.router.delete
|
||||
- name: upstream
|
||||
cname: 上游
|
||||
value: 'upstream'
|
||||
children:
|
||||
- team.service.upstream.view
|
||||
- team.service.upstream.add
|
||||
- team.service.upstream.edit
|
||||
- team.service.upstream.delete
|
||||
- name: release
|
||||
cname: 发布
|
||||
value: 'release'
|
||||
children:
|
||||
- team.service.release.view
|
||||
- team.service.release.add
|
||||
- team.service.release.rollback
|
||||
- team.service.release.delete
|
||||
- team.service.release.approval
|
||||
- team.service.release.online
|
||||
- team.service.release.cancel
|
||||
- team.service.release.stop
|
||||
- name: subscription management
|
||||
cname: 订阅方管理
|
||||
value: 'subscription'
|
||||
children:
|
||||
- team.service.subscription.view
|
||||
- team.service.subscription.approval
|
||||
- team.service.subscription.add
|
||||
- team.service.subscription.delete
|
||||
- name: service
|
||||
cname: 服务管理
|
||||
value: 'service'
|
||||
children:
|
||||
- team.service.service.view
|
||||
- team.service.service.add
|
||||
- team.service.service.edit
|
||||
- team.service.service.delete
|
||||
- name: application
|
||||
cname: 应用
|
||||
value: 'application'
|
||||
children:
|
||||
- name: subscription Service
|
||||
cname: 订阅服务
|
||||
value: 'subscription'
|
||||
children:
|
||||
- team.application.subscription.view
|
||||
- team.application.subscription.add
|
||||
- team.application.subscription.edit
|
||||
- team.application.subscription.delete
|
||||
- name: authorization
|
||||
cname: 访问授权
|
||||
value: 'authorization'
|
||||
children:
|
||||
- team.application.authorization.view
|
||||
- team.application.authorization.manager
|
||||
- team.application.authorization.add
|
||||
- team.application.authorization.edit
|
||||
- team.application.authorization.delete
|
||||
- name: application
|
||||
cname: 应用
|
||||
value: 'application'
|
||||
children:
|
||||
- team.application.application.view
|
||||
- team.application.application.add
|
||||
- team.application.application.edit
|
||||
- team.application.application.delete
|
||||
- name: team
|
||||
cname: 团队
|
||||
value: 'team'
|
||||
children:
|
||||
- name: member
|
||||
cname: 成员
|
||||
value: 'member'
|
||||
children:
|
||||
- team.team.member.view
|
||||
- team.team.member.add
|
||||
- team.team.member.edit
|
||||
- name: team
|
||||
cname: 团队管理
|
||||
value: 'team'
|
||||
children:
|
||||
- team.team.team.view
|
||||
- team.team.team.edit
|
||||
@@ -0,0 +1,88 @@
|
||||
import { codeBoxLanguagesType } from "@common/components/postcat/api/Codebox";
|
||||
|
||||
export const MatchRules = [
|
||||
{ value: 'inner', label: '数据格式' },
|
||||
{ value: 'keyword', label: '关键字' },
|
||||
{ value: 'regex', label: '正则表达式' },
|
||||
{ value: 'json_path', label: 'JSON Path' }
|
||||
];
|
||||
|
||||
|
||||
export const DataFormatOptions = [
|
||||
{ label: '姓名', value: 'name' },
|
||||
{ label: '手机号', value: 'phone' },
|
||||
{ label: '身份证号', value: 'id-card' },
|
||||
{ label: '银行卡号', value: 'bank-card' },
|
||||
{ label: '日期', value: 'date' },
|
||||
{ label: '金额', value: 'amount' }
|
||||
];
|
||||
|
||||
|
||||
export const DataMaskBaseOptionOptions = [
|
||||
{ value: 'partial-display', label: '局部显示' },
|
||||
{ value: 'partial-masking', label: '局部遮蔽' },
|
||||
{ value: 'truncation', label: '截取' },
|
||||
{ value: 'replacement', label: '替换' },
|
||||
];
|
||||
|
||||
|
||||
export const DataMaskOrderOptions = [
|
||||
...DataMaskBaseOptionOptions,
|
||||
{ label: '乱序', value: 'shuffling' }
|
||||
]
|
||||
|
||||
|
||||
export const DataMaskReplaceStrOptions = [
|
||||
{ value: 'random', label: '随机字符串' },
|
||||
{ value: 'custom', label: '自定义字符串' }
|
||||
];
|
||||
|
||||
|
||||
export const PolicyOptions = [
|
||||
{label:'数据脱敏',value:'data-masking'},
|
||||
]
|
||||
|
||||
export const StrategyStatusEnum = {
|
||||
'update':'待更新',
|
||||
'online':'已发布',
|
||||
'offline':'未发布',
|
||||
"delete":'待删除',
|
||||
}
|
||||
|
||||
export const StrategyStatusColorClass = {
|
||||
"online":'text-status_success',
|
||||
"update":'text-status_pending',
|
||||
"offline":'text-status_fail',
|
||||
"delete":'text-status_offline',
|
||||
}
|
||||
|
||||
export const contentTypeToLanguageMap: Record<string, codeBoxLanguagesType> = {
|
||||
// JSON
|
||||
"application/json": "json",
|
||||
|
||||
// XML
|
||||
"application/xml": "xml",
|
||||
"text/xml": "xml",
|
||||
|
||||
// HTML
|
||||
"text/html": "html",
|
||||
|
||||
// Plain text
|
||||
"text/plain": "plaintext",
|
||||
|
||||
// JavaScript
|
||||
"application/javascript": "javascript",
|
||||
"text/javascript": "javascript",
|
||||
|
||||
// CSS
|
||||
"text/css": "css",
|
||||
|
||||
// YAML
|
||||
"application/x-yaml": "yaml",
|
||||
"text/yaml": "yaml",
|
||||
|
||||
// Others (fallback)
|
||||
"*/*": "plaintext", // 任意类型默认处理为普通文本
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import { DefaultOptionType } from "antd/es/select";
|
||||
import { StrategyStatusEnum } from "./consts";
|
||||
import { EntityItem } from "../type";
|
||||
|
||||
export type DataMaskRuleTableProps = {
|
||||
disabled?: boolean;
|
||||
value?: MaskRuleData[];
|
||||
onChange?: (value: MaskRuleData[]) => void;
|
||||
}
|
||||
|
||||
|
||||
export type MaskRuleData = {
|
||||
match: {
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
mask: {
|
||||
type: string;
|
||||
begin?: number;
|
||||
length?: number;
|
||||
replace?: {
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
};
|
||||
eoKey?: string;
|
||||
}
|
||||
|
||||
export type DataMaskRuleFormProps = {
|
||||
editData?: MaskRuleData;
|
||||
ruleList: MaskRuleData[];
|
||||
onSave: (ruleList: MaskRuleData[]) => void;
|
||||
onClose: () => void;
|
||||
modalVisible:boolean
|
||||
}
|
||||
|
||||
|
||||
export type DataMaskingConfigHandle = {
|
||||
save: (values: any) => void
|
||||
}
|
||||
|
||||
export type PolicyMatchType = {name:string, values:string[], label?:string, title?:string, type?:string}
|
||||
|
||||
export type DataMaskingRulesType = {}
|
||||
|
||||
export type DataMaskingConfigFieldType = {
|
||||
id:string
|
||||
name:string
|
||||
priority:number
|
||||
description:string
|
||||
filters:PolicyMatchType[]
|
||||
config:{
|
||||
rules:DataMaskingRulesType
|
||||
}
|
||||
}
|
||||
|
||||
export type DataMaskStrategyItem = {
|
||||
id:string
|
||||
name:string
|
||||
priority:number
|
||||
isStop:boolean
|
||||
isDelete:boolean
|
||||
publishStatus:keyof typeof StrategyStatusEnum
|
||||
filters:string
|
||||
conf:string
|
||||
updater:EntityItem
|
||||
updateTime:string
|
||||
}
|
||||
export type DataMaskLogItem = {
|
||||
id:string
|
||||
service: {
|
||||
id:string
|
||||
name:string
|
||||
}
|
||||
method:string
|
||||
url:string
|
||||
remote_ip:string
|
||||
consumer: {
|
||||
id:string
|
||||
name:string
|
||||
}
|
||||
authorization:string
|
||||
record_time:string
|
||||
}
|
||||
|
||||
|
||||
export type FilterFormField= {
|
||||
name: string;
|
||||
values:string[] |string;
|
||||
label:string
|
||||
title:string
|
||||
}
|
||||
|
||||
export type FilterOptionType = {
|
||||
name:string
|
||||
pattern:string
|
||||
title:string
|
||||
type:'remote'|'pattern'|'static'
|
||||
options:string[]
|
||||
}
|
||||
|
||||
|
||||
export type FilterTableProps = {
|
||||
disabled?: boolean;
|
||||
drawerTitle?: string;
|
||||
value?:FilterFormField[];
|
||||
onChange?:(val:FilterFormField[])=>void
|
||||
}
|
||||
|
||||
export type FilterFormType = {
|
||||
name:string
|
||||
values:unknown
|
||||
type?:string
|
||||
}
|
||||
|
||||
export type FilterFormProps = {
|
||||
filterForm: FilterFormType;
|
||||
filterOptions:DefaultOptionType[];
|
||||
selectedOptionNameSet: Set<string>;
|
||||
disabled: boolean;
|
||||
onFilterFormChange: (form: FilterFormType) => void;
|
||||
setFormCanSubmit:(canSubmit:boolean)=>void
|
||||
serviceId?:string
|
||||
teamId?:string
|
||||
}
|
||||
|
||||
export type FilterFormHandle = {
|
||||
clear:()=>void
|
||||
save:()=>Promise<FilterFormField>
|
||||
}
|
||||
|
||||
export type FilterFormItemProps = {
|
||||
value?: string[];
|
||||
onChange?: (value: string[]) => void;
|
||||
disabled:boolean
|
||||
option:unknown
|
||||
onShowValueChange?:(value:string)=>void
|
||||
serviceId?:string
|
||||
teamId?:string
|
||||
}
|
||||
|
||||
export type RemoteTitleType = {
|
||||
title:string
|
||||
field:string
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import { FC, ReactElement, ReactNode } from "react"
|
||||
import { PERMISSION_DEFINITION } from "./permissions"
|
||||
import { MatchPositionEnum, MatchTypeEnum } from "@core/const/system/const"
|
||||
import usePluginLoader from "@common/hooks/pluginLoader"
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext"
|
||||
import { StrategyStatusEnum } from "./policy/consts"
|
||||
|
||||
export type UserInfoType = {
|
||||
username: string
|
||||
@@ -7,6 +11,7 @@ export type UserInfoType = {
|
||||
email: string
|
||||
phone: string
|
||||
avatar: string
|
||||
type:string
|
||||
}
|
||||
|
||||
export type UserProfileProps = {
|
||||
@@ -98,4 +103,112 @@ export type SimpleMemberItem = {
|
||||
email:string
|
||||
department:string
|
||||
avatar:string
|
||||
}
|
||||
|
||||
|
||||
export type RouteConfig = {
|
||||
path:string
|
||||
pathPrefix?:string
|
||||
component?:ReactElement
|
||||
children?:(RouteConfig|false)[]
|
||||
key:string
|
||||
provider?:FC<{ children: ReactNode; }>
|
||||
lazy?:unknown
|
||||
data?:Record<string, string>
|
||||
lifecycle?:{
|
||||
canActivate?:()=>Promise<boolean>
|
||||
canLoad?:()=>Promise<boolean>
|
||||
canDeactivate?:()=>Promise<boolean>
|
||||
deactivated?:()=>Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
export type RouterParams = {
|
||||
teamId:string
|
||||
apiId:string
|
||||
serviceId:string
|
||||
clusterId:string;
|
||||
memberGroupId:string
|
||||
userGroupId:string
|
||||
pluginName:string
|
||||
moduleId:string
|
||||
accessType:'project'|'team'|'service'
|
||||
categoryId:string
|
||||
tagId:string
|
||||
dashboardType:string
|
||||
dashboardDetailId:string
|
||||
topologyId:string
|
||||
appId:string
|
||||
roleType:string
|
||||
roleId:string
|
||||
routeId:string
|
||||
policyId:string
|
||||
}
|
||||
|
||||
|
||||
export type PluginRouterConfig = {
|
||||
name:string
|
||||
path:string;
|
||||
type:string;
|
||||
expose?:string
|
||||
}
|
||||
|
||||
export type CoreObj = {
|
||||
routerConfig: RouteConfig[];
|
||||
setExecuteList: (param:unknown[])=>void;
|
||||
pluginLoader: {
|
||||
loadModule: (path: string, name: string, expose: string, pluginPath: string) => Promise<any>;
|
||||
};
|
||||
pluginProvider: ReturnType<typeof useGlobalContext>
|
||||
// pluginLifecycleGuard: PluginLifecycleGuard;
|
||||
builtInPluginLoader: (name: string) => any;
|
||||
}
|
||||
|
||||
export type PluginConfigType = {
|
||||
name: string;
|
||||
router: Array<PluginRouterConfig>;
|
||||
path?: string;
|
||||
driver:string
|
||||
}
|
||||
|
||||
|
||||
export type ApiparkPluginDriverType = {
|
||||
[key:string]:{[key:string]:(coreObj?:CoreObj, pluginConfig?:PluginConfigType)=>(CoreObj|undefined)}
|
||||
}
|
||||
|
||||
|
||||
export type RouterMapConfig = {
|
||||
type: 'component' | 'module',
|
||||
component: ReactElement,
|
||||
provider?: FC,
|
||||
lazy?: FC
|
||||
key?: string
|
||||
children?: RouteConfig[]
|
||||
data?:Record<string, string>
|
||||
pathMatch?:string
|
||||
}
|
||||
|
||||
|
||||
export type PolichPublishItemType = {
|
||||
name:string
|
||||
priority:number
|
||||
status:keyof typeof StrategyStatusEnum
|
||||
optTime:string
|
||||
}
|
||||
|
||||
// 发布详情(版本)
|
||||
export type PolicyPublishInfoType = {
|
||||
source:string
|
||||
strategies:Array<PolichPublishItemType>
|
||||
isPublish:boolean
|
||||
versionName:string
|
||||
unpublishMsg:string
|
||||
};
|
||||
|
||||
export type PolicyPublishModalProps = {
|
||||
data:PolicyPublishInfoType
|
||||
}
|
||||
|
||||
export type PolicyPublishModalHandle = {
|
||||
publish:()=>Promise<boolean|string|Record<string, unknown>>
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
import {createContext, Dispatch, FC, ReactNode, useContext, useReducer, useState} from "react";
|
||||
import {createContext, Dispatch, FC, ReactNode, useContext, useEffect, useReducer, useState} from "react";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { App } from "antd";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const";
|
||||
import { checkAccess } from "@common/utils/permission";
|
||||
import { PERMISSION_DEFINITION } from "@common/const/permissions";
|
||||
import { $t } from "@common/locales";
|
||||
|
||||
import { MenuItem } from "@common/utils/navigation";
|
||||
import { ErrorBoundary } from "@ant-design/pro-components";
|
||||
import NotFound from "@common/components/aoplatform/NotFound";
|
||||
import { RouteConfig } from "@common/const/type";
|
||||
import { ProtectedRoute } from "@core/components/aoplatform/RenderRoutes";
|
||||
import Login from "@core/pages/Login";
|
||||
import { useLocaleContext } from "./LocaleContext";
|
||||
import Root from "@core/pages/Root"
|
||||
import DataMaskingCompare from "@core/pages/policy/dataMasking/DataMaskingCompare";
|
||||
interface GlobalState {
|
||||
isAuthenticated: boolean;
|
||||
userData: UserData | null;
|
||||
@@ -14,6 +22,7 @@ interface GlobalState {
|
||||
powered:string;
|
||||
mainPage:string;
|
||||
language:string;
|
||||
pluginsLoaded:boolean
|
||||
}
|
||||
|
||||
interface UserData {
|
||||
@@ -29,8 +38,171 @@ export type GlobalAction =
|
||||
| { type: 'UPDATE_POWER'; powered: string }
|
||||
| { type: 'UPDATE_MAIN_PAGE'; mainPage: string }
|
||||
| { type: 'UPDATE_LANGUAGE'; language: string }
|
||||
| { type: 'SET_PLUGINS_LOADED'; pluginsLoaded: boolean }
|
||||
|
||||
|
||||
const mockData = [
|
||||
{
|
||||
"name": "工作空间",
|
||||
"key": "workspace",
|
||||
"path": "/guide",
|
||||
"icon": "ic:baseline-space-dashboard",
|
||||
"children": [
|
||||
{
|
||||
"name": "首页",
|
||||
"key": "guide",
|
||||
"path": "/guide",
|
||||
"icon": "ic:baseline-home",
|
||||
"access": "all"
|
||||
},
|
||||
{
|
||||
"name": "服务",
|
||||
"key": "service",
|
||||
"path": "/service",
|
||||
"icon": "ic:baseline-blinds-closed",
|
||||
"access": "all"
|
||||
},
|
||||
{
|
||||
"name": "消费者",
|
||||
"key": "consumer",
|
||||
"path": "/consumer",
|
||||
"icon": "ic:baseline-apps",
|
||||
"access": "all"
|
||||
},
|
||||
{
|
||||
"name": "团队",
|
||||
"key": "team",
|
||||
"path": "/team",
|
||||
"icon": "ic:baseline-people-alt",
|
||||
"access": "all"
|
||||
},
|
||||
// {
|
||||
// "name": "路由组件",
|
||||
// "key": "router",
|
||||
// "path": "/router1",
|
||||
// "icon": "ic:baseline-people-alt",
|
||||
// "access": "all"
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "API 市场",
|
||||
"key": "serviceHub",
|
||||
"path": "/serviceHub",
|
||||
"icon": "ic:baseline-hub",
|
||||
"access": "system.api_portal.api_portal.view"
|
||||
},
|
||||
{
|
||||
"name": "仪表盘",
|
||||
"key": "analytics",
|
||||
"path": "/analytics",
|
||||
"icon": "ic:baseline-bar-chart",
|
||||
"children": [
|
||||
{
|
||||
"name": "运行视图",
|
||||
"key": "analytics",
|
||||
"path": "/analytics",
|
||||
"icon": "ic:baseline-bar-chart",
|
||||
"access": "system.analysis.run_view.view"
|
||||
}
|
||||
],
|
||||
"access": "system.analysis.run_view.view"
|
||||
},
|
||||
{
|
||||
"name": "系统设置",
|
||||
"key": "operationCenter",
|
||||
"path": "/commonsetting",
|
||||
"icon": "ic:baseline-settings",
|
||||
"children": [
|
||||
{
|
||||
"name": "系统",
|
||||
"key": "serviceHubSetting",
|
||||
"path": "/commonsetting",
|
||||
"children": [
|
||||
{
|
||||
"name": "常规",
|
||||
"key": "commonsetting",
|
||||
"path": "/commonsetting",
|
||||
"icon": "ic:baseline-hub",
|
||||
"access": "system.api_market.service_classification.view"
|
||||
},
|
||||
{
|
||||
"name": "API 网关",
|
||||
"key": "cluster",
|
||||
"path": "/cluster",
|
||||
"icon": "ic:baseline-device-hub",
|
||||
"access": "system.settings.api_gateway.view"
|
||||
},
|
||||
{
|
||||
"name": "AI 模型",
|
||||
"key": "aisetting",
|
||||
"path": "/aisetting",
|
||||
"icon": "hugeicons:ai-network",
|
||||
"access": "system.settings.ai_provider.view"
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "用户",
|
||||
"key": "organization",
|
||||
"path": "/member",
|
||||
"children": [
|
||||
{
|
||||
"name": "账号",
|
||||
"key": "member",
|
||||
"path": "/member",
|
||||
"icon": "ic:baseline-people-alt",
|
||||
"access": "system.settings.account.view"
|
||||
},
|
||||
{
|
||||
"name": "角色",
|
||||
"key": "role",
|
||||
"path": "/role",
|
||||
"icon": "ic:baseline-verified-user",
|
||||
"access": "system.organization.role.view"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "集成",
|
||||
"key": "maintenanceCenter",
|
||||
"path": "/datasourcing",
|
||||
"children": [
|
||||
{
|
||||
"name": "数据源",
|
||||
"key": "datasourcing",
|
||||
"path": "/datasourcing",
|
||||
"icon": "ic:baseline-monitor-heart",
|
||||
"access": "system.settings.data_source.view"
|
||||
},
|
||||
{
|
||||
"name": "全局策略",
|
||||
"key": "globalpolicy",
|
||||
"path": "/globalpolicy",
|
||||
"icon": "icon-park-solid:exchange-three",
|
||||
"access": "system.settings.data_source.view"
|
||||
},
|
||||
{
|
||||
"name": "证书",
|
||||
"key": "cert",
|
||||
"path": "/cert",
|
||||
"icon": "ic:baseline-security",
|
||||
"access": "system.settings.ssl_certificate.view"
|
||||
},
|
||||
{
|
||||
"name": "日志",
|
||||
"key": "logsettings",
|
||||
"path": "/logsettings",
|
||||
"icon": "ic:baseline-sticky-note-2",
|
||||
"access": "system.settings.log_configuration.view"
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
/*
|
||||
存储用户登录、信息、权限等数据
|
||||
*/
|
||||
@@ -39,9 +211,11 @@ export const GlobalContext = createContext<{
|
||||
dispatch: Dispatch<GlobalAction>;
|
||||
accessData:Map<string,string[]>;
|
||||
pluginAccessDictionary:{[k:string]:string};
|
||||
menuList:MenuItem[];
|
||||
getGlobalAccessData:()=>Promise<{ access:string[]}>;
|
||||
getTeamAccessData:(teamId:string)=>void;
|
||||
getPluginAccessDictionary:(pluginData:{[k:string]:string})=>void
|
||||
getMenuList:()=>void
|
||||
resetAccess:()=>void
|
||||
cleanTeamAccessData:()=>void
|
||||
checkPermission:(access:keyof typeof PERMISSION_DEFINITION[0] | Array<keyof typeof PERMISSION_DEFINITION[0]>)=>boolean
|
||||
@@ -49,6 +223,11 @@ export const GlobalContext = createContext<{
|
||||
accessInit:boolean
|
||||
aiConfigFlushed:boolean
|
||||
setAiConfigFlushed:(flush:boolean)=>void
|
||||
routeConfig: RouteConfig[];
|
||||
setRouterConfig: (isRoot: boolean, config: RouteConfig) => void;
|
||||
addRouteConfig: (parentRoute: RouteConfig, config: RouteConfig) => void;
|
||||
fetchData: ReturnType<typeof useFetch>['fetchData'];
|
||||
$t: typeof $t;
|
||||
} | undefined>(undefined);
|
||||
|
||||
const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState => {
|
||||
@@ -94,23 +273,38 @@ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState =>
|
||||
...state,
|
||||
language: action.language,
|
||||
};
|
||||
case 'SET_PLUGINS_LOADED':
|
||||
return {
|
||||
...state,
|
||||
pluginsLoaded: action.pluginsLoaded,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const DefaultRouteConfig = [
|
||||
{ path: '/', pathMatch: 'full', component: <Root /> ,key:'root',},
|
||||
{ path: '/login', component: <Login /> ,key:'login'},
|
||||
{ path: '/dataMaskCompare/:logId/:serviceId?/:teamId?', component: <DataMaskingCompare /> ,key:'dataMaskCompare'},
|
||||
{ path: '/', pathMatch:'prefix',component:<ProtectedRoute /> ,key:'basciLayout',children:[
|
||||
{ path: '*', component: <ErrorBoundary><NotFound/></ErrorBoundary>, key: 'errorBoundary' }
|
||||
]}
|
||||
]
|
||||
// Create a context provider component
|
||||
export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const {fetchData} = useFetch()
|
||||
const { message } = App.useApp()
|
||||
const { setLocale } = useLocaleContext();
|
||||
const [state, dispatch] = useReducer(globalReducer, {
|
||||
isAuthenticated: true, //mock用
|
||||
isAuthenticated: false, //mock用
|
||||
userData: null,
|
||||
version: '1.0.0',
|
||||
updateDate: '2024-07-01',
|
||||
powered:'Powered by https://apipark.com',
|
||||
mainPage:'/guide/page',
|
||||
language:'en-US'
|
||||
language:'en-US',
|
||||
pluginsLoaded:false
|
||||
});
|
||||
const [accessData,setAccessData] = useState<Map<string,string[]>>(new Map())
|
||||
const [pluginAccessDictionary, setPluginAccessDictionary] = useState<{[k:string]:string}>({})
|
||||
@@ -118,6 +312,43 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const [accessInit, setAccessInit] = useState<boolean>(false)
|
||||
const [aiConfigFlushed, setAiConfigFlushed] = useState<boolean>(false)
|
||||
let getGlobalAccessPromise: Promise<BasicResponse<{ access:string[] }>> | null = null
|
||||
const [menuList, setMenuList] = useState<MenuItem[]>(mockData);
|
||||
const [routeConfig, setRouteConfigState] = useState<RouteConfig[]>(DefaultRouteConfig)
|
||||
|
||||
useEffect(() => {
|
||||
setLocale(state.language);
|
||||
}, [state.language, setLocale]);
|
||||
|
||||
const { fetchData } = useFetch();
|
||||
|
||||
const setRouterConfig = (isRoot: boolean, config: RouteConfig) => {
|
||||
setRouteConfigState(prevConfig => {
|
||||
if (isRoot) {
|
||||
return [config,...prevConfig];
|
||||
} else {
|
||||
const rootRoute = prevConfig.find(route => route.path === '/' && route?.pathMatch === 'prefix') ;
|
||||
if (rootRoute ) {
|
||||
rootRoute.children = rootRoute.children ? [config, ...rootRoute.children] : [config];
|
||||
}
|
||||
return [...prevConfig];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const addRouteConfig = (parentRoute: RouteConfig, config: RouteConfig) => {
|
||||
const addConfigToParent = (routes: RouteConfig[]): RouteConfig[] => {
|
||||
return routes.map(route => {
|
||||
if (route.key === parentRoute.key) {
|
||||
route.children = route.children ? [...route.children, config] : [config];
|
||||
} else if (route.children) {
|
||||
route.children = addConfigToParent(route.children);
|
||||
}
|
||||
return route;
|
||||
});
|
||||
};
|
||||
|
||||
setRouteConfigState(prevConfig => addConfigToParent(prevConfig));
|
||||
};
|
||||
|
||||
const getGlobalAccessData = ()=>{
|
||||
if(getGlobalAccessPromise){
|
||||
@@ -151,6 +382,18 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getMenuList = ()=>{
|
||||
// TODO 等待对接后端接口
|
||||
// fetchData<BasicResponse<{ access:string[]}>>('profile/permission/team',{method:'GET',eoParams:{team:teamId}},).then(response=>{
|
||||
// const {code,data,msg} = response
|
||||
// if(code === STATUS_CODE.SUCCESS){
|
||||
// setMenuList(data.menus)
|
||||
// }else{
|
||||
// message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
const cleanTeamAccessData = ()=>{
|
||||
setTeamDataFlushed(false)
|
||||
setAccessData(prevData => prevData.set('team',[]))
|
||||
@@ -176,15 +419,26 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
return revs
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={
|
||||
{ state, dispatch,accessData,pluginAccessDictionary,
|
||||
{ state, dispatch,
|
||||
accessData,
|
||||
pluginAccessDictionary,
|
||||
getGlobalAccessData,
|
||||
getPluginAccessDictionary,
|
||||
getTeamAccessData,teamDataFlushed,
|
||||
getTeamAccessData,teamDataFlushed,getMenuList,menuList,
|
||||
cleanTeamAccessData,
|
||||
resetAccess ,checkPermission,accessInit,
|
||||
aiConfigFlushed, setAiConfigFlushed}}>
|
||||
resetAccess ,checkPermission,
|
||||
accessInit,
|
||||
aiConfigFlushed,
|
||||
setAiConfigFlushed,
|
||||
routeConfig,
|
||||
setRouterConfig,
|
||||
addRouteConfig,
|
||||
fetchData,
|
||||
$t:$t,}}>
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
);
|
||||
@@ -194,7 +448,40 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
export const useGlobalContext = () => {
|
||||
const context = useContext(GlobalContext);
|
||||
if (!context) {
|
||||
throw new Error('useGlobalContext must be used within a GlobalProvider');
|
||||
|
||||
console.warn('useGlobalContext must be used within a GlobalProvider. Returning default context.');
|
||||
return {
|
||||
state: {
|
||||
isAuthenticated: false,
|
||||
userData: null,
|
||||
version: '1.0.0',
|
||||
updateDate: '',
|
||||
powered: '',
|
||||
mainPage: '',
|
||||
language: 'en-US',
|
||||
pluginsLoaded: false,
|
||||
},
|
||||
dispatch: () => {},
|
||||
accessData: new Map(),
|
||||
pluginAccessDictionary: {},
|
||||
menuList: [],
|
||||
getGlobalAccessData: async () => ({ access: [] }),
|
||||
getTeamAccessData: () => {},
|
||||
getPluginAccessDictionary: () => {},
|
||||
getMenuList: () => {},
|
||||
resetAccess: () => {},
|
||||
cleanTeamAccessData: () => {},
|
||||
checkPermission: () => false,
|
||||
teamDataFlushed: false,
|
||||
accessInit: false,
|
||||
aiConfigFlushed: false,
|
||||
setAiConfigFlushed: () => {},
|
||||
routeConfig: [],
|
||||
setRouterConfig: () => {},
|
||||
addRouteConfig: () => {},
|
||||
fetchData: async () => ({}),
|
||||
$t: (key: string) => key,
|
||||
};
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useMemo, FC, ReactNode } from 'react';
|
||||
import { ConfigProviderProps } from 'antd';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
import zhTW from 'antd/locale/zh_TW';
|
||||
import jaJP from 'antd/locale/ja_JP';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/zh-tw';
|
||||
import 'dayjs/locale/ja';
|
||||
|
||||
type Locale = ConfigProviderProps['locale'];
|
||||
|
||||
const languageMap: Record<string, Locale> = {
|
||||
'zh-CN': zhCN,
|
||||
'en-US': enUS,
|
||||
'zh-TW': zhTW,
|
||||
'ja-JP': jaJP,
|
||||
};
|
||||
|
||||
const LocaleContext = createContext<{
|
||||
locale: Locale;
|
||||
setLocale: (locale: string) => void;
|
||||
}|undefined>(undefined);
|
||||
|
||||
export const LocaleProvider: FC<{children:ReactNode}> = ({ children }) => {
|
||||
const [locale, setLocaleState] = useState<Locale>(zhCN);
|
||||
|
||||
const setLocale = (language: string) => {
|
||||
dayjs.locale(language);
|
||||
setLocaleState(languageMap[language]);
|
||||
};
|
||||
|
||||
return (
|
||||
<LocaleContext.Provider value={{ locale, setLocale }}>
|
||||
{children}
|
||||
</LocaleContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useLocaleContext = () => {
|
||||
const context = useContext(LocaleContext);
|
||||
if (!context) {
|
||||
throw new Error('useLocaleContext must be used within a LocaleContext');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
|
||||
|
||||
class EventEmitter {
|
||||
// 用来存放注册的事件与回调
|
||||
_events:any
|
||||
constructor () {
|
||||
this._events = {}
|
||||
}
|
||||
|
||||
on (eventName:string, callback:Function) {
|
||||
// 由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列
|
||||
const callbacks = this._events[eventName] || []
|
||||
callbacks.push(callback)
|
||||
this._events[eventName] = callbacks
|
||||
}
|
||||
|
||||
// 此处需要处理,emit时需要按顺序执行监听的函数,每个函数都会返回是否中止的参数,如果中止则不执行后续的函数
|
||||
// emit传入eventName 和 event, 返回 event
|
||||
emit (eventName:string, event:any) {
|
||||
return new Promise((resolve) => {
|
||||
const callbacks = this._events[eventName] || []
|
||||
for (const cb of callbacks) {
|
||||
const cbRes = cb(event.data)
|
||||
if (cbRes.continue === false) {
|
||||
resolve(cbRes)
|
||||
break
|
||||
} else {
|
||||
event = cbRes
|
||||
}
|
||||
}
|
||||
resolve(event.data)
|
||||
})
|
||||
}
|
||||
|
||||
// 取消订阅
|
||||
off (eventName:string, callback:Function) {
|
||||
const callbacks = this._events[eventName] || []
|
||||
const newCallbacks = callbacks.filter((fn:any) => fn !== callback && fn.initialCallback !== callback /* 用于once的取消订阅 */)
|
||||
this._events[eventName] = newCallbacks
|
||||
}
|
||||
|
||||
// 单次订阅,后台插件可以自行决定取消对事件的订阅
|
||||
once (eventName:string, callback:Function) {
|
||||
// 由于需要在回调函数执行后,取消订阅当前事件,所以需要对传入的回调函数做一层包装,然后绑定包装后的函数
|
||||
const one = (...args:any) => {
|
||||
callback(...args)
|
||||
this.off(eventName, one)
|
||||
}
|
||||
|
||||
// 由于:我们订阅事件的时候,修改了原回调函数的引用,所以,用户触发 off 的时候不能找到对应的回调函数
|
||||
// 所以,我们需要在当前函数与用户传入的回调函数做一个绑定,我们通过自定义属性来实现
|
||||
one.initialCallback = callback
|
||||
this.on(eventName, one)
|
||||
}
|
||||
}
|
||||
|
||||
export const PluginEventHubContext = createContext<EventEmitter | undefined>(undefined);
|
||||
|
||||
export const PluginEventHubProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [pluginEventHub] = useState<EventEmitter>(new EventEmitter());
|
||||
|
||||
return (
|
||||
<PluginEventHubContext.Provider value={pluginEventHub}>
|
||||
{children}
|
||||
</PluginEventHubContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePluginEventHub = () => {
|
||||
const context = useContext(PluginEventHubContext);
|
||||
if (!context) {
|
||||
throw new Error('usePluginEventHub must be used within a PluginEventHubProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
|
||||
export const PluginSlotHubContext = createContext<{
|
||||
addSlot: (name: string, content: unknown) => void;
|
||||
addSlotArr: (name: string, content: unknown[]) => void;
|
||||
removeSlot: (name: string) => void;
|
||||
getSlot: (name: string) => unknown;
|
||||
} | undefined>(undefined);
|
||||
|
||||
export const PluginSlotHubProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [pluginSlotHub] = useState<Map<string, unknown>>(new Map());
|
||||
|
||||
const pluginSlotHubService = {
|
||||
addSlot: (name: string, content: any) => {
|
||||
pluginSlotHub.set(name, pluginSlotHub.get(name) ? [...(pluginSlotHub.get(name) as Array<unknown>), content] : [content] ); },
|
||||
addSlotArr: (name: string, content: any[]) => { pluginSlotHub.get(name) ? pluginSlotHub.set(name, (pluginSlotHub.get(name) as Array<unknown>).push(content)) : pluginSlotHub.set(name, content); },
|
||||
removeSlot: (name: string) => { pluginSlotHub.delete(name); },
|
||||
getSlot: (name: string) => {
|
||||
|
||||
return pluginSlotHub.get(name) ; }
|
||||
};
|
||||
|
||||
return (
|
||||
<PluginSlotHubContext.Provider value={pluginSlotHubService}>
|
||||
{children}
|
||||
</PluginSlotHubContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePluginSlotHub = () => {
|
||||
const context = useContext(PluginSlotHubContext);
|
||||
if (!context) {
|
||||
throw new Error('usePluginSlotHub must be used within a PluginSlotHubProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
import { RESPONSE_TIPS } from '@common/const/const';
|
||||
import { message } from 'antd';
|
||||
import { $t } from "@common/locales"
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const useCopyToClipboard = () => {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* @Date: 2024-01-31 15:00:11
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-05-10 17:03:03
|
||||
* @FilePath: \frontend\packages\core\src\hooks\crypto.ts
|
||||
*/
|
||||
// import CryptoJS from 'crypto-js';
|
||||
|
||||
// export const useCrypto = () => {
|
||||
// const key = '1e42=7838a1vfc6n';
|
||||
|
||||
// const encryptByEnAES = (secretKey: string, data: string, initializationVector?: string): string => {
|
||||
// const iv = CryptoJS.enc.Latin1.parse(initializationVector || key);
|
||||
// const keyForEncryption = CryptoJS.enc.Latin1.parse(CryptoJS.MD5(secretKey).toString());
|
||||
|
||||
// const cipher = CryptoJS.AES.encrypt(data, keyForEncryption, {
|
||||
// iv,
|
||||
// mode: CryptoJS.mode.CBC,
|
||||
// padding: CryptoJS.pad.Pkcs7,
|
||||
// });
|
||||
|
||||
// return CryptoJS.enc.Base64.stringify(cipher.ciphertext);
|
||||
// };
|
||||
|
||||
// return { encryptByEnAES };
|
||||
// };
|
||||
@@ -1,4 +1,6 @@
|
||||
import { STATUS_CODE } from "@common/const/const";
|
||||
import { BasicResponse, STATUS_CODE } from "@common/const/const";
|
||||
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
||||
import EventEmitter from "events";
|
||||
|
||||
const urlWhiteList = [/api.example.com\/users/, /api.example2.com\/products/]; // 正则白名单
|
||||
|
||||
@@ -137,7 +139,10 @@ type EoRequest = RequestInit & {eoParams?:{[k:string]:unknown},eoTransformKeys?:
|
||||
|
||||
type EoHeaders = Headers | {[k:string]:string}
|
||||
|
||||
export function useFetch(){
|
||||
export function useFetch() {
|
||||
// plugin cannot use usePluginEventHub directly, so we need to pass it as a parameter
|
||||
const pluginEventHub = usePluginEventHub()
|
||||
|
||||
function fetchData<T>(url:string, options: EoRequest ) {
|
||||
// 合并传入的headers与默认headers
|
||||
const headers = { ...(options.body ? {}:DEFAULT_HEADERS), ...options.headers };
|
||||
@@ -184,9 +189,11 @@ export function useFetch(){
|
||||
// 如果响应体为JSON且指定了转换键,则转换响应数据
|
||||
if ( isJsonHttp(response.headers)) {
|
||||
const data = await response.json();
|
||||
return shouldTransformKeys ? keysToCamel(data,options.eoTransformKeys as string[]) as T:data
|
||||
const newData = await pluginEventHub.emit('httpResponse', {data,continue:true}) as Response;
|
||||
return shouldTransformKeys ? keysToCamel(newData,options.eoTransformKeys as string[]) as T:data
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { DEFAULT_LOCAL_PLUGIN_PATH, generateRemoteModuleTemplate, loadRemoteModule, validateExportLifecycle } from "@common/utils/plugin.tsx";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { PluginConfigType, RouteConfig } from "@common/const/type.ts";
|
||||
import { ApiparkPluginDriverType ,RouterMapConfig} from "@common/const/type";
|
||||
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
||||
import { usePluginSlotHub } from "@common/contexts/PluginSlotHubContext";
|
||||
import { App } from "antd";
|
||||
|
||||
const mockData = {
|
||||
buildAt:'2024-09-13T03:51:25Z',
|
||||
build_user:'gitlab-runner',
|
||||
git_commint:'6438d5aaff146dc560ed0d8563788e64a49640a5',
|
||||
goversion:'go version go1.21.4 linux/amd64',
|
||||
guide:true,
|
||||
plugins:[
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'guide',
|
||||
router:[
|
||||
{
|
||||
path:'guide/*',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'team',
|
||||
router:[
|
||||
{
|
||||
path:'team',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'service',
|
||||
router:[
|
||||
{
|
||||
path:'service',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'datasourcing',
|
||||
router:[
|
||||
{
|
||||
path:'datasourcing',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'cluster',
|
||||
router:[
|
||||
{
|
||||
path:'cluster',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'aisetting',
|
||||
router:[
|
||||
{
|
||||
path:'aisetting',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'cert',
|
||||
router:[
|
||||
{
|
||||
path:'cert',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'serviceHub',
|
||||
router:[
|
||||
{
|
||||
path:'serviceHub',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'commonsetting',
|
||||
router:[
|
||||
{
|
||||
path:'commonsetting',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'consumer',
|
||||
router:[
|
||||
{
|
||||
path:'consumer',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'member',
|
||||
router:[
|
||||
{
|
||||
path:'member',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'role',
|
||||
router:[
|
||||
{
|
||||
path:'role',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'analytics',
|
||||
router:[
|
||||
{
|
||||
path:'analytics',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'template',
|
||||
router:[
|
||||
{
|
||||
path:'template/:moduleId',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'logsettings',
|
||||
router:[
|
||||
{
|
||||
path:'logsettings/*',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'resourcesettings',
|
||||
router:[
|
||||
{
|
||||
path:'resourcesettings/*',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'userProfile',
|
||||
router:[
|
||||
{
|
||||
path:'userProfile',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
driver:'apipark.builtIn.component',
|
||||
name:'globalPolicy',
|
||||
router:[
|
||||
{
|
||||
path:'globalPolicy',
|
||||
type:'normal'
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// "driver": "apipark.remote.normal",
|
||||
// "name": "remote",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "remote",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.local.preload",
|
||||
// "name": "auth",
|
||||
// "router": [
|
||||
// {
|
||||
// "expose": "AppModule",
|
||||
// "path": "auth",
|
||||
// "type": "root"
|
||||
// },
|
||||
// {
|
||||
// "expose": "AuthInfoModule",
|
||||
// "path": "auth-info",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.builtIn.component",
|
||||
// "name": "email",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "system/email",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.builtIn.module",
|
||||
// "name": "open-api",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "system/ext-app",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.local.preload",
|
||||
// "name": "remote",
|
||||
// "router": [
|
||||
// {
|
||||
// "expose": "App",
|
||||
// "path": "router1/*",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "driver": "apipark.remote.normal",
|
||||
// "name": "apispace",
|
||||
// "router": [
|
||||
// {
|
||||
// "path": "remote/apispace",
|
||||
// "type": "normal"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
powered:'Powered by https://eolink.com',
|
||||
product:'apipark',
|
||||
version:'6438d5aa'
|
||||
}
|
||||
|
||||
export type ExecutePluginType = PluginConfigType & {
|
||||
expose:string,
|
||||
bootstrap:string
|
||||
}
|
||||
|
||||
const usePluginLoader = (apipark:ApiparkPluginDriverType,routerMap:Map<string, RouterMapConfig>) => {
|
||||
const [modules, setModules] = useState(new Map());
|
||||
const [executeList, setExecuteList] = useState<ExecutePluginType[]>([]);
|
||||
const [baseHref, setBaseHref] = useState('');
|
||||
const [pendingTasks, setPendingTasks] = useState(0);
|
||||
const {fetchData} = useFetch();
|
||||
const pluginProvider = useGlobalContext();
|
||||
const pluginEventHub = usePluginEventHub();
|
||||
const pluginSlotHub = usePluginSlotHub();
|
||||
const { getMenuList,dispatch} = pluginProvider
|
||||
const { modal,message } = App.useApp()
|
||||
const [startLoadExecutePlugin, setStartLoadExecutePlugin] = useState<boolean>(false)
|
||||
const messageService = message;
|
||||
const modalService = modal;
|
||||
let startInstallPlugin = false
|
||||
|
||||
useEffect(()=>{
|
||||
if (startLoadExecutePlugin && pendingTasks === 0 && executeList.length > 0) {
|
||||
loadExecutedPlugin();
|
||||
}
|
||||
},[pendingTasks, executeList])
|
||||
|
||||
|
||||
const getModule = (routerPrefix:string, specific = false) => {
|
||||
if (routerPrefix.startsWith('/')) {
|
||||
routerPrefix = routerPrefix.substring(1);
|
||||
}
|
||||
if (specific) {
|
||||
return modules.get(routerPrefix);
|
||||
}
|
||||
let matchedModule = null;
|
||||
let matchedLength = 0;
|
||||
|
||||
modules.forEach((value, key) => {
|
||||
if (routerPrefix.startsWith(key) && key.length > matchedLength) {
|
||||
matchedModule = value;
|
||||
matchedLength = key.length;
|
||||
}
|
||||
});
|
||||
return matchedModule;
|
||||
};
|
||||
|
||||
const loadModule = async (routerPrefix: string, pluginName: any, exposedModule: string , pluginPath: any) => {
|
||||
if (!modules.get(routerPrefix)) {
|
||||
try {
|
||||
const loadedModule = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, exposedModule, pluginPath));
|
||||
const Module = loadedModule.default ?? loadedModule
|
||||
let ModuleBootstrap;
|
||||
try {
|
||||
ModuleBootstrap = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, 'Bootstrap', pluginPath));
|
||||
} catch (error) {
|
||||
console.warn('Bootstrap module not found:', error);
|
||||
}
|
||||
setModules(prevModules => new Map(prevModules).set(routerPrefix,Module[exposedModule] ));
|
||||
if (!validateExportLifecycle(Module)) {
|
||||
console.error('需要导出插件生命周期函数');
|
||||
return;
|
||||
}
|
||||
await Module.bootstrap?.({
|
||||
pluginProvider,
|
||||
pluginEventHub,
|
||||
pluginSlotHub
|
||||
});
|
||||
return Module;
|
||||
} catch (error) {
|
||||
console.error('导入插件失败:', error);
|
||||
}
|
||||
}
|
||||
return getModule(routerPrefix, true);
|
||||
};
|
||||
|
||||
const loadExecutedPlugin = async () => {
|
||||
setStartLoadExecutePlugin(true)
|
||||
for (const plugin of executeList) {
|
||||
try {
|
||||
const Module = await loadRemoteModule(generateRemoteModuleTemplate(plugin.name, plugin?.expose || 'Bootstrap', plugin.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${plugin.name}/apipark.js`));
|
||||
const bootstrap = Module.bootstrap;
|
||||
if (!bootstrap) {
|
||||
console.warn('立即执行插件未导出Bootstrap模块或bootstrap函数');
|
||||
} else {
|
||||
await bootstrap({
|
||||
pluginEventHub,
|
||||
pluginSlotHub,
|
||||
pluginProvider,
|
||||
platformProvider:null,
|
||||
messageService,
|
||||
modalService,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('执行插件失败:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const loadPlugins = () => {
|
||||
return new Promise((resolve) => {
|
||||
if(startInstallPlugin) {
|
||||
return resolve(true)
|
||||
}
|
||||
startInstallPlugin = true
|
||||
installPlugin().then(async (res)=>{
|
||||
// reset route after loading executed plugins
|
||||
await loadExecutedPlugin();
|
||||
return resolve(res)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const installPlugin = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// fetchData('system/plugins',{method:'GET'}).then((resp) => {
|
||||
// if (resp.code === 0){
|
||||
const resp = {data:mockData}
|
||||
dispatch({type:'UPDATE_VERSION',version:resp.data.version})
|
||||
dispatch({type:'UPDATE_DATE',updateDate:resp.data.buildAt})
|
||||
dispatch({type:'UPDATE_POWER',powered:resp.data.powered})
|
||||
const driverMethod = { apipark: apipark };
|
||||
const pluginConfigList = resp.data.plugins;
|
||||
const pluginLoader = { loadModule };
|
||||
const pluginLifecycleGuard ={};
|
||||
const builtInPluginLoader = loadBuiltInModule;
|
||||
pluginSlotHub.addSlot('renewMenu', () => {
|
||||
getMenuList()
|
||||
});
|
||||
for (const plugin of pluginConfigList) {
|
||||
try {
|
||||
const driverName = plugin.driver;
|
||||
if (!driverName) {
|
||||
console.error('no driver name');
|
||||
continue;
|
||||
}
|
||||
const driver = driverName.split('.').reduce((driverMethod: { [x: string]: any; }, driverName: string | number) => driverMethod[driverName], driverMethod);
|
||||
if(driverName.split('.')[2] === 'preload'){
|
||||
setPendingTasks(prev => prev + 1);
|
||||
}
|
||||
;(driver as Function )?.({ setExecuteList:(callback:ExecutePluginType[]) => {
|
||||
setExecuteList(callback);
|
||||
setPendingTasks(prev => prev - 1);
|
||||
}, pluginLoader, pluginProvider, pluginLifecycleGuard, builtInPluginLoader }, plugin);
|
||||
} catch (err) {
|
||||
console.warn('安装插件出错:', err);
|
||||
}
|
||||
}
|
||||
resolve(true);
|
||||
// } else {
|
||||
// messageService.error(resp.msg || '获取插件配置列表失败,请重试!');
|
||||
// reject(new Error(resp.msg || '获取插件配置列表失败'));
|
||||
// }
|
||||
// });
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const loadBuiltInModule = (pluginName: any) => {
|
||||
try {
|
||||
const { module } = routerMap.get(pluginName)!;
|
||||
return module;
|
||||
} catch (err) {
|
||||
console.warn(`安装内置插件[${pluginName}]出错:`, err);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loadPlugins,
|
||||
loadModule,
|
||||
loadExecutedPlugin,
|
||||
setBaseHref,
|
||||
getModule
|
||||
};
|
||||
};
|
||||
|
||||
export default usePluginLoader;
|
||||
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @Date: 2024-06-04 14:58:33
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-06-04 15:39:24
|
||||
* @FilePath: \frontend\packages\common\src\index.css
|
||||
*/
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -1,31 +1,8 @@
|
||||
{
|
||||
"工作空间": "Kc0e5ef9f",
|
||||
"首页": "K4de11e23",
|
||||
"消费者": "Kfe93ef35",
|
||||
"服务": "Kb58e0c3f",
|
||||
"团队": "Kc9e489f5",
|
||||
"API 市场": "K61c89f5f",
|
||||
"仪表盘": "K16d71239",
|
||||
"运行视图": "K714c192d",
|
||||
"系统拓扑图": "Kd57dfe97",
|
||||
"系统设置": "K3fe97dcc",
|
||||
"系统": "Kecbb0e45",
|
||||
"常规": "Ka358e23d",
|
||||
"API 网关": "K449058e9",
|
||||
"AI 模型": "K99935e6f",
|
||||
"用户": "K1deaa2dd",
|
||||
"账号": "K80a560a1",
|
||||
"角色": "Kf644225f",
|
||||
"集成": "K4057391a",
|
||||
"数据源": "K8fa58214",
|
||||
"证书": "K481e8a05",
|
||||
"日志": "Kca53edd0",
|
||||
"资源": "Kb283e720",
|
||||
"Open API": "K631d646f",
|
||||
"账号设置": "K6535ff9c",
|
||||
"退出登录": "Kf15499b4",
|
||||
"文档": "Kabbd6e6",
|
||||
"APIPark - 企业API数据开放平台": "K1196b104",
|
||||
"APIPark": "K630c9e6d",
|
||||
"HTTP 状态码": "K1f42de3",
|
||||
"系统状态码": "K4770dff4",
|
||||
"描述": "Kf89e58f1",
|
||||
@@ -43,6 +20,8 @@
|
||||
"ID": "K11d3633a",
|
||||
"名称": "Kbff43de3",
|
||||
"Driver": "K16ca79ef",
|
||||
"资源": "Kb283e720",
|
||||
"日志": "Kca53edd0",
|
||||
"已发布": "K7a369eef",
|
||||
"下线": "Kcfa1a4d2",
|
||||
"上线": "K771dc3b7",
|
||||
@@ -50,6 +29,8 @@
|
||||
"删除": "Kecbd7449",
|
||||
"确认": "K1cbe2507",
|
||||
"搜索(0)名称": "K48325b6",
|
||||
"发布名称": "Ka3e9f580",
|
||||
"策略列表": "Kb2480682",
|
||||
"上下文": "Kc6340091",
|
||||
"查询内容": "K74ecb1fa",
|
||||
"会话历史": "K79f2e2f9",
|
||||
@@ -64,6 +45,8 @@
|
||||
"成功": "K43fcaf94",
|
||||
"上线失败": "Kc71c6a9",
|
||||
"失败": "K56c686f8",
|
||||
"正常": "Ke039b9b5",
|
||||
"无效": "K1da86266",
|
||||
"申请系统": "K1ff96ff",
|
||||
"所属团队": "K9bf855d6",
|
||||
"申请人": "K11b994ed",
|
||||
@@ -95,8 +78,8 @@
|
||||
"只读成员": "Ke41d7451",
|
||||
"服务管理员": "Kf99e8b66",
|
||||
"服务开发者": "Kda8db57a",
|
||||
"消费者开发者": "K216a1ac7",
|
||||
"消费者管理员": "K27924db",
|
||||
"消费者开发者": "Kc8054dba",
|
||||
"消费者管理员": "Keb1673a6",
|
||||
"驱动名称": "K8dc5c723",
|
||||
"请求失败数": "Kda249fe8",
|
||||
"转发失败数": "Kcf2df651",
|
||||
@@ -131,8 +114,8 @@
|
||||
"上传 OpenAPI 文档 (.json/.yaml)": "K6206e4ad",
|
||||
"替换 OpenAPI 文档 (.json/.yaml)": "Kfba46e6d",
|
||||
"打开 OpenAPI YAML 编辑器": "Kdac8ce7e",
|
||||
"无需审核:允许任何消费者调用该服务": "Kffd7e274",
|
||||
"人工审核:仅允许通过人工审核的消费者调用该服务": "K8a8b13e4",
|
||||
"无需审核:允许任何消费者调用该服务": "K1fc2cc28",
|
||||
"人工审核:仅允许通过人工审核的消费者调用该服务": "K8dabb98e",
|
||||
"永久": "Kbfe02d7f",
|
||||
"否": "K1e9c479e",
|
||||
"是": "Kaddfcb6b",
|
||||
@@ -150,7 +133,7 @@
|
||||
"版本状态": "Kcbf39b82",
|
||||
"创建人": "K339d15b5",
|
||||
"审核时间": "K7194cea2",
|
||||
"申请方-消费者": "K831aa6c0",
|
||||
"申请方-消费者": "K7c1fb123",
|
||||
"审核状态": "K7ad449bc",
|
||||
"审核人": "K3b3a98ce",
|
||||
"来源": "K61b62ace",
|
||||
@@ -207,6 +190,55 @@
|
||||
"每小时": "Kf00f01ca",
|
||||
"每天": "Kfcda87fc",
|
||||
"每周": "K29ec75dc",
|
||||
"上线结果": "K93c2696e",
|
||||
"订阅服务数量": "K6e32a344",
|
||||
"鉴权数量": "Ka701316",
|
||||
"列表": "K9eaa2eb6",
|
||||
"块": "Kfaec39e9",
|
||||
"HTTP 请求头": "K76036e25",
|
||||
"全等匹配": "K44607e3f",
|
||||
"前缀匹配": "Kc287500a",
|
||||
"后缀匹配": "Kfc0b1147",
|
||||
"子串匹配": "Ka4a92043",
|
||||
"非等匹配": "K30b2e44f",
|
||||
"空值匹配": "Kb1587991",
|
||||
"存在匹配": "K1e97dbd8",
|
||||
"不存在匹配": "Kc8ee3e62",
|
||||
"区分大小写的正则匹配": "K87c5a801",
|
||||
"不区分大小写的正则匹配": "K95f062f1",
|
||||
"任意匹配": "Kfbd230a5",
|
||||
"驳回": "Kd85208a3",
|
||||
"已订阅": "Kad6aa439",
|
||||
"取消申请": "K9a68443b",
|
||||
"透传客户端请求 Host": "Kaeba0229",
|
||||
"使用上游服务 Host": "K6d7e2fd0",
|
||||
"重写 Host": "K31332633",
|
||||
"动态服务发现": "K2c2bc64f",
|
||||
"地址": "K78b1ca25",
|
||||
"新增": "K1644b775",
|
||||
"申请方消费者": "Kec91f0db",
|
||||
"策略名称": "K931615d7",
|
||||
"优先级": "K31faa2a1",
|
||||
"筛选条件": "Kbdec9fa",
|
||||
"处理数": "Kbcbb7391",
|
||||
"数据格式": "K118d8d74",
|
||||
"关键字": "Kfe7c7d2d",
|
||||
"正则表达式": "K2f57a694",
|
||||
"手机号": "K8953e0a6",
|
||||
"身份证号": "K6f86a038",
|
||||
"银行卡号": "K7954e7c8",
|
||||
"金额": "K320fdb17",
|
||||
"日期": "K7867acda",
|
||||
"局部显示": "K7d327ae8",
|
||||
"局部遮蔽": "Kfbf38e3c",
|
||||
"截取": "Kd8c1fbb0",
|
||||
"替换": "K89829921",
|
||||
"乱序": "K480a7165",
|
||||
"随机字符串": "Kea0d69df",
|
||||
"自定义字符串": "Ke7c84d1d",
|
||||
"请输入IP地址或CIDR范围,每条以换行分割": "K49731763",
|
||||
"待更新": "K3a34d49b",
|
||||
"待删除": "Kd2850420",
|
||||
"暂无操作权限,请联系管理员分配。": "K23fda291",
|
||||
"微信小程序": "K4618cb0a",
|
||||
"获取文件,需填路径": "Ka854f511",
|
||||
@@ -294,14 +326,18 @@
|
||||
"至": "K7e1ab4b0",
|
||||
"详情": "Kf1b166e7",
|
||||
"暂不支持带有双斜杠//的url": "K28555332",
|
||||
"输入的IP或CIDR不符合格式": "K83237c89",
|
||||
"请正确输入路径,如/usr/*或*/usr/*": "K5ae2c87a",
|
||||
"必填项": "K71661ee8",
|
||||
"不是有效邮箱地址": "Kcbee3f8",
|
||||
"最近一次更新者": "K617f34f1",
|
||||
"最近一次更新时间": "K6ebca204",
|
||||
"保存": "Kabfe9512",
|
||||
"服务": "Kb58e0c3f",
|
||||
"API 路由": "K51d1eb5d",
|
||||
"API 文档": "Ka2b6d281",
|
||||
"使用说明": "Kdefa9caa",
|
||||
"服务策略": "K52f72551",
|
||||
"发布": "K36856e71",
|
||||
"订阅管理": "K6382bbfd",
|
||||
"订阅审核": "K31af5b99",
|
||||
@@ -353,6 +389,8 @@
|
||||
"发布申请": "K56b4254f",
|
||||
"API 调用地址": "Kea2f9279",
|
||||
"API base URL 一般设置为API 网关的外部网络访问地址,或者是API网关绑定的域名。": "K7fc496a1",
|
||||
"集成地址": "K508d8bf4",
|
||||
"与外部平台集成时,获取 API 市场中文档信息的域名": "K67f4e9bb",
|
||||
"常规设置": "K8ab0fc95",
|
||||
"API 请求设置": "Kb66fec9d",
|
||||
"服务分类": "K4de0af74",
|
||||
@@ -369,23 +407,26 @@
|
||||
"创建 AI 服务和 API": "Kc057704a",
|
||||
"创建 AI 类型的服务,并且你可以将 Prompt 提示词设置为一个 API,简化使用 AI 的流程。": "K76bb4a09",
|
||||
"创建调用 Token": "K71b2c70f",
|
||||
"为了安全地调用 API,你需要创建一个消费者以及Token。": "K9bdd8403",
|
||||
"为了安全地调用 API,你需要创建一个消费者以及Token。": "Kdea9a418",
|
||||
"调用": "Kc5738b6c",
|
||||
"现在你可以通过 Token 来调用这些 API。": "Kd6d7ca1f",
|
||||
"快速接入 REST API": "K86cf95f",
|
||||
"创建 REST 服务和 API": "K7a3a8417",
|
||||
"仪表盘": "K16d71239",
|
||||
"统计 API 调用情况": "K4a84214e",
|
||||
"仪表盘中提供了多种统计图表,帮助我们了解 API 的运行情况。": "K297d8563",
|
||||
"核心功能": "K2cdbb773",
|
||||
"账号与角色": "K3378c50d",
|
||||
"邀请你的团队成员加入 APIPark,共同管理和调用 API。": "Kda5bb930",
|
||||
"团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。": "Kc8239422",
|
||||
"团队": "Kc9e489f5",
|
||||
"团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。": "Keee27105",
|
||||
"服务内包含一组 API,并且可以发布到 API 市场被其他团队使用。": "Kd5be0cd7",
|
||||
"权限管理": "K62e89ee7",
|
||||
"订阅服务": "K8f7808e6",
|
||||
"如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。": "Kf2410413",
|
||||
"审核订阅申请": "K6c2e44b8",
|
||||
"提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的消费者才可发起 API 请求。": "Ka0a8840a",
|
||||
"提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的消费者才可发起 API 请求。": "Kaa717866",
|
||||
"集成": "K4057391a",
|
||||
"APIPark 提供详尽的 API 调用日志,帮助企业监控、分析和审计 API 的运行状况。": "K3453272",
|
||||
"Hello!欢迎使用 APIPark": "Kd518ba3e",
|
||||
"你能通过 APIPark 快速在企业内部构建 API 开放门户/市场,享受极致的转发性能、API 可观测、服务治理、多租户管理、订阅审核流程等诸多好处。": "K7e04ea16",
|
||||
@@ -396,10 +437,11 @@
|
||||
"了解 APIPark 如何更好地管理 API 和 AI": "K1afaf20e",
|
||||
"了解更多功能": "K48f7e21f",
|
||||
"隐藏该教程": "K698296e2",
|
||||
"登录": "Kd2c1a316",
|
||||
"请输入账号": "Kf076f63c",
|
||||
"账号": "K80a560a1",
|
||||
"请输入密码": "K25c895d5",
|
||||
"密码": "K551b0348",
|
||||
"登录": "Kd2c1a316",
|
||||
"访客模式": "K192b3e38",
|
||||
"您可通过访客模式查看所有页面和功能,但是无法编辑数据。访客模式仅用于了解产品功能,您可以在正式产品中关闭该功能。": "K91aa4801",
|
||||
"Version (0)-(1)": "K480045ce",
|
||||
@@ -428,7 +470,6 @@
|
||||
"添加部门": "K26c698bb",
|
||||
"添加子部门": "Kb9cf2a7d",
|
||||
"重命名": "Kc83551f5",
|
||||
"该数据删除后将无法找回,请确认是否删除?": "K5cfdd950",
|
||||
"成员": "K74aef1ad",
|
||||
"设置成员和对应的角色,成员只能够看到权限范围内的功能和数据。": "K3f1077c9",
|
||||
"搜索部门": "Kdce62a6",
|
||||
@@ -439,6 +480,7 @@
|
||||
"密钥": "K8ef69ee2",
|
||||
"上传密钥": "Kba3507d6",
|
||||
"密钥文件的后缀名一般为 .key 的文件内容": "K93ac0f23",
|
||||
"证书": "K481e8a05",
|
||||
"上传证书": "K7cdd1331",
|
||||
"证书文件的后缀名一般为 .crt 或 .pem 的文件内容": "K6d91905d",
|
||||
"添加证书": "Kd0f6ded7",
|
||||
@@ -448,7 +490,6 @@
|
||||
"集群": "Ke93d36ed",
|
||||
"修改配置": "K877985b7",
|
||||
"设置访问 API 的集群,让 API 在分布式环境中稳定运行,并且能够根据业务需求进行灵活扩展和优化。": "Kdf66a675",
|
||||
"正常": "Ke039b9b5",
|
||||
"异常": "K23a3bd72",
|
||||
"私有网络": "Ke1b1865",
|
||||
"公共网络": "K4786c57c",
|
||||
@@ -457,11 +498,39 @@
|
||||
"同步地址": "K2a49373f",
|
||||
"集群地址": "K5878440c",
|
||||
"下一步": "K5e9022f8",
|
||||
"数据源": "K8fa58214",
|
||||
"设置监控报表的数据来源,设置完成之后即可获得详细的API调用统计图表。": "Kdbafd6f9",
|
||||
"统计图表": "K1358acf",
|
||||
"地址(IP:端口)": "K62dabdf6",
|
||||
"组织(Organization)": "K2db12335",
|
||||
"添加策略": "K34d0d409",
|
||||
"输入名称、筛选条件查找": "Kbb4298ac",
|
||||
"编辑策略": "Kc82b8374",
|
||||
"策略类型": "K4b34a5e5",
|
||||
"匹配条件": "K57f0fee8",
|
||||
"数据脱敏规则": "K10650c58",
|
||||
"配置脱敏规则": "K1b34a9ab",
|
||||
"匹配值": "K26d22405",
|
||||
"脱敏类型": "K1546e1fe",
|
||||
"起始位置": "K9b9b0629",
|
||||
"长度": "K52c84fe1",
|
||||
"替换类型": "Kde84409c",
|
||||
"替换值": "K338653b4",
|
||||
"JSON Path": "Kbaeed3b7",
|
||||
"脱敏规则": "K4cd91d61",
|
||||
"自定义字符串; 值:": "K8dcad979",
|
||||
"起始位置:(0)位;长度:(1)位": "K82e3f7b7",
|
||||
"编辑": "Kad207008",
|
||||
"已选择(0)项(1)数据": "K49dfc123",
|
||||
"所有(0)": "K8457ea34",
|
||||
"属性名称": "K7ca9a795",
|
||||
"属性值": "Kc4391744",
|
||||
"配置(0)": "K678e13fc",
|
||||
"数据脱敏": "Kabac9caf",
|
||||
"全局策略": "Ke8cbb878",
|
||||
"支持对系统全局进行统一的策略配置,从而简化管理并确保一致性。全局策略的优先级比服务策略略低。": "Kc975cd5a",
|
||||
"资源配置": "K8e7a0f80",
|
||||
"角色": "Kf644225f",
|
||||
"设置角色的权限范围。": "K95c3fd8b",
|
||||
"系统级别角色": "K138facd3",
|
||||
"添加角色": "K6eac768d",
|
||||
@@ -480,6 +549,8 @@
|
||||
"只允许上传PNG、JPG或SVG格式的图片": "Ka9c08390",
|
||||
"服务名称": "K413b9869",
|
||||
"服务类型": "K9919285b",
|
||||
"AI 服务": "Kd2c34e2c",
|
||||
"REST 服务": "K62840d62",
|
||||
"默认 AI 供应商": "Kcef64f4d",
|
||||
"创建 API 时会默认选择该供应商,修改默认供应商不会影响现有 API": "K300c89d4",
|
||||
"未配置任何 AI 模型供应商,": "Kcab588a9",
|
||||
@@ -517,8 +588,8 @@
|
||||
"移除成员": "K395acc14",
|
||||
"添加成员": "Kec46a57f",
|
||||
"输入姓名查找": "K48724410",
|
||||
"搜索用户名、邮箱": "Kb9052305",
|
||||
"设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。": "K5ece3bac",
|
||||
"输入名称查找用户": "Kf5fd27ed",
|
||||
"设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。": "K4c72fb6f",
|
||||
"添加团队": "K510cdd27",
|
||||
"输入名称、ID、负责人查找团队": "K9244ae14",
|
||||
"配置团队": "Kc7b24b4b",
|
||||
@@ -538,8 +609,9 @@
|
||||
"导出": "Ka2c794a2",
|
||||
"退出全屏": "Kaf70c3b",
|
||||
"(0)调用详情": "Kd22841a4",
|
||||
"消费者调用统计": "K1512e983",
|
||||
"请选择消费者": "Kb4d2007f",
|
||||
"消费者调用统计": "K61cca533",
|
||||
"消费者": "K7acfcfad",
|
||||
"请选择消费者": "Kdfff59d4",
|
||||
"调用趋势": "K8c7f2d2e",
|
||||
"(0)-(1)调用趋势": "K657c3452",
|
||||
"调用量统计": "Kc04efb87",
|
||||
@@ -562,7 +634,7 @@
|
||||
"请选择服务": "Kffcfe375",
|
||||
"调用详情": "Ka65f739c",
|
||||
"API 请求量 Top10": "K89b7ac79",
|
||||
"消费者调用量 Top10": "Kc0915603",
|
||||
"消费者调用量 Top10": "K386857bd",
|
||||
"服务被调用量 Top10": "Kf90b54",
|
||||
"暂无请求统计数据": "Kfb26388",
|
||||
"请求统计": "Kc8cbd8f8",
|
||||
@@ -571,6 +643,7 @@
|
||||
"暂无调用量统计数据": "Kcd125e4d",
|
||||
"暂无报文量统计数据": "Kaa114e8b",
|
||||
"报文量统计": "K3ad84406",
|
||||
"运行视图": "K714c192d",
|
||||
"集群配置并开启监控": "Kfa088d49",
|
||||
"监控功能用于辅助管理集群内信息,请配置集群、设置监控信息后查看当前集群监控情况;": "K3da3b9a0",
|
||||
"集群配置": "Kaddacfb",
|
||||
@@ -585,9 +658,22 @@
|
||||
"万": "Ke6a935d",
|
||||
"搜索分类或标签": "Kd59290a2",
|
||||
"暂无API数据": "K6b75bdbc",
|
||||
"搜索或选择消费者": "Kd8a7a689",
|
||||
"搜索或选择消费者": "Kb684c806",
|
||||
"申请理由": "K4b15d6f5",
|
||||
"消费者管理": "Kb7e869a4",
|
||||
"支持把当前服务对接主流的 AI Agent平台,实现在 Agent 平台上快速、安全和合规地使用企业开放的 API 能力。": "K2ec0fa56",
|
||||
"可按以下步骤进行对接:": "K35f23b64",
|
||||
"步骤一:Agent 平台上创建自定义插件": "Kf5cd608b",
|
||||
"不同 Agent 平台的操作细节可查看": "K4c81c7b6",
|
||||
"《 Agent 对接手册》": "K275f7ffa",
|
||||
"步骤二:导入 API 文档数据": "K49b81d06",
|
||||
"可通过以下 URL 或 下载 Json 文件,导入 API 文档数据到 Agent 平台中。": "K4a3b62be",
|
||||
"复制 URL": "K42697e11",
|
||||
"下载 Json 文件": "K27a809c5",
|
||||
"步骤三:配置 API 密钥": "K1e61fdee",
|
||||
"在": "K55912595",
|
||||
"菜单中,选择已通过本 API 服务申请的消费者,": "K33b1bc3",
|
||||
"把 \"访问权限\" 菜单下的密钥填入到 Agent 平台对应的插件密钥配置中。": "K62adc41e",
|
||||
"消费者管理": "Ke0fbd1c8",
|
||||
"鉴权类型": "Kb71b5a13",
|
||||
"Iss": "K4d1465ee",
|
||||
"签名算法": "K5dcd7ed8",
|
||||
@@ -600,9 +686,9 @@
|
||||
"SK": "K31418470",
|
||||
"Apikey": "Kbfeb5297",
|
||||
"隐藏鉴权信息": "Ke64e43a",
|
||||
"消费者名称": "K5168eb63",
|
||||
"消费者 ID": "K546e46f",
|
||||
"删除消费者": "K95764d1d",
|
||||
"消费者名称": "K67b530f",
|
||||
"消费者 ID": "K11f34de",
|
||||
"删除消费者": "Kc01002",
|
||||
"鉴权详情": "K217cb125",
|
||||
"添加鉴权": "K2bb63eca",
|
||||
"编辑鉴权": "Kd74d69b7",
|
||||
@@ -619,9 +705,11 @@
|
||||
"请确认是否取消订阅申请?": "K1856c229",
|
||||
"搜索服务": "K66ea2f0",
|
||||
"审核中": "K8adf7f8b",
|
||||
"添加消费者": "K667bbbe7",
|
||||
"暂无服务描述": "Ka4b45550",
|
||||
"添加消费者": "K84c4dc71",
|
||||
"暂无消费者描述": "Kc3b7bfa8",
|
||||
"创建并管理自己的消费者实体,每个消费者可以订阅多个API服务,确保在调用之前已获得相应权限。你可以为消费者生成 API 密钥等鉴权方式,用于安全地调用 API 服务": "K5c4e2865",
|
||||
"订阅的服务数量:已通过 (0) 个,申请中 (1) 个": "K3c7b175f",
|
||||
"输入名称、ID 查找消费者": "K3a6f905d",
|
||||
"退出测试": "Kbe3e9335",
|
||||
"服务市场": "K370a3eb2",
|
||||
"服务详情": "Kf7ec36d",
|
||||
@@ -630,20 +718,22 @@
|
||||
"Base URL": "Kc29dabf2",
|
||||
"申请": "K4aa9ed2c",
|
||||
"服务信息": "K6c060779",
|
||||
"接入消费者": "K8723422e",
|
||||
"接入消费者": "Kba74f26d",
|
||||
"供应方": "Kb97544cb",
|
||||
"分类": "Kb32f0afe",
|
||||
"版本": "K81634069",
|
||||
"更新时间": "Keefda53d",
|
||||
"无标签": "K96a2f1c8",
|
||||
"暂无服务描述": "Ka4b45550",
|
||||
"API 数量": "K72b0c0b3",
|
||||
"接入消费者数量": "K93d5a66e",
|
||||
"接入消费者数量": "K70b79760",
|
||||
"关联标签": "K96059c69",
|
||||
"更新者": "K8b7c2592",
|
||||
"添加 Open Api": "K32263abd",
|
||||
"配置 Open Api": "K7829bb78",
|
||||
"Open Api": "Kcdf76005",
|
||||
"调用服务": "Ke2601944",
|
||||
"系统拓扑图": "Kd57dfe97",
|
||||
"放大": "K8504bca8",
|
||||
"缩小": "K693c1b41"
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"Kc0e5ef9f": "Workspace",
|
||||
"K4de11e23": "Home",
|
||||
"Kfe93ef35": "Application",
|
||||
"Kb58e0c3f": "Service",
|
||||
"Kc9e489f5": "Team",
|
||||
"K61c89f5f": "API Portal",
|
||||
@@ -91,8 +90,6 @@
|
||||
"K6206e4ad": "Upload OpenAPI File (.json/.yaml)",
|
||||
"Kfba46e6d": "Replace OpenAPI File (.json/.yaml)",
|
||||
"Kdac8ce7e": "Open OpenAPI YAML Editor",
|
||||
"Kffd7e274": "No Review: All applications are allowed to subscribe to this service",
|
||||
"K8a8b13e4": "Manual Review: Only reviewed and approved applications can subscribe to this service",
|
||||
"Kbfe02d7f": "Permanent",
|
||||
"K1e9c479e": "No",
|
||||
"Kaddfcb6b": "Yes",
|
||||
@@ -259,7 +256,6 @@
|
||||
"Kc057704a": "Create AI Services and APIs",
|
||||
"K76bb4a09": "Create AI-based services, and you can set the prompt as an API to simplify the process of using AI.",
|
||||
"K71b2c70f": "Create Call Token",
|
||||
"K9bdd8403": "To securely call APIs, you need to create an application and a token.",
|
||||
"Kc5738b6c": "Call",
|
||||
"Kd6d7ca1f": "You can now call these APIs with the token.",
|
||||
"K86cf95f": "Quickly Integrate REST API",
|
||||
@@ -269,13 +265,11 @@
|
||||
"K2cdbb773": "Core Features",
|
||||
"K3378c50d": "Account and Role",
|
||||
"Kda5bb930": "Invite your team members to APIPark to collaboratively manage and call APIs.",
|
||||
"Kc8239422": "Teams include personnel, applications, and services. Data between different teams is isolated, and can be used to manage different departments/project teams/teams within the enterprise.",
|
||||
"Kd5be0cd7": "Services include a set of APIs and can be published to the API Marketplace for use by other teams.",
|
||||
"K62e89ee7": "Permission Management",
|
||||
"K8f7808e6": "Subscribe to Services",
|
||||
"Kf2410413": "To call an API from a service, you need to subscribe to that service and wait for approval from the providing team before initiating the API request.",
|
||||
"K6c2e44b8": "Review Subscription",
|
||||
"Ka0a8840a": "Review subscription requests from other applications. Only approved requests can initiate API calls.",
|
||||
"K3453272": "APIPark provides detailed API call logs, helping enterprises monitor, analyze, and audit API operations.",
|
||||
"Kd518ba3e": "Hello! Welcome to APIPark",
|
||||
"K7e04ea16": "🦄 APIPark is an open-source, all-in-one AI gateway and API developer portal, enabling enterprises and developers to quickly integrate over 100 AI models, combine AI models and prompts into new APIs, and standardize all AI request data formats, ensuring that switching AI models or adjusting prompts does not affect your APP or microservice. Additionally, APIPark’s developer portal allows you to share APIs within your team, manage applications that call your APIs, and ensure API security, while monitoring your AI API usage with clear charts.",
|
||||
@@ -325,7 +319,7 @@
|
||||
"Ka46b9b24": "Data Source Type",
|
||||
"Kbb0cdcd0": "Data Source Address",
|
||||
"Kd9dfb884": "Organization",
|
||||
"K3e770a75": "Authentication Token",
|
||||
"K3e770a75": "Credentials Token",
|
||||
"K8ef69ee2": "Key",
|
||||
"Kba3507d6": "Upload Key",
|
||||
"K93ac0f23": "Key file suffix is usually .key",
|
||||
@@ -371,7 +365,7 @@
|
||||
"Kcef64f4d": "Default AI Provider",
|
||||
"Kcab588a9": "No AI model provider set,",
|
||||
"Kb9b56111": "Set Now",
|
||||
"Kcf756b7a": "API Call Prefix",
|
||||
"Kcf756b7a": "API Request Prefix",
|
||||
"K13edc043": "As a prefix for all APIs in the service, e.g., host/{service_name}/{api_path}, cannot be modified once saved.",
|
||||
"Kf52a584d": "Service Category",
|
||||
"K72b21be5": "Set the category in which the service will be displayed in the service marketplace",
|
||||
@@ -397,15 +391,14 @@
|
||||
"K813e1c0a": "Team Name",
|
||||
"K692f5aa6": "Team ID",
|
||||
"K5de0bc2": "Team ID can be used to retrieve the team, cannot be modified once saved.",
|
||||
"Ka63dd985": "Team Leader",
|
||||
"Ka6bcd272": "The leader has management authority over the team, services, and members within the team",
|
||||
"Ka63dd985": "Team Administrator",
|
||||
"Ka6bcd272": "The Administrator has management authority over the team, services, and members within the team",
|
||||
"Ka2012bdd": "Delete Team",
|
||||
"Kbde1f3d": "Service data must be cleared before deletion",
|
||||
"K395acc14": "Remove",
|
||||
"Kec46a57f": "Add Member",
|
||||
"K48724410": "Enter Name to Search",
|
||||
"Kb9052305": "Search Username, Email",
|
||||
"K5ece3bac": "Set up teams and members. You can then create services and applications, subscribe to APIs within the team. Members can only see services and applications within their team.",
|
||||
"K510cdd27": "Add Team",
|
||||
"K9244ae14": "Enter Name, ID, Person in Charge to Search Teams",
|
||||
"Kc7b24b4b": "Configure Team",
|
||||
@@ -425,8 +418,6 @@
|
||||
"Ka2c794a2": "Export",
|
||||
"Kaf70c3b": "Exit Fullscreen",
|
||||
"Kd22841a4": "(0) Call Details",
|
||||
"K1512e983": "Application Call Statistics",
|
||||
"Kb4d2007f": "Please Select Application",
|
||||
"K8c7f2d2e": "Call Trend",
|
||||
"K657c3452": "(0)-(1) Call Trend",
|
||||
"Kc04efb87": "Call Volume Statistics",
|
||||
@@ -449,7 +440,6 @@
|
||||
"Kffcfe375": "Please Select Service",
|
||||
"Ka65f739c": "Call Details",
|
||||
"K89b7ac79": "API Top 10",
|
||||
"Kc0915603": "Application Top 10",
|
||||
"Kf90b54": "Service Top 10",
|
||||
"Kfb26388": "No Request Data",
|
||||
"Kc8cbd8f8": "Request Statistics",
|
||||
@@ -472,10 +462,8 @@
|
||||
"Ke6a935d": "Ten Thousand",
|
||||
"Kd59290a2": "Search Category or Tag",
|
||||
"K6b75bdbc": "No API Data",
|
||||
"Kd8a7a689": "Search or Select Application",
|
||||
"K4b15d6f5": "Application Reason",
|
||||
"Kb7e869a4": "Application Settings",
|
||||
"Kb71b5a13": "Authentication Type",
|
||||
"Kb71b5a13": "Credentials Type",
|
||||
"K4d1465ee": "ISS",
|
||||
"K5dcd7ed8": "Signature Algorithm",
|
||||
"K5b0eedd3": "Secret",
|
||||
@@ -487,13 +475,10 @@
|
||||
"K31418470": "SK",
|
||||
"Kbfeb5297": "API Key",
|
||||
"K1a78e6f0": "Expiration Time",
|
||||
"Ke64e43a": "Hide Authentication Info",
|
||||
"K5168eb63": "Application Name",
|
||||
"K546e46f": "Application ID",
|
||||
"K95764d1d": "Delete Application",
|
||||
"K217cb125": "Authentication Details",
|
||||
"K2bb63eca": "Add Authentication",
|
||||
"Kd74d69b7": "Edit Authentication",
|
||||
"Ke64e43a": "Hide Credentials Info",
|
||||
"K217cb125": "Credentials Details",
|
||||
"K2bb63eca": "Add Credentials",
|
||||
"Kd74d69b7": "Edit Credentials",
|
||||
"K9cbe1e0": "Modify",
|
||||
"Kb6e9328f": "Authorization",
|
||||
"Kd23d1716": "Add Authorization",
|
||||
@@ -507,7 +492,6 @@
|
||||
"K1856c229": "Are you sure you want to cancel the subscription request?",
|
||||
"K66ea2f0": "Search Services",
|
||||
"K8adf7f8b": "Under Review",
|
||||
"K667bbbe7": "Add Application",
|
||||
"Ka4b45550": "No Service Description",
|
||||
"K3c7b175f": "Number of Subscribed Services: (0) Approved, (1) Pending",
|
||||
"Kbe3e9335": "Exit Test",
|
||||
@@ -517,7 +501,6 @@
|
||||
"K59cdbec3": "Intro",
|
||||
"K4aa9ed2c": "Subscribe",
|
||||
"K6c060779": "Service Information",
|
||||
"K8723422e": "Access Application",
|
||||
"Kb97544cb": "Provider",
|
||||
"Kb32f0afe": "Category",
|
||||
"K81634069": "Version",
|
||||
@@ -525,7 +508,6 @@
|
||||
"Keefda53d": "Update Time",
|
||||
"K96a2f1c8": "No Tags",
|
||||
"K72b0c0b3": "Number of APIs",
|
||||
"K93d5a66e": "Number of Access Applications",
|
||||
"K96059c69": "Associated Tags",
|
||||
"K32263abd": "Add Open API",
|
||||
"K7829bb78": "Configure Open API",
|
||||
@@ -546,8 +528,6 @@
|
||||
"Ke41d7451": "Read-Only Member",
|
||||
"Kf99e8b66": "Service Administrator",
|
||||
"Kda8db57a": "Service Developer",
|
||||
"K216a1ac7": "Application Developer",
|
||||
"K27924db": "Application Administrator",
|
||||
"K8dc5c723": "Driver Name",
|
||||
"Kda249fe8": "Failure",
|
||||
"Kcf2df651": "Failure",
|
||||
@@ -575,7 +555,6 @@
|
||||
"K593e0c7e": "No Review Required",
|
||||
"Ke2d747d9": "Review Required",
|
||||
"Kc29dabf2": "Base URL",
|
||||
"Kd55c6887": "Review",
|
||||
"K300c89d4": "When creating an API, this provider is selected by default. Changing the default provider will not affect existing APIs.",
|
||||
"Kefaf9956": "Create Time",
|
||||
"Kad1c674c": "Protocol",
|
||||
@@ -589,7 +568,6 @@
|
||||
"Kcbf39b82": "Status",
|
||||
"K339d15b5": "Creator",
|
||||
"K7194cea2": "Review Time",
|
||||
"K831aa6c0": "Applicant - Application",
|
||||
"K7ad449bc": "Status",
|
||||
"K3b3a98ce": "Reviewer",
|
||||
"K61b62ace": "Source",
|
||||
@@ -602,8 +580,8 @@
|
||||
"Kd7d84192": "Name",
|
||||
"Kc88e03b6": "Team Roles",
|
||||
"Ke08ff808": "Addition Date",
|
||||
"K19a3ebe0": "Successful Requests",
|
||||
"Kcaa8259": "Successful Forwards",
|
||||
"K19a3ebe0": "Success",
|
||||
"Kcaa8259": "Success",
|
||||
"K17f93984": "API",
|
||||
"K888f038f": "Failed Status Code Count",
|
||||
"Ke792d01c": "Service Association",
|
||||
@@ -629,7 +607,7 @@
|
||||
"Ke108c369": "Success",
|
||||
"K9168d3e": "Redirecting to Login Page",
|
||||
"K2f8a7ab7": "Review Comments Not Provided",
|
||||
"Kb858d78a": "Copy Successful",
|
||||
"Kb858d78a": "Copied",
|
||||
"K26e85d15": "Copy Failed, Please Copy Manually",
|
||||
"Kd60d204": "Service Team",
|
||||
"K823bfe63": "Online",
|
||||
@@ -646,5 +624,144 @@
|
||||
"K29ec75dc": "Per Week",
|
||||
"Kac172626": "Please provide a reason when rejecting the request.",
|
||||
"Ke1b1865": "Private",
|
||||
"K4786c57c": "Public"
|
||||
"K4786c57c": "Public",
|
||||
"K7acfcfad": "Consumer",
|
||||
"Kc8054dba": "Consumer Developer",
|
||||
"Keb1673a6": "Consumer Administrator",
|
||||
"K1fc2cc28": "No Review: All consumers are allowed to subscribe to this service",
|
||||
"K8dabb98e": "Manual Review: Only reviewed and approved consumers can subscribe to this service",
|
||||
"K7c1fb123": "Applicant - Application",
|
||||
"Kdea9a418": "To securely call APIs, you need to create an consumer and a token.",
|
||||
"Keee27105": "Teams include personnel, consumers, and services. Data between different teams is isolated, and can be used to manage different departments/project teams/teams within the enterprise.",
|
||||
"Kaa717866": "Review subscription requests from other consumers. Only approved requests can initiate API calls.",
|
||||
"Kd2c34e2c": "AI Service",
|
||||
"K62840d62": "REST Service",
|
||||
"K4c72fb6f": "Set up teams and members. You can then create services and consumers, subscribe to APIs within the team. Members can only see services and applications within their team.",
|
||||
"K61cca533": "Consumer Call Statistics",
|
||||
"Kdfff59d4": "Please Select Consumer",
|
||||
"K386857bd": "Consumer Top 10",
|
||||
"Kb684c806": "Search or Select Consumer",
|
||||
"Ke0fbd1c8": "Consumer Settings",
|
||||
"K67b530f": "Consumer Name",
|
||||
"K11f34de": "Consumer ID",
|
||||
"Kc01002": "Delete Consumer",
|
||||
"K84c4dc71": "Add Consumer",
|
||||
"K5c4e2865": "Create and manage your own consumer entities, with each consumer able to subscribe to multiple API services, ensuring the necessary permissions are obtained before making any calls. You can generate API keys or other credentials for consumers to securely call API services.",
|
||||
"K40a89bd8": "Enter Name, ID to Search Member",
|
||||
"Kba74f26d": "Access Consumer",
|
||||
"K70b79760": "Number of Access Consumers",
|
||||
"K93c2696e": "Online Result",
|
||||
"K6e32a344": "Number of Services",
|
||||
"Ka701316": "Number of Auths",
|
||||
"K9eaa2eb6": "List",
|
||||
"Kfaec39e9": "Block",
|
||||
"Kc3b7bfa8": "No Consumer Description",
|
||||
"K3a6f905d": "Enter Name, ID to Search Consumer",
|
||||
"K76036e25": "HTTP Request Header",
|
||||
"K44607e3f": "Exact Match",
|
||||
"Kc287500a": "Prefix Match",
|
||||
"Kfc0b1147": "Suffix Match",
|
||||
"Ka4a92043": "Substring Match",
|
||||
"K30b2e44f": "Non-Exact Match",
|
||||
"Kb1587991": "Null Match",
|
||||
"K87c5a801": "Case-Sensitive Regex Match",
|
||||
"K95f062f1": "Case-Insensitive Regex Match",
|
||||
"Kfbd230a5": "Any Match",
|
||||
"Kd85208a3": "Reject",
|
||||
"Kad6aa439": "Subscribed",
|
||||
"K9a68443b": "Cancel Request",
|
||||
"Kaeba0229": "Pass-through Client Request Host",
|
||||
"K6d7e2fd0": "Use Upstream Service Host",
|
||||
"K31332633": "Rewrite Host",
|
||||
"K2c2bc64f": "Dynamic Service Discovery",
|
||||
"K78b1ca25": "Address",
|
||||
"K1644b775": "Add",
|
||||
"Kc8ee3e62": "Non-Existence",
|
||||
"K1e97dbd8": "Existence",
|
||||
"Kec91f0db": "Applicant Consumer",
|
||||
"Kf5fd27ed": "Enter Name to Search User",
|
||||
"K2ec0fa56": "Support integration with mainstream AI Agent platforms to enable the use of enterprise APIs in a fast, secure, and compliant manner on the Agent platform.",
|
||||
"K35f23b64": "Follow these steps for integration:",
|
||||
"Kf5cd608b": "Step 1: Create a custom plugin on the Agent platform",
|
||||
"K4c81c7b6": "For details on the operations of different Agent platforms, refer to",
|
||||
"K275f7ffa": "the Agent Integration Manual",
|
||||
"K49b81d06": "Step 2: Import API documentation data",
|
||||
"K4a3b62be": "You can import API documentation data to the Agent platform via the following URL or by downloading the JSON file.",
|
||||
"K42697e11": "Copy URL",
|
||||
"K27a809c5": "Download JSON file",
|
||||
"K1e61fdee": "Step 3: Configure API keys",
|
||||
"K55912595": "In the",
|
||||
"K33b1bc3": "menu, select the consumer that has applied for the API service,",
|
||||
"K62adc41e": "and fill in the key from the 'Access Permission' menu into the corresponding plugin key configuration on the Agent platform.",
|
||||
"Ke8cbb878": "Global Policy",
|
||||
"K34d0d409": "Add Policy",
|
||||
"Kbb4298ac": "Enter name, filter criteria to search",
|
||||
"Kabac9caf": "Data Masking",
|
||||
"Kc975cd5a": "Supports unified policy configuration for the system globally, simplifying management and ensuring consistency. The priority of global policies is slightly lower than that of service policies.",
|
||||
"K52f72551": "Service Policy",
|
||||
"K931615d7": "Policy Name",
|
||||
"K31faa2a1": "Priority",
|
||||
"Kbdec9fa": "Filter Criteria",
|
||||
"Kbcbb7391": "Processed Count",
|
||||
"Kad207008": "Edit",
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "Release Name",
|
||||
"Kb2480682": "Policy List",
|
||||
"K118d8d74": "Data Format",
|
||||
"Kfe7c7d2d": "Keyword",
|
||||
"K2f57a694": "Regular Expression",
|
||||
"K8953e0a6": "Mobile Number",
|
||||
"K6f86a038": "ID Card Number",
|
||||
"K7954e7c8": "Bank Card Number",
|
||||
"K320fdb17": "Amount",
|
||||
"K7867acda": "Date",
|
||||
"K7d327ae8": "Partial Display",
|
||||
"Kfbf38e3c": "Partial Masking",
|
||||
"Kd8c1fbb0": "Truncate",
|
||||
"K89829921": "Replace",
|
||||
"K480a7165": "Shuffle",
|
||||
"Kea0d69df": "Random String",
|
||||
"Ke7c84d1d": "Custom String",
|
||||
"K49731763": "Please enter IP address or CIDR range, each separated by a newline.",
|
||||
"K83237c89": "The entered IP or CIDR does not meet the format.",
|
||||
"K5ae2c87a": "Please enter the correct path, such as /usr/* or */usr/*.",
|
||||
"Kc82b8374": "Edit Policy",
|
||||
"K4b34a5e5": "Policy Type",
|
||||
"K57f0fee8": "Match Conditions",
|
||||
"K10650c58": "Data Masking Rules",
|
||||
"K1b34a9ab": "Configure Masking Rules",
|
||||
"K26d22405": "Match Value",
|
||||
"K1546e1fe": "Masking Type",
|
||||
"K9b9b0629": "Starting Position",
|
||||
"K52c84fe1": "Length",
|
||||
"Kde84409c": "Replace Type",
|
||||
"K338653b4": "Replace Value",
|
||||
"Kbaeed3b7": "JSON Path",
|
||||
"K4cd91d61": "Masking Rules",
|
||||
"K8dcad979": "Custom String; Value:",
|
||||
"K82e3f7b7": "Starting Position: (0); Length: (1)",
|
||||
"K49dfc123": "Selected (0) items (1) data",
|
||||
"K8457ea34": "All (0)",
|
||||
"K7ca9a795": "Attribute Name",
|
||||
"Kc4391744": "Attribute Value",
|
||||
"K678e13fc": "Configure (0)",
|
||||
"K508d8bf4": "Integration Address",
|
||||
"K67f4e9bb": "The domain name for obtaining API market documentation information when integrating with external platforms",
|
||||
"K1da86266": "Invalid",
|
||||
"K3a34d49b": "Pending Update",
|
||||
"Kd2850420": "Pending Deletion",
|
||||
"K9ada4366": "Operation successful, the page will refresh shortly",
|
||||
"K9b332ab1": "Request prefix",
|
||||
"K3d78d483": "HTTP headers",
|
||||
"K17dc3a62": "Data logs",
|
||||
"Ke429194e": "Processing logs",
|
||||
"K84ffb1dd": "Enter the invocation address, consumer IP, and consumer condition to search",
|
||||
"Kb147fabc": "Create",
|
||||
"K40ca4f2": "Update",
|
||||
"K3e7aa0ad": "Content",
|
||||
"K2f5fdf5e": "Call Address",
|
||||
"K1bc5e0a3": "Consumer IP",
|
||||
"K6f39ea21": "Authentication Name",
|
||||
"K8c34c02f": "Before Masking",
|
||||
"K8e3d388d": "After Masking"
|
||||
}
|
||||
|
||||
@@ -646,5 +646,144 @@
|
||||
"Kfcda87fc": "毎日",
|
||||
"K29ec75dc": "毎週",
|
||||
"Ke1b1865": "プライベート",
|
||||
"K4786c57c": "パブリック"
|
||||
"K4786c57c": "パブリック",
|
||||
"K7acfcfad": "コンシューマー",
|
||||
"Kc8054dba": "コンシューマー開発者",
|
||||
"Keb1673a6": "コンシューマー管理者",
|
||||
"K1fc2cc28": "審査不要:どのコンシューマーでもこのサービスを呼び出せます",
|
||||
"K8dabb98e": "手動審査:手動審査に合格したコンシューマーのみ、このサービスを呼び出せます",
|
||||
"K7c1fb123": "申請元-コンシューマー",
|
||||
"K93c2696e": "オンライン結果",
|
||||
"K6e32a344": "サブスクライブサービス数",
|
||||
"Ka701316": "認証数",
|
||||
"K9eaa2eb6": "リスト",
|
||||
"Kfaec39e9": "ブロック",
|
||||
"Kdea9a418": "API を安全に呼び出すためには、コンシューマーとトークンを作成する必要があります。",
|
||||
"Keee27105": "チームにはメンバー、コンシューマー、サービスが含まれ、異なるチームのコンシューマーとサービスデータは分離されています。企業内の部門やプロジェクトチームの管理に役立ちます。",
|
||||
"Kaa717866": "サービスを提供するチームは、他のチームからのサブスクリプション申請を審査できます。審査に合格したコンシューマーのみ API リクエストを行うことができます。",
|
||||
"Kd2c34e2c": "AI サービス",
|
||||
"K62840d62": "REST サービス",
|
||||
"K4c72fb6f": "チームとメンバーを設定してから、チーム内でサービスとコンシューマーを作成し、API をサブスクライブできます。メンバーは所属チーム内のサービスとコンシューマーのみを表示できます。",
|
||||
"K61cca533": "コンシューマー呼び出し統計",
|
||||
"Kdfff59d4": "コンシューマーを選択してください",
|
||||
"K386857bd": "コンシューマー呼び出し量トップ10",
|
||||
"Kb684c806": "コンシューマーを検索または選択",
|
||||
"Ke0fbd1c8": "コンシューマー管理",
|
||||
"K67b530f": "コンシューマー名",
|
||||
"K11f34de": "コンシューマー ID",
|
||||
"Kc01002": "コンシューマーを削除",
|
||||
"K40a89bd8": "名前または ID を入力してサービスを検索",
|
||||
"Kba74f26d": "コンシューマーを接続",
|
||||
"K70b79760": "接続コンシューマー数",
|
||||
"K5c4e2865": "コンシューマーエンティティを作成および管理し、各コンシューマーは複数の API サービスにサブスクライブできます。呼び出し前に適切な権限が付与されていることを確認してください。コンシューマー用に API キーなどの認証方法を生成して、安全に API サービスを呼び出せます。",
|
||||
"K84c4dc71": "コンシューマーを追加",
|
||||
"Kc3b7bfa8": "コンシューマーの説明がありません",
|
||||
"K3a6f905d": "名前、IDを入力してコンシューマーを検索",
|
||||
"K76036e25": "HTTPリクエストヘッダー",
|
||||
"K44607e3f": "完全一致",
|
||||
"Kc287500a": "プレフィックス一致",
|
||||
"Kfc0b1147": "サフィックス一致",
|
||||
"Ka4a92043": "部分一致",
|
||||
"K30b2e44f": "非完全一致",
|
||||
"Kb1587991": "ヌル一致",
|
||||
"K87c5a801": "大文字小文字を区別する正規表現一致",
|
||||
"K95f062f1": "大文字小文字を区別しない正規表現一致",
|
||||
"Kfbd230a5": "任意一致",
|
||||
"Kd85208a3": "拒否",
|
||||
"Kad6aa439": "申し込み済み",
|
||||
"K9a68443b": "申し込み取消",
|
||||
"Kaeba0229": "クライアントリクエストホストのパススルー",
|
||||
"K6d7e2fd0": "上位サービスホストの使用",
|
||||
"K31332633": "ホストの書き換え",
|
||||
"K2c2bc64f": "動的サービス発見",
|
||||
"K78b1ca25": "アドレス",
|
||||
"K1644b775": "追加",
|
||||
"Kc8ee3e62": "存在しない",
|
||||
"K1e97dbd8": "存在する",
|
||||
"Kec91f0db": "申請側コンシューマー",
|
||||
"Kf5fd27ed": "名前を入力してユーザーを検索",
|
||||
"K2ec0fa56": "主要なAIエージェントプラットフォームと連携し、エージェントプラットフォーム上で企業のAPIを迅速、安全、かつコンプライアンスに準拠して使用できるようサポートします。",
|
||||
"K35f23b64": "以下の手順で統合を行います:",
|
||||
"Kf5cd608b": "ステップ1:エージェントプラットフォームでカスタムプラグインを作成",
|
||||
"K4c81c7b6": "異なるエージェントプラットフォームの操作詳細については、",
|
||||
"K275f7ffa": "「エージェント統合マニュアル」を参照してください。",
|
||||
"K49b81d06": "ステップ2:APIドキュメントデータのインポート",
|
||||
"K4a3b62be": "以下のURLを使用するか、JSONファイルをダウンロードして、APIドキュメントデータをエージェントプラットフォームにインポートできます。",
|
||||
"K42697e11": "URLをコピー",
|
||||
"K27a809c5": "JSONファイルをダウンロード",
|
||||
"K1e61fdee": "ステップ3:APIキーの設定",
|
||||
"K55912595": "「",
|
||||
"K33b1bc3": "メニュー」から、APIサービスを申し込んだ消費者を選択し、",
|
||||
"K62adc41e": "「アクセス権限」メニューのキーをエージェントプラットフォームのプラグインキー設定に入力します。",
|
||||
"Ke8cbb878": "グローバルポリシー",
|
||||
"K34d0d409": "ポリシーを追加",
|
||||
"Kbb4298ac": "名前、フィルタ条件を入力して検索",
|
||||
"Kabac9caf": "データマスキング",
|
||||
"Kc975cd5a": "システム全体で統一されたポリシー設定をサポートし、管理の簡素化と一貫性の確保を実現します。グローバルポリシーの優先度はサービスポリシーより少し低いです。",
|
||||
"K52f72551": "サービスポリシー",
|
||||
"K931615d7": "ポリシー名",
|
||||
"K31faa2a1": "優先度",
|
||||
"Kbdec9fa": "フィルタ条件",
|
||||
"Kbcbb7391": "処理数",
|
||||
"Kad207008": "編集",
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "リリース名",
|
||||
"Kb2480682": "ポリシーリスト",
|
||||
"K118d8d74": "データフォーマット",
|
||||
"Kfe7c7d2d": "キーワード",
|
||||
"K2f57a694": "正規表現",
|
||||
"K8953e0a6": "携帯番号",
|
||||
"K6f86a038": "IDカード番号",
|
||||
"K7954e7c8": "銀行カード番号",
|
||||
"K320fdb17": "金額",
|
||||
"K7867acda": "日付",
|
||||
"K7d327ae8": "部分表示",
|
||||
"Kfbf38e3c": "部分マスキング",
|
||||
"Kd8c1fbb0": "切り取り",
|
||||
"K89829921": "置換",
|
||||
"K480a7165": "シャッフル",
|
||||
"Kea0d69df": "ランダム文字列",
|
||||
"Ke7c84d1d": "カスタム文字列",
|
||||
"K49731763": "IPアドレスまたはCIDR範囲を入力してください。各行で改行してください。",
|
||||
"K83237c89": "入力されたIPまたはCIDRがフォーマットに一致しません。",
|
||||
"K5ae2c87a": "正しいパスを入力してください。例: /usr/* または */usr/*。",
|
||||
"Kc82b8374": "ポリシーを編集",
|
||||
"K4b34a5e5": "ポリシータイプ",
|
||||
"K57f0fee8": "一致条件",
|
||||
"K10650c58": "データマスキングルール",
|
||||
"K1b34a9ab": "マスキングルールを設定",
|
||||
"K26d22405": "一致値",
|
||||
"K1546e1fe": "マスキングタイプ",
|
||||
"K9b9b0629": "開始位置",
|
||||
"K52c84fe1": "長さ",
|
||||
"Kde84409c": "置換タイプ",
|
||||
"K338653b4": "置換値",
|
||||
"Kbaeed3b7": "JSON パス",
|
||||
"K4cd91d61": "マスキングルール",
|
||||
"K8dcad979": "カスタム文字列; 値:",
|
||||
"K82e3f7b7": "開始位置: (0); 長さ: (1)",
|
||||
"K49dfc123": "選択された (0) アイテム (1) データ",
|
||||
"K8457ea34": "すべて (0)",
|
||||
"K7ca9a795": "属性名",
|
||||
"Kc4391744": "属性値",
|
||||
"K678e13fc": "設定 (0)",
|
||||
"K508d8bf4": "統合アドレス",
|
||||
"K67f4e9bb": "外部プラットフォームと統合する際に、API市場のドキュメント情報を取得するためのドメイン名",
|
||||
"K1da86266": "無効",
|
||||
"K3a34d49b": "更新待ち",
|
||||
"Kd2850420": "削除待ち",
|
||||
"K9ada4366": "操作成功、ページを更新します",
|
||||
"K9b332ab1": "リクエストプレフィックス",
|
||||
"K3d78d483": "HTTPヘッダー",
|
||||
"K17dc3a62": "データログ",
|
||||
"Ke429194e": "ログの処理",
|
||||
"K84ffb1dd": "呼び出しアドレス、コンシューマーIP、条件を入力して検索",
|
||||
"Kb147fabc": "新規作成",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "内容",
|
||||
"K2f5fdf5e": "呼び出しアドレス",
|
||||
"K1bc5e0a3": "コンシューマー IP",
|
||||
"K6f39ea21": "認証名",
|
||||
"K8c34c02f": "マスキング前",
|
||||
"K8e3d388d": "マスキング後"
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"K630c9e6d": "APIPark",
|
||||
"Ka3e9f580": "发布名称",
|
||||
"Kb2480682": "策略列表",
|
||||
"K1da86266": "无效",
|
||||
"K76036e25": "HTTP 请求头",
|
||||
"K44607e3f": "全等匹配",
|
||||
"Kc287500a": "前缀匹配",
|
||||
"Kfc0b1147": "后缀匹配",
|
||||
"Ka4a92043": "子串匹配",
|
||||
"K30b2e44f": "非等匹配",
|
||||
"Kb1587991": "空值匹配",
|
||||
"K1e97dbd8": "存在匹配",
|
||||
"Kc8ee3e62": "不存在匹配",
|
||||
"K87c5a801": "区分大小写的正则匹配",
|
||||
"K95f062f1": "不区分大小写的正则匹配",
|
||||
"Kfbd230a5": "任意匹配",
|
||||
"Kd85208a3": "驳回",
|
||||
"Kad6aa439": "已订阅",
|
||||
"K9a68443b": "取消申请",
|
||||
"Kaeba0229": "透传客户端请求 Host",
|
||||
"K6d7e2fd0": "使用上游服务 Host",
|
||||
"K31332633": "重写 Host",
|
||||
"K2c2bc64f": "动态服务发现",
|
||||
"K78b1ca25": "地址",
|
||||
"K1644b775": "新增",
|
||||
"Kec91f0db": "申请方消费者",
|
||||
"K118d8d74": "数据格式",
|
||||
"Kfe7c7d2d": "关键字",
|
||||
"K2f57a694": "正则表达式",
|
||||
"K8953e0a6": "手机号",
|
||||
"K6f86a038": "身份证号",
|
||||
"K7954e7c8": "银行卡号",
|
||||
"K320fdb17": "金额",
|
||||
"K7867acda": "日期",
|
||||
"K7d327ae8": "局部显示",
|
||||
"Kfbf38e3c": "局部遮蔽",
|
||||
"Kd8c1fbb0": "截取",
|
||||
"K89829921": "替换",
|
||||
"K480a7165": "乱序",
|
||||
"Kea0d69df": "随机字符串",
|
||||
"Ke7c84d1d": "自定义字符串",
|
||||
"K49731763": "请输入IP地址或CIDR范围,每条以换行分割",
|
||||
"K3a34d49b": "待更新",
|
||||
"Kd2850420": "待删除",
|
||||
"K83237c89": "输入的IP或CIDR不符合格式",
|
||||
"K5ae2c87a": "请正确输入路径,如/usr/*或*/usr/*",
|
||||
"K508d8bf4": "集成地址",
|
||||
"K67f4e9bb": "与外部平台集成时,获取 API 市场中文档信息的域名",
|
||||
"Kc82b8374": "编辑策略",
|
||||
"K4b34a5e5": "策略类型",
|
||||
"K57f0fee8": "匹配条件",
|
||||
"K10650c58": "数据脱敏规则",
|
||||
"K1b34a9ab": "配置脱敏规则",
|
||||
"K26d22405": "匹配值",
|
||||
"K1546e1fe": "脱敏类型",
|
||||
"K9b9b0629": "起始位置",
|
||||
"K52c84fe1": "长度",
|
||||
"Kde84409c": "替换类型",
|
||||
"K338653b4": "替换值",
|
||||
"Kbaeed3b7": "JSON Path",
|
||||
"K4cd91d61": "脱敏规则",
|
||||
"K8dcad979": "自定义字符串; 值:",
|
||||
"K82e3f7b7": "起始位置:(0)位;长度:(1)位",
|
||||
"K49dfc123": "已选择(0)项(1)数据",
|
||||
"K8457ea34": "所有(0)",
|
||||
"K7ca9a795": "属性名称",
|
||||
"Kc4391744": "属性值",
|
||||
"K678e13fc": "配置(0)",
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"Kc0e5ef9f": "Workspace",
|
||||
"K4de11e23": "Home",
|
||||
"K61c89f5f": "API Portal",
|
||||
"K3fe97dcc": "System Settings",
|
||||
"Kecbb0e45": "System",
|
||||
"Ka358e23d": "General",
|
||||
"K449058e9": "API Gateway",
|
||||
"K99935e6f": "AI Model",
|
||||
"K1deaa2dd": "User",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"K5cfdd950": "This data cannot be recovered after deletion. Are you sure you want to delete?",
|
||||
"Kb9052305": "Search Username, Email",
|
||||
"K40a89bd8": "Enter Name, ID to Search Member"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"Kc0e5ef9f": "Workspace",
|
||||
"K4de11e23": "Home",
|
||||
"Kfe93ef35": "Application",
|
||||
"K61c89f5f": "API Portal",
|
||||
"K3fe97dcc": "設定",
|
||||
"Kecbb0e45": "システム",
|
||||
"Ka358e23d": "一般",
|
||||
"K449058e9": "API ゲートウェイ",
|
||||
"K99935e6f": "AI モデル",
|
||||
"K1deaa2dd": "ユーザー",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"Kffd7e274": "無審査:すべてのアプリケーションがこのサービスにサブスクライブできます",
|
||||
"K8a8b13e4": "手動審査:承認されたアプリケーションのみがこのサービスにサブスクライブできます",
|
||||
"K9bdd8403": "API を安全に呼び出すためには、アプリケーションとトークンを作成する必要があります。",
|
||||
"Kc8239422": "チームにはユーザー、アプリケーション、サービスが含まれ、異なるチームのアプリケーションとサービスのデータは分離されています。企業内の部門/プロジェクトグループ/チームの管理に使用できます。",
|
||||
"Ka0a8840a": "他のアプリケーションのサブスクリプション申請をレビューし、承認後に API リクエストが発行できます。",
|
||||
"K5cfdd950": "このデータを削除すると、復元できません。削除しますか?",
|
||||
"Kb9052305": "ユーザー名またはメールを検索",
|
||||
"K5ece3bac": "チームとメンバーを設定してから、チーム内でサービスとアプリケーションを作成し、API をサブスクライブできます。メンバーは所属チーム内のサービスとアプリケーションのみを表示できます。",
|
||||
"K1512e983": "アプリケーション呼び出し統計",
|
||||
"Kb4d2007f": "Application を選択",
|
||||
"Kc0915603": "Application トップ10",
|
||||
"Kd8a7a689": "アプリケーションを検索または選択",
|
||||
"Kb7e869a4": "アプリケーション管理",
|
||||
"K5168eb63": "Application 名",
|
||||
"K546e46f": "Application ID",
|
||||
"K95764d1d": "Application を削除",
|
||||
"K667bbbe7": "Application を追加",
|
||||
"K8723422e": "アプリケーションを接続",
|
||||
"K93d5a66e": "接続アプリケーション数",
|
||||
"K216a1ac7": "アプリケーション開発者",
|
||||
"K27924db": "アプリケーション管理者",
|
||||
"Kd55c6887": "レビュー",
|
||||
"K831aa6c0": "申請元-アプリケーション",
|
||||
"K40a89bd8": "名前または ID を入力してサービスを検索"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"Kc0e5ef9f": "工作空间",
|
||||
"K4de11e23": "首页",
|
||||
"Kfe93ef35": "消费者",
|
||||
"K61c89f5f": "API 门户",
|
||||
"K3fe97dcc": "系统设置",
|
||||
"Kecbb0e45": "系统",
|
||||
"Ka358e23d": "常规",
|
||||
"K449058e9": "API 网关",
|
||||
"K99935e6f": "AI 模型",
|
||||
"K1deaa2dd": "用户",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"Kffd7e274": "无审核:允许所有消费者订阅该服务",
|
||||
"K8a8b13e4": "人工审核:仅允许审核通过的消费者订阅该服务",
|
||||
"K9bdd8403": "为了安全地调用 API,你需要创建一个消费者以及Token。",
|
||||
"Kc8239422": "团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。",
|
||||
"Ka0a8840a": "审核其他消费者的订阅申请,审核通过后的才可发起 API 请求。",
|
||||
"K5cfdd950": "该数据删除后将无法找回,是否删除?",
|
||||
"Kb9052305": "搜索用户名、邮箱",
|
||||
"K5ece3bac": "设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。",
|
||||
"K1512e983": "消费者调用统计",
|
||||
"Kb4d2007f": "请选择消费者",
|
||||
"Kc0915603": "消费者 Top10",
|
||||
"Kd8a7a689": "搜索或选择消费者",
|
||||
"Kb7e869a4": "消费者管理",
|
||||
"K5168eb63": "消费者名称",
|
||||
"K546e46f": "消费者 ID",
|
||||
"K95764d1d": "删除消费者",
|
||||
"K667bbbe7": "添加消费者",
|
||||
"K8723422e": "接入消费者",
|
||||
"K93d5a66e": "接入消费者数量",
|
||||
"K216a1ac7": "消费者开发者",
|
||||
"K27924db": "消费者管理员",
|
||||
"Kd55c6887": "审核",
|
||||
"K831aa6c0": "申请方-消费者",
|
||||
"K40a89bd8": "输入名称、ID 查找服务"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"Kc0e5ef9f": "工作區",
|
||||
"K4de11e23": "主頁",
|
||||
"Kfe93ef35": "應用程式",
|
||||
"K61c89f5f": "API 門戶",
|
||||
"K3fe97dcc": "系統設置",
|
||||
"Kecbb0e45": "系統",
|
||||
"Ka358e23d": "常規",
|
||||
"K449058e9": "API 網關",
|
||||
"K99935e6f": "AI 模型",
|
||||
"K1deaa2dd": "用戶",
|
||||
"K631d646f": "Open API",
|
||||
"K1196b104": "APIPark",
|
||||
"Kffd7e274": "無審核:允許所有應用程式訂閱該服務",
|
||||
"K8a8b13e4": "人工審核:僅允許審核通過的應用程式訂閱該服務",
|
||||
"K9bdd8403": "為了安全地調用 API,你需要創建一個應用以及Token。",
|
||||
"Kc8239422": "團隊中包含了人員、應用程式和服務,不同團隊之間的應用程式和服務數據是隔離的,可用於管理企業內部不同的部門/項目組/團隊。",
|
||||
"Ka0a8840a": "審核其他應用程式的訂閱申請,審核通過後的才可發起 API 請求。",
|
||||
"K5cfdd950": "該數據刪除後將無法找回,是否刪除?",
|
||||
"Kb9052305": "搜索用戶名、電郵",
|
||||
"K5ece3bac": "設置團隊和成員,然後你可以在團隊內創建服務和應用程式、訂閱API,成員只能看到所屬團隊內的服務和應用程式。",
|
||||
"K1512e983": "應用程式調用統計",
|
||||
"Kb4d2007f": "請選擇應用程式",
|
||||
"Kc0915603": "應用程式 Top10",
|
||||
"Kd8a7a689": "搜索或選擇應用程式",
|
||||
"Kb7e869a4": "應用程式管理",
|
||||
"K5168eb63": "應用程式名稱",
|
||||
"K546e46f": "應用程式 ID",
|
||||
"K95764d1d": "刪除應用程式",
|
||||
"K667bbbe7": "添加應用程式",
|
||||
"K8723422e": "接入應用程式",
|
||||
"K93d5a66e": "接入應用程式數量",
|
||||
"K216a1ac7": "應用程式開發者",
|
||||
"K27924db": "應用程式管理員",
|
||||
"Kd55c6887": "審核",
|
||||
"K831aa6c0": "申請方-應用程式",
|
||||
"K40a89bd8": "輸入名稱、ID 查找服務"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user