mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0362f7784f | |||
| 1ab56708a5 | |||
| 42e8030cf7 | |||
| 17b4ede566 | |||
| bbc3fea848 | |||
| 82e46b872b | |||
| 0f6a091c73 | |||
| 4e87adb4b3 | |||
| 320a2b6cf8 | |||
| b216556867 | |||
| 7fbb98a2a9 | |||
| 461a8edbea | |||
| cdef179bed | |||
| a067388d79 | |||
| 2d5e541593 | |||
| be40186ad3 | |||
| c9ae05b22e | |||
| 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 | |||
| 68e8cb72d3 | |||
| a86d3cd65a | |||
| a4b4cbf60f | |||
| 2dcb7ebd74 | |||
| 8fa1985feb | |||
| 451efb8d3e | |||
| d6bf3139ff | |||
| 309b9ea937 | |||
| 554bff38c6 | |||
| d5e6062ec9 | |||
| 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 | |||
| 4ba2b0c9ab | |||
| b3672b8c66 | |||
| b33dda4a32 | |||
| 450e565718 | |||
| 00bd72c1e4 | |||
| 81da1f45f1 | |||
| fd3d6433e2 | |||
| 9592a0ddda |
@@ -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
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="800px" height="800px" viewBox="0 0 512 512" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st0{fill:#000000;}
|
||||
]]>
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M485.016,220.691c12.422-8.422,22.188-57.266,7.797-87.016c-26.859,28.125-80.109,49.859-142,72.922
|
||||
c-64.656,24.078-71.531,41.859-94.813,42.172c-23.297-0.313-30.156-18.094-94.813-42.172c-61.891-23.063-115.141-44.797-142-72.922
|
||||
c-14.406,29.75-4.625,78.594,7.781,87.016C13.484,214.332,0,210.051,0,210.051s3.813,68.172,33.25,106.563
|
||||
c24.953,32.547,86.984,72.906,145.828,58.828c62.219-14.875,62.344-41.406,76.922-41.266c14.563-0.141,14.688,26.391,76.906,41.266
|
||||
c58.844,14.078,120.875-26.281,145.844-58.828C508.156,278.223,512,210.051,512,210.051S498.5,214.332,485.016,220.691z
|
||||
M131.438,318.848c-25.109-11.641-46.063-37.422-43.188-73.891c12.813,5.078,48.844,9.406,69.094,17.281
|
||||
c23,8.953,46.031,23.984,48.922,41.25C205.313,317.879,170.75,337.066,131.438,318.848z M380.563,318.848
|
||||
c-39.344,18.219-73.875-0.969-74.828-15.359c2.891-17.266,25.891-32.297,48.922-41.25c20.25-7.875,56.281-12.203,69.094-17.281
|
||||
C426.625,281.426,405.656,307.207,380.563,318.848z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="800px" height="800px" viewBox="0 0 512 512" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st0{fill:#000000;}
|
||||
]]>
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M485.016,220.691c12.422-8.422,22.188-57.266,7.797-87.016c-26.859,28.125-80.109,49.859-142,72.922
|
||||
c-64.656,24.078-71.531,41.859-94.813,42.172c-23.297-0.313-30.156-18.094-94.813-42.172c-61.891-23.063-115.141-44.797-142-72.922
|
||||
c-14.406,29.75-4.625,78.594,7.781,87.016C13.484,214.332,0,210.051,0,210.051s3.813,68.172,33.25,106.563
|
||||
c24.953,32.547,86.984,72.906,145.828,58.828c62.219-14.875,62.344-41.406,76.922-41.266c14.563-0.141,14.688,26.391,76.906,41.266
|
||||
c58.844,14.078,120.875-26.281,145.844-58.828C508.156,278.223,512,210.051,512,210.051S498.5,214.332,485.016,220.691z
|
||||
M131.438,318.848c-25.109-11.641-46.063-37.422-43.188-73.891c12.813,5.078,48.844,9.406,69.094,17.281
|
||||
c23,8.953,46.031,23.984,48.922,41.25C205.313,317.879,170.75,337.066,131.438,318.848z M380.563,318.848
|
||||
c-39.344,18.219-73.875-0.969-74.828-15.359c2.891-17.266,25.891-32.297,48.922-41.25c20.25-7.875,56.281-12.203,69.094-17.281
|
||||
C426.625,281.426,405.656,307.207,380.563,318.848z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,30 @@
|
||||
provider: fakegpt
|
||||
label:
|
||||
en_US: FakeGPT
|
||||
description:
|
||||
en_US: FakeGPT is a fake model provider that does not actually connect to any model service. It is useful for testing and development purposes.
|
||||
icon_small:
|
||||
en_US: icon_s_en.svg
|
||||
icon_large:
|
||||
en_US: icon_l_en.svg
|
||||
background: "#FCFDFF"
|
||||
help:
|
||||
title:
|
||||
en_US: Get your Access Details from Google
|
||||
url:
|
||||
en_US: https://apipark.com
|
||||
supported_model_types:
|
||||
- llm
|
||||
- text-embedding
|
||||
configurate_methods:
|
||||
- predefined-model
|
||||
provider_credential_schema:
|
||||
credential_form_schemas:
|
||||
- variable: apikey
|
||||
label:
|
||||
en_US: API Key
|
||||
type: secret-input
|
||||
required: true
|
||||
placeholder:
|
||||
en_US: Enter your API key
|
||||
address: https://apipark.com
|
||||
@@ -0,0 +1,51 @@
|
||||
model: fakegpt-1.0
|
||||
label:
|
||||
en_US: FakeGPT 1.0
|
||||
model_type: llm
|
||||
features:
|
||||
- agent-thought
|
||||
- vision
|
||||
model_properties:
|
||||
mode: chat
|
||||
context_size: 200000
|
||||
parameter_rules:
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
type: int
|
||||
default: 4096
|
||||
min: 1
|
||||
max: 4096
|
||||
help:
|
||||
zh_Hans: 停止前生成的最大令牌数。
|
||||
en_US: The maximum number of tokens to generate before stopping.
|
||||
- name: temperature
|
||||
use_template: temperature
|
||||
required: false
|
||||
type: float
|
||||
default: 1
|
||||
min: 0.0
|
||||
max: 1.0
|
||||
help:
|
||||
zh_Hans: 生成内容的随机性。
|
||||
en_US: The amount of randomness injected into the response.
|
||||
- name: top_p
|
||||
required: false
|
||||
type: float
|
||||
default: 0.999
|
||||
min: 0.000
|
||||
max: 1.000
|
||||
help:
|
||||
zh_Hans: 在核采样中,按概率递减顺序计算每个后续标记的所有选项的累积分布,并在达到 top_p 指定的特定概率时将其切断。您应该更改温度或top_p,但不能同时更改两者。
|
||||
en_US: In nucleus sampling, computes the cumulative distribution over all the options for each subsequent token in decreasing probability order and cuts it off once it reaches a particular probability specified by top_p. You should alter either temperature or top_p, but not both.
|
||||
- name: top_k
|
||||
required: false
|
||||
type: int
|
||||
default: 0
|
||||
min: 0
|
||||
# tip docs from aws has error, max value is 500
|
||||
max: 500
|
||||
help:
|
||||
zh_Hans: 对于每个后续标记,仅从前 K 个选项中进行采样。使用 top_k 删除长尾低概率响应。
|
||||
en_US: Only sample from the top K options for each subsequent token. Use top_k to remove long tail low probability responses.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 2048
|
||||
|
||||
@@ -23,7 +23,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ parameter_rules:
|
||||
use_template: presence_penalty
|
||||
- name: frequency_penalty
|
||||
use_template: frequency_penalty
|
||||
- name: max_output_tokens
|
||||
- name: max_tokens
|
||||
use_template: max_tokens
|
||||
required: true
|
||||
default: 8192
|
||||
|
||||
@@ -5,6 +5,9 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
@@ -151,8 +154,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 +215,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.",
|
||||
})
|
||||
@@ -236,7 +237,12 @@ func (i *imlServiceController) SearchMyServices(ctx *gin.Context, teamId string,
|
||||
//}
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
func (i *imlServiceController) Search(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error) {
|
||||
@@ -278,6 +284,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)
|
||||
}
|
||||
|
||||
@@ -42,6 +42,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
|
||||
}
|
||||
|
||||
@@ -319,12 +319,12 @@ func (i *imlInitController) OnInit() {
|
||||
}
|
||||
func (i *imlInitController) createAIService(ctx context.Context, teamID string, input *service_dto.CreateService) error {
|
||||
|
||||
providerId := "openai"
|
||||
err := i.providerModule.UpdateProviderConfig(ctx, "openai", &ai_dto.UpdateConfig{
|
||||
Config: "{\n \"openai_api_base\": \"API Base\",\n \"openai_api_key\": \"API Key\",\n \"openai_organization\": \"Organization\"\n}",
|
||||
providerId := "fakegpt"
|
||||
err := i.providerModule.UpdateProviderConfig(ctx, providerId, &ai_dto.UpdateConfig{
|
||||
Config: "{\n \"apikey\": \"xxx\" \n}",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("update openai config error: %v", err)
|
||||
return fmt.Errorf("update %s config error: %v", providerId, err)
|
||||
}
|
||||
input.Provider = &providerId
|
||||
if input.Id == "" {
|
||||
@@ -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,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"
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<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>
|
||||
<title>2APIPark</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": " vite --port 5000 --strictPort",
|
||||
"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",
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/*
|
||||
* @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': {},
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @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';
|
||||
|
||||
|
||||
@@ -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,19 +1,16 @@
|
||||
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 { 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';
|
||||
@@ -21,270 +18,270 @@ import { ProjectFilled } from '@ant-design/icons';
|
||||
import { getNavItem } 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';
|
||||
|
||||
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 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'),
|
||||
function BasicLayout({ project = 'core' }: { project: string }) {
|
||||
const navigator = useNavigate()
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const { state, accessData, checkPermission, accessInit, dispatch, resetAccess, getGlobalAccessData } = useGlobalContext()
|
||||
const [pathname, setPathname] = useState(currentUrl); const mainPage = project === 'core' ? '/service/list' : '/serviceHub/list'
|
||||
|
||||
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'),
|
||||
getNavItem($t('API 市场'), 'serviceHub', '/serviceHub', <Icon icon="ic:baseline-hub" width="18" height="18" />, undefined, undefined, 'system.api_portal.api_portal.view'),
|
||||
|
||||
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,
|
||||
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.analysis.run_view.view'),
|
||||
APP_MODE === 'pro' ? getNavItem(<a >{$t('系统拓扑图')}</a>, 'systemrunning', '/systemrunning', <ProjectFilled />, undefined, undefined, 'system.dashboard.systemrunning.view') : null,
|
||||
], undefined, 'system.analysis.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.settings.api_gateway.view'),
|
||||
getNavItem(<a>{$t('AI 模型')}</a>, 'aisetting', '/aisetting', <Icon icon="hugeicons:ai-network" width="18" height="18" />, undefined, undefined, 'system.settings.api_gateway.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.settings.account.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.settings.data_source.view'),
|
||||
getNavItem(<a>{$t('全局策略')}</a>, 'globalPolicy', '/globalPolicy', <Icon icon="uil:comment-shield" width="18" height="18" />, undefined, undefined, 'system.settings.data_source.view'),
|
||||
getNavItem(<a>{$t('证书')}</a>, 'cert', '/cert', <Icon icon="ic:baseline-security" width="18" height="18" />, undefined, undefined, 'system.settings.ssl_certificate.view'),
|
||||
getNavItem(<a>{$t('日志')}</a>, 'logsettings', '/logsettings', <Icon icon="ic:baseline-sticky-note-2" width="18" height="18" />, undefined, undefined, 'system.settings.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])
|
||||
], [state.language, accessInit])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if(currentUrl === '/'){
|
||||
navigator(mainPage)
|
||||
}
|
||||
|
||||
}, [currentUrl]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 如果没有 access 和 routes,则保留
|
||||
return item;
|
||||
})
|
||||
.filter(x => x); // 过滤掉处理后为 null 的项
|
||||
};
|
||||
|
||||
// 初始过滤操作
|
||||
const res = [...TOTAL_MENU_ITEMS]!.filter(x => x).map((x: any) => (x.routes ? { ...x, routes: filterMenu(x.routes) } : x));
|
||||
// 返回处理后的数据
|
||||
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]);
|
||||
|
||||
|
||||
|
||||
|
||||
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))
|
||||
}
|
||||
})
|
||||
useEffect(() => {
|
||||
if (currentUrl === '/') {
|
||||
navigator(mainPage)
|
||||
}
|
||||
|
||||
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))
|
||||
}, [currentUrl]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 如果没有 access 和 routes,则保留
|
||||
return item;
|
||||
})
|
||||
}
|
||||
.filter(x => x); // 过滤掉处理后为 null 的项
|
||||
};
|
||||
|
||||
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 res = [...TOTAL_MENU_ITEMS]!.filter(x => x).map((x: any) => (x.routes ? { ...x, routes: filterMenu(x.routes) } : x));
|
||||
// 返回处理后的数据
|
||||
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]);
|
||||
|
||||
|
||||
|
||||
return(
|
||||
<div
|
||||
id="test-pro-layout"
|
||||
style={{
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
|
||||
const { message } = App.useApp()
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
id="test-pro-layout"
|
||||
style={{
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<ProConfigProvider hashed={false}>
|
||||
<ConfigProvider
|
||||
getTargetContainer={() => {
|
||||
return document.getElementById('test-pro-layout') || document.body;
|
||||
}}
|
||||
>
|
||||
<ProConfigProvider hashed={false}>
|
||||
<ConfigProvider
|
||||
getTargetContainer={() => {
|
||||
return document.getElementById('test-pro-layout') || document.body;
|
||||
<ProLayout
|
||||
prefixCls="apipark-layout"
|
||||
location={{
|
||||
pathname,
|
||||
}}
|
||||
siderWidth={220}
|
||||
breakpoint={'lg'}
|
||||
route={headerMenuData}
|
||||
token={themeToken}
|
||||
siderMenuType="group"
|
||||
menu={{
|
||||
type: 'group',
|
||||
collapsedShowGroupTitle: true,
|
||||
}}
|
||||
disableMobile={true}
|
||||
avatarProps={{
|
||||
src: AvatarPic || userInfo?.avatar,
|
||||
size: 'small',
|
||||
title: userInfo?.username || 'unknown',
|
||||
render: (props, dom) => {
|
||||
return (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items
|
||||
}}
|
||||
>
|
||||
<ProLayout
|
||||
prefixCls="apipark-layout"
|
||||
location={{
|
||||
pathname,
|
||||
}}
|
||||
siderWidth={220}
|
||||
breakpoint={'lg'}
|
||||
route={headerMenuData}
|
||||
token={themeToken}
|
||||
siderMenuType="group"
|
||||
menu={{
|
||||
type: 'group',
|
||||
collapsedShowGroupTitle: true,
|
||||
}}
|
||||
disableMobile={true}
|
||||
avatarProps={{
|
||||
src: AvatarPic || userInfo?.avatar,
|
||||
size: 'small',
|
||||
title: userInfo?.username||'unknown',
|
||||
render: (props, dom) => {
|
||||
return (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items
|
||||
}}
|
||||
>
|
||||
<div className='avatar-dom'>{dom}
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
},
|
||||
}}
|
||||
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>
|
||||
];
|
||||
}}
|
||||
headerTitleRender={() => (
|
||||
<div className="w-[192px] flex items-center">
|
||||
<img
|
||||
className="h-[20px] cursor-pointer "
|
||||
src={Logo}
|
||||
onClick={()=> navigator(mainPage)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
logo={Logo}
|
||||
pageTitleRender={()=>$t('APIPark - 企业API数据开放平台')}
|
||||
menuFooterRender={(props) => {
|
||||
if (props?.collapsed) return undefined;
|
||||
}}
|
||||
menuItemRender={(item, dom) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
// 同级目录点击无效
|
||||
if(item.key && routerKeyMap.get(item.key) && routerKeyMap.get(item.key).length > 0 && routerKeyMap.get(item.key)?.indexOf(pathname.split('/')[1]) !== -1){
|
||||
return
|
||||
}
|
||||
if(item.key === pathname.split('/')[1]){
|
||||
return
|
||||
}
|
||||
|
||||
if(item.path){
|
||||
navigator(item.path)
|
||||
}
|
||||
setPathname(item.path || '');
|
||||
}}
|
||||
>
|
||||
{dom}
|
||||
</div>
|
||||
)}
|
||||
fixSiderbar={true}
|
||||
layout='mix'
|
||||
splitMenus={true}
|
||||
collapsed={false}
|
||||
collapsedButtonRender={false}
|
||||
>
|
||||
<div className={`w-full h-calc-100vh-minus-navbar pl-PAGE_INSIDE_X pt-PAGE_INSIDE_T ${currentUrl.startsWith('/role/list') ? 'overflow-auto' : 'overflow-hidden' }`}>
|
||||
<Outlet />
|
||||
>
|
||||
<div className='avatar-dom'>{dom}
|
||||
</div>
|
||||
</ProLayout>
|
||||
</ConfigProvider>
|
||||
</ProConfigProvider>
|
||||
</div>
|
||||
)
|
||||
</Dropdown>
|
||||
);
|
||||
},
|
||||
}}
|
||||
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>
|
||||
];
|
||||
}}
|
||||
headerTitleRender={() => (
|
||||
<div className="w-[192px] flex items-center">
|
||||
<img
|
||||
className="h-[20px] cursor-pointer "
|
||||
src={Logo}
|
||||
onClick={() => navigator(mainPage)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
logo={Logo}
|
||||
pageTitleRender={() => $t('APIPark')}
|
||||
menuFooterRender={(props) => {
|
||||
if (props?.collapsed) return undefined;
|
||||
}}
|
||||
menuItemRender={(item, dom) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
// 同级目录点击无效
|
||||
if (item.key && routerKeyMap.get(item.key) && routerKeyMap.get(item.key).length > 0 && routerKeyMap.get(item.key)?.indexOf(pathname.split('/')[1]) !== -1) {
|
||||
return
|
||||
}
|
||||
if (item.key === pathname.split('/')[1]) {
|
||||
return
|
||||
}
|
||||
|
||||
if (item.path) {
|
||||
navigator(item.path)
|
||||
}
|
||||
setPathname(item.path || '');
|
||||
}}
|
||||
>
|
||||
{dom}
|
||||
</div>
|
||||
)}
|
||||
fixSiderbar={true}
|
||||
layout='mix'
|
||||
splitMenus={true}
|
||||
collapsed={false}
|
||||
collapsedButtonRender={false}
|
||||
>
|
||||
<div className={`w-full h-calc-100vh-minus-navbar pl-PAGE_INSIDE_X pt-PAGE_INSIDE_T ${currentUrl.startsWith('/role/list') ? 'overflow-auto' : 'overflow-hidden'}`}>
|
||||
<Outlet />
|
||||
</div>
|
||||
</ProLayout>
|
||||
</ConfigProvider>
|
||||
</ProConfigProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default BasicLayout
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -219,12 +219,12 @@ export const PublishApprovalModalContent = forwardRef<PublishApprovalModalHandle
|
||||
/></Row>
|
||||
</>
|
||||
}
|
||||
<Form.Item
|
||||
{/* <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,65 @@ 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 { 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 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>
|
||||
useEffect(() => {
|
||||
access ? setBtnAccess(lastAccess) : setBtnAccess(true)
|
||||
}, [access, lastAccess])
|
||||
|
||||
|
||||
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>
|
||||
|
||||
}</>
|
||||
);
|
||||
}
|
||||
|
||||
}</>
|
||||
);
|
||||
}
|
||||
|
||||
export default TableBtnWithPermission
|
||||
@@ -137,7 +137,32 @@ export const TranslateWord = ()=>{
|
||||
{$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('处理数')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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>}
|
||||
|
||||
</>
|
||||
|
||||
@@ -343,11 +343,6 @@ export const PUBLISH_APPROVAL_RECORD_INNER_TABLE_COLUMN : PageProColumns<Publish
|
||||
dataIndex: 'status',
|
||||
ellipsis:true,
|
||||
},
|
||||
{
|
||||
title:('备注'),
|
||||
dataIndex: 'comments',
|
||||
ellipsis:true
|
||||
},
|
||||
{
|
||||
title:('申请人'),
|
||||
dataIndex: ['applicant','name'],
|
||||
|
||||
@@ -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,94 @@ 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.workspace.application.view_all": {
|
||||
@@ -244,19 +244,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 +276,252 @@ 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.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": {
|
||||
|
||||
@@ -7,7 +7,7 @@ system:
|
||||
cname: '成员'
|
||||
value: 'member'
|
||||
access:
|
||||
- system.organization.member.view
|
||||
- system.settings.account.view
|
||||
- system.organization.member.add
|
||||
- system.organization.member.edit
|
||||
- system.organization.member.delete
|
||||
@@ -18,7 +18,7 @@ system:
|
||||
- name: team_manager
|
||||
cname: '团队管理'
|
||||
desc: '团队管理'
|
||||
- system.organization.team.view
|
||||
- system.workspace.team.view_all
|
||||
- system.organization.team.add
|
||||
- system.organization.team.edit
|
||||
- system.organization.team.delete
|
||||
@@ -55,7 +55,7 @@ system:
|
||||
cname: 集群
|
||||
value: 'cluster'
|
||||
children:
|
||||
- system.devops.cluster.view
|
||||
- system.settings.api_gateway.view
|
||||
- system.devops.cluster.add
|
||||
- system.devops.cluster.edit
|
||||
- system.devops.cluster.delete
|
||||
@@ -63,7 +63,7 @@ system:
|
||||
cname: 证书
|
||||
value: 'ssl_certificate'
|
||||
children:
|
||||
- system.devops.ssl_certificate.view
|
||||
- system.settings.ssl_certificate.view
|
||||
- system.devops.ssl_certificate.add
|
||||
- system.devops.ssl_certificate.edit
|
||||
- system.devops.ssl_certificate.delete
|
||||
@@ -71,7 +71,7 @@ system:
|
||||
cname: 日志
|
||||
value: 'log_configuration'
|
||||
children:
|
||||
- system.devops.log_configuration.view
|
||||
- system.settings.log_configuration.view
|
||||
- system.devops.log_configuration.add
|
||||
- system.devops.log_configuration.edit
|
||||
- system.devops.log_configuration.publish
|
||||
@@ -99,7 +99,7 @@ system:
|
||||
cname: API市场
|
||||
value: 'api_market'
|
||||
children:
|
||||
- system.workspace.api_market.view
|
||||
- system.api_portal.api_portal.view
|
||||
team:
|
||||
- name: service
|
||||
cname: 服务
|
||||
@@ -172,8 +172,8 @@ team:
|
||||
cname: 访问授权
|
||||
value: 'authorization'
|
||||
children:
|
||||
- team.application.authorization.view
|
||||
- team.application.authorization.manager
|
||||
- team.consumer.authorization.view
|
||||
- team.consumer.authorization.manager
|
||||
- team.application.authorization.add
|
||||
- team.application.authorization.edit
|
||||
- team.application.authorization.delete
|
||||
|
||||
@@ -7,6 +7,8 @@ export type UserInfoType = {
|
||||
email: string
|
||||
phone: string
|
||||
avatar: string
|
||||
type:string
|
||||
|
||||
}
|
||||
|
||||
export type UserProfileProps = {
|
||||
|
||||
@@ -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,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;
|
||||
@@ -18,6 +18,7 @@
|
||||
"角色": "Kf644225f",
|
||||
"集成": "K4057391a",
|
||||
"数据源": "K8fa58214",
|
||||
"全局策略": "Ke8cbb878",
|
||||
"证书": "K481e8a05",
|
||||
"日志": "Kca53edd0",
|
||||
"资源": "Kb283e720",
|
||||
@@ -212,6 +213,28 @@
|
||||
"鉴权数量": "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",
|
||||
"暂无操作权限,请联系管理员分配。": "K23fda291",
|
||||
"微信小程序": "K4618cb0a",
|
||||
"获取文件,需填路径": "Ka854f511",
|
||||
@@ -466,6 +489,14 @@
|
||||
"统计图表": "K1358acf",
|
||||
"地址(IP:端口)": "K62dabdf6",
|
||||
"组织(Organization)": "K2db12335",
|
||||
"添加策略": "K34d0d409",
|
||||
"输入名称、筛选条件查找": "Kbb4298ac",
|
||||
"策略名称": "K931615d7",
|
||||
"优先级": "K31faa2a1",
|
||||
"筛选条件": "Kbdec9fa",
|
||||
"处理数": "Kbcbb7391",
|
||||
"数据脱敏": "Kabac9caf",
|
||||
"支持对系统全局进行统一的策略配置,从而简化管理并确保一致性。全局策略的优先级比服务策略略低。": "Kc975cd5a",
|
||||
"资源配置": "K8e7a0f80",
|
||||
"设置角色的权限范围。": "K95c3fd8b",
|
||||
"系统级别角色": "K138facd3",
|
||||
@@ -501,6 +532,7 @@
|
||||
"删除服务": "Kde6bae17",
|
||||
"删除操作不可恢复,请谨慎操作!": "K885ea699",
|
||||
"上游": "Kda8d5ea1",
|
||||
"服务策略": "K52f72551",
|
||||
"服务提供了高性能 API 网关,并且可以无缝接入多种大型 AI 模型,并将这些 AI 能力打包成 API 进行调用,从而大幅简化了 AI 模型的使用门槛。同时,我们的平台提供了完善的 API 管理功能,支持 API 的创建、监控、访问控制等,保障开发者可以高效、安全地开发和管理 API 服务。": "K12f58863",
|
||||
"添加服务": "K2d6658ed",
|
||||
"输入名称、ID、所属团队、负责人查找服务": "K7b8f623f",
|
||||
@@ -524,7 +556,7 @@
|
||||
"移除成员": "K395acc14",
|
||||
"添加成员": "Kec46a57f",
|
||||
"输入姓名查找": "K48724410",
|
||||
"搜索用户名、邮箱": "Kb9052305",
|
||||
"输入名称查找用户": "Kf5fd27ed",
|
||||
"设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。": "K4c72fb6f",
|
||||
"添加团队": "K510cdd27",
|
||||
"输入名称、ID、负责人查找团队": "K9244ae14",
|
||||
@@ -594,6 +626,19 @@
|
||||
"暂无API数据": "K6b75bdbc",
|
||||
"搜索或选择消费者": "Kb684c806",
|
||||
"申请理由": "K4b15d6f5",
|
||||
"支持把当前服务对接主流的 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",
|
||||
@@ -627,10 +672,10 @@
|
||||
"搜索服务": "K66ea2f0",
|
||||
"审核中": "K8adf7f8b",
|
||||
"添加消费者": "K84c4dc71",
|
||||
"暂无服务描述": "Ka4b45550",
|
||||
"暂无消费者描述": "Kc3b7bfa8",
|
||||
"创建并管理自己的消费者实体,每个消费者可以订阅多个API服务,确保在调用之前已获得相应权限。你可以为消费者生成 API 密钥等鉴权方式,用于安全地调用 API 服务": "K5c4e2865",
|
||||
"订阅的服务数量:已通过 (0) 个,申请中 (1) 个": "K3c7b175f",
|
||||
"输入名称、ID 查找服务": "K40a89bd8",
|
||||
"输入名称、ID 查找消费者": "K3a6f905d",
|
||||
"退出测试": "Kbe3e9335",
|
||||
"服务市场": "K370a3eb2",
|
||||
"服务详情": "Kf7ec36d",
|
||||
@@ -645,6 +690,7 @@
|
||||
"版本": "K81634069",
|
||||
"更新时间": "Keefda53d",
|
||||
"无标签": "K96a2f1c8",
|
||||
"暂无服务描述": "Ka4b45550",
|
||||
"API 数量": "K72b0c0b3",
|
||||
"接入消费者数量": "K70b79760",
|
||||
"关联标签": "K96059c69",
|
||||
|
||||
@@ -319,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",
|
||||
@@ -365,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",
|
||||
@@ -391,8 +391,8 @@
|
||||
"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",
|
||||
@@ -463,7 +463,7 @@
|
||||
"Kd59290a2": "Search Category or Tag",
|
||||
"K6b75bdbc": "No API Data",
|
||||
"K4b15d6f5": "Application Reason",
|
||||
"Kb71b5a13": "Authentication Type",
|
||||
"Kb71b5a13": "Credentials Type",
|
||||
"K4d1465ee": "ISS",
|
||||
"K5dcd7ed8": "Signature Algorithm",
|
||||
"K5b0eedd3": "Secret",
|
||||
@@ -475,10 +475,10 @@
|
||||
"K31418470": "SK",
|
||||
"Kbfeb5297": "API Key",
|
||||
"K1a78e6f0": "Expiration Time",
|
||||
"Ke64e43a": "Hide Authentication Info",
|
||||
"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",
|
||||
@@ -580,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",
|
||||
@@ -607,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",
|
||||
@@ -654,5 +654,54 @@
|
||||
"K6e32a344": "Number of Services",
|
||||
"Ka701316": "Number of Auths",
|
||||
"K9eaa2eb6": "List",
|
||||
"Kfaec39e9": "Block"
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -672,8 +672,58 @@
|
||||
"K67b530f": "コンシューマー名",
|
||||
"K11f34de": "コンシューマー ID",
|
||||
"Kc01002": "コンシューマーを削除",
|
||||
"K84c4dc71": "コンシューマーエンティティを作成および管理し、各コンシューマーは複数の API サービスにサブスクライブできます。呼び出し前に適切な権限が付与されていることを確認してください。コンシューマー用に API キーなどの認証方法を生成して、安全に API サービスを呼び出せます。",
|
||||
"K40a89bd8": "名前または ID を入力してサービスを検索",
|
||||
"Kba74f26d": "コンシューマーを接続",
|
||||
"K70b79760": "接続コンシューマー数"
|
||||
"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": "編集"
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
{}
|
||||
{
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
@@ -1,32 +1,3 @@
|
||||
{
|
||||
"K7acfcfad": "消费者",
|
||||
"Kc8054dba": "消费者开发者",
|
||||
"Keb1673a6": "消费者管理员",
|
||||
"K1fc2cc28": "无需审核:允许任何消费者调用该服务",
|
||||
"K8dabb98e": "人工审核:仅允许通过人工审核的消费者调用该服务",
|
||||
"K7c1fb123": "申请方-消费者",
|
||||
"K93c2696e": "上线结果",
|
||||
"K6e32a344": "订阅服务数量",
|
||||
"Ka701316": "鉴权数量",
|
||||
"K9eaa2eb6": "列表",
|
||||
"Kfaec39e9": "块",
|
||||
"Kdea9a418": "为了安全地调用 API,你需要创建一个消费者以及Token。",
|
||||
"Keee27105": "团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。",
|
||||
"Kaa717866": "提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的消费者才可发起 API 请求。",
|
||||
"Kd2c34e2c": "AI 服务",
|
||||
"K62840d62": "REST 服务",
|
||||
"K4c72fb6f": "设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。",
|
||||
"K61cca533": "消费者调用统计",
|
||||
"Kdfff59d4": "请选择消费者",
|
||||
"K386857bd": "消费者调用量 Top10",
|
||||
"Kb684c806": "搜索或选择消费者",
|
||||
"Ke0fbd1c8": "消费者管理",
|
||||
"K67b530f": "消费者名称",
|
||||
"K11f34de": "消费者 ID",
|
||||
"Kc01002": "删除消费者",
|
||||
"K84c4dc71": "添加消费者",
|
||||
"K5c4e2865": "创建并管理自己的消费者实体,每个消费者可以订阅多个API服务,确保在调用之前已获得相应权限。你可以为消费者生成 API 密钥等鉴权方式,用于安全地调用 API 服务",
|
||||
"K40a89bd8": "输入名称、ID 查找服务",
|
||||
"Kba74f26d": "接入消费者",
|
||||
"K70b79760": "接入消费者数量"
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
@@ -1,7 +1,27 @@
|
||||
{
|
||||
"K93c2696e": "上线结果",
|
||||
"K6e32a344": "订阅服务数量",
|
||||
"Ka701316": "鉴权数量",
|
||||
"K9eaa2eb6": "列表",
|
||||
"Kfaec39e9": "块"
|
||||
"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": "申请方消费者",
|
||||
"Kf5fd27ed": "输入名称查找用户",
|
||||
"Kc3b7bfa8": "暂无消费者描述",
|
||||
"K3a6f905d": "输入名称、ID 查找消费者"
|
||||
}
|
||||
@@ -1,32 +1,3 @@
|
||||
{
|
||||
"K7acfcfad": "消费者",
|
||||
"Kc8054dba": "消费者开发者",
|
||||
"Keb1673a6": "消费者管理员",
|
||||
"K1fc2cc28": "无需审核:允许任何消费者调用该服务",
|
||||
"K8dabb98e": "人工审核:仅允许通过人工审核的消费者调用该服务",
|
||||
"K7c1fb123": "申请方-消费者",
|
||||
"K93c2696e": "上线结果",
|
||||
"K6e32a344": "订阅服务数量",
|
||||
"Ka701316": "鉴权数量",
|
||||
"K9eaa2eb6": "列表",
|
||||
"Kfaec39e9": "块",
|
||||
"Kdea9a418": "为了安全地调用 API,你需要创建一个消费者以及Token。",
|
||||
"Keee27105": "团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。",
|
||||
"Kaa717866": "提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的消费者才可发起 API 请求。",
|
||||
"Kd2c34e2c": "AI 服务",
|
||||
"K62840d62": "REST 服务",
|
||||
"K4c72fb6f": "设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。",
|
||||
"K61cca533": "消费者调用统计",
|
||||
"Kdfff59d4": "请选择消费者",
|
||||
"K386857bd": "消费者调用量 Top10",
|
||||
"Kb684c806": "搜索或选择消费者",
|
||||
"Ke0fbd1c8": "消费者管理",
|
||||
"K67b530f": "消费者名称",
|
||||
"K11f34de": "消费者 ID",
|
||||
"Kc01002": "删除消费者",
|
||||
"K84c4dc71": "添加消费者",
|
||||
"K5c4e2865": "创建并管理自己的消费者实体,每个消费者可以订阅多个API服务,确保在调用之前已获得相应权限。你可以为消费者生成 API 密钥等鉴权方式,用于安全地调用 API 服务",
|
||||
"K40a89bd8": "输入名称、ID 查找服务",
|
||||
"Kba74f26d": "接入消费者",
|
||||
"K70b79760": "接入消费者数量"
|
||||
"Kf5fd27ed": "输入名称查找用户"
|
||||
}
|
||||
@@ -1,24 +1,4 @@
|
||||
{
|
||||
"Kfe93ef35": "Application",
|
||||
"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",
|
||||
"K9bdd8403": "To securely call APIs, you need to create an application and a token.",
|
||||
"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.",
|
||||
"Ka0a8840a": "Review subscription requests from other applications. Only approved requests can initiate API calls.",
|
||||
"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.",
|
||||
"K1512e983": "Application Call Statistics",
|
||||
"Kb4d2007f": "Please Select Application",
|
||||
"Kc0915603": "Application Top 10",
|
||||
"Kd8a7a689": "Search or Select Application",
|
||||
"Kb7e869a4": "Application Settings",
|
||||
"K5168eb63": "Application Name",
|
||||
"K546e46f": "Application ID",
|
||||
"K95764d1d": "Delete Application",
|
||||
"K667bbbe7": "Add Application",
|
||||
"K8723422e": "Access Application",
|
||||
"K93d5a66e": "Number of Access Applications",
|
||||
"K216a1ac7": "Application Developer",
|
||||
"K27924db": "Application Administrator",
|
||||
"Kd55c6887": "Review",
|
||||
"K831aa6c0": "Applicant - Application"
|
||||
"Kb9052305": "Search Username, Email",
|
||||
"K40a89bd8": "Enter Name, ID to Search Member"
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
"K9bdd8403": "API を安全に呼び出すためには、アプリケーションとトークンを作成する必要があります。",
|
||||
"Kc8239422": "チームにはユーザー、アプリケーション、サービスが含まれ、異なるチームのアプリケーションとサービスのデータは分離されています。企業内の部門/プロジェクトグループ/チームの管理に使用できます。",
|
||||
"Ka0a8840a": "他のアプリケーションのサブスクリプション申請をレビューし、承認後に API リクエストが発行できます。",
|
||||
"Kb9052305": "ユーザー名またはメールを検索",
|
||||
"K5ece3bac": "チームとメンバーを設定してから、チーム内でサービスとアプリケーションを作成し、API をサブスクライブできます。メンバーは所属チーム内のサービスとアプリケーションのみを表示できます。",
|
||||
"K1512e983": "アプリケーション呼び出し統計",
|
||||
"Kb4d2007f": "Application を選択",
|
||||
@@ -20,5 +21,6 @@
|
||||
"K216a1ac7": "アプリケーション開発者",
|
||||
"K27924db": "アプリケーション管理者",
|
||||
"Kd55c6887": "レビュー",
|
||||
"K831aa6c0": "申請元-アプリケーション"
|
||||
"K831aa6c0": "申請元-アプリケーション",
|
||||
"K40a89bd8": "名前または ID を入力してサービスを検索"
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
"K9bdd8403": "为了安全地调用 API,你需要创建一个消费者以及Token。",
|
||||
"Kc8239422": "团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。",
|
||||
"Ka0a8840a": "审核其他消费者的订阅申请,审核通过后的才可发起 API 请求。",
|
||||
"Kb9052305": "搜索用户名、邮箱",
|
||||
"K5ece3bac": "设置团队和成员,然后你可以在团队内创建服务和消费者、订阅API,成员只能看到所属团队内的服务和消费者。",
|
||||
"K1512e983": "消费者调用统计",
|
||||
"Kb4d2007f": "请选择消费者",
|
||||
@@ -20,5 +21,6 @@
|
||||
"K216a1ac7": "消费者开发者",
|
||||
"K27924db": "消费者管理员",
|
||||
"Kd55c6887": "审核",
|
||||
"K831aa6c0": "申请方-消费者"
|
||||
"K831aa6c0": "申请方-消费者",
|
||||
"K40a89bd8": "输入名称、ID 查找服务"
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
"K9bdd8403": "為了安全地調用 API,你需要創建一個應用以及Token。",
|
||||
"Kc8239422": "團隊中包含了人員、應用程式和服務,不同團隊之間的應用程式和服務數據是隔離的,可用於管理企業內部不同的部門/項目組/團隊。",
|
||||
"Ka0a8840a": "審核其他應用程式的訂閱申請,審核通過後的才可發起 API 請求。",
|
||||
"Kb9052305": "搜索用戶名、電郵",
|
||||
"K5ece3bac": "設置團隊和成員,然後你可以在團隊內創建服務和應用程式、訂閱API,成員只能看到所屬團隊內的服務和應用程式。",
|
||||
"K1512e983": "應用程式調用統計",
|
||||
"Kb4d2007f": "請選擇應用程式",
|
||||
@@ -20,5 +21,6 @@
|
||||
"K216a1ac7": "應用程式開發者",
|
||||
"K27924db": "應用程式管理員",
|
||||
"Kd55c6887": "審核",
|
||||
"K831aa6c0": "申請方-應用程式"
|
||||
"K831aa6c0": "申請方-應用程式",
|
||||
"K40a89bd8": "輸入名稱、ID 查找服務"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -676,5 +676,54 @@
|
||||
"K5c4e2865": "創建並管理自己的消費者實體,每個消費者可以訂閱多個API服務,確保在調用之前已獲得相應權限。你可以為消費者生成 API 密鑰等鑒權方式,用於安全地調用 API 服務",
|
||||
"K40a89bd8": "輸入名稱、ID 查找服務",
|
||||
"Kba74f26d": "接入消費者",
|
||||
"K70b79760": "接入消費者數量"
|
||||
"K70b79760": "接入消費者數量",
|
||||
"Kc3b7bfa8": "暫無消費者描述",
|
||||
"K3a6f905d": "輸入名稱、ID 查找消費者",
|
||||
"K76036e25": "HTTP請求頭",
|
||||
"K44607e3f": "全等匹配",
|
||||
"Kc287500a": "前綴匹配",
|
||||
"Kfc0b1147": "後綴匹配",
|
||||
"Ka4a92043": "子串匹配",
|
||||
"K30b2e44f": "非等匹配",
|
||||
"Kb1587991": "空值匹配",
|
||||
"K87c5a801": "區分大小寫的正則匹配",
|
||||
"K95f062f1": "不區分大小寫的正則匹配",
|
||||
"Kfbd230a5": "任意匹配",
|
||||
"Kd85208a3": "駁回",
|
||||
"Kad6aa439": "已訂閱",
|
||||
"K9a68443b": "取消申請",
|
||||
"Kaeba0229": "透傳客戶端請求Host",
|
||||
"K6d7e2fd0": "使用上游服務Host",
|
||||
"K31332633": "重寫Host",
|
||||
"K2c2bc64f": "動態服務發現",
|
||||
"K78b1ca25": "位址",
|
||||
"K1644b775": "新增",
|
||||
"Kc8ee3e62": "不存在匹配",
|
||||
"K1e97dbd8": "存在匹配",
|
||||
"Kec91f0db": "申請方消費者",
|
||||
"Kf5fd27ed": "輸入名稱查找使用者",
|
||||
"K2ec0fa56": "支援將當前服務對接主流的 AI Agent 平台,實現在 Agent 平台上快速、安全和合規地使用企業開放的 API 能力。",
|
||||
"K35f23b64": "可按以下步驟進行對接:",
|
||||
"Kf5cd608b": "步驟一:Agent 平台上創建自定義插件",
|
||||
"K4c81c7b6": "不同 Agent 平台的操作細節可查看",
|
||||
"K275f7ffa": "《 Agent 對接手冊》",
|
||||
"K49b81d06": "步驟二:導入 API 文檔數據",
|
||||
"K4a3b62be": "可通過以下 URL 或下載 json 文件,導入 API 文檔數據到 Agent 平台中。",
|
||||
"K42697e11": "複製 URL",
|
||||
"K27a809c5": "下載 Json 文件",
|
||||
"K1e61fdee": "步驟三:配置 API 密鑰",
|
||||
"K55912595": "在",
|
||||
"K33b1bc3": "菜單中,選擇已通過本 API 服務申請的消費者,",
|
||||
"K62adc41e": "把「訪問權限」菜單下的密鑰填入到 Agent 平台對應的插件密鑰配置中。",
|
||||
"Ke8cbb878": "全域策略",
|
||||
"K34d0d409": "新增策略",
|
||||
"Kbb4298ac": "輸入名稱、篩選條件查找",
|
||||
"Kabac9caf": "資料脫敏",
|
||||
"Kc975cd5a": "支援對系統全域進行統一的策略配置,從而簡化管理並確保一致性。全域策略的優先級比服務策略略低。",
|
||||
"K52f72551": "服務策略",
|
||||
"K931615d7": "策略名稱",
|
||||
"K31faa2a1": "優先級",
|
||||
"Kbdec9fa": "篩選條件",
|
||||
"Kbcbb7391": "處理數",
|
||||
"Kad207008": "編輯"
|
||||
}
|
||||
|
||||
@@ -13,10 +13,15 @@ export const checkAccess:(access:AccessDataType, accessData:Map<string,string[]>
|
||||
return false
|
||||
}
|
||||
const neededBackendAccessArr = PERMISSION_DEFINITION[0]?.[access]?.granted?.anyOf[0].backend || []
|
||||
return accessData?.has(accLevel)&& accessData.get(accLevel)!.length > 0 ? hasIntersection(neededBackendAccessArr, accessData.get(accLevel)!) : false
|
||||
let accessSet = new Set(accessData.get('system'))
|
||||
if(accLevel === 'team'){
|
||||
accessSet = new Set(Array.from(accessSet).concat(accessData?.get('team') || []))
|
||||
}
|
||||
return accessSet!.size > 0 ? hasIntersection(neededBackendAccessArr, accessSet) : false
|
||||
}
|
||||
|
||||
const hasIntersection = (arr1:string[], arr2:string[])=> {
|
||||
const hasIntersection = (arr1:string[], set1:Set<string>)=> {
|
||||
const arr2 = Array.from(set1)
|
||||
const set = new Set(arr1.length > arr2.length ? arr2:arr1)
|
||||
const arr = arr1.length > arr2.length ? arr1:arr2
|
||||
for (const item of arr) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @Date: 2024-06-04 15:05:05
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-08-01 17:59:56
|
||||
* @FilePath: \frontend\packages\common\tailwind.config.js
|
||||
*/
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
important:true,
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<head id="head">
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/frontend/favicon.ico" />
|
||||
<link id="favicon" 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>
|
||||
<body id="eo-body">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script async src="/frontend/iconpark_eolink.js"></script>
|
||||
<script async src="/frontend/iconpark_apinto.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const eoBody = document.getElementById('eo-body');
|
||||
const favicon = document.getElementById('favicon');
|
||||
|
||||
const createScript = (id, src) => {
|
||||
const script = document.createElement('script');
|
||||
script.id = id;
|
||||
script.async = true;
|
||||
script.src = src;
|
||||
return script;
|
||||
};
|
||||
|
||||
const iconparkApintoSrc = window.location.hostname === 'localhost' ? '/iconpark_apinto.js' : '/frontend/iconpark_apinto.js';
|
||||
const iconparkEolinkSrc = window.location.hostname === 'localhost' ? '/iconpark_eolink.js' : '/frontend/iconpark_eolink.js';
|
||||
const faviconSrc = window.location.hostname === 'localhost' ? '/favicon.ico' : '/frontend/favicon.ico';
|
||||
|
||||
favicon.href = faviconSrc;
|
||||
|
||||
eoBody.appendChild(createScript('iconpark_apinto', iconparkApintoSrc));
|
||||
eoBody.appendChild(createScript('iconpark_eolink', iconparkEolinkSrc));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @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': {},
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -290,3 +290,13 @@ a{
|
||||
transition: background-color 0s 600000s, color 0s 600000s !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select-selection-overflow-item:first-child {
|
||||
max-width: calc(100% - 60px);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
a[disabled]:hover {
|
||||
color: #BBB;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@ export type MemberDropdownModalFieldType = {
|
||||
parent?:string
|
||||
email?:string
|
||||
departmentIds?:string[]
|
||||
password:string
|
||||
};
|
||||
|
||||
export type MemberDropdownModalProps = {
|
||||
|
||||
@@ -1005,6 +1005,19 @@ p{
|
||||
}
|
||||
}
|
||||
|
||||
.global-policy-tabs {
|
||||
.ant-tabs-nav {
|
||||
&::before {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.ant-tabs-content {
|
||||
height: 100%;
|
||||
.ant-tabs-tabpane {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tooltip{
|
||||
max-width: 280px !important;
|
||||
|
||||
@@ -137,7 +137,7 @@ const ServiceInsideDocument = ()=>{
|
||||
<div className=" pl-[8px] py-btnbase ">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[14px] leading-[20px] text-[#999999]"><span className="mr-[20px]">{$t('最近一次更新者')}:{updater || '-'}</span><span>{$t('最近一次更新时间')}:{updateTime || '-'}</span></p>
|
||||
<WithPermission access="team.service.service.edit"><Button type="primary" className="mr-btnbase" onClick={save}>{$t('保存')}</Button></WithPermission>
|
||||
<WithPermission access="team.service.service_intro.edit"><Button type="primary" className="mr-btnbase" onClick={save}>{$t('保存')}</Button></WithPermission>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
|
||||
@@ -42,6 +42,7 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
|
||||
|
||||
const getApiDefine = ()=>{
|
||||
console.log('@@@@@@@')
|
||||
setApiPrefix('')
|
||||
setPrefixForce(false)
|
||||
fetchData<BasicResponse<{ prefix:string, force:boolean }>>('service/router/define',{method:'GET',eoParams:{service:serviceId,team:teamId}}).then(response=>{
|
||||
@@ -62,7 +63,7 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
[
|
||||
getItem(<Link to="./route">{$t('API 路由')}</Link>, 'route',undefined,undefined,undefined,'team.service.router.view'),
|
||||
getItem(<Link to="./api">{$t('API 文档')}</Link>, 'api',undefined,undefined,undefined,'team.service.api_doc.view'),
|
||||
getItem(<Link to="./document">{$t('使用说明')}</Link>, 'document',undefined,undefined,undefined,''),
|
||||
getItem(<Link to="./document">{$t('使用说明')}</Link>, 'document',undefined,undefined,undefined,'team.service.service_intro.view'),
|
||||
getItem(<Link to="./publish">{$t('发布')}</Link>, 'publish',undefined,undefined,undefined,'team.service.release.view'),
|
||||
],
|
||||
'group'),
|
||||
@@ -84,19 +85,22 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
const filterMenu = (menu:MenuItemGroupType<MenuItemType>[])=>{
|
||||
const newMenu = cloneDeep(menu)
|
||||
return newMenu!.filter((m:MenuItemGroupType )=>{
|
||||
if(m.children && m.children.length > 0){
|
||||
if(m&&m.children && m.children.length > 0){
|
||||
m.children = m.children.filter(
|
||||
(c)=>(c&&(c as MenuItemType&{access:string} ).access ?
|
||||
(c)=>{
|
||||
if(!c) return false
|
||||
return (((c as MenuItemType&{access:string} ).access ?
|
||||
checkPermission((c as MenuItemType&{access:string} ).access as keyof typeof PERMISSION_DEFINITION[0]):
|
||||
true))
|
||||
true))})
|
||||
}
|
||||
return m.children && m.children.length > 0
|
||||
})
|
||||
}
|
||||
const filteredMenu = filterMenu(SYSTEM_PAGE_MENU_ITEMS as MenuItemGroupType<MenuItemType>[])
|
||||
setActiveMenu((pre)=>{
|
||||
return pre ?? 'route'
|
||||
})
|
||||
const menu = activeMenu ?? filteredMenu[0]?.children ? filteredMenu[0]?.children?.[0]?.key : filteredMenu[0]?.key
|
||||
if(menu && currentUrl.split('/')[-1] !== menu){
|
||||
navigateTo(`/service/${teamId}/aiInside/${serviceId}/${menu}`)
|
||||
}
|
||||
return filteredMenu || []
|
||||
},[accessData,accessInit, SYSTEM_PAGE_MENU_ITEMS])
|
||||
|
||||
@@ -116,7 +120,7 @@ const AiServiceInsidePage:FC = ()=> {
|
||||
}, [currentUrl]);
|
||||
|
||||
useEffect(()=>{
|
||||
if(accessData && accessData.get('team') && accessData.get('team')?.indexOf('team.service.router.view') !== -1){
|
||||
if(accessData && checkPermission('team.service.router.view')){
|
||||
getApiDefine()
|
||||
}
|
||||
},[accessData])
|
||||
|
||||
@@ -256,7 +256,7 @@ const AiServiceInsideRouterCreate = () => {
|
||||
</Form.Item>
|
||||
|
||||
|
||||
<Form.Item label={$t("请求路径")}>
|
||||
<Form.Item className="flex-1" label={$t("请求路径")}>
|
||||
<Space.Compact block>
|
||||
<Form.Item
|
||||
name="pathMatch"
|
||||
@@ -276,7 +276,7 @@ const AiServiceInsideRouterCreate = () => {
|
||||
}]}
|
||||
noStyle
|
||||
>
|
||||
<Input prefix={(prefixForce ? `${apiPrefix}/` :"/")} className="w-INPUT_NORMAL"
|
||||
<Input prefix={(prefixForce ? `${apiPrefix}/` :"/")}
|
||||
placeholder={$t(PLACEHOLDER.input)} onChange={(e)=>{
|
||||
if((e.target.value as string).endsWith('/*')){
|
||||
form.setFieldValue('path',e.target.value.slice(0,-2))
|
||||
|
||||
@@ -18,6 +18,7 @@ export type AiServiceRouterModelConfigProps = {
|
||||
}
|
||||
|
||||
type AiServiceRouterModelConfigField = {
|
||||
provider:string
|
||||
id:string
|
||||
config:string
|
||||
}
|
||||
@@ -70,6 +71,10 @@ const AiServiceRouterModelConfig = forwardRef<AiServiceRouterModelConfigHandle,
|
||||
getLlmList(provider)
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
getLlmList(entity.provider)
|
||||
},[])
|
||||
|
||||
return (
|
||||
<Form
|
||||
layout='vertical'
|
||||
|
||||
@@ -146,7 +146,7 @@ const AiSettingList = ()=>{
|
||||
}
|
||||
|
||||
</div>
|
||||
<WithPermission access="system.devops.ai_provider.view">
|
||||
<WithPermission access="system.settings.ai_provider.view">
|
||||
<Button block icon={<Icon icon="ic:outline-settings" width={18} height={18}/>} onClick={()=>openModal(provider)} classNames={{icon:'h-[18px]'}}>{$t('设置')}</Button>
|
||||
</WithPermission>
|
||||
</div>
|
||||
|
||||
@@ -106,10 +106,7 @@ const AiSettingModalContent = forwardRef<AiSettingModalContentHandle,AiSettingMo
|
||||
label:<div className="flex items-center gap-[10px]">
|
||||
<span>{x.id}</span>
|
||||
{x?.scopes?.map(s=><Tag >{s?.toLocaleUpperCase()}</Tag>)}
|
||||
</div>}))}
|
||||
onChange={(e)=>{
|
||||
form.setFieldValue('config',llmList?.find(x=>x.id===e)?.config)
|
||||
}}>
|
||||
</div>}))}>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
@@ -21,22 +21,22 @@ export default function Guide(){
|
||||
{
|
||||
title: $t("配置你的 AI 模型"),
|
||||
description: $t('通过 APIPark 快速接入各种 AI 模型,使用统一的格式来调用API,并且可以随意切换模型。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/pre-work/team'
|
||||
link: 'https://docs.apipark.com/docs/system_setting/ai_model_providers'
|
||||
},
|
||||
{
|
||||
title: $t("创建 AI 服务和 API"),
|
||||
description: $t('创建 AI 类型的服务,并且你可以将 Prompt 提示词设置为一个 API,简化使用 AI 的流程。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/provider/service'
|
||||
link: 'https://docs.apipark.com/docs/services/ai_services'
|
||||
},
|
||||
{
|
||||
title: $t("创建调用 Token"),
|
||||
description: $t('为了安全地调用 API,你需要创建一个消费者以及Token。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/suberscriber/application'
|
||||
link: 'https://docs.apipark.com/docs/consumers'
|
||||
},
|
||||
{
|
||||
title: $t("调用"),
|
||||
description: $t('现在你可以通过 Token 来调用这些 API。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/suberscriber/application'
|
||||
link: 'https://docs.apipark.com/docs/call_api'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -46,17 +46,17 @@ export default function Guide(){
|
||||
{
|
||||
title: $t("创建 REST 服务和 API"),
|
||||
description: $t('创建 AI 类型的服务,并且你可以将 Prompt 提示词设置为一个 API,简化使用 AI 的流程。'),
|
||||
link: 'https://docs.apipark.com/docs/tutorials/api-market/service'
|
||||
link: 'https://docs.apipark.com/docs/services/rest_services'
|
||||
},
|
||||
{
|
||||
title: $t("创建调用 Token"),
|
||||
description: $t('为了安全地调用 API,你需要创建一个消费者以及Token。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/suberscriber/subscribe'
|
||||
link: 'https://docs.apipark.com/docs/consumers'
|
||||
},
|
||||
{
|
||||
title: $t("调用"),
|
||||
description: $t('现在你可以通过 Token 来调用这些 API。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/provider/approve'
|
||||
link: 'https://docs.apipark.com/docs/call_api'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -66,7 +66,7 @@ export default function Guide(){
|
||||
{
|
||||
title: $t("统计 API 调用情况"),
|
||||
description: $t('仪表盘中提供了多种统计图表,帮助我们了解 API 的运行情况。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/pre-work/monitor'
|
||||
link: 'https://docs.apipark.com/docs/analysis'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -78,17 +78,17 @@ export default function Guide(){
|
||||
{
|
||||
title: $t("账号与角色"),
|
||||
description: $t('邀请你的团队成员加入 APIPark,共同管理和调用 API。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/pre-work/team'
|
||||
link: 'https://docs.apipark.com/docs/system_setting/account_role'
|
||||
},
|
||||
{
|
||||
title: $t("团队"),
|
||||
description: $t('团队中包含了人员、消费者和服务,不同团队之间的消费者和服务数据是隔离的,可用于管理企业内部不同的部门/项目组/团队。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/provider/service'
|
||||
link: 'https://docs.apipark.com/docs/teams'
|
||||
},
|
||||
{
|
||||
title: $t("服务"),
|
||||
description: $t('服务内包含一组 API,并且可以发布到 API 市场被其他团队使用。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/suberscriber/application'
|
||||
link: 'https://docs.apipark.com/docs/category/-%E6%9C%8D%E5%8A%A1'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -98,12 +98,12 @@ export default function Guide(){
|
||||
{
|
||||
title: $t("订阅服务"),
|
||||
description: $t('如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。'),
|
||||
link: 'https://docs.apipark.com/docs/tutorials/api-market/service'
|
||||
link: 'https://docs.apipark.com/docs/developer_portal'
|
||||
},
|
||||
{
|
||||
title: $t("审核订阅申请"),
|
||||
description: $t('提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的消费者才可发起 API 请求。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/suberscriber/subscribe'
|
||||
link: 'https://docs.apipark.com/docs/services/review_consumers'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -113,7 +113,7 @@ export default function Guide(){
|
||||
{
|
||||
title: $t("日志"),
|
||||
description: $t('APIPark 提供详尽的 API 调用日志,帮助企业监控、分析和审计 API 的运行状况。'),
|
||||
link: 'https://docs.apipark.com/docs/quick/pre-work/monitor'
|
||||
link: 'https://docs.apipark.com/docs/system_setting/log/'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const LogSettings = ()=>{
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
'system.devops.log_configuration.view')
|
||||
'system.settings.log_configuration.view')
|
||||
})
|
||||
return newMenu
|
||||
},[state.language,menuItems])
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission";
|
||||
import { useBreadcrumb } from "@common/contexts/BreadcrumbContext";
|
||||
import { $t } from "@common/locales";
|
||||
import { useEffect } from "react";
|
||||
@@ -24,7 +25,7 @@ export default function LogSettingsInstruction() {
|
||||
<div className="h-[208px] w-[384px] flex flex-col items-center py-[32px] px-[24px] gap-[16px] rounded-DEFAULT bg-MENU_BG mr-[24px]">
|
||||
<p className="text-[20px] font-medium leading-[32px] text-MAIN_TEXT">环境配置</p>
|
||||
<p className="text-[12px] font-normal leading-[20px] text-DESC_TEXT">新增集群的地址、名称、描述和其他相关属性,以确保插件能够正确识别和连接到集群</p>
|
||||
<p><Link to="/cluster">添加集群地址</Link></p>
|
||||
<p><WithPermission access="system.settings.api_gateway.view" ><Link to="/cluster">添加集群地址</Link></WithPermission></p>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {App, Form, Input, TreeSelect} from "antd";
|
||||
import {forwardRef, useEffect, useImperativeHandle, useState} from "react";
|
||||
import {forwardRef, useEffect, useImperativeHandle, useMemo, useState} from "react";
|
||||
import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE, VALIDATE_MESSAGE} from "@common/const/const.tsx";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import { MemberDropdownModalHandle, MemberDropdownModalProps, DepartmentListItem, MemberDropdownModalFieldType, MemberTableListItem } from "../../const/member/type.ts";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { $t } from "@common/locales/index.ts";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx";
|
||||
|
||||
export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDropdownModalProps>((props,ref)=>{
|
||||
const { message} = App.useApp()
|
||||
@@ -12,6 +13,7 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
|
||||
const {type,entity,selectedMemberGroupId} = props
|
||||
const {fetchData} = useFetch()
|
||||
const [departmentList, setDepartmentList] = useState<DepartmentListItem[]>([])
|
||||
const { state } = useGlobalContext()
|
||||
|
||||
const save:()=>Promise<boolean | string> = ()=>{
|
||||
let url:string
|
||||
@@ -78,6 +80,15 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
|
||||
})
|
||||
}
|
||||
|
||||
const generateRandomString = () =>{
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
for (let i = 0; i < 8; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
switch(type){
|
||||
case 'addChild':
|
||||
@@ -87,7 +98,7 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
|
||||
form.setFieldsValue({id:entity!.id,name:entity!.name})
|
||||
break
|
||||
case 'addMember':
|
||||
form.setFieldsValue('-1' === selectedMemberGroupId ? {} : {departmentIds:selectedMemberGroupId})
|
||||
form.setFieldsValue({...('-1' === selectedMemberGroupId ? {} : {departmentIds:selectedMemberGroupId}), password:generateRandomString()})
|
||||
break
|
||||
case 'editMember':
|
||||
form.setFieldsValue({...entity,departmentIds:(entity as MemberTableListItem )?.department?.map(x=>x.id)})
|
||||
@@ -97,6 +108,23 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
|
||||
|
||||
}, []);
|
||||
|
||||
|
||||
const treeData = useMemo(() => {
|
||||
const loop = (data: DepartmentListItem[]): unknown[] =>
|
||||
data?.map((item) => {
|
||||
const title = ['unknown','disable'].indexOf(item.id) === -1 ?item.name : $t(item.name) as string;
|
||||
if (item.children) {
|
||||
return {...item,name:title, children:loop(item.children)}
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
name: title
|
||||
};
|
||||
});
|
||||
return loop(departmentList);
|
||||
}, [departmentList,state.language]);
|
||||
|
||||
|
||||
return (<WithPermission access="">
|
||||
<Form
|
||||
@@ -163,6 +191,13 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
|
||||
>
|
||||
<Input className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)}/>
|
||||
</Form.Item>
|
||||
<Form.Item<MemberDropdownModalFieldType>
|
||||
label={$t("密码")}
|
||||
name="password"
|
||||
rules={[{required: type === 'addMember',whitespace:true }]}
|
||||
>
|
||||
<Input className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)}/>
|
||||
</Form.Item>
|
||||
<Form.Item<MemberDropdownModalFieldType>
|
||||
label={$t("部门")}
|
||||
name="departmentIds"
|
||||
@@ -175,7 +210,7 @@ export const MemberDropdownModal = forwardRef<MemberDropdownModalHandle,MemberDr
|
||||
placeholder={$t(PLACEHOLDER.select)}
|
||||
allowClear
|
||||
treeDefaultExpandAll
|
||||
treeData={departmentList}
|
||||
treeData={treeData}
|
||||
multiple
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -346,7 +346,7 @@ const MemberList = ()=>{
|
||||
<WithPermission access="system.organization.member.edit">
|
||||
<Select
|
||||
className="w-full"
|
||||
mode="multiple"
|
||||
mode="multiple"
|
||||
value={entity.roles?.map((x:EntityItem)=>x.id)}
|
||||
options={roleSelectableList?.map((x:{id:string,name:string})=>({label:(x.name), value:x.id}))}
|
||||
onChange={(value)=>{
|
||||
|
||||
@@ -0,0 +1,464 @@
|
||||
import { ActionType } from "@ant-design/pro-components";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { Button, message, Switch } from 'antd'
|
||||
import PageList, { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { DATA_MASSKING_TABLE_COLUMNS } from './dataMaskingColumn'
|
||||
import { $t } from "@common/locales";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const.tsx";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission";
|
||||
|
||||
|
||||
const DataMasking = (props: any) => {
|
||||
|
||||
const {
|
||||
// 是否显示发布按钮
|
||||
publishBtn = false,
|
||||
// 行操作
|
||||
rowOperation = []
|
||||
} = props;
|
||||
const { checkPermission, getGlobalAccessData, accessInit, state } = useGlobalContext()
|
||||
/**
|
||||
* 列表ref
|
||||
*/
|
||||
const pageListRef = useRef<ActionType>(null);
|
||||
|
||||
/**
|
||||
* 表格数据重新加载
|
||||
*/
|
||||
const [tableHttpReload, setTableHttpReload] = useState(true);
|
||||
|
||||
/**
|
||||
* 表格数据
|
||||
*/
|
||||
const [tableListDataSource, setTableListDataSource] = useState<ServiceHubAppListItem[]>([]);
|
||||
|
||||
/**
|
||||
* 请求数据
|
||||
*/
|
||||
const { fetchData } = useFetch()
|
||||
|
||||
/**
|
||||
* 搜索关键字
|
||||
*/
|
||||
const [searchWord, setSearchWord] = useState<string>('')
|
||||
|
||||
/**
|
||||
* 获取列数据,国际化变化时重新获取
|
||||
*/
|
||||
const columns = useMemo(() => {
|
||||
const res = DATA_MASSKING_TABLE_COLUMNS.map(x => {
|
||||
// 启动列渲染
|
||||
if (x.dataIndex === 'enabled') {
|
||||
x.render = (text: any, record: any) => <Switch checked={record.enabled} onChange={(e) => { changeOpenApiStatus(e, record) }} />
|
||||
}
|
||||
// 处理数列渲染
|
||||
if (x.dataIndex === 'treatmentNumber') {
|
||||
x.render = (text: any, record: any) => <span className="w-full block cursor-pointer [&>.ant-typography]:text-theme" onClick={(e) => { openLogsModal(record) }} >{ text }</span>
|
||||
}
|
||||
// 名称筛选,这里是全量返回时候的,分页的话应该要接口返回对应的筛选数据
|
||||
if (x.dataIndex === 'name') {
|
||||
const nameList = tableListDataSource.map(item => item.name)
|
||||
const valueEnum: any = {}
|
||||
nameList.forEach(item => {
|
||||
valueEnum[item] = { text: item }
|
||||
})
|
||||
x.valueEnum = valueEnum
|
||||
}
|
||||
return {
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title as string) : x.title
|
||||
}
|
||||
})
|
||||
return res
|
||||
}, [tableListDataSource, state.language])
|
||||
|
||||
/**
|
||||
* 操作列
|
||||
*/
|
||||
const operation: PageProColumns<any>[] = rowOperation.length ? [
|
||||
{
|
||||
title: '',
|
||||
key: 'option',
|
||||
btnNums: rowOperation.length,
|
||||
fixed: 'right',
|
||||
valueType: 'option',
|
||||
render: (_: React.ReactNode, entity: any) => [
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'edit') ? [<TableBtnWithPermission access="system.organization.member.edit" key="edit" btnType="edit" onClick={() => { openEditModal(entity) }} btnTitle="编辑" />] : []),
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [<TableBtnWithPermission access="system.organization.member.edit" key="logs" btnType="logs" onClick={() => { openLogsModal(entity) }} btnTitle="详情" />] : []),
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'delete') ? [<TableBtnWithPermission access="system.organization.member.edit" key="delete" btnType="delete" onClick={() => { deletePolicy(entity) }} btnTitle="删除" />] : []),
|
||||
],
|
||||
}
|
||||
] : []
|
||||
|
||||
/**
|
||||
* 手动刷新表格数据
|
||||
*/
|
||||
const manualReloadTable = () => {
|
||||
setTableHttpReload(true)
|
||||
pageListRef.current?.reload()
|
||||
};
|
||||
|
||||
/**
|
||||
* 更改启动状态
|
||||
* @param enabled 状态
|
||||
* @param entity 行数据
|
||||
*/
|
||||
const changeOpenApiStatus = (enabled: boolean, entity: any) => {
|
||||
console.log('更改启动状态', enabled, entity);
|
||||
|
||||
manualReloadTable()
|
||||
// 待补充,请求接口更改状态,然后刷新表格
|
||||
// fetchData<BasicResponse<null>>(
|
||||
// `external-app/${enabled ? 'disable' : 'enable'}`,
|
||||
// {
|
||||
// method: 'PUT',
|
||||
// eoParams: {
|
||||
// id: entity.id
|
||||
// }
|
||||
// }
|
||||
// ).then(response => {
|
||||
// const { code, msg } = response
|
||||
// if (code === STATUS_CODE.SUCCESS) {
|
||||
// message.success(msg || $t(RESPONSE_TIPS.success))
|
||||
// manualReloadTable()
|
||||
// } else {
|
||||
// message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
* @param dataType
|
||||
* @returns
|
||||
*/
|
||||
const getServiceList = () => {
|
||||
if (!accessInit) {
|
||||
getGlobalAccessData()?.then?.(() => { getServiceList() })
|
||||
return Promise.resolve({ data: [], success: false })
|
||||
}
|
||||
|
||||
if (!tableHttpReload) {
|
||||
setTableHttpReload(true)
|
||||
return Promise.resolve({
|
||||
data: tableListDataSource,
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
return fetchData<BasicResponse<any>>(
|
||||
!checkPermission('system.workspace.team.view_all') ? 'teams' : 'manager/teams',
|
||||
{
|
||||
method: 'GET',
|
||||
eoParams: { keyword: searchWord },
|
||||
eoTransformKeys: ['create_time', 'service_num', 'can_delete']
|
||||
}
|
||||
).then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
const data = [
|
||||
{
|
||||
name: 'test',
|
||||
priority: 1,
|
||||
status: true,
|
||||
enabled: true,
|
||||
condition: 'test',
|
||||
treatmentNumber: 1,
|
||||
updater: 'test',
|
||||
createTime: '2021-10-01'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
priority: 2,
|
||||
status: false,
|
||||
enabled: false,
|
||||
condition: 'test2',
|
||||
treatmentNumber: 2,
|
||||
updater: 'test2',
|
||||
createTime: '2021-10-02'
|
||||
}
|
||||
]
|
||||
// 保存数据
|
||||
setTableListDataSource(data)
|
||||
setTableHttpReload(false)
|
||||
return {
|
||||
data,
|
||||
success: true
|
||||
}
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
return { data: [], success: false }
|
||||
}
|
||||
}).catch(() => {
|
||||
return { data: [], success: false }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加策略
|
||||
* @param type
|
||||
*/
|
||||
const addPolicy = () => {
|
||||
console.log('添加策略');
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布策略
|
||||
*/
|
||||
const publish = () => {
|
||||
console.log('发布策略');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
const openEditModal = (entity: any) => {
|
||||
console.log('编辑', entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志
|
||||
* @param entity
|
||||
*/
|
||||
const openLogsModal = (entity: any) => {
|
||||
console.log('日志', entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param entity
|
||||
*/
|
||||
const deletePolicy = (entity: any) => {
|
||||
console.log('删除', entity);
|
||||
manualReloadTable()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageList
|
||||
id="data_masking_list"
|
||||
ref={pageListRef}
|
||||
columns={[...columns, ...operation]}
|
||||
request={() => getServiceList()}
|
||||
addNewBtnTitle={$t("添加策略")}
|
||||
onAddNewBtnClick={() => { addPolicy() }}
|
||||
searchPlaceholder={$t("输入名称、筛选条件查找")}
|
||||
afterNewBtn={
|
||||
publishBtn && [<WithPermission key="removeFromDepPermission" access="system.organization.member.edit"><Button className="mr-btnbase" key="removeFromDep" onClick={() => publish()}>{$t('发布')}</Button></WithPermission>]
|
||||
}
|
||||
onSearchWordChange={(e) => {
|
||||
setSearchWord(e.target.value)
|
||||
}}
|
||||
manualReloadTable={manualReloadTable}
|
||||
onChange={() => {
|
||||
setTableHttpReload(false)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DataMasking;
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
import { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { frontendTimeSorter } from "@common/utils/dataTransfer";
|
||||
import { $t } from "@common/locales";
|
||||
|
||||
export const DATA_MASSKING_TABLE_COLUMNS: PageProColumns<any>[] = [
|
||||
{
|
||||
title: ('策略名称'),
|
||||
dataIndex: 'name',
|
||||
ellipsis: true,
|
||||
filters: true,
|
||||
onFilter: true,
|
||||
valueType: 'select',
|
||||
filterSearch: true,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: ('优先级'),
|
||||
dataIndex: 'priority',
|
||||
width: 140,
|
||||
ellipsis: true,
|
||||
sorter: (a: any, b: any) => {
|
||||
return (a.priority as number) - (b.priority as number)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: ('发布状态'),
|
||||
dataIndex: 'status',
|
||||
filters: true,
|
||||
onFilter: true,
|
||||
width: 140,
|
||||
valueEnum: new Map([
|
||||
[true, <span className="text-status_success">{$t('已发布')}</span>],
|
||||
[false, <span className="text-status_fail">{$t('未发布')}</span>]
|
||||
])
|
||||
},
|
||||
{
|
||||
title: ('启用'),
|
||||
dataIndex: 'enabled',
|
||||
filters: true,
|
||||
onFilter: true,
|
||||
valueEnum: {
|
||||
true: { text: <span className="text-status_success">{$t('启用')}</span> },
|
||||
false: { text: <span className="text-status_fail">{$t('禁用')}</span> }
|
||||
}
|
||||
},
|
||||
{
|
||||
title: ('筛选条件'),
|
||||
dataIndex: 'condition',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('处理数'),
|
||||
dataIndex: 'treatmentNumber',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('更新者'),
|
||||
dataIndex: 'updater',
|
||||
width: 140,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('更新时间'),
|
||||
dataIndex: 'createTime',
|
||||
width: 182,
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => frontendTimeSorter(a, b, 'createTime')
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,33 @@
|
||||
import InsidePage from "@common/components/aoplatform/InsidePage.tsx";
|
||||
import { $t } from "@common/locales/index.ts";
|
||||
import PolicyTabContainer from "./policyTabContainer.tsx";
|
||||
import DataMasking from "./dataMasking.tsx";
|
||||
|
||||
|
||||
const PartitionInsideGlobalPolicy = () => {
|
||||
/**
|
||||
* tab列表
|
||||
*/
|
||||
const tabItems = [
|
||||
{
|
||||
key: 'dataMasking',
|
||||
label: $t('数据脱敏'),
|
||||
children: <div className="pr-[40px] preview-document h-full pb-[40px]"><DataMasking publishBtn rowOperation={['edit', 'logs', 'delete']} /></div>
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<InsidePage
|
||||
pageTitle={$t('全局策略')}
|
||||
description={$t("支持对系统全局进行统一的策略配置,从而简化管理并确保一致性。全局策略的优先级比服务策略略低。")}
|
||||
showBorder={false}
|
||||
scrollPage={false}
|
||||
>
|
||||
<PolicyTabContainer tabs={tabItems} />
|
||||
</InsidePage>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartitionInsideGlobalPolicy
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Tabs } from "antd";
|
||||
|
||||
const PolicyTabContainer = (props: any) => {
|
||||
/**
|
||||
* 支持的tab
|
||||
*/
|
||||
const { tabs } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
className="overflow-hidden h-full [&>.ant-tabs-content-holder]:overflow-auto global-policy-tabs"
|
||||
items={tabs}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PolicyTabContainer;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { $t } from "@common/locales/index.ts";
|
||||
import DataMasking from "@core/pages/policy/dataMasking";
|
||||
import PolicyTabContainer from "@core/pages/policy/policyTabContainer";
|
||||
|
||||
const servicePolicy = () => {
|
||||
/**
|
||||
* tab列表
|
||||
*/
|
||||
const tabItems = [
|
||||
{
|
||||
key: 'dataMasking',
|
||||
label: $t('数据脱敏'),
|
||||
children: <div className="pr-[40px] h-full preview-document mb-PAGE_INSIDE_B"><DataMasking rowOperation={['edit', 'logs', 'delete']} /></div>
|
||||
}
|
||||
]
|
||||
return (
|
||||
<>
|
||||
<PolicyTabContainer tabs={tabItems} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default servicePolicy;
|
||||
@@ -47,7 +47,7 @@ const LogSettings = ()=>{
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
'system.devops.log_configuration.view')
|
||||
'system.settings.log_configuration.view')
|
||||
})
|
||||
return newMenu
|
||||
},[state.language,menuItems])
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission";
|
||||
import { useBreadcrumb } from "@common/contexts/BreadcrumbContext";
|
||||
import { useEffect } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
@@ -24,7 +25,7 @@ export default function ResourceSettingsInstruction() {
|
||||
<div className="h-[208px] w-[384px] flex flex-col items-center py-[32px] px-[24px] gap-[16px] rounded-DEFAULT bg-MENU_BG mr-[24px]">
|
||||
<p className="text-[20px] font-medium leading-[32px] text-MAIN_TEXT">集群配置</p>
|
||||
<p className="text-[12px] font-normal leading-[20px] text-DESC_TEXT">新增集群地址、描述和其他相关属性,以确保插件能够正确识别和连接到集群</p>
|
||||
<p><Link to="/cluster">配置集群地址</Link></p>
|
||||
<p><WithPermission access="system.settings.data_source.view" ><Link to="/cluster">配置集群地址</Link></WithPermission></p>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
@@ -176,13 +176,17 @@ const RoleConfig = ()=>{
|
||||
},[permissionInfo, state.language])
|
||||
|
||||
useEffect(() => {
|
||||
getPermissionTemplate()
|
||||
form.setFieldsValue({name:'',permits:[]})
|
||||
if(roleId){
|
||||
getPermissionInfo()
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(()=>{
|
||||
getPermissionTemplate()
|
||||
|
||||
},[state.language])
|
||||
|
||||
const onFinish =async() => {
|
||||
const body = await form.validateFields()
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ const SystemConfig = forwardRef<SystemConfigHandle>((_,ref) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<WithPermission access={onEdit ? 'team.service.service.edit' :''}>
|
||||
<WithPermission access={onEdit ? ['team.service.service.edit'] :''}>
|
||||
<Form
|
||||
layout='vertical'
|
||||
labelAlign='left'
|
||||
@@ -460,7 +460,7 @@ const SystemConfig = forwardRef<SystemConfigHandle>((_,ref) => {
|
||||
<Row className="mb-[10px]"
|
||||
// wrapperCol={{ offset: 5, span: 19 }}
|
||||
>
|
||||
<WithPermission access={onEdit ? 'team.service.service.edit' :''}>
|
||||
<WithPermission access={onEdit ? ['team.service.service.edit'] :''}>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{$t('保存')}
|
||||
</Button>
|
||||
@@ -468,11 +468,11 @@ const SystemConfig = forwardRef<SystemConfigHandle>((_,ref) => {
|
||||
</Row></>}
|
||||
</div>
|
||||
{onEdit && <>
|
||||
<WithPermission access="team.service.service.delete" showDisabled={false}>
|
||||
<WithPermission access={["team.service.service.delete"]} showDisabled={false}>
|
||||
<div className="bg-[rgb(255_120_117_/_5%)] rounded-[10px] mt-[50px] p-btnrbase pb-0">
|
||||
<p className="text-left"><span className="font-bold">{$t('删除服务')}:</span>{$t('删除操作不可恢复,请谨慎操作!')}</p>
|
||||
<div className="text-left">
|
||||
<WithPermission access="team.service.service.delete">
|
||||
<WithPermission access={["team.service.service.delete"]}>
|
||||
<Button className="m-auto mt-[16px] mb-[20px]" type="default" danger={true} onClick={deleteSystemModal}>{$t('删除服务')}</Button>
|
||||
</WithPermission>
|
||||
</div>
|
||||
|
||||
@@ -137,7 +137,7 @@ const ServiceInsideDocument = ()=>{
|
||||
<div className=" pl-[8px] py-btnbase ">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[14px] leading-[20px] text-[#999999]"><span className="mr-[20px]">{$t('最近一次更新者')}:{updater || '-'}</span><span>{$t('最近一次更新时间')}:{updateTime || '-'}</span></p>
|
||||
<WithPermission access="team.service.service.edit"><Button type="primary" className="mr-btnbase" onClick={save}>{$t('保存')}</Button></WithPermission>
|
||||
<WithPermission access="team.service.service_intro.edit"><Button type="primary" className="mr-btnbase" onClick={save}>{$t('保存')}</Button></WithPermission>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
import {FC, useEffect, useMemo, useState} from "react";
|
||||
import {Link, Outlet, useLocation, useNavigate, useParams} from "react-router-dom";
|
||||
import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx";
|
||||
import {App, Menu, MenuProps} from "antd";
|
||||
import {BasicResponse, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import { useSystemContext} from "../../contexts/SystemContext.tsx";
|
||||
import { FC, useEffect, useMemo, useState } from "react";
|
||||
import { Link, Outlet, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { RouterParams } from "@core/components/aoplatform/RenderRoutes.tsx";
|
||||
import { App, Menu, MenuProps } from "antd";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const.tsx";
|
||||
import { useFetch } from "@common/hooks/http.ts";
|
||||
import { useSystemContext } from "../../contexts/SystemContext.tsx";
|
||||
import { SystemConfigFieldType } from "../../const/system/type.ts";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx";
|
||||
import { PERMISSION_DEFINITION } from "@common/const/permissions.ts";
|
||||
@@ -17,143 +17,147 @@ import { $t } from "@common/locales/index.ts";
|
||||
import { getItem } from "@common/utils/navigation.tsx";
|
||||
const APP_MODE = import.meta.env.VITE_APP_MODE;
|
||||
|
||||
const SystemInsidePage:FC = ()=> {
|
||||
const { message } = App.useApp()
|
||||
const { teamId,serviceId,apiId,routeId} = useParams<RouterParams>();
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const {fetchData} = useFetch()
|
||||
const { setPrefixForce,setApiPrefix ,systemInfo,setSystemInfo} = useSystemContext()
|
||||
const { accessData,checkPermission,accessInit,state} = useGlobalContext()
|
||||
const [activeMenu, setActiveMenu] = useState<string>()
|
||||
const navigateTo = useNavigate()
|
||||
const [showMenu, setShowMenu] = useState<boolean>(false)
|
||||
const SystemInsidePage: FC = () => {
|
||||
const { message } = App.useApp()
|
||||
const { teamId, serviceId, apiId, routeId } = useParams<RouterParams>();
|
||||
const location = useLocation()
|
||||
const currentUrl = location.pathname
|
||||
const { fetchData } = useFetch()
|
||||
const { setPrefixForce, setApiPrefix, systemInfo, setSystemInfo } = useSystemContext()
|
||||
const { accessData, checkPermission, accessInit, state } = useGlobalContext()
|
||||
const [activeMenu, setActiveMenu] = useState<string>()
|
||||
const navigateTo = useNavigate()
|
||||
const [showMenu, setShowMenu] = useState<boolean>(false)
|
||||
|
||||
const getSystemInfo = ()=>{
|
||||
fetchData<BasicResponse<{ service:SystemConfigFieldType }>>('service/info',{method:'GET',eoParams:{team:teamId, service:serviceId}}).then(response=>{
|
||||
const {code,data,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
setSystemInfo(data.service)
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
const getSystemInfo = () => {
|
||||
fetchData<BasicResponse<{ service: SystemConfigFieldType }>>('service/info', { method: 'GET', eoParams: { team: teamId, service: serviceId } }).then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setSystemInfo(data.service)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getApiDefine = ()=>{
|
||||
setApiPrefix('')
|
||||
setPrefixForce(false)
|
||||
fetchData<BasicResponse<{ prefix:string, force:boolean }>>('service/router/define',{method:'GET',eoParams:{service:serviceId,team:teamId}}).then(response=>{
|
||||
const {code,data,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
setApiPrefix(data.prefix)
|
||||
setPrefixForce(data.force)
|
||||
}else{
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
const getApiDefine = () => {
|
||||
setApiPrefix('')
|
||||
setPrefixForce(false)
|
||||
fetchData<BasicResponse<{ prefix: string, force: boolean }>>('service/router/define', { method: 'GET', eoParams: { service: serviceId, team: teamId } }).then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setApiPrefix(data.prefix)
|
||||
setPrefixForce(data.force)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SYSTEM_PAGE_MENU_ITEMS = useMemo(()=>[
|
||||
|
||||
const SYSTEM_PAGE_MENU_ITEMS = useMemo(() => [
|
||||
getItem($t('服务'), 'assets', null,
|
||||
[
|
||||
getItem(<Link to="./route">{$t('API 路由')}</Link>, 'route',undefined,undefined,undefined,'team.service.router.view'),
|
||||
getItem(<Link to="./api">{$t('API 文档')}</Link>, 'api',undefined,undefined,undefined,'team.service.api_doc.view'),
|
||||
getItem(<Link to="./upstream">{$t('上游')}</Link>, 'upstream',undefined,undefined,undefined,'team.service.upstream.view'),
|
||||
getItem(<Link to="./document">{$t('使用说明')}</Link>, 'document',undefined,undefined,undefined,''),
|
||||
getItem(<Link to="./publish">{$t('发布')}</Link>, 'publish',undefined,undefined,undefined,'team.service.release.view'),
|
||||
],
|
||||
'group'),
|
||||
[
|
||||
getItem(<Link to="./route">{$t('API 路由')}</Link>, 'route', undefined, undefined, undefined, 'team.service.router.view'),
|
||||
getItem(<Link to="./api">{$t('API 文档')}</Link>, 'api', undefined, undefined, undefined, 'team.service.api_doc.view'),
|
||||
getItem(<Link to="./upstream">{$t('上游')}</Link>, 'upstream', undefined, undefined, undefined, 'team.service.upstream.view'),
|
||||
getItem(<Link to="./document">{$t('使用说明')}</Link>, 'document', undefined, undefined, undefined, 'team.service.service_intro.view'),
|
||||
getItem(<Link to="./servicePolicy">{$t('服务策略')}</Link>, 'servicePolicy', undefined, undefined, undefined, 'team.service.service_intro.view'),
|
||||
getItem(<Link to="./publish">{$t('发布')}</Link>, 'publish', undefined, undefined, undefined, 'team.service.release.view'),
|
||||
],
|
||||
'group'),
|
||||
getItem($t('订阅管理'), 'provideSer', null,
|
||||
[
|
||||
getItem(<Link to="./approval">{$t('订阅审核')}</Link>, 'approval',undefined,undefined,undefined,'team.service.subscription.view'),
|
||||
getItem(<Link to="./subscriber">{$t('订阅方管理')}</Link>, 'subscriber',undefined,undefined,undefined,'team.service.subscription.view'),
|
||||
],
|
||||
'group'),
|
||||
[
|
||||
getItem(<Link to="./approval">{$t('订阅审核')}</Link>, 'approval', undefined, undefined, undefined, 'team.service.subscription.view'),
|
||||
getItem(<Link to="./subscriber">{$t('订阅方管理')}</Link>, 'subscriber', undefined, undefined, undefined, 'team.service.subscription.view'),
|
||||
],
|
||||
'group'),
|
||||
getItem($t('管理'), 'mng', null,
|
||||
[
|
||||
APP_MODE === 'pro' ? getItem(<Link to="./topology">{$t('调用拓扑图')}</Link>, 'topology',undefined,undefined,undefined,'project.mySystem.topology.view'):null,
|
||||
getItem(<Link to="./setting">{$t('设置')}</Link>, 'setting',undefined,undefined,undefined,'')],
|
||||
'group'),
|
||||
],[state.language])
|
||||
[
|
||||
APP_MODE === 'pro' ? getItem(<Link to="./topology">{$t('调用拓扑图')}</Link>, 'topology', undefined, undefined, undefined, 'project.mySystem.topology.view') : null,
|
||||
getItem(<Link to="./setting">{$t('设置')}</Link>, 'setting', undefined, undefined, undefined, '')],
|
||||
'group'),
|
||||
], [state.language])
|
||||
|
||||
|
||||
const menuData = useMemo(()=>{
|
||||
const filterMenu = (menu:MenuItemGroupType<MenuItemType>[])=>{
|
||||
const newMenu = cloneDeep(menu)
|
||||
return newMenu!.filter((m:MenuItemGroupType )=>{
|
||||
if(m.children && m.children.length > 0){
|
||||
m.children = m.children.filter(
|
||||
(c)=>(c&&(c as MenuItemType&{access:string} ).access ?
|
||||
checkPermission((c as MenuItemType&{access:string} ).access as keyof typeof PERMISSION_DEFINITION[0]):
|
||||
true))
|
||||
}
|
||||
return m.children && m.children.length > 0
|
||||
const menuData = useMemo(() => {
|
||||
const filterMenu = (menu: MenuItemGroupType<MenuItemType>[]) => {
|
||||
const newMenu = cloneDeep(menu)
|
||||
return newMenu!.filter((m: MenuItemGroupType) => {
|
||||
if (m && m.children && m.children.length > 0) {
|
||||
m.children = m.children.filter(
|
||||
(c) => {
|
||||
if (!c) return false
|
||||
return (((c as MenuItemType & { access: string }).access ?
|
||||
checkPermission((c as MenuItemType & { access: string }).access as keyof typeof PERMISSION_DEFINITION[0]) :
|
||||
true))
|
||||
})
|
||||
}
|
||||
const filteredMenu = filterMenu(SYSTEM_PAGE_MENU_ITEMS as MenuItemGroupType<MenuItemType>[])
|
||||
setActiveMenu((pre)=>{
|
||||
return pre ?? 'route'
|
||||
})
|
||||
return filteredMenu || []
|
||||
},[accessData,accessInit, SYSTEM_PAGE_MENU_ITEMS])
|
||||
|
||||
const onMenuClick: MenuProps['onClick'] = ({key}) => {
|
||||
setActiveMenu(key)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setShowMenu(!routeId && !currentUrl.includes('route/create'))
|
||||
if(apiId !== undefined){
|
||||
setActiveMenu('api')
|
||||
}else if(serviceId !== currentUrl.split('/')[currentUrl.split('/').length - 1]){
|
||||
setActiveMenu(currentUrl.split('/')[currentUrl.split('/').length - 1])
|
||||
}else{
|
||||
setActiveMenu('route')
|
||||
}
|
||||
}, [currentUrl]);
|
||||
return m.children && m.children.length > 0
|
||||
})
|
||||
}
|
||||
const filteredMenu = filterMenu(SYSTEM_PAGE_MENU_ITEMS as MenuItemGroupType<MenuItemType>[])
|
||||
const menu = activeMenu ?? filteredMenu[0]?.children ? filteredMenu[0]?.children?.[0]?.key : filteredMenu[0]?.key
|
||||
if (menu && currentUrl.split('/')[-1] !== menu) navigateTo(`/service/${teamId}/inside/${serviceId}/${menu}`)
|
||||
return filteredMenu || []
|
||||
}, [accessData, accessInit, SYSTEM_PAGE_MENU_ITEMS])
|
||||
|
||||
useEffect(()=>{
|
||||
if(accessData && accessData.get('team') && accessData.get('team')?.indexOf('team.service.router.view') !== -1){
|
||||
getApiDefine()
|
||||
}
|
||||
},[accessData])
|
||||
const onMenuClick: MenuProps['onClick'] = ({ key }) => {
|
||||
setActiveMenu(key)
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
if( activeMenu && serviceId === currentUrl.split('/')[currentUrl.split('/').length - 1]){
|
||||
navigateTo(`/service/${teamId}/inside/${serviceId}/${activeMenu}`)
|
||||
}
|
||||
},[activeMenu])
|
||||
useEffect(() => {
|
||||
setShowMenu(!routeId && !currentUrl.includes('route/create'))
|
||||
if (apiId !== undefined) {
|
||||
setActiveMenu('api')
|
||||
} else if (serviceId !== currentUrl.split('/')[currentUrl.split('/').length - 1]) {
|
||||
setActiveMenu(currentUrl.split('/')[currentUrl.split('/').length - 1])
|
||||
} else {
|
||||
setActiveMenu('route')
|
||||
}
|
||||
}, [currentUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
serviceId && getSystemInfo()
|
||||
}, [serviceId]);
|
||||
useEffect(() => {
|
||||
if (accessData && checkPermission('team.service.router.view')) {
|
||||
getApiDefine()
|
||||
}
|
||||
}, [accessData])
|
||||
|
||||
return (
|
||||
<>{showMenu ?
|
||||
<InsidePage pageTitle={systemInfo?.name || '-'}
|
||||
tagList={[{label:
|
||||
<Paragraph className="mb-0" copyable={serviceId ? { text: serviceId } : false}>{$t('服务 ID')}:{serviceId || '-'}</Paragraph>
|
||||
}]}
|
||||
backUrl="/service/list">
|
||||
<div className="flex flex-1 h-full">
|
||||
<Menu
|
||||
onClick={onMenuClick}
|
||||
className="h-full overflow-y-auto"
|
||||
style={{ width: 220 }}
|
||||
selectedKeys={[activeMenu!]}
|
||||
mode="inline"
|
||||
items={menuData as unknown as ItemType<MenuItemType>[] }
|
||||
/>
|
||||
<div className={` ${['setting', 'upstream'].indexOf(activeMenu!) !== -1 ? '' :''} w-full h-full flex flex-1 flex-col overflow-auto bg-MAIN_BG pt-[20px] pl-[20px] pb-PAGE_INSIDE_B ` }>
|
||||
<Outlet/>
|
||||
</div>
|
||||
</div>
|
||||
</InsidePage>: <Outlet/> }
|
||||
useEffect(() => {
|
||||
if (activeMenu && serviceId === currentUrl.split('/')[currentUrl.split('/').length - 1]) {
|
||||
navigateTo(`/service/${teamId}/inside/${serviceId}/${activeMenu}`)
|
||||
}
|
||||
}, [activeMenu])
|
||||
|
||||
</>
|
||||
)
|
||||
useEffect(() => {
|
||||
serviceId && getSystemInfo()
|
||||
}, [serviceId]);
|
||||
|
||||
return (
|
||||
<>{showMenu ?
|
||||
<InsidePage pageTitle={systemInfo?.name || '-'}
|
||||
tagList={[{
|
||||
label:
|
||||
<Paragraph className="mb-0" copyable={serviceId ? { text: serviceId } : false}>{$t('服务 ID')}:{serviceId || '-'}</Paragraph>
|
||||
}]}
|
||||
backUrl="/service/list">
|
||||
<div className="flex flex-1 h-full">
|
||||
<Menu
|
||||
onClick={onMenuClick}
|
||||
className="h-full overflow-y-auto"
|
||||
style={{ width: 220 }}
|
||||
selectedKeys={[activeMenu!]}
|
||||
mode="inline"
|
||||
items={menuData as unknown as ItemType<MenuItemType>[]}
|
||||
/>
|
||||
<div className={` ${['setting', 'upstream'].indexOf(activeMenu!) !== -1 ? '' : ''} w-full h-full flex flex-1 flex-col overflow-auto bg-MAIN_BG pt-[20px] pl-[20px] pb-PAGE_INSIDE_B `}>
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
</InsidePage> : <Outlet />}
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default SystemInsidePage
|
||||
@@ -153,7 +153,7 @@ const SystemList:FC = ()=>{
|
||||
|
||||
<InsidePage
|
||||
pageTitle={$t('服务')}
|
||||
description={'APIPark '+$t("服务提供了高性能 API 网关,并且可以无缝接入多种大型 AI 模型,并将这些 AI 能力打包成 API 进行调用,从而大幅简化了 AI 模型的使用门槛。同时,我们的平台提供了完善的 API 管理功能,支持 API 的创建、监控、访问控制等,保障开发者可以高效、安全地开发和管理 API 服务。")}
|
||||
description={$t("服务提供了高性能 API 网关,并且可以无缝接入多种大型 AI 模型,并将这些 AI 能力打包成 API 进行调用,从而大幅简化了 AI 模型的使用门槛。同时,我们的平台提供了完善的 API 管理功能,支持 API 的创建、监控、访问控制等,保障开发者可以高效、安全地开发和管理 API 服务。")}
|
||||
showBorder={false}
|
||||
contentClassName=" pr-PAGE_INSIDE_X pb-PAGE_INSIDE_B"
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@ import {App, Button, Form, Input, Row, Select} from "antd";
|
||||
import {Link, useLocation, useNavigate, useParams} from "react-router-dom";
|
||||
import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx";
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE, VALIDATE_MESSAGE} from "@common/const/const.tsx";
|
||||
import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import {MemberItem} from "@common/const/type.ts";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import {DefaultOptionType} from "antd/es/cascader";
|
||||
@@ -34,10 +34,10 @@ const TeamConfig= forwardRef<TeamConfigHandle,TeamConfigProps>((props,ref) => {
|
||||
const [managerOption, setManagerOption] = useState<DefaultOptionType[]>([])
|
||||
const { setBreadcrumb} = useBreadcrumb()
|
||||
const { setTeamInfo } =useTeamContext()
|
||||
const {checkPermission,accessInit} = useGlobalContext()
|
||||
const {checkPermission,accessInit,state} = useGlobalContext()
|
||||
const pageType= useMemo(()=>{
|
||||
if(!accessInit) return 'myteam'
|
||||
return checkPermission('system.organization.team.view') ? 'manage' : 'myteam'
|
||||
return checkPermission('system.workspace.team.view_all') ? 'manage' : 'myteam'
|
||||
},[checkPermission,accessInit])
|
||||
|
||||
const [canDelete, setCanDelete] = useState<boolean>(false)
|
||||
@@ -128,7 +128,10 @@ const TeamConfig= forwardRef<TeamConfigHandle,TeamConfigProps>((props,ref) => {
|
||||
getTeamInfo();
|
||||
} else {
|
||||
setOnEdit(false);
|
||||
form.setFieldsValue({id:uuidv4()}); // 清空 initialValues
|
||||
form.setFieldsValue(
|
||||
{id:uuidv4(),
|
||||
master:state?.userData?.uid
|
||||
}); // 清空 initialValues
|
||||
}
|
||||
return (form.setFieldsValue({}))
|
||||
}, [teamId]);
|
||||
@@ -197,7 +200,7 @@ const TeamConfig= forwardRef<TeamConfigHandle,TeamConfigProps>((props,ref) => {
|
||||
<p className="text-left"><span className="font-bold">{$t('删除团队')}:</span>{$t('删除操作不可恢复,请谨慎操作!')}</p>
|
||||
<div className="text-left">
|
||||
<WithPermission access="system.organization.team.delete" disabled={!canDelete} tooltip={canDelete ? '':$t('服务数据清除后,方可删除')}>
|
||||
<Button className="m-auto mt-[16px] mb-[20px]" type="default" danger onClick={()=>deleteTeam(entity!)}>{$t('删除')}</Button>
|
||||
<Button className="m-auto mt-[16px] mb-[20px]" type="default" danger onClick={()=>deleteTeam()}>{$t('删除')}</Button>
|
||||
</WithPermission>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { $t } from "@common/locales/index.ts";
|
||||
|
||||
export const getDepartmentWithMember = (department:(DepartmentListItem & {type?:'department'|'member'})[],departmentMap:Map<string, (MemberItem & {type:'department'|'member'})[]>) : (DepartmentWithMemberItem | undefined)[] =>{
|
||||
return department.map((x:DepartmentListItem & {type?:'department'|'member'})=>{
|
||||
return department?.map((x:DepartmentListItem & {type?:'department'|'member'})=>{
|
||||
const res = ({
|
||||
...x,
|
||||
key:x.id,
|
||||
@@ -28,7 +28,7 @@ export const getDepartmentWithMember = (department:(DepartmentListItem & {type?:
|
||||
type: x.type || 'department',
|
||||
children:((x.type === 'member' || (!x.children||x.children.length === 0 )&& (!departmentMap.get(x.id) || departmentMap.get(x.id)!.length === 0))? undefined : [...(x.children && x.children.length > 0 ? getDepartmentWithMember(x.children,departmentMap) : []),...departmentMap.get(x.id) || []])
|
||||
});
|
||||
return res}).filter(node=>node.type === 'member' ||( node.children && node.children.length > 0))
|
||||
return res})?.filter(node=>node.type === 'member' ||( node.children && node.children.length > 0)) || []
|
||||
}
|
||||
|
||||
export const addMemberToDepartment = (departmentMap: Map<string, (MemberItem & {type:'department'|'member'})[]>, departmentId: string, member: MemberItem) => {
|
||||
@@ -84,6 +84,7 @@ const TeamInsideMember:FC = ()=>{
|
||||
addMemberToDepartment(departmentMap, '_withoutDepartment', member);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const finalData = departmentResponse.data.department
|
||||
? [
|
||||
@@ -93,30 +94,33 @@ const TeamInsideMember:FC = ()=>{
|
||||
name: departmentResponse.data.department.name,
|
||||
title:departmentResponse.data.department.name,
|
||||
children: [
|
||||
...getDepartmentWithMember(departmentResponse.data.department.children, departmentMap),
|
||||
...getDepartmentWithMember(departmentResponse.data.department?.children || [], departmentMap),
|
||||
...departmentMap.get('_withoutDepartment') || []
|
||||
]
|
||||
}
|
||||
]
|
||||
: [...departmentMap.get('_withoutDepartment') || []];
|
||||
|
||||
|
||||
let allMemberSelectedFlag:boolean = true
|
||||
for(const [k,v] of departmentMap){
|
||||
if(k !== '_withoutDepartment' && allMemberIds.length > 0 ){
|
||||
// 筛选出部门内没被勾选的用户,如果不存在没勾选用户,需要将部门id放入ids中
|
||||
if(v.filter(m => allMemberIds.indexOf(m.id) === -1).length === 0){
|
||||
setAllMemberSelectedDepartIds((pre)=>[...pre, k])
|
||||
}else if(['unknown','disable'].indexOf(k) === -1){
|
||||
allMemberSelectedFlag = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!finalData[0].children || finalData[0].children.filter(m => allMemberIds.indexOf(m.id) === -1).length === 0){
|
||||
setAllMemberSelectedDepartIds((pre)=>[...pre, topDepartmentId])
|
||||
|
||||
if(departmentMap.get('_withoutDepartment')?.filter(x=>allMemberIds.indexOf(x)!==-1).length === 0 && allMemberSelectedFlag){
|
||||
setAllMemberSelectedDepartIds((pre)=>[...pre, topDepartmentId])
|
||||
}
|
||||
|
||||
return {data:finalData, success: true}
|
||||
}).catch(()=>({data:[], success:false}))
|
||||
}
|
||||
|
||||
|
||||
const getMemberList = ()=>{
|
||||
return fetchData<BasicResponse<{members:TeamMemberTableListItem}>>('team/members',{method:'GET',eoParams:{keyword:searchWord, team:teamId},eoTransformKeys:['attach_time','is_delete']}).then(response=>{
|
||||
@@ -214,7 +218,6 @@ const TeamInsideMember:FC = ()=>{
|
||||
|
||||
|
||||
const changeMemberInfo = (value:string[],entity:TeamMemberTableListItem )=>{
|
||||
//console.log(value)
|
||||
return new Promise((resolve, reject) => {
|
||||
fetchData<BasicResponse<null>>(`team/member/role`, {method: 'PUT',eoBody:({roles:value, users:[entity.user.id]}), eoParams: {team:teamId}}).then(response => {
|
||||
const {code, msg} = response
|
||||
@@ -252,6 +255,7 @@ const TeamInsideMember:FC = ()=>{
|
||||
<Select
|
||||
className="w-full"
|
||||
mode="multiple"
|
||||
maxTagCount="responsive"
|
||||
value={entity.roles?.map((x:EntityItem)=>x.id)}
|
||||
options={roleList?.map((x:{id:string,name:string})=>({label:(x.name), value:x.id}))}
|
||||
onChange={(value)=>{
|
||||
@@ -272,7 +276,6 @@ const TeamInsideMember:FC = ()=>{
|
||||
},[ state.language,roleList])
|
||||
|
||||
useEffect(() => {
|
||||
getRoleList()
|
||||
setBreadcrumb([
|
||||
{title:<Link to="/team/list">{$t('团队')}</Link>},
|
||||
{title:$t('成员')}
|
||||
@@ -280,6 +283,11 @@ const TeamInsideMember:FC = ()=>{
|
||||
manualReloadTable()
|
||||
}, [teamId]);
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
getRoleList()
|
||||
},[state.language])
|
||||
|
||||
const treeDisabledData = useMemo(()=>{ return [...allMemberIds,...allMemberSelectedDepartIds]},[allMemberIds,allMemberSelectedDepartIds])
|
||||
|
||||
return (
|
||||
@@ -302,7 +310,7 @@ const TeamInsideMember:FC = ()=>{
|
||||
title={$t("添加成员")}
|
||||
open={modalVisible}
|
||||
destroyOnClose={true}
|
||||
width={900}
|
||||
width={600}
|
||||
onCancel={() => cleanModalData()}
|
||||
maskClosable={false}
|
||||
footer={[
|
||||
@@ -329,7 +337,7 @@ const TeamInsideMember:FC = ()=>{
|
||||
const memberKeyFromModal = Array.from(selectedData)?.filter(x => allMemberIds.indexOf(x) === -1 &&selectableMemberIds.has(x)) || [];
|
||||
setAddMemberBtnDisabled((memberKeyFromModal.length === 0));
|
||||
}}
|
||||
searchPlaceholder={$t("搜索用户名、邮箱")}
|
||||
searchPlaceholder={$t("输入名称查找用户")}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
|
||||
import PageList, { PageProColumns } from "@common/components/aoplatform/PageList.tsx"
|
||||
import PageList from "@common/components/aoplatform/PageList.tsx"
|
||||
import {ActionType} from "@ant-design/pro-components";
|
||||
import {FC, useEffect, useMemo, useRef, useState} from "react";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import {App, Divider, Modal} from "antd";
|
||||
import {BasicResponse, COLUMNS_TITLE, DELETE_TIPS, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import {App, Modal} from "antd";
|
||||
import {BasicResponse, DELETE_TIPS, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import { SimpleMemberItem } from "@common/const/type.ts";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import { TEAM_TABLE_COLUMNS } from "../../const/team/const.tsx";
|
||||
import { TeamConfigFieldType, TeamConfigHandle, TeamTableListItem } from "../../const/team/type.ts";
|
||||
import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx";
|
||||
import { checkAccess } from "@common/utils/permission.ts";
|
||||
import TeamConfig from "./TeamConfig.tsx";
|
||||
@@ -131,21 +130,6 @@ const TeamList:FC = ()=>{
|
||||
})
|
||||
}
|
||||
|
||||
const operation:PageProColumns<TeamTableListItem>[] =[
|
||||
{
|
||||
title: COLUMNS_TITLE.operate,
|
||||
key: 'option',
|
||||
fixed:'right',
|
||||
btnNums:2,
|
||||
valueType: 'option',
|
||||
render: (_: React.ReactNode, entity: TeamTableListItem) => [
|
||||
<TableBtnWithPermission access="" key="view" btnType="view" navigateTo={`../inside/${entity.id}/setting`} btnTitle="查看"/>,
|
||||
<Divider type="vertical" className="mx-0" key="div2"/>,
|
||||
<TableBtnWithPermission access="system.organization.team.delete" key="delete" btnType="delete" disabled={!entity.canDelete} tooltip="服务数据清除后,方可删除" onClick={()=>{openModal('delete',entity)}} btnTitle="删除"/>,
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumb([
|
||||
{title: $t('团队')}
|
||||
@@ -173,7 +157,7 @@ const TeamList:FC = ()=>{
|
||||
id="global_team"
|
||||
className="pl-btnbase"
|
||||
ref={pageListRef}
|
||||
columns = {[...columns,...operation]}
|
||||
columns = {[...columns]}
|
||||
request = {()=>getTeamList()}
|
||||
showPagination={false}
|
||||
addNewBtnTitle={$t('添加团队')}
|
||||
@@ -207,7 +191,7 @@ const TeamList:FC = ()=>{
|
||||
}
|
||||
return res})}
|
||||
>
|
||||
<TeamConfig ref={teamConfigRef} inModal entity={modalType === 'add' ? undefined : curTeam} />
|
||||
<TeamConfig ref={teamConfigRef} entity={modalType === 'add' ? undefined : curTeam} />
|
||||
</Modal>
|
||||
</InsidePage>
|
||||
)
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @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';
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
/*
|
||||
* @Date: 2023-11-27 17:31:44
|
||||
* @LastEditors: maggieyyy
|
||||
* @LastEditTime: 2024-06-05 10:36:46
|
||||
* @FilePath: \frontend\packages\core\tailwind.config.js
|
||||
*/
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
|
||||
export default {
|
||||
|
||||
@@ -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': {},
|
||||
|
||||
@@ -231,9 +231,9 @@ const MonitorTotalPage = (props:MonitorTotalPageProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`h-full overflow-hidden pb-btnybase flex flex-col bg-[#fff]`}>
|
||||
<div className={`h-full overflow-hidden pb-btnybase flex flex-col bg-[#fff] `}>
|
||||
<ScrollableSection>
|
||||
<div className="flex items-center flex-wrap pb-[10px] px-btnbase content-before bg-MAIN_BG">
|
||||
<div className="flex items-center flex-wrap pb-[10px] px-btnbase content-before bg-MAIN_BG pr-PAGE_INSIDE_X ">
|
||||
<TimeRangeSelector
|
||||
labelSize="small"
|
||||
initialTimeButton={timeButton}
|
||||
@@ -247,7 +247,7 @@ const MonitorTotalPage = (props:MonitorTotalPageProps) => {
|
||||
</div>
|
||||
<Spin wrapperClassName={`flex-1 ${totalEmpty ?'':'overflow-auto'}`} indicator={<LoadingOutlined style={{ fontSize: 24 }} spin/>} spinning={queryBtnLoading}>
|
||||
{totalEmpty ?<Empty className="mt-[100px]" image={Empty.PRESENTED_IMAGE_SIMPLE} />:
|
||||
<div className=" h-full scroll-area">
|
||||
<div className=" h-full scroll-area pr-PAGE_INSIDE_X ">
|
||||
{/* 图表区域 */}
|
||||
<div className=" px-btnbase mt-[12px] mb-[16px] grid gap-[20px]" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(570px, 1fr))'}}>
|
||||
{/* 请求统计饼图 */}
|
||||
|
||||
@@ -10,7 +10,6 @@ import { reject } from "lodash-es";
|
||||
import { EntityItem } from "@common/const/type";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import DashboardInstruction from "./DashboardInstruction";
|
||||
import cluster from "cluster";
|
||||
|
||||
export default function Dashboard(){
|
||||
const { setBreadcrumb } = useBreadcrumb()
|
||||
@@ -47,7 +46,7 @@ export default function Dashboard(){
|
||||
|
||||
return (
|
||||
<>
|
||||
<Spin wrapperClassName="h-full w-full pr-PAGE_INSIDE_X pb-PAGE_INSIDE_B " indicator={<LoadingOutlined style={{ fontSize: 24 }} spin/>} spinning={loading}>
|
||||
<Spin wrapperClassName="h-full w-full pb-PAGE_INSIDE_B " indicator={<LoadingOutlined style={{ fontSize: 24 }} spin/>} spinning={loading}>
|
||||
{
|
||||
!loading && <>
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission";
|
||||
import { $t } from "@common/locales";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
@@ -15,13 +16,13 @@ export default function DashboardInstruction({showClusterIns, showMonitorIns}:{s
|
||||
{showClusterIns && <div className="h-[208px] w-[50%] max-w-[384px] flex flex-col items-center py-[32px] px-[24px] gap-[16px] rounded-DEFAULT bg-MENU_BG mr-[24px] justify-around">
|
||||
<p className="text-[20px] font-medium leading-[32px] text-MAIN_TEXT">{$t('集群配置')}</p>
|
||||
<p className="text-[12px] font-normal leading-[20px] text-DESC_TEXT">{$t('配置集群地址,以确保监控系统能够正确识别和连接到集群')}</p>
|
||||
<p><a href="/cluster" target="_blank">{$t('配置集群信息')}</a></p>
|
||||
<p><WithPermission access="system.settings.api_gateway.view" ><a href="/cluster" target="_blank">{$t('配置集群信息')}</a></WithPermission></p>
|
||||
</div>}
|
||||
{showMonitorIns &&
|
||||
<div className="h-[208px] w-[50%] max-w-[384px] flex flex-col items-center py-[32px] px-[24px] gap-[16px] rounded-DEFAULT bg-MENU_BG justify-around">
|
||||
<p className="text-[20px] font-medium leading-[32px] text-MAIN_TEXT">{$t('监控设置')}</p>
|
||||
<p className="text-[12px] font-normal leading-[20px] text-DESC_TEXT">{$t('设置监控报表的数据来源,设置完成之后即可获得详细的API调用统计图表。')}</p>
|
||||
<p><a href="/datasourcing" target="_blank">{$t('配置监控信息')}</a></p>
|
||||
<p><WithPermission access="system.settings.data_source.view" ><a href="/datasourcing" target="_blank">{$t('配置监控信息')}</a></WithPermission></p>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user