From 5d36585ec40ad8e735929064a62cd467bc86af1f Mon Sep 17 00:00:00 2001 From: Liujian <824010343@qq.com> Date: Mon, 12 Aug 2024 15:48:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/README.md | 4 +- frontend/README.pro.md | 8 +- frontend/package.json | 4 - .../packages/businessEntry/tailwind.config.js | 87 ---- .../src/components/aoplatform/BasicLayout.tsx | 20 - .../IntelligentPluginPublish.tsx | 179 ------- .../core/src/const/organization/const.tsx | 63 --- .../core/src/const/organization/type.ts | 27 - .../src/pages/access/AccessList.module.css | 13 - .../core/src/pages/access/AccessList.tsx | 252 ---------- .../core/src/pages/access/AccessPage.tsx | 95 ---- .../core/src/pages/auditLog/AuditLog.tsx | 2 - .../pages/organization/OrganizationConfig.tsx | 180 ------- .../pages/organization/OrganizationList.tsx | 200 -------- .../partitions/PartitionClusterConfig.tsx | 159 ------ .../src/pages/partitions/PartitionConfig.tsx | 260 ---------- .../PartitionInsideDashboardSetting.tsx | 149 ------ .../pages/partitions/PartitionInsidePage.tsx | 81 --- .../src/pages/partitions/PartitionList.tsx | 163 ------- .../src/pages/system/SystemInsideAccess.tsx | 134 ----- .../src/pages/system/SystemInsideMember.tsx | 327 ------------- .../authority/SystemAuthorityConfig.tsx | 250 ---------- .../system/authority/SystemAuthorityView.tsx | 29 -- .../authority/SystemInsideAuthority.tsx | 211 -------- .../system/myService/MyServiceInsideApi.tsx | 191 -------- .../myService/MyServiceInsideConfig.tsx | 461 ------------------ .../myService/MyServiceInsideDocument.tsx | 146 ------ .../system/myService/MyServiceInsideMenu.tsx | 51 -- .../myService/SystemInsideMyService.tsx | 205 -------- .../system/subSubscribe/SubServiceDetail.tsx | 130 ----- ...SubSubscribeApprovalDetailModalContent.tsx | 108 ---- .../subSubscribe/SystemInsideSubService.tsx | 278 ----------- .../upstream/SystemInsideUpstream.module.css | 6 - .../upstream/SystemInsideUpstreamConfig.tsx | 257 ---------- .../upstream/SystemInsideUpstreamList.tsx | 178 ------- .../core/src/pages/team/TeamInsideAccess.tsx | 133 ----- .../packages/core/src/pages/user/UserList.tsx | 328 ------------- .../packages/core/src/pages/user/UserPage.tsx | 264 ---------- .../market/src/const/serviceHub/type.ts | 1 + .../src/pages/serviceHub/ServiceHubDetail.tsx | 6 +- frontend/packages/market/tailwind.config.js | 86 ---- 41 files changed, 7 insertions(+), 5719 deletions(-) delete mode 100644 frontend/packages/businessEntry/tailwind.config.js delete mode 100644 frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginPublish.tsx delete mode 100644 frontend/packages/core/src/const/organization/const.tsx delete mode 100644 frontend/packages/core/src/const/organization/type.ts delete mode 100644 frontend/packages/core/src/pages/access/AccessList.module.css delete mode 100644 frontend/packages/core/src/pages/access/AccessList.tsx delete mode 100644 frontend/packages/core/src/pages/access/AccessPage.tsx delete mode 100644 frontend/packages/core/src/pages/organization/OrganizationConfig.tsx delete mode 100644 frontend/packages/core/src/pages/organization/OrganizationList.tsx delete mode 100644 frontend/packages/core/src/pages/partitions/PartitionClusterConfig.tsx delete mode 100644 frontend/packages/core/src/pages/partitions/PartitionConfig.tsx delete mode 100644 frontend/packages/core/src/pages/partitions/PartitionInsideDashboardSetting.tsx delete mode 100644 frontend/packages/core/src/pages/partitions/PartitionInsidePage.tsx delete mode 100644 frontend/packages/core/src/pages/partitions/PartitionList.tsx delete mode 100644 frontend/packages/core/src/pages/system/SystemInsideAccess.tsx delete mode 100644 frontend/packages/core/src/pages/system/SystemInsideMember.tsx delete mode 100644 frontend/packages/core/src/pages/system/authority/SystemAuthorityConfig.tsx delete mode 100644 frontend/packages/core/src/pages/system/authority/SystemAuthorityView.tsx delete mode 100644 frontend/packages/core/src/pages/system/authority/SystemInsideAuthority.tsx delete mode 100644 frontend/packages/core/src/pages/system/myService/MyServiceInsideApi.tsx delete mode 100644 frontend/packages/core/src/pages/system/myService/MyServiceInsideConfig.tsx delete mode 100644 frontend/packages/core/src/pages/system/myService/MyServiceInsideDocument.tsx delete mode 100644 frontend/packages/core/src/pages/system/myService/MyServiceInsideMenu.tsx delete mode 100644 frontend/packages/core/src/pages/system/myService/SystemInsideMyService.tsx delete mode 100644 frontend/packages/core/src/pages/system/subSubscribe/SubServiceDetail.tsx delete mode 100644 frontend/packages/core/src/pages/system/subSubscribe/SubSubscribeApprovalDetailModalContent.tsx delete mode 100644 frontend/packages/core/src/pages/system/subSubscribe/SystemInsideSubService.tsx delete mode 100644 frontend/packages/core/src/pages/system/upstream/SystemInsideUpstream.module.css delete mode 100644 frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamConfig.tsx delete mode 100644 frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamList.tsx delete mode 100644 frontend/packages/core/src/pages/team/TeamInsideAccess.tsx delete mode 100644 frontend/packages/core/src/pages/user/UserList.tsx delete mode 100644 frontend/packages/core/src/pages/user/UserPage.tsx delete mode 100644 frontend/packages/market/tailwind.config.js diff --git a/frontend/README.md b/frontend/README.md index 921d7f2..68a7459 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -13,6 +13,4 @@ `pnpm install` ## 编译 - 仅编译管理后台(打包目录为dist):`pnpm run build` - 仅编译租户端(打包目录为tenant_dist):`pnpm run build:tenant` - 同时编译管理后台和租户端:`pnpm run build:all` \ No newline at end of file + `pnpm run build` \ No newline at end of file diff --git a/frontend/README.pro.md b/frontend/README.pro.md index e080d34..93bfd81 100644 --- a/frontend/README.pro.md +++ b/frontend/README.pro.md @@ -12,10 +12,6 @@ ## 编译 ### 开源版本 - 仅编译管理后台(打包目录为dist):`pnpm run build` - 仅编译租户端(打包目录为tenant_dist):`pnpm run build:tenant` - 同时编译管理后台和租户端:`pnpm run build:all` + `pnpm run build` ### 企业版本 - 仅编译管理后台(打包目录为dist):`pnpm run build:pro` - 仅编译租户端(租户端暂时不区分企业版和开源版,打包目录为tenant_dist):`pnpm run build:tenant` - 同时编译管理后台和租户端:`pnpm run build:pro:all` \ No newline at end of file + `pnpm run build:pro` \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 515a8d1..bcd484a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,16 +8,12 @@ "description": "", "scripts": { "test": "jest", - "build:all": "set NODE_OPTIONS=--max-old-space-size=16384 && lerna run build --scope=core --scope=market --stream", - "build:pro:all": "set NODE_OPTIONS=--max-old-space-size=16384 && lerna run build --scope=businessEntry --scope=market --stream", "build": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=core --stream --verbose ", "build:pro": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=business-entry --stream --verbose ", - "build:tenant": "set NODE_OPTIONS=--max-old-space-size=16384 && lerna run build --scope=market --stream", "serve": "lerna run preview --parallel", "serve:remotes": "lerna run serve --scope=remote --parallel", "dev": "lerna run dev --scope=core --stream", "dev:pro": "lerna run dev --scope=business-entry --stream", - "dev:tenant": "lerna run dev --scope=market --stream", "stop": "kill-port --port 5000,5001" }, "keywords": [], diff --git a/frontend/packages/businessEntry/tailwind.config.js b/frontend/packages/businessEntry/tailwind.config.js deleted file mode 100644 index 75a018c..0000000 --- a/frontend/packages/businessEntry/tailwind.config.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * @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 { - important:true, - content: [ - `./index.html`, - `../*/src/**/*.{js,ts,jsx,tsx}`, - - ], - theme: { - extend: { - width: { - INPUT_NORMAL: '100%', - // INPUT_NORMAL: '346px', - INPUT_LARGE: '508px', - GROUP: '240px', - SEARCH: '276px', - LOG: '254px' - }, - minHeight:{ - TEXTAREA:'68px' - }, - borderRadius: { - DEFAULT: 'var(--border-radius)', - SEARCH_RADIUS: '50px' - }, - boxShadow:{ - SCROLL: '0 2px 2px #0000000d', - SCROLL_TOP:' 0 -2px 2px -2px var(--border-color)' - }, - colors: { - DISABLE_BG: 'var(--disabled-background-color)', - MAIN_TEXT: 'var(--text-color)', - MAIN_HOVER_TEXT: 'var(--text-hover-color)', - SECOND_TEXT:'var(--disabled-text-color)', - MAIN_BG: 'var(--background-color)', - MENU_BG:'var(--MENU-BG-COLOR)', - 'bar-theme': 'var(--bar-background-color)', - BORDER: 'var(--border-color)', - NAVBAR_BTN_BG: 'var(--item-active-background-color)', - MAIN_DISABLED_BG: 'var(--disabled-background-color)', - theme: 'var(--primary-color)', - DESC_TEXT: 'var(--TITLE_TEXT)', - HOVER_BG: 'var(--item-hover-background-color)', - guide_cluster: '#ee6760', - guide_upstream: '#f9a429', - guide_api: '#71d24d', - guide_publishApi: '#5884ff', - guide_final: '#915bf9', - table_text: 'var(--table-text-color)', - status_success:'#138913', - status_fail:"#ff3b30", - status_update:"#03a9f4", - status_pending:"#ffa500", - status_offline:"#8f8e93", - A_HOVER:'var(--button-primary-hover-background-color)' - }, - spacing: { - mbase: 'var(--FORM_SPAN)', - label: '12px', // 选择器和label之间的间距,待删 - btnbase: 'var(--LAYOUT_MARGIN)', // x方向的间距 - btnybase: 'var(--LAYOUT_MARGIN)', // y轴方向的间距 - btnrbase: '20px', // 页面最右侧边距20px - formtop: 'var(--FORM_SPAN)', - icon: '5px', - blockbase: '40px', - DEFAULT_BORDER_RADIUS: 'var(--border-radius)', - TREE_TITLE:'var(--small-padding) var(--LAYOUT_PADDING);' - }, - borderColor: { - 'color-base': 'var(--border-color)' - } - } - }, - plugins: [], - corePlugins: { - preflight: false, - }, - } - - \ No newline at end of file diff --git a/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx b/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx index 407c9e9..7446e5a 100644 --- a/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx +++ b/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx @@ -35,18 +35,11 @@ const themeToken = { const navigator = useNavigate() const location = useLocation() const currentUrl = location.pathname - const query =new URLSearchParams(useLocation().search) - const [isServiceHub,setIsServiceHub] = useState(false) - const [,setIsRentMng] = useState(false) - const [isMng,setIsMng] = useState(false) const { accessData,checkPermission} = useGlobalContext() const [pathname, setPathname] = useState(currentUrl); const mainPage = project === 'core' ?'/service/list':'/serviceHub/list' useEffect(() => { - setIsServiceHub(currentUrl.includes('/serviceHub')) - setIsRentMng(currentUrl.includes('/tenantManagement')) - setIsMng(project === 'core' && !currentUrl.includes('/serviceHub') && !currentUrl.includes('/tenantManagement')) if(currentUrl === '/'){ navigator(mainPage) } @@ -87,20 +80,7 @@ const themeToken = { // 返回处理后的数据 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]); - - - - const openServiceHub =()=>{ - isMng ? window.open(`/serviceHub/list`,'_blank') : navigator('/serviceHub/list') - } - - const backToPage =()=>{ - // const backUrl = query.get('callbackUrl') - // navigator(backUrl&& backUrl !== 'null' ?backUrl : '/') - isServiceHub?window.open(`/tenantManagement/list`,'_blank') : navigator('/serviceHub/list') - } - const { modal,message } = App.useApp() const { dispatch,resetAccess,getGlobalAccessData} = useGlobalContext() const [userInfo,setUserInfo] = useState() diff --git a/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginPublish.tsx b/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginPublish.tsx deleted file mode 100644 index d219d17..0000000 --- a/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginPublish.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import {forwardRef, useEffect, useImperativeHandle, useState} from "react"; -import {DynamicPublishCluster, StatusColorClass} from "./IntelligentPluginList.tsx"; -import {App, Col, Row, Table} from "antd"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; - -export type IntelligentPluginPublishProps = { - entity:{[k:string]:unknown} - moduleId:string -} - -export type IntelligentPluginPublishHandle = { - offline:()=>Promise - online:()=>Promise -} - -export type DynamicPublish = { - code:number, - msg:string, - data:{ - success:Array, - fail:Array - } -} - -export const IntelligentPluginPublish = forwardRef((props,ref)=>{ - const { message } = App.useApp() - const { entity, moduleId} = props - const [showNoCluster, setShowNoCluster]= useState(false) - const [selectedCluster, setSelectedCluster] = useState([]) - const [selectedClusterUuid, setSelectedClusterUuid] = useState([]) - const [partitionDataSource, setPartitionDataSource] = useState(entity?.partitions) - const {fetchData} = useFetch() - const [startCheckClusterNum,setStartCCN] = useState(false) - const apiColumns = [ - { - title:'环境', - dataIndex:'title', - copyable: true, - ellipsis:true - }, - { - title:'状态', - dataIndex:'status', - render:(dom, entity)=> { - return {(entity.status as string)} - }, - }, - { - title:'更新人', - dataIndex:['updater','name'], - width:88 - }, - { - title:'更新时间', - dataIndex:'updateTime', - width:182, - } - ] - - const online :()=>Promise = ()=>{ - setStartCCN(true) - if (!selectedCluster.length) { - setShowNoCluster(!selectedCluster.length) - return Promise.reject('操作失败') - } - - return fetchData>(`dynamic/${moduleId}/online`, { - method: 'PUT', - eoParams:{id:entity.id}, - eoBody: ({partitions:selectedClusterUuid}), - }).then(response => { - const {code, msg} = response - if (code === STATUS_CODE.SUCCESS) { - message.success(msg || '操作成功!') - return Promise.resolve(true) - } else { - message.error(msg || '操作失败') - return Promise.reject(msg || '操作失败') - } - }).catch((errorInfo)=> Promise.reject(errorInfo)) - } - - const offline :()=>Promise = ()=>{ - setStartCCN(true) - if (!selectedCluster.length) { - setShowNoCluster(!selectedCluster.length) - return Promise.reject('操作失败') - } - - return fetchData>(`dynamic/${moduleId}/offline`, { - method: 'PUT', - eoParams:{id:entity.id}, - eoBody: ({partitions:selectedClusterUuid}), - }).then(response => { - const {code, msg} = response - if (code === STATUS_CODE.SUCCESS) { - message.success(msg || '操作成功!') - return Promise.resolve(true) - } else { - message.error(msg || '操作失败') - return Promise.reject(msg || '操作失败') - } - }).catch((errorInfo)=> Promise.reject(errorInfo)) - } - - useImperativeHandle(ref, ()=>({ - online,offline - }) - ) - - // rowSelection object indicates the need for row selection - const rowSelection = { - selectedRowKeys:selectedClusterUuid, - onChange: (selectedRowKeys: React.Key[], selectedRows: {[k:string]:unknown}[]) => { - setStartCCN(true) - setSelectedCluster(selectedRows?.map((x)=>x.title)) - setSelectedClusterUuid(selectedRows?.map((x)=>x.name)) - } - }; - - const handleRowClick = (entity:DynamicPublishCluster)=>{ - setSelectedCluster(prev=>prev.indexOf(entity.title) === -1 ? [...prev, entity.title]:prev.filter(x=>x !== entity.title)) - setSelectedClusterUuid(prev=>prev.indexOf(entity.name) === -1 ? [...prev, entity.name]:prev.filter(x=>x !== entity.name)) - } - - useEffect(()=>{ - startCheckClusterNum && setShowNoCluster(selectedClusterUuid.length === 0) - },[selectedClusterUuid]) - - return ( - <> - - 名称: - {entity.title ?? '-'} - - - - ID: - {entity.id ??'-'} - - - - 描述: - {entity.description ??'-'} - - - - ({ - onClick: () => { - handleRowClick(record); - } - })} - /> - - {showNoCluster && - -

请至少选中一个集群

- } - - -
已选择 {selectedCluster.length } 项{selectedCluster.length > 0 && :{selectedCluster.join(',')}}
- - - ) -}) \ No newline at end of file diff --git a/frontend/packages/core/src/const/organization/const.tsx b/frontend/packages/core/src/const/organization/const.tsx deleted file mode 100644 index 0063bd6..0000000 --- a/frontend/packages/core/src/const/organization/const.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * @Date: 2024-04-19 15:22:46 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-05-14 11:01:34 - * @FilePath: \frontend\packages\core\src\const\organization\const.tsx - */ - - -import { ProColumns } from "@ant-design/pro-components"; -import { OrganizationTableListItem } from "./type"; - -export const ORGANIZATION_TABLE_COLUMNS: ProColumns[] = [ - { - title: '名称', - dataIndex: 'name', - copyable: true, - ellipsis:true, - width:160, - fixed:'left', - sorter: (a,b)=> { - return a.name.localeCompare(b.name) - }, - }, - { - title: 'ID', - dataIndex: 'id', - width: 140, - copyable: true, - ellipsis:true - }, - { - title: '描述', - dataIndex: 'description', - copyable: true, - ellipsis:true - }, - { - title: '环境权限', - dataIndex: 'partition', - ellipsis:true, - renderText:(_,entity:OrganizationTableListItem)=>(entity.partition?.map(x=>x.name).join(',') || '-') - }, - { - title: '负责人', - dataIndex: ['master','name'], - ellipsis: true, - width:108, - filters: true, - onFilter: true, - valueType: 'select', - filterSearch: true - }, - { - title: '创建时间', - key: 'createTime', - dataIndex: 'createTime', - ellipsis: true, - width:182, - sorter: (a,b)=> { - return a.createTime.localeCompare(b.createTime) - }, - }, -]; \ No newline at end of file diff --git a/frontend/packages/core/src/const/organization/type.ts b/frontend/packages/core/src/const/organization/type.ts deleted file mode 100644 index 14abe84..0000000 --- a/frontend/packages/core/src/const/organization/type.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * @Date: 2024-02-04 11:05:42 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-03-04 18:34:13 - * @FilePath: \frontend\packages\core\src\const\organization\type.ts - */ -import { EntityItem } from "@common/const/type"; - -export type OrganizationFieldType = { - name?: string; - id?: string; - description?: string; - master?:string; - partitions?:Array - prefix?:string -}; - -export type OrganizationTableListItem = { - id:string; - name: string; - description:string; - master:EntityItem; - partition:EntityItem[] - createTime:string; - updateTime:string; - canDelete:boolean -}; diff --git a/frontend/packages/core/src/pages/access/AccessList.module.css b/frontend/packages/core/src/pages/access/AccessList.module.css deleted file mode 100644 index e02b518..0000000 --- a/frontend/packages/core/src/pages/access/AccessList.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.collapse-without-padding{ - :global .ant-collapse-header{ - background:#f7f8fa; - height:40px; - border-radius: 4px; - } - :global .ant-collapse-content-box{ - padding:0px !important; - } - :global .ant-list-footer{ - padding:4px 0; - } -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/access/AccessList.tsx b/frontend/packages/core/src/pages/access/AccessList.tsx deleted file mode 100644 index ea40807..0000000 --- a/frontend/packages/core/src/pages/access/AccessList.tsx +++ /dev/null @@ -1,252 +0,0 @@ -import { App, Collapse, List, Select} from "antd"; -import styles from './AccessList.module.css' -import { DownOutlined, UpOutlined} from "@ant-design/icons"; -import {DefaultOptionType} from "antd/es/cascader"; -import {useEffect, useRef, useState} from "react"; -import {debounce} from "lodash-es"; -import {useOutletContext, useParams} from "react-router-dom"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { BasicResponse, STATUS_CODE } from "@common/const/const.ts"; -import { useFetch } from "@common/hooks/http.ts"; -import { PermissionOptionType } from "./AccessPage.tsx"; -import TagWithPermission from "@common/components/aoplatform/TagWithPermission.tsx"; - -export type PermissionType = { - system : PermissionListItem[] - team : PermissionListItem[] - project : PermissionListItem[] -} - -export type PermissionListItem = { - access:string - name:string - description:string - grant:AccessOptionItem[] - key?:string - children:Array<{key:string,label:string,children:JSX.Element}> -} - -export type AccessOptionItem = { - key:string, label:string, name:string, tag:string, type:string -} - -const AccessRoleOrder: {[key: string]: number} = { - '特殊角色': 1, - '用户组': 2, - '用户': 3, - '成员': 4, - }; - -const AddNewMember = ({requestOption,addNewItem,selectedMember,permissionStr}:{permissionStr:string,requestOption: (keyword?:string)=>Promise<{options:AccessOptionItem[]}>,addNewItem:(member:DefaultOptionType)=>Promise>,selectedMember:string[]})=>{ - const [keyword,setKeyword] = useState() - const [oriOptions,setOriOptions] = useState() - const [options,setOptions] = useState([]) - const [value, setValue] = useState() - const onSelect = async (member:DefaultOptionType)=>{ - setValue(member.value as string) - if(addNewItem){ - const res = await addNewItem(member) - res && setValue(undefined) - } - } - - - const getGroup = (objArr: Array)=> { - const map = new Map(); - for (const obj of objArr) { - const tag = obj.tag; - let options = map.get(tag); - if (!options) { - options = []; - map.set(tag, options); - } - options.push({ - label: obj.label, - value: obj.key, - disabled:selectedMember.indexOf(obj.key) !== -1 - }); - } - - const result = Array.from(map.entries())?.map(([tag, options]) => ({ - label: tag, - options, - })); - return result; - } - - useEffect(()=>{ - const newOpt = oriOptions ? getGroup(oriOptions) : [] - setTimeout(()=>{setOptions(newOpt)}) - },[oriOptions,selectedMember]) - - const getOptionList = (curKeyword?:string)=>{ - requestOption(curKeyword ?? keyword).then((res)=>{ - setOriOptions(res.options) - }) - } - - useEffect(() => { - getOptionList() - }, []); - return ( - - - - label="组织ID" - name="id" - extra="组织ID(org_id)可用于检索组织,一旦保存无法修改。" - rules={[{ required: true, message: '必填项' ,whitespace:true }]} - > - - - - - label="描述" - name="description" - > - - - - - label="负责人" - name="master" - extra="负责人对组织内的团队、服务、成员有管理权限" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="组织请求前缀" - name="prefix" - extra="该请求前缀将会拼接到API请求路径中,格式为:{协议}{主机地址}{组织前缀}{环境前缀}{系统前缀}{API请求路径}" - rules={[ - { - validator: validateUrlSlash, - }]} - > - - - - - label="环境权限" - name="partitions" - rules={[{ required: true, message: '必填项' }]} - > - - - - - - - ) -}) -export default OrganizationConfig \ No newline at end of file diff --git a/frontend/packages/core/src/pages/organization/OrganizationList.tsx b/frontend/packages/core/src/pages/organization/OrganizationList.tsx deleted file mode 100644 index 5721817..0000000 --- a/frontend/packages/core/src/pages/organization/OrganizationList.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import PageList from "@common/components/aoplatform/PageList.tsx" -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {App, Divider, Modal} from "antd"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import { OrganizationFieldType, OrganizationTableListItem } from "../../const/organization/type.ts"; -import { ORGANIZATION_TABLE_COLUMNS } from "../../const/organization/const.tsx"; -import { SimpleMemberItem } from "@common/const/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 OrganizationConfig, { OrganizationConfigHandle } from "./OrganizationConfig.tsx"; -import { PartitionItem } from "@common/const/type.ts"; - -const OrganizationList:FC = ()=>{ - const [searchWord, setSearchWord] = useState('') - const { setBreadcrumb } = useBreadcrumb() - const { modal,message } = App.useApp() - const pageListRef = useRef(null); - const [memberValueEnum, setMemberValueEnum] = useState<{[k:string]:{text:string}}>({}) - const {fetchData} = useFetch() - const {accessData} = useGlobalContext() - const orgConfigRef = useRef(null) - const [curOrg, setCurOrg] = useState({}) - const [modalVisible, setModalVisible] = useState(false) - const [modalType, setModalType] = useState<'add'|'edit'>('add') - - const getOrganizationList = ()=>{ - //console.log('此处应该获取最新列表',searchWord) - return fetchData>('manager/organizations',{method:'GET',eoTransformKeys:['update_time','can_delete','create_time'],eoParams:{keyword:searchWord}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - return {data:data.organizations, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - const deleteOrganization = (id:string)=>{ - return new Promise((resolve, reject)=>{ - fetchData>(`manager/organization`,{method:'DELETE',eoParams:{id}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=>{ - reject(errorInfo || '操作失败') - }) - }) - } - - const openModal = async (type:'add'|'edit'|'delete',entity?:OrganizationTableListItem)=>{ - let title:string = '' - let content:string | React.ReactNode= '' - switch (type){ - case 'add':{ - setModalType('add') - setModalVisible(true) - return;} - case 'edit':{ - message.loading('正在加载数据') - const {code,data,msg} = await fetchData>('manager/organization',{method:'GET',eoParams:{id:entity!.id},eoTransformKeys:['create_time','master_id','update_time']}) - message.destroy() - if(code === STATUS_CODE.SUCCESS){ - setCurOrg({...data.organization,partitions:data.organization.partitions?.map((x:PartitionItem)=>(x.id)),master:data.organization.master.id}) - setModalVisible(true) - }else{ - message.error(msg || '操作失败') - return - } - setModalType('edit') - return;} - case 'delete': - title='删除' - content='该数据删除后将无法找回,请确认是否删除?' - break; - } - - modal.confirm({ - title, - content, - onOk:()=>{ - return deleteOrganization(entity!.id).then((res)=>{if(res === true) pageListRef.current?.reload()}) - }, - okText:'确认', - okButtonProps:{ - disabled : !checkAccess('system.organization.self.delete', accessData) - }, - cancelText:'取消', - closable:true, - icon:<> - }) - } - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 107, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: OrganizationTableListItem) => [ - openModal('edit',entity)} btnTitle="编辑"/>, - , - {openModal('delete',entity)}} btnTitle="删除"/>, - ], - } - ] - - const getMemberList = async ()=>{ - setMemberValueEnum({}) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.members?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setMemberValueEnum(tmpValueEnum) - }else{ - message.error(msg || '操作失败') - } - } - - useEffect(() => { - getMemberList() - setBreadcrumb([ - { - title: '组织'} - ]) - }, []); - - - const columns = useMemo(()=>{ - return ORGANIZATION_TABLE_COLUMNS.map(x=>{if(x.filters &&(x.dataIndex as string[])?.indexOf('master') !== -1 ){x.valueEnum = memberValueEnum} return x}) - },[memberValueEnum]) - - - const manualReloadTable = () => { - pageListRef.current?.reload() - }; - - - return ( - <> - getOrganizationList()} - addNewBtnTitle="添加组织" - addNewBtnAccess="system.organization.self.add" - tableClickAccess="system.organization.self.edit" - searchPlaceholder="输入名称、ID、负责人查找组织" - onAddNewBtnClick={()=>{openModal('add')}} - onSearchWordChange={(e)=>{setSearchWord(e.target.value)}} - onRowClick={(row:OrganizationTableListItem)=>openModal('edit',row)} - /> - { - if(!open){ - setModalVisible(false) - setCurOrg({} as unknown as OrganizationFieldType) - } - }} - onCancel={() => {setModalVisible(false)}} - okText="确认" - okButtonProps={{disabled : !checkAccess( modalType === 'add' ? 'system.organization.self.add':'system.organization.self.edit', accessData)}} - cancelText='取消' - closable={true} - onOk={()=>orgConfigRef.current?.save().then((res)=>{ - if(res){ - setModalVisible(false) - manualReloadTable() - } - return res})} - > - - - {/* orgConfigRef.current?.save()?.then((res)=>{res && pageListRef.current?.reload();return res})} submitAccess={curOrgId === undefined ? } > - */} - - ) - -} -export default OrganizationList \ No newline at end of file diff --git a/frontend/packages/core/src/pages/partitions/PartitionClusterConfig.tsx b/frontend/packages/core/src/pages/partitions/PartitionClusterConfig.tsx deleted file mode 100644 index ee46af5..0000000 --- a/frontend/packages/core/src/pages/partitions/PartitionClusterConfig.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import {forwardRef, useEffect, useImperativeHandle, useReducer, useState} from "react"; -import {App, Form, Input, Table} from "antd"; -import {useFetch} from "@common/hooks/http.ts"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { PartitionClusterFieldType, ClusterConfigHandle, ClusterConfigProps, PartitionClusterNodeTableListItem, PartitionClusterNodeModalTableListItem } from "../../const/partitions/types.ts"; -import { useParams } from "react-router-dom"; -import { RouterParams } from "@core/components/aoplatform/RenderRoutes.tsx"; -import { NODE_MODAL_COLUMNS } from "../../const/partitions/const.tsx"; -import { v4 as uuidv4} from 'uuid' -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; - -const formReducer = (state: PartitionClusterFieldType, action: { type: 'UPDATE_FIELD'; value: PartitionClusterFieldType }) => { - switch (action.type) { - case 'UPDATE_FIELD': - return { ...action.value }; - default: - return state; - } -}; - -export const PartitionClusterConfig = forwardRef((props, ref)=>{ - const {clusterId,mode,initFormValue} = props - const { message } = App.useApp() - const [form] = Form.useForm(); - const [formData, dispatch] = useReducer(formReducer, {}); - const [dataSource,setDataSource] = useState([]) - const {fetchData} = useFetch() - const {partitionId} = useParams() - - const save:()=>Promise = ()=>{ - // eslint-disable-next-line no-async-promise-executor - return new Promise( async (resolve, reject)=>{ - let body - if(mode === 'edit') { - body = await form.validateFields() - }else{ - body = { - name:formData.name, - description:formData.description, - managerAddress: formData.address - } - } - - fetchData>('partition/cluster',{ - method:mode === 'edit' ? 'PUT':'POST' , - eoBody:(body), - eoTransformKeys:['managerAddress'], - eoParams:(mode === 'edit' ? {id:clusterId}:{partition:partitionId}) - } - ).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const check:()=>Promise = ()=>{ - setDataSource([]) - return new Promise((resolve, reject)=>{ - form.validateFields().then((value)=>{ - dispatch({type:'UPDATE_FIELD',value}) - fetchData>('partition/cluster/check',{method:'POST',eoBody:({address: value.address}),eoTransformKeys:['manager_address','service_address','peer_address']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setDataSource(data.nodes) - resolve(true) - }else{ - form.setFields([{ - name:'address',errors:[msg] - }]) - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - useImperativeHandle(ref, ()=>({ - save, check - }) - ) - - useEffect(() => { - if(mode === 'edit' && initFormValue && Object.keys(initFormValue).length > 0 ){ - form.setFieldsValue(initFormValue) - }else{ - form.setFieldsValue({id:uuidv4()}) - - } - }, [partitionId]); - - return (<> - { mode !== 'result' ? - -
- - label="集群名称" - name="name" - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - - - - - - - - - { mode !== 'edit' && - - - } - -
- : -
-

检查通过。该集群有一个节点

-
- - } - ) -}) diff --git a/frontend/packages/core/src/pages/partitions/PartitionConfig.tsx b/frontend/packages/core/src/pages/partitions/PartitionConfig.tsx deleted file mode 100644 index 2adda1c..0000000 --- a/frontend/packages/core/src/pages/partitions/PartitionConfig.tsx +++ /dev/null @@ -1,260 +0,0 @@ -import {forwardRef, useEffect, useImperativeHandle, useReducer, useState} from "react"; -import {App, Button, Divider, Form, Input, Row, Table} from "antd"; -import {Link, useNavigate, useParams} from "react-router-dom"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import { PartitionClusterFieldType, PartitionClusterNodeModalTableListItem, PartitionClusterNodeTableListItem, PartitionConfigFieldType } from "../../const/partitions/types.ts"; -import { v4 as uuidv4} from 'uuid' -import { validateUrlSlash } from "@common/utils/validate.ts"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext.tsx"; -import { usePartitionContext } from "../../contexts/PartitionContext.tsx"; -import { NODE_MODAL_COLUMNS } from "../../const/partitions/const.tsx"; - -export type PartitionConfigProps = { - mode:'config' | 'retry' | 'result' | 'edit', -} -export interface PartitionConfigHandle{ - save:()=>Promise - check:()=>Promise -} - -const formReducer = (state: PartitionClusterFieldType, action: { type: 'UPDATE_FIELD'; value: PartitionClusterFieldType }) => { - switch (action.type) { - case 'UPDATE_FIELD': - return { ...action.value }; - default: - return state; - } -}; - - -const PartitionConfig = forwardRef((props,ref)=> { - const {mode} = props - const { message,modal } = App.useApp() - const { partitionId } = useParams(); - const [ onEdit, setOnEdit] = useState(!!partitionId) - const [ form ] = Form.useForm(); - const { fetchData} = useFetch() - const [formData, dispatch] = useReducer(formReducer, {}); - const navigate = partitionId === undefined ? ()=>{} : useNavigate(); - const { setBreadcrumb } = partitionId === undefined ?{setBreadcrumb:()=>{}} : useBreadcrumb() - const { setPartitionInfo} = partitionId === undefined ?{setPartitionInfo:()=>{}}: usePartitionContext() - const [dataSource,setDataSource] = useState([]) - const [canDelete, setCanDelete] = useState(false) - useImperativeHandle(ref, ()=>({ - save:onFinish, - check - })) - - const onFinish =async () => { - // eslint-disable-next-line no-async-promise-executor - let body - if(mode === 'edit') { - body = await form.validateFields() - }else{ - body = {...formData - } - } - - return fetchData>('partition',{method:partitionId === undefined? 'POST' : 'PUT',eoTransformKeys:['managerAddress'],eoBody:({...body}),...(partitionId !== undefined?{eoParams:{id:partitionId}}:{})}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - setPartitionInfo(data.partition) - return Promise.resolve(true) - }else{ - message.error(msg || '操作失败') - return Promise.reject(msg || '操作失败') - } - }).catch((errInfo)=>Promise.reject(errInfo)) - }; - - - const check:()=>Promise = ()=>{ - setDataSource([]) - return form.validateFields().then((value)=>{ - dispatch({type:'UPDATE_FIELD',value}) - return fetchData>('partition/cluster/check',{method:'POST',eoBody:({address: value.managerAddress}),eoTransformKeys:['manager_address','service_address','peer_address']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setDataSource(data.nodes) - return Promise.resolve(true) - }else{ - form.setFields([{ - name:'address',errors:[msg] - }]) - message.error(msg || '操作失败') - return Promise.reject(msg || '操作失败') - } - }).catch((errorInfo)=> Promise.reject(errorInfo)) - }).catch((err)=> {form.scrollToField(err.errorFields[0].name[0]); return Promise.reject(err)}) - } - - // 获取表单默认值 - const getPartitionInfo = () => { - fetchData>('partition',{method:'GET',eoParams:{id:partitionId}, eoTransformKeys:['can_delete']},).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTimeout(()=>{form.setFieldsValue(data.partition)},0) - setCanDelete(data.partition.canDelete) - }else{ - message.error(msg || '操作失败') - } - }) - }; - - const deletePartitionModal = async ()=>{ - modal.confirm({ - title:'删除', - content:'该数据删除后将无法找回,请确认是否删除?', - onOk:()=> { - return deletePartition() - }, - width:600, - okText:'确认', - okButtonProps:{ - danger:true - }, - cancelText:'取消', - closable:true, - icon:<> - }) - } - - const deletePartition = ()=>{ - fetchData>('partition',{method:'DELETE',eoParams:{id:partitionId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - navigate('/partition/list') - }else{ - message.error(msg || '操作失败') - } - }) - } - - useEffect(() => { - if (partitionId !== undefined) { - setBreadcrumb([ - {title:部署管理}, - {title:'环境设置'} - ]) - setOnEdit(true); - getPartitionInfo(); - } else { - setOnEdit(false); - form.setFieldsValue({id:uuidv4()}); // 清空 initialValues - } - - return (form.setFieldsValue({})) - }, [partitionId]); - - return ( - <> -
- { mode !== 'result' ? - -
-
- - label="环境名称" - name="name" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="环境 ID" - name="id" - extra="环境 ID(partition_id)可用于检索环境,一旦保存无法修改。" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="环境请求前缀" - name="prefix" - extra="该请求前缀将会拼接到API请求路径中,格式为:{协议}{主机地址}{组织前缀}{环境前缀}{服务前缀}{API请求路径}" - rules={[ - { - validator: validateUrlSlash, - }]} - > - - - - {!onEdit && - - label="集群地址" - name="managerAddress" - rules={[{ required: true, message: '必填项' }]} - > - {/* */} - - {/* */} - {/* */} - } - - - label="描述" - name="description" - > - - - - { onEdit && - - - - - } -
- {onEdit && -
- - -

删除环境:删除操作不可恢复,请谨慎操作!

-
- -
-
- } - -
- : -
-

检查通过。该集群有一个节点

-
- - } - - - ) -}) -export default PartitionConfig \ No newline at end of file diff --git a/frontend/packages/core/src/pages/partitions/PartitionInsideDashboardSetting.tsx b/frontend/packages/core/src/pages/partitions/PartitionInsideDashboardSetting.tsx deleted file mode 100644 index a041661..0000000 --- a/frontend/packages/core/src/pages/partitions/PartitionInsideDashboardSetting.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { App, Form, Input, Select, Button, Divider, Row } from "antd"; -import { useState, useEffect } from "react"; -import { useParams, Link } from "react-router-dom"; -import { RouterParams } from "@core/components/aoplatform/RenderRoutes"; -import WithPermission from "@common/components/aoplatform/WithPermission"; -import { BasicResponse, STATUS_CODE } from "@common/const/const"; -import { PartitionDashboardConfigFieldType } from "../../const/partitions/types"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext"; -import { useFetch } from "@common/hooks/http"; -import { DASHBOARD_SETTING_DRIVER_OPTION_LIST } from "../../const/partitions/const"; - -export default function PartitionInsideDashboardSetting(){ - - const { message } = App.useApp() - const { partitionId } = useParams(); - const [ form ] = Form.useForm(); - const { setBreadcrumb } = useBreadcrumb() - const { fetchData} = useFetch() - const [, forceUpdate] = useState({}); - const onFinish = () => { - form.validateFields().then((value)=>{ - fetchData>('partition/monitor',{method: 'POST',eoBody:(value),eoParams:{partition:partitionId}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - const config = data.info.config - form.setFieldsValue({...data.info,config:{addr:config.addr || '', org:config.org || '', token:config.token || ''}}) - message.success(msg || '操作成功!') - }else{ - message.error(msg || '操作失败') - } - }) - }) - } - - // 获取表单默认值 - const getDashboardSetting = () => { - fetchData>('partition/monitor',{method:'GET',eoParams:{partition:partitionId}},).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - const config = data.info.config - form.setFieldsValue({...data.info,config:{addr:config.addr || '', org:config.org || '', token:config.token || ''}}) - forceUpdate({}) - }else{ - message.error(msg || '操作失败') - } - }) - }; - - const resetDashboardConfig = ()=>{ - fetchData>('partition/monitor',{method:'DELETE',eoParams:{partition:partitionId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - form.resetFields() - getDashboardSetting() - }else{ - message.error(msg || '操作失败') - } - }) - } - - useEffect(() => { - getDashboardSetting(); - - setBreadcrumb([ - {title:部署管理}, - {title:'监控配置'} - ]) - return (form.setFieldsValue({})) - }, [partitionId]); - - return ( - <> -
- -
- {/* - label="环境名称" - name="name" - rules={[{ required: true, message: '必填项' }]} - > - - */} -
- - label="数据源类型" - name="driver" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="Organization" - name={['config','org']} - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - - - label="鉴权 Token" - name={['config','token']} - > - - - - - - - - -
-
- -

重置监控:重置操作不可恢复,请谨慎操作!!

-
- -
-
- -
-
- - ) -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/partitions/PartitionInsidePage.tsx b/frontend/packages/core/src/pages/partitions/PartitionInsidePage.tsx deleted file mode 100644 index e745dcc..0000000 --- a/frontend/packages/core/src/pages/partitions/PartitionInsidePage.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-04 19:09:10 - * @FilePath: \frontend\packages\core\src\pages\partitions\PartitionInsidePage.tsx - */ -import {useEffect, useState} from "react"; -import { Outlet, useLocation, useParams} from "react-router-dom"; -import {App, Menu, MenuProps} from "antd"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { PartitionConfigFieldType } from "../../const/partitions/types.ts"; -import { PARTITIONS_INNER_MENU } from "../../const/partitions/const.tsx"; -import { usePartitionContext } from "../../contexts/PartitionContext.tsx"; -import InsidePage from "@common/components/aoplatform/InsidePage.tsx"; -import Paragraph from "antd/es/typography/Paragraph"; - -const PartitionInsidePage = ()=> { - const { message } = App.useApp() - const {partitionId,moduleId} = useParams(); - const {fetchData} = useFetch() - const location = useLocation() - const { partitionInfo,setPartitionInfo} = usePartitionContext() - const [activeMenu, setActiveMenu] = useState() - - const onMenuClick: MenuProps['onClick'] = ({key}) => { - setActiveMenu(key) - }; - - const getPartitionInfo = ()=>{ - fetchData>(`partition`,{method:'GET',eoParams:{id:partitionId}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setPartitionInfo(data.partition) - }else{ - message.error(msg || '操作失败') - } - }) - } - - useEffect(() => { - const menuStr = location.pathname.split('/')[location.pathname.split('/').length -1] - let currentMenu:string = menuStr - if(menuStr === 'node'){currentMenu = 'cluster'} - if(moduleId &&location.pathname.split('/')[location.pathname.split('/').length -2] === 'template'){ - currentMenu = `template/${moduleId}` - } - setActiveMenu(currentMenu) - }, [location, moduleId]); - - useEffect(() => { - getPartitionInfo() - }, [partitionId]); - - return ( - <> - 环境 ID:{partitionId || '-'} - }]} - backUrl="/partition/list"> -
- -
- -
-
-
- - ) -} -export default PartitionInsidePage \ No newline at end of file diff --git a/frontend/packages/core/src/pages/partitions/PartitionList.tsx b/frontend/packages/core/src/pages/partitions/PartitionList.tsx deleted file mode 100644 index af268ec..0000000 --- a/frontend/packages/core/src/pages/partitions/PartitionList.tsx +++ /dev/null @@ -1,163 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-07-12 09:57:09 - * @FilePath: \frontend\packages\core\src\pages\partitions\PartitionList.tsx - */ -import PageList from "@common/components/aoplatform/PageList.tsx" -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import { useNavigate} from "react-router-dom"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {App, Button, Modal} from "antd"; -import { PARTITION_LIST_COLUMNS } from "../../const/partitions/const.tsx"; -import { PartitionTableListItem } from "../../const/partitions/types.ts"; -import { SimpleMemberItem } from "@common/const/type.ts"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import PartitionConfig, { PartitionConfigHandle } from "./PartitionConfig.tsx"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; - - -const PartitionList:FC = ()=>{ - const { message, } = App.useApp() - const [searchWord, setSearchWord] = useState('') - const navigate = useNavigate(); - const { setBreadcrumb } = useBreadcrumb() - const {fetchData} = useFetch() - const [init, setInit] = useState(true) - const [memberValueEnum, setMemberValueEnum] = useState<{[k:string]:{text:string}}>({}) - const addPartitionRef = useRef(null) - const pageListRef = useRef(null); - const [modalVisible,setModalVisible] = useState(false) - const [addClusterStep,setAddClusterStep] = useState<'config'|'retry'|'result'>('config') - const [configBtnLoading,setConfigBtnLoading] = useState(false) - const [retryBtnLoading,setRetryBtnLoading] = useState(false) - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 62, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: PartitionTableListItem) => [ - , - ], - } - ] - - - const getPartitionList =(): Promise<{ data: PartitionTableListItem[], success: boolean }>=> { - return fetchData>('partitions',{method:'GET',eoParams:{keyword:searchWord},eoTransformKeys:['cluster_num','update_time']}).then(response=>{ - const {code,data,msg} = response - //console.log(code, data,STATUS_CODE.SUCCESS,code === STATUS_CODE.SUCCESS) - if(code === STATUS_CODE.SUCCESS){ - setInit((prev)=>prev ? false : prev) - return {data:data.partitions, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - useEffect(() => { - setBreadcrumb([ - { - title:'部署管理' - }, - ]) - getMemberList() - }, []); - - const openModal = ()=>{ - setModalVisible(true) - setAddClusterStep('config') - // modal.confirm({ - // title:'添加环境', - // content:, - // onOk:()=> { - // return addPartitionRef.current?.save().then((res)=>{if(res === true) manualReloadTable()}) - // }, - // width:600, - // okText:'下一步,检查集群', - // cancelText:'取消', - // closable:true, - // icon:<>, - // }) - } - - const getMemberList = async ()=>{ - setMemberValueEnum({}) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.members?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setMemberValueEnum(tmpValueEnum) - }else{ - message.error(msg || '操作失败') - } - } - - const columns = useMemo(()=>{ - return PARTITION_LIST_COLUMNS.map(x=>{if(x.filters &&((x.dataIndex as string[])?.indexOf('updater') !== -1 || (x.dataIndex as string[])?.indexOf('approver') !== -1) ){x.valueEnum = memberValueEnum} return x}) - },[memberValueEnum]) - - const manualReloadTable = () => { - pageListRef.current?.reload() - }; - - return ( - <> - getPartitionList()} - addNewBtnTitle="添加环境" - showPagination={false} - searchPlaceholder="输入名称、ID 查找环境" - onAddNewBtnClick={()=>{openModal()}} - addNewBtnAccess="system.partition.self.add" - onSearchWordChange={(e)=>{setSearchWord(e.target.value)}} - onRowClick={(row:PartitionTableListItem)=>navigate(`../inside/${row.id}/cluster`)} - tableClickAccess="system.partition.self.view" - /> - { - !open && setModalVisible(false);setAddClusterStep('config');setConfigBtnLoading(false);setRetryBtnLoading(false) - }} - onCancel={() => {setModalVisible(false);setAddClusterStep('config');setConfigBtnLoading(false);setRetryBtnLoading(false)}} - footer={[ - , - <>{addClusterStep === 'result' && <> - - - }, - <>{addClusterStep === 'config' && - - }, - <>{addClusterStep === 'retry' && - - } - ]} - > - - - - ) - -} -export default PartitionList \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/SystemInsideAccess.tsx b/frontend/packages/core/src/pages/system/SystemInsideAccess.tsx deleted file mode 100644 index f978e38..0000000 --- a/frontend/packages/core/src/pages/system/SystemInsideAccess.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-04 19:09:27 - * @FilePath: \frontend\packages\core\src\pages\system\SystemInsideAccess.tsx - */ -import {App, Collapse, Empty} from "antd"; -import styles from "../team/Team.module.css"; -import {DownOutlined, UpOutlined} from "@ant-design/icons"; -import {AccessMemberList, AccessOptionItem, PermissionListItem} from "../access/AccessList.tsx"; -import {useEffect, useRef, useState} from "react"; -import {Link, useParams} from "react-router-dom"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import {DefaultOptionType} from "antd/es/cascader"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { PermissionOptionType } from "../access/AccessPage.tsx"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext.tsx"; - -export default function SystemInsideAccess(){ - const [accessList, setAccessList] = useState>([]) - const { message } = App.useApp() - const {systemId} = useParams(); - const {fetchData} = useFetch() - const {setBreadcrumb} = useBreadcrumb() - const [activeKey, setActiveKey] = useState([]) - - const requestState = useRef<{ keyword?: string, promise?: Promise}>({ }); - - const getMemberOptionList = ( keyword?: string): Promise => { - // 如果type或keyword与缓存中的相同,返回缓存的promise - if (requestState.current.keyword === keyword && requestState.current.promise) { - return requestState.current.promise!; - } - - // 创建新的promise并更新引用 - const newPromise = new Promise((resolve, reject)=>{ - fetchData>('project/setting/permission/options',{method:'GET',eoParams:{project:systemId, keyword:keyword||""}} - ).then((response) => { - const { code, data, msg } = response; - if (code === STATUS_CODE.SUCCESS) { - resolve(data); - } else { - message.error(msg || '操作失败'); - reject(msg || '操作失败'); - } - }).catch((error) => { - // 处理错误 - reject(error) - throw error; - }); - }) - - // 更新引用 - requestState.current = {keyword, promise: newPromise }; - - // 返回新的promise - return newPromise; - }; - - - const addMember = (value:{[k:string]:unknown})=>{ - //console.log(value) - return fetchData>('project/setting/permission',{method:'POST',eoBody:({...value}), eoParams:{project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - getAccessList() - }else{ - message.error(msg || '操作失败') - } - }) - } - - const removeMember :(entity:AccessOptionItem & {access:string})=>Promise = (entity:AccessOptionItem& {access:string})=>{ - return new Promise((resolve, reject)=>{ - fetchData>('project/setting/permission',{method:'DELETE',eoParams:{access:entity.access,key:entity.key,project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - getAccessList() - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(false) - } - }).catch(()=>reject(false)) - }) - } - - const getAccessList = ()=>{ - fetchData>('project/setting/permissions',{method:'GET',eoParams:{project:systemId}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setAccessList(data.permissions?.map((x:PermissionListItem)=>({ - key:x.access, label: <>{x.name} {x.description}, - children: - }))) - setActiveKey(data.permissions?.map((x:PermissionListItem)=>x.access)) - }else{ - message.error(msg || '操作失败') - } - }) - } - - useEffect(()=>{ - setBreadcrumb([ - {title: 内部数据服务}, - {title:'权限'} - ]) - },[]) - - useEffect(() => { - getAccessList() - }, [systemId]); - - return ( -
-

权限设置

-
- { accessList?.length > 0 ? <> - {setActiveKey(val as string[])}} - expandIcon={({isActive})=>(isActive? : )}/> - :
- } -
-
- ) -} - diff --git a/frontend/packages/core/src/pages/system/SystemInsideMember.tsx b/frontend/packages/core/src/pages/system/SystemInsideMember.tsx deleted file mode 100644 index f9d0a4c..0000000 --- a/frontend/packages/core/src/pages/system/SystemInsideMember.tsx +++ /dev/null @@ -1,327 +0,0 @@ -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {App, Button, Modal, Select} from "antd"; -import PageList from "@common/components/aoplatform/PageList.tsx"; -import {useEffect, useMemo, useRef, useState} from "react"; -import {Link, useParams} from "react-router-dom"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {TransferTableHandle} from "@common/components/aoplatform/TransferTable.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import {EntityItem, MemberItem, TeamSimpleMemberItem} from "@common/const/type.ts"; -import { SYSTEM_MEMBER_TABLE_COLUMN } from "../../const/system/const.tsx"; -import { SystemMemberTableListItem } from "../../const/system/type.ts"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { checkAccess } from "@common/utils/permission.ts"; -import MemberTransfer from "@common/components/aoplatform/MemberTransfer.tsx"; -import { DepartmentListItem } from "../../const/member/type.ts"; -import { addMemberToDepartment, getDepartmentWithMember } from "../user/UserList.tsx"; -import {v4 as uuidv4} from 'uuid' - -export default function SystemInsideMember(){ - const {systemId, teamId} = useParams(); - const [searchWord, setSearchWord] = useState('') - const {modal, message} = App.useApp() - const {setBreadcrumb} = useBreadcrumb() - // const [confirmLoading, setConfirmLoading] = useState(false); - const {fetchData} = useFetch() - const [init, setInit] = useState(true) - const [tableListDataSource, setTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const pageListRef = useRef(null); - const addRef = useRef>(null) - const [columns,setColumns] = useState[]>([]) - const [allMemberIds,setAllMemberIds] = useState([]) - const {accessData} = useGlobalContext() - const [selectableMemberIds,setSelectableMemberIds] = useState>(new Set()) - const [addMemberBtnLoading, setAddMemberBtnLoading] = useState(false) - const [modalVisible, setModalVisible] = useState(false) - const [addMemberBtnDisabled, setAddMemberBtnDisabled] = useState(true) - const [allMemberSelectedDepartIds, setAllMemberSelectedDepartIds] = useState([]) - - const operation: ProColumns[] = [ - { - title: '操作', - key: 'option', - width: 62, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: SystemMemberTableListItem) => [ - {openModal('delete',entity)}} btnTitle="删除"/>, - ], - } - ] - - const getMemberList = (): Promise<{ data: SystemMemberTableListItem[], success: boolean }> => { - if (!tableHttpReload) { - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - return fetchData>('project/members', {method: 'GET', eoParams:{project:systemId},eoTransformKeys:['can_delete']}).then(response => { - const {code, data, msg} = response - if (code === STATUS_CODE.SUCCESS) { - if(!searchWord) setAllMemberIds(data.members?.map((x:SystemMemberTableListItem)=>x.user.id) || []) - setTableListDataSource(data.members) - setInit((prev) => prev ? false : prev) - setTableHttpReload(false) - return {data: data.members, success: true} - } else { - message.error(msg || '操作失败') - return {data: [], success: false} - } - }).catch(() => { - return {data: [], success: false} - }) - } - - const getDepartmentMemberList = () => { - const topDepartmentId:string = uuidv4() - return Promise.all([ - fetchData>('simple/departments', {method:'GET'}), - fetchData>('team/members/simple',{method:'GET',eoParams:{team:teamId},eoTransformKeys:['user_group','attach_time','user_id']}) - ]).then(([departmentResponse, memberResponse])=>{ - const departmentMap = new Map(); - memberResponse.data.teams.forEach((member: (TeamSimpleMemberItem | MemberItem) & {title?:string, key?:string}) => { - setSelectableMemberIds((pre)=>{pre.add((member as TeamSimpleMemberItem).user?.id);return pre}) - member = {department:(member as TeamSimpleMemberItem).department ? (member as TeamSimpleMemberItem).department : undefined, email:(member as TeamSimpleMemberItem).mail, ...(member as TeamSimpleMemberItem).user, title:(member as TeamSimpleMemberItem).user.name, key:(member as TeamSimpleMemberItem).user.id} - if (member.department) { - member.department.forEach((department: EntityItem) => { - addMemberToDepartment(departmentMap, department.id, member); - }); - } else { - addMemberToDepartment(departmentMap, '_withoutDepartment', member); - } - }); - const finalData = departmentResponse.data.department - ? [ - { - id: topDepartmentId, - key:topDepartmentId, - name: departmentResponse.data.department.name, - title:departmentResponse.data.department.name, - children: [ - ...getDepartmentWithMember(departmentResponse.data.department.children, departmentMap), - ...departmentMap.get('_withoutDepartment') || [] - ] - } - ] - : [...departmentMap.get('_withoutDepartment') || []]; - - 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]) - } - } - } - - if(!finalData[0].children || finalData[0].children.filter(m => allMemberIds.indexOf(m.id) === -1).length === 0){ - setAllMemberSelectedDepartIds((pre)=>[...pre, topDepartmentId]) - } - - return {data:finalData, success: true} - }).catch(()=>({data:[], success:false})) - } - - - const openModal = (type: 'add' | 'edit' | 'delete', entity?: SystemMemberTableListItem) => { - let title: string = '' - let content: string | React.ReactNode = '' - switch (type) { - case 'add': - setModalVisible(true) - setAddMemberBtnDisabled(true) - setAddMemberBtnLoading(false) - return; - case 'delete': - title = '删除' - content = '该数据删除后将无法找回,请确认是否删除?' - break; - } - - modal.confirm({ - title, - content, - onOk:()=> removeMember(entity!).then((res)=>{if(res === true) manualReloadTable()}), - width: 600, - okText: '确认', - okButtonProps:{ - disabled : !checkAccess( `project.mySystem.member.edit`, accessData) - }, - cancelText: '取消', - closable: true, - icon: <>, - }) - } - - const addMember = () => { - setAddMemberBtnLoading(true) - const keyFromModal = addRef.current?.selectedRowKeys() - const memberKeyFromModal = keyFromModal?.filter(x => allMemberIds.indexOf(x as string) === -1 && selectableMemberIds.has(x)) || []; - fetchData>('project/member', {method: 'POST', eoBody: ({users: memberKeyFromModal}), eoParams: {project: systemId}}).then(response => { - const {code, msg} = response - setAddMemberBtnLoading(false) - if (code === STATUS_CODE.SUCCESS) { - setModalVisible(false) - message.success(msg || '操作成功!') - manualReloadTable() - } else { - message.error(msg || '操作失败') - } - }).finally(()=>setAddMemberBtnLoading(false)) - } - - const manualReloadTable = () => { - setTableHttpReload(true) - pageListRef.current?.reload() - }; - - const removeMember = (entity: SystemMemberTableListItem) => { - return new Promise((resolve, reject) => { - fetchData>(`project/member`, {method: 'DELETE', eoParams: {project: systemId, user:entity.user.id}}).then(response => { - const {code, msg} = response - if (code === STATUS_CODE.SUCCESS) { - message.success(msg || '操作成功!') - resolve(true) - } else { - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const changeMemberInfo = (value:string[],entity:SystemMemberTableListItem )=>{ - //console.log(value) - return new Promise((resolve, reject) => { - fetchData>(`project/member`, {method: 'PUT',eoBody:({roles:value}), eoParams: {project: systemId, user:entity.user.id}}).then(response => { - const {code, msg} = response - if (code === STATUS_CODE.SUCCESS) { - message.success(msg || '操作成功!') - resolve(true) - } else { - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const getRoleList = ()=>{ - fetchData}>>('simple/roles', {method: 'GET'}).then(response => { - const {code, data,msg} = response - if (code === STATUS_CODE.SUCCESS) { - - const newCol = [...SYSTEM_MEMBER_TABLE_COLUMN] - for(const col of newCol){ - //console.log(col) - if(col.dataIndex instanceof Array && col.dataIndex[0] === 'roles'){ - col.render = (_,entity)=>( - - - - - ); - - const onAlgorithmChange = (algorithm:string)=>{ - setAlgorithm(algorithm) - } - - const onDriverChange = (driver:string)=>{ - setDriver(driver) - if(driver === 'jwt' && !form.getFieldValue(['config','algorithm'])){ - form.setFieldValue(['config','algorithm'],'HS256') - forceUpdate({}) - } - } - - - const disabledDate = (current: moment.Moment | null): boolean => { - // 禁用今天以前的日期,包括今天 - // 使用current?.startOf('day')是为了获取日期的开始时间点,以确保整个今天都被禁用 - // 如果只需要禁用今天之前的日期(今天可选),则可以将`isBefore`的第二个参数设置为 'day' - return current ? current.startOf('day') < moment().startOf('day') : false; - }; - - - useEffect(() => { - //console.log(data) - if(type === 'edit' && data){ - form.setFieldsValue({...data,expireTime:data.expireTime === 0 ? '' : moment(data.expireTime *1000)}) - forceUpdate({}) - }else{ - form.setFieldsValue({driver, position:'Header',tokenName:'Authorization'}) - form.setFieldValue(['config','userName'],uuidv4()) - form.setFieldValue(['config','password'],uuidv4()) - form.setFieldValue(['config','apikey'],uuidv4()) - forceUpdate({}) - } - }, []); - - return ( - // -
- - label="名称" - name="name" - rules={[{required: true, message: '必填项',whitespace:true }]} - > - - - - - label="鉴权类型" - name="driver" - rules={[{required: true, message: '必填项'}]} - > - - - - {(()=>{ - switch(form.getFieldValue('driver')){ - case 'basic': - return <> - - label="用户名" - name={['config','userName']} - rules={[{required: true, message: '必填项',whitespace:true }]} - > - - - - - label="密码" - name={['config','password']} - rules={[{required: true, message: '必填项',whitespace:true }]} - > - - - - case 'jwt': - return <> - - label="Iss" - name={['config','iss']} - rules={[{required: true, message: '必填项'}]} - > - - - - - label="签名算法" - name={['config','algorithm']} - rules={[{required: true, message: '必填项'}]} - > - - - - - label="用户名" - name={['config','user']} - > - - - - - label="用户名 JsonPath" - name={['config','userPath']} - > - - - - - label="校验字段" - name={['config','claimsToVerify']} - > - - - - - label="SK" - name={['config','sk']} - rules={[{required: true, message: '必填项'}]} - > - - - - case 'apikey': - return <> - - label="Apikey" - name={['config','apikey']} - rules={[{required: true, message: '必填项',whitespace:true }]} - > - - - - } - - })()} - - - label="过期时间" - name="expireTime" - > - - - - - label="隐藏鉴权信息" - name="hideCredential" valuePropName="checked" - > - - - - //
- ); -}) \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/authority/SystemAuthorityView.tsx b/frontend/packages/core/src/pages/system/authority/SystemAuthorityView.tsx deleted file mode 100644 index 45caad5..0000000 --- a/frontend/packages/core/src/pages/system/authority/SystemAuthorityView.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-05-31 16:08:35 - * @FilePath: \frontend\packages\core\src\pages\system\authority\SystemAuthorityView.tsx - */ -import {Col, Row} from "antd"; -import {useEffect, useState} from "react"; -import { SystemAuthorityViewProps } from "../../../const/system/type"; - -export const SystemAuthorityView = ({entity}:SystemAuthorityViewProps)=>{ - const [detail,setDetail] = useState>(entity) - - useEffect(() => { - setDetail(entity) - }, [entity]); - - return ( -
{ - detail?.length > 0 && detail.map((k,i)=>( - -
{k.key}: - { k.value || '-'} - - )) - } - - ) -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/authority/SystemInsideAuthority.tsx b/frontend/packages/core/src/pages/system/authority/SystemInsideAuthority.tsx deleted file mode 100644 index d56ceeb..0000000 --- a/frontend/packages/core/src/pages/system/authority/SystemInsideAuthority.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import PageList from "@common/components/aoplatform/PageList.tsx" -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import {Link, useParams} from "react-router-dom"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import { App, Divider } from "antd"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { SimpleMemberItem } from "@common/const/type.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {SystemAuthorityView} from "./SystemAuthorityView.tsx"; -import { - SystemAuthorityConfig, -} from "./SystemAuthorityConfig.tsx"; -import { SYSTEM_AUTHORITY_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import { SystemAuthorityTableListItem, SystemAuthorityConfigHandle, EditAuthFieldType} from "../../../const/system/type.ts"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { checkAccess } from "@common/utils/permission.ts"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; - - - -const SystemInsideAuthority:FC = ()=>{ - const { setBreadcrumb } = useBreadcrumb() - const { modal,message } = App.useApp() - const {fetchData} = useFetch() - const [init, setInit] = useState(true) - const [tableListDataSource, setTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const {systemId} = useParams(); - const addRef = useRef(null) - const editRef = useRef(null) - const pageListRef = useRef(null); - const [memberValueEnum, setMemberValueEnum] = useState<{[k:string]:{text:string}}>({}) - const {accessData} = useGlobalContext() - const getSystemAuthority = ()=>{ - if(!tableHttpReload){ - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - return fetchData>('project/authorizations',{method:'GET',eoParams:{project:systemId},eoTransformKeys:['hide_credential','create_time','update_time','expire_time']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTableListDataSource(data.authorizations) - setInit((prev)=>prev ? false : prev) - setTableHttpReload(false) - return {data:data.authorizations, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - const deleteAuthority = (entity:SystemAuthorityTableListItem)=>{ - return new Promise((resolve, reject)=>{ - fetchData>('project/authorization',{method:'DELETE',eoParams:{authorization:entity!.id,project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const openModal =async (type:'view'|'delete'|'add'|'edit',entity?:unknown)=>{ - //console.log(type,entity) - let title:string = '' - let content:string|React.ReactNode = '' - switch (type){ - case 'view':{ - title='鉴权详情' - message.loading('正在加载数据') - const {code,data,msg} = await fetchData>('project/authorization/details',{method:'GET',eoParams:{authorization:entity!.id,project:systemId}}) - message.destroy() - if(code === STATUS_CODE.SUCCESS){ - content= - }else{ - message.error(msg || '操作失败') - return - }} - break; - case 'add': - title='添加鉴权' - content= - break; - case 'edit':{ - title='编辑鉴权' - message.loading('正在加载数据') - const {code,data,msg} = await fetchData>('project/authorization',{method:'GET',eoParams:{authorization:entity!.id,project:systemId},eoTransformKeys:['hide_credential','token_name','expire_time','user_name','public_key','user_path','claims_to_verify','signature_is_base64']}) - message.destroy() - if(code === STATUS_CODE.SUCCESS){ - content= - }else{ - message.error(msg || '操作失败') - return - }} - break; - case 'delete': - title='删除' - content='该数据删除后将无法找回,请确认是否删除?' - break; - } - - modal.confirm({ - title, - content, - onOk:()=>{ - switch (type){ - case 'add': - return addRef.current?.save().then((res)=>{if(res === true) manualReloadTable()}) - case 'edit': - return editRef.current?.save().then((res)=>{if(res === true) manualReloadTable()}) - case 'delete': - return deleteAuthority(entity).then((res)=>{if(res === true) manualReloadTable()}) - case 'view': - return true - } - }, - width:600, - okText:'确认', - okButtonProps:{ - disabled : !checkAccess( `project.mySystem.auth.${type}`, accessData) - }, - cancelText:'取消', - closable:true, - icon:<>, - }) - } - - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 138, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: SystemAuthorityTableListItem) => [ - {openModal('view',entity)}} btnTitle="查看"/>, - , - {openModal('edit',entity)}} btnTitle="编辑"/>, - , - {openModal('delete',entity)}} btnTitle="删除"/>, - ], - } - ] - - - const getMemberList = async ()=>{ - setMemberValueEnum({}) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.members?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setMemberValueEnum(tmpValueEnum) - }else{ - message.error(msg || '操作失败') - } - } - - useEffect(() => { - setBreadcrumb([ - { - title:内部数据服务 - }, - { - title:'身份认证' - } - ]) - getMemberList() - manualReloadTable() - }, [systemId]); - - const columns = useMemo(()=>{ - return SYSTEM_AUTHORITY_TABLE_COLUMNS.map(x=>{if(x.filters &&((x.dataIndex as string[])?.indexOf('creator') !== -1 ) ){x.valueEnum = memberValueEnum} return x}) - },[memberValueEnum]) - - return ( - getSystemAuthority()} - dataSource={tableListDataSource} - showPagination={false} - addNewBtnTitle="添加鉴权" - onAddNewBtnClick={()=>{openModal('add')}} - addNewBtnAccess="project.mySystem.auth.add" - onRowClick={(row:SystemAuthorityTableListItem)=>openModal('view',row)} - tableClickAccess="project.mySystem.auth.view" - /> - ) -} - -export default SystemInsideAuthority \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/myService/MyServiceInsideApi.tsx b/frontend/packages/core/src/pages/system/myService/MyServiceInsideApi.tsx deleted file mode 100644 index ff0d653..0000000 --- a/frontend/packages/core/src/pages/system/myService/MyServiceInsideApi.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import { useRef, useState} from "react"; -import PageList from "@common/components/aoplatform/PageList.tsx"; -import {App, Button, Modal} from "antd"; -import TransferTable, {TransferTableHandle} from "@common/components/aoplatform/TransferTable.tsx"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import { apiModalColumn, SYSTEM_MYSERVICE_API_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import { ServiceApiTableListItem, SimpleApiItem } from "../../../const/system/type.ts"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { checkAccess } from "@common/utils/permission.ts"; - -const MyServiceInsideApi = ({systemId,serviceId}:{systemId:string, serviceId:string})=>{ - const { modal,message } = App.useApp() - const [open, setOpen] = useState(false); - const {fetchData} = useFetch() - const [init, setInit] = useState(true) - const pageListRef = useRef(null); - const [addApiBtnLoading, setAddApiBtnLoading] = useState() - const [addApiBtnDisabled, setAddApiBtnDisabled] = useState(true) - const addRef = useRef>(null) - const [apiIds, setApiIds] = useState([]) - const {accessData} = useGlobalContext() - - const getServiceApiList = ()=>{ - return fetchData>('project/service/apis',{method:'GET',eoParams:{service:serviceId,project:systemId}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setInit((prev)=>prev ? false : prev) - setApiIds(data.apis?.map((x:ServiceApiTableListItem)=>x.id) || []) - return {data:data.apis, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - const handleDragSortEnd = (beforeIndex: number, afterIndex: number, newDataSource: ServiceApiTableListItem[]) => { - fetchData>('project/service/api/sort',{method:'PUT',eoParams:{service:serviceId,project:systemId},eoBody:({apis:newDataSource?.map(x=>x.id)})|| []}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - manualReloadTable() - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }) - }; - - const manualReloadTable = () => { - pageListRef.current?.reload() - }; - - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 62, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: ServiceApiTableListItem) => [ - {openModal('delete',entity)}} btnTitle="删除"/>, - ], - } - ] - - const deleteApi = (entity:ServiceApiTableListItem) =>{ - return new Promise((resolve, reject)=>{ - fetchData>('project/service/unbind',{method:'DELETE',eoParams:{service:serviceId,project:systemId, apis:JSON.stringify([entity.id])}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const addApi = ()=>{ - setAddApiBtnLoading(true) - fetchData>('project/service/bind',{method:'POST' ,eoBody:({apis:addRef.current?.selectedRowKeys().filter(x=>apiIds.indexOf(x) === -1)}),eoParams:{service:serviceId,project:systemId}}).then(response=>{ - const {code,msg} = response - setAddApiBtnLoading(false) - if(code === STATUS_CODE.SUCCESS){ - setOpen(false) - message.success(msg || '操作成功!') - manualReloadTable() - }else{ - message.error(msg || '操作失败') - } - }) - } - - const openModal = async (type:'add'|'delete',entity?:ServiceApiTableListItem)=>{ - switch(type){ - case 'add': - setOpen(true) - break; - case 'delete': - modal.confirm({ - title:'删除', - content:'该数据删除后将无法找回,请确认是否删除?', - onOk:()=> deleteApi(entity!).then((res)=>{if(res === true) manualReloadTable()}), - width:600, - okText:'确认', - okButtonProps:{ - disabled : !checkAccess( 'project.mySystem.service.delete', accessData) - }, - cancelText:'取消', - closable:true, - icon:<> - }) - } - } - - const getSelectableApiList = (keyword?:string)=>{ - return fetchData>('project/apis/simple',{method:'GET',eoParams:{ keyword,project:systemId},eoTransformKeys:['request_path']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - return {data:data.apis, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - return ( -
- getServiceApiList()} - addNewBtnTitle="添加 API" - addNewBtnAccess="project.mySystem.service.edit" - onAddNewBtnClick={() => { - openModal('add') - }} - dragSortKey="id" - onDragSortEnd={handleDragSortEnd} - /> - setOpen(false)} - footer={[ - , - , - ]} - > - { - setAddApiBtnDisabled(!(selectedData.length > 0)); - }} - /> - -
- ) -} -export default MyServiceInsideApi \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/myService/MyServiceInsideConfig.tsx b/frontend/packages/core/src/pages/system/myService/MyServiceInsideConfig.tsx deleted file mode 100644 index c549dff..0000000 --- a/frontend/packages/core/src/pages/system/myService/MyServiceInsideConfig.tsx +++ /dev/null @@ -1,461 +0,0 @@ -import { forwardRef, useEffect, useImperativeHandle, useState} from "react"; -import { App, Button, Checkbox, Divider, Form, Input, Row, Select, Spin, TagType, TreeSelect, Upload, UploadFile, UploadProps} from "antd"; -import {LoadingOutlined, PlusOutlined} from "@ant-design/icons"; -import {RcFile, UploadChangeParam} from "antd/es/upload"; -import Radio from "antd/es/radio"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {DefaultOptionType} from "antd/es/cascader"; -import {useSystemContext} from "../../../contexts/SystemContext.tsx"; -import {v4 as uuidv4} from 'uuid' -import { visualizations } from "../../../const/system/const.tsx"; -import { SimpleSystemItem, MyServiceFieldType, MyServiceInsideConfigHandle, MyServiceInsideConfigProps } from "../../../const/system/type.ts"; -import { EntityItem, SimpleTeamItem } from "@common/const/type.ts"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { getImgBase64 } from "@common/utils/dataTransfer.ts"; -import { CategorizesType } from "@market/const/serviceHub/type.ts"; - -const MAX_SIZE = 2 * 1024; // 1KB - -const MyServiceInsideConfig = forwardRef((props,ref)=>{ - const {teamId, systemId, serviceId,closeDrawer} = props - const { message,modal } = App.useApp() - const [onEdit, setOnEdit] = useState(!!serviceId) - const [form] = Form.useForm(); - const {fetchData} = useFetch() - const [, setImageUrl] = useState(); - const [teamOptionList, setTeamOptionList] = useState([]) - const [systemOptionList, setSystemOptionList] = useState([]) - const [tagOptionList, setTagOptionList] = useState([]) - const {partitionList} = useSystemContext() - const [serviceClassifyOptionList, setServiceClassifyOptionList] = useState() - const [showClassify, setShowClassify] = useState() - const [imageBase64, setImageBase64] = useState(null); - const [status,setStatus] = useState<'off'|'on'>('on') - const [loading, setLoading] = useState(false) - const [uploadLoading, setUploadLoading] = useState(false) - const [startBtnLoading, setStartBtnLoading] = useState(false) - const [delBtnLoading, setDelBtnLoading] = useState(false) - - const beforeUpload = async (file: RcFile) => { - if (!['image/png', 'image/jpeg', 'image/svg+xml'].includes(file.type)) { - alert('只允许上传PNG、JPG或SVG格式的图片'); - return false; - } - - if (file.size > MAX_SIZE) { - try { - const compressedBase64 = await compressImage(file, MAX_SIZE); - setImageBase64(`data:${file.type};base64,${compressedBase64}`); - form.setFieldValue('logo', `data:${file.type};base64,${compressedBase64}`); - } catch (error) { - console.error('压缩图片时出错', error); - } - } else { - const reader = new FileReader(); - reader.onload = (e: ProgressEvent) => { - - setImageBase64(e.target?.result as string); - form.setFieldValue('logo', e.target?.result); - }; - reader.readAsDataURL(file); - } - return false; - }; - - - const compressImage = (file: RcFile, maxSize: number): Promise => { - const img = document.createElement('img'); - const canvas = document.createElement('canvas'); - const reader = new FileReader(); - - return new Promise((resolve, reject) => { - reader.onload = (e) => { - img.src = e.target.result as string; - img.onload = () => { - let quality = 0.9; - let width = img.width; - let height = img.height; - - const ctx = canvas.getContext('2d'); - - const compress = () => { - canvas.width = width; - canvas.height = height; - ctx.clearRect(0, 0, width, height); - ctx.drawImage(img, 0, 0, width, height); - - const dataUrl = canvas.toDataURL(file.type, quality); - const base64 = dataUrl.split(',')[1]; - return { base64, size: base64.length * 0.75 }; - }; - - let { base64, size } = compress(); - - while (size > maxSize && quality > 0.1) { - quality -= 0.1; - ({ base64, size } = compress()); - } - - while (size > maxSize && (width > 50 || height > 50)) { - width *= 0.9; - height *= 0.9; - ({ base64, size } = compress()); - } - - resolve(base64); - }; - }; - reader.onerror = (e) => reject(e); - reader.readAsDataURL(file); - }); - }; - // 获取表单默认值 - const getServiceInfo = () => { - setLoading(true) - fetchData>('project/service/info',{method:'GET',eoParams:{service:serviceId,project:systemId},eoTransformKeys:['service_type']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTimeout(()=>{form.setFieldsValue({...data.service, logoFile:[ - { - uid: '-1', // 文件唯一标识 - name: 'image.png', // 文件名 - status: 'done', // 状态有:uploading, done, error, removed - url: data.service.logo, // 图片 Base64 数据 - } - ],team:data.service.team.id, project:data.service.project.id,tags:data.service.tags?.map((x:EntityItem)=>x.name)||[],partition:data.service.partition?.map((x:EntityItem)=>x.id)||[],group:data.service.group.id})},0) - setImageBase64(data.service.logo) - setStatus( data.service.status) - setShowClassify(data.service.serviceType === 'public') - }else{ - message.error(msg || '操作失败') - } - }).finally(()=>setLoading(false)) - - } - const onFinish = () => { - return form.validateFields().then((value)=>{ - return fetchData>(serviceId === undefined?'project/service':'project/service/info',{method:serviceId === undefined? 'POST' : 'PUT',eoBody:({...value,tags:value.tags?.map((x:string|EntityItem)=>typeof x === 'string' ? x : x.name),partition:value.partition?.map((x:string)=>x.toString())}), eoParams:serviceId === undefined ? {project:systemId}:{service:serviceId,project:systemId},eoTransformKeys:['serviceType']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - // setServiceInfo(data.service) - message.success(msg || '操作成功!') - return Promise.resolve(true) - // if(serviceId === undefined) navigate(`/system/${orgId}/${teamId}/inside/${systemId}/myService/inside/${data.service.id}/api`) - }else{ - message.error(msg || '操作失败') - return Promise.reject(msg || '操作失败') - } - }).catch((errInfo)=>Promise.reject(errInfo)) - }).catch((err) => { - form.scrollToField(err.errorFields[0].name[0]); - return Promise.reject(msg || '操作失败') - }); - }; - - - useImperativeHandle(ref,()=>({ - save:onFinish - }) -) - - const handleChange: UploadProps['onChange'] = (info: UploadChangeParam) => { - if (info.file.status === 'uploading') { - setUploadLoading(true); - return; - } - if (info.file.status === 'done') { - // Get this url from response in real world. - getImgBase64(info.file.originFileObj as RcFile, (url) => { - setUploadLoading(false); - setImageUrl(url); - }); - } - if (info.fileList.length === 0) { - // 如果文件被移除,清除 logo 字段 - form.setFieldValue( "logo", null ); - } - }; - - const uploadButton = ( -
- {uploadLoading ? : } -
- ); - - const getTeamList = ()=>{ - setTeamOptionList([]) - fetchData>('simple/teams/mine',{method:'GET'}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTeamOptionList(data.teams?.map((x:SimpleTeamItem)=>{return { - label:x.name, value:x.id - }})||[]) - }else{ - message.error(msg || '操作失败') - } - }) - } - - const getSystemList = ()=>{ - setSystemOptionList([]) - fetchData>('simple/projects/mine',{method:'GET'}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setSystemOptionList(data.projects?.map((x:SimpleSystemItem)=>{return { - label:x.name, value:x.id, partition:x.partition?.map((x:EntityItem)=>x.id) - }}) || []) - }else{ - message.error(msg || '操作失败') - } - }) - } - - const getTagAndServiceClassifyList = ()=>{ - setTagOptionList([]) - setServiceClassifyOptionList([]) - fetchData>('catalogues',{method:'GET'}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTagOptionList(data.tags?.map((x:TagType)=>{return { - label:x.name, value:x.name - }})||[]) - setServiceClassifyOptionList(data.catalogues) - - }else{ - message.error(msg || '操作失败') - } - }) - } - - const deleteService = ()=>{ - fetchData>('project/service',{method:'DELETE',eoParams:{service:serviceId,project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功,即将返回列表页') - closeDrawer?.() - }else{ - message.error(msg || '操作失败') - } - }).finally(()=>setDelBtnLoading(false)) - } - - const enabledService =()=>{ - setStartBtnLoading(true) - fetchData>(`project/service/${status==='off'?'enable':'disable'}`,{method:'PUT',eoParams:{service:serviceId,project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - setStatus((prevState)=>prevState === 'off' ? 'on' :'off') - }else{ - message.error(msg || '操作失败') - } - }).finally(()=>setStartBtnLoading(false)) - } - - -const normFile = (e: unknown) => { - if (Array.isArray(e)) { - return e; - } - return( e as {fileList:unknown} )?.fileList; - }; - - - const deleteSystemModal = async ()=>{ - setDelBtnLoading(true) - modal.confirm({ - title:'删除', - content:'该数据删除后将无法找回,请确认是否删除?', - onOk:()=> { - return deleteService() - }, - width:600, - okText:'确认', - okButtonProps:{ - danger:true - }, - onCancel:()=>{ - setDelBtnLoading(false) - }, - cancelText:'取消', - closable:true, - icon:<> - }) -} - - - useEffect(() => { - getTeamList() - getSystemList() - getTagAndServiceClassifyList() - if (serviceId !== undefined) { - setOnEdit(true); - getServiceInfo(); - } else { - setOnEdit(false); - form.setFieldsValue({id:uuidv4(), serviceType:'inner',partition:partitionList?.length === 1 ? [partitionList[0].id] : [], team:teamId,project:systemId}); // 清空 initialValues - } - - return (form.setFieldsValue({})) - }, []); - - return ( - } spinning={loading}> -
- -
- - label="服务名称" - name="name" - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - - - label="服务ID" - name="id" - extra="服务ID(service_id)可用于检索服务或日志" - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - - - label="图标" - name="logoFile" - extra="仅支持 .png .jpg .jpeg .svg 格式的图片文件, 大于 1KB 的文件将被压缩" - valuePropName="fileList" getValueFromEvent={normFile} - > - -
- {imageBase64 ? Logo : uploadButton} -
-
- - - - - - label="Logo" - name="logo" - hidden - > - - - - label="所属团队" - name="team" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="所属服务" - name="project" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="标签" - name="tags" - > - - - - - - label="描述" - name="description" - > - - - - - label="可访问环境" - name="partition" - rules={[{required: true, message: '必填项'}]} - > - ({label:x.name, value:x.id})) || []} /> - - - - label="可见性" - name="serviceType" - rules={[{required: true, message: '必填项'}]} - > - {setShowClassify(e.target.value === 'public')}} /> - - - {showClassify && - - label="所属服务分类" - name="group" - extra="设置服务展示在服务市场中的哪个分类下" - rules={[{required: true, message: '必填项'}]} - > - - - } - {serviceId !== undefined && - - - } - {serviceId !== undefined && <> - -

停用服务后,服务将从服务市场中下线,所有请求将无法通过该服务访问 API,请谨慎操作!

-
- - -

删除操作不可恢复,请谨慎操作!

-
- } - -
-
-
- ) -}) -export default MyServiceInsideConfig \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/myService/MyServiceInsideDocument.tsx b/frontend/packages/core/src/pages/system/myService/MyServiceInsideDocument.tsx deleted file mode 100644 index ed6f85d..0000000 --- a/frontend/packages/core/src/pages/system/myService/MyServiceInsideDocument.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { Editor } from '@tinymce/tinymce-react'; -import hljs from 'highlight.js'; -import 'highlight.js/styles/default.css'; -import {useEffect, useState} from "react"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {App, Button} from "antd"; -import { EntityItem } from '@common/const/type.ts'; -import WithPermission from '@common/components/aoplatform/WithPermission.tsx'; -const MyServiceInsideDocument = ({systemId,serviceId}:{systemId:string, serviceId:string})=>{ - const { message } = App.useApp() - const [serviceName,setServiceName] = useState() - const [updater,setUpdater] = useState() - const [updateTime,setUpdateTime]=useState() - const [initDoc, setInitDoc] = useState() - const [doc, setDoc] = useState() - const {fetchData} = useFetch() - - const save = ()=>{ - fetchData>('project/service/doc',{method:'PUT',eoBody:({doc:doc}) ,eoParams:{service:serviceId,project:systemId},eoTransformKeys:['update_time']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - getServiceDoc() - }else{ - message.error(msg || '操作失败') - } - }) - } - - const handleEditorChange = (content:string, editor:unknown) => { - setDoc(content) - }; - const setupEditor = (editor:unknown) => { - editor.on('init', () => { - editor.contentDocument.querySelectorAll('pre code').forEach((block:HTMLElement) => { - hljs.highlightBlock(block); - }); - }); - - editor.on('SetContent', () => { - editor.contentDocument.querySelectorAll('pre code').forEach((block:HTMLElement) => { - hljs.highlightBlock(block); - }); - }); - }; - - const getServiceDoc = ()=>{ - fetchData>('project/service/doc',{method:'GET',eoParams:{service:serviceId,project:systemId},eoTransformKeys:['update_time']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setServiceName(data.doc.name) - setUpdater(data.doc.updater.id === '' ? '-' : data.doc.updater.name) - setUpdateTime(data.doc.updater.id === '' ? '-' : data.doc.updateTime) - setInitDoc(data.doc.doc) - }else{ - message.error(msg || '操作失败') - } - }) - } - - useEffect(() => { - getServiceDoc() - }, []); - - return ( -
-
-

{serviceName || '-'}

-
-

最近一次更新者:{updater || '-'}最近一次更新时间:{updateTime || '-'}

- -
-
-
-
- -
) -} -export default MyServiceInsideDocument \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/myService/MyServiceInsideMenu.tsx b/frontend/packages/core/src/pages/system/myService/MyServiceInsideMenu.tsx deleted file mode 100644 index af103c4..0000000 --- a/frontend/packages/core/src/pages/system/myService/MyServiceInsideMenu.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-02-07 18:47:17 - * @FilePath: \frontend\packages\core\src\pages\system\myService\MyServiceInsideMenu.tsx - */ -import {FC, useEffect, useState} from "react"; -import {Link, Outlet, useLocation} from "react-router-dom"; -import {Menu, MenuProps} from "antd"; -import { getItem } from "@common/utils/navigation.tsx"; - -const MyServiceInsideMenu:FC = ()=> { - const [selectedKeys, setSelectedKey] = useState('') - const location = useLocation() - const currentLocation = location.pathname - - const items: MenuProps['items'] = [ - getItem('管理', 'grp', null, - [getItem(API, 'api'), - getItem(服务详情, 'document'), - getItem(服务设置, 'setting')], - 'group'), - ]; - - const onMenuClick: MenuProps['onClick'] = ({key}) => { - setSelectedKey(key) - }; - - useEffect(()=>{ - const currentKey = currentLocation.split('/')[currentLocation.split('/').length -1] - setSelectedKey(currentKey) - },[currentLocation]) - - return ( - <> -
- -
- -
-
- - ) -} -export default MyServiceInsideMenu \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/myService/SystemInsideMyService.tsx b/frontend/packages/core/src/pages/system/myService/SystemInsideMyService.tsx deleted file mode 100644 index 3e1c119..0000000 --- a/frontend/packages/core/src/pages/system/myService/SystemInsideMyService.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import PageList from "@common/components/aoplatform/PageList.tsx" -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import {Link, useParams} from "react-router-dom"; -import {App, Divider, Drawer, Tabs, Select, Switch} from "antd"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {useSystemContext} from "../../../contexts/SystemContext.tsx"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import { SYSTEM_MYSERVICE_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import { MyServiceInsideConfigHandle, MyServiceTableListItem } from "../../../const/system/type.ts"; -import { EntityItem } from "@common/const/type.ts"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter.tsx"; -import MyServiceInsideConfig from "./MyServiceInsideConfig.tsx"; -import MyServiceInsideApi from "./MyServiceInsideApi.tsx"; -import MyServiceInsideDocument from "./MyServiceInsideDocument.tsx"; -import type { TabsProps } from 'antd'; - - -const SystemInsideMyService:FC = ()=>{ - const { message } = App.useApp() - const {orgId, teamId,systemId} = useParams() - const [searchWord, setSearchWord] = useState('') - const { setBreadcrumb } = useBreadcrumb() - const [init, setInit] = useState(true) - const [tableListDataSource, setTableListDataSource] = useState([]); - const [originTableListDataSource, setOriginTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const pageListRef = useRef(null); - const {fetchData} = useFetch() - const {partitionList } = useSystemContext() - const [selectedPartition, setSelectedPartition] = useState([]) - const drawerFormRef = useRef(null) - const [open, setOpen] = useState(false); - const [editDrawerOpen, setEditDrawerOpen] =useState(false) - const [curService, setCurService] = useState() - const [switchLoading, setSwitchLoading] = useState>(new Set()) - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 60, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: MyServiceTableListItem) => [ - openDrawer('api',entity)} btnTitle="编辑"/>, - // , - // openDrawer('detail',entity)} btnTitle="服务详情"/>, - // , - // openDrawer('setting',entity)} btnTitle="服务设置"/>, - ], - } - ] - - const SYSTEM_MYSERVICE_EDIT_DRAWER_ITEM:TabsProps['items'] = [ - {label:'API 管理',key:'api',children:}, - {label:'服务详情',key:'detail',children:}, - {label:'服务设置',key:'setting',children:{setCurService(undefined); setEditDrawerOpen(false);manualReloadTable()}}/>} - ] - - const getMyServiceList =(): Promise<{ data: MyServiceTableListItem[], success: boolean }>=> { - if(!tableHttpReload){ - setTableHttpReload(true) - //console.log(selectedPartition,originTableListDataSource) - const newTableListData = selectedPartition.length > 0 ? originTableListDataSource.filter((x:MyServiceTableListItem)=>x.partition.filter((p:EntityItem)=>selectedPartition.includes(p.id)).length >0 ):originTableListDataSource - setTableListDataSource(newTableListData) - return Promise.resolve({ - data: newTableListData, - success: true, - }); - } - return fetchData>('project/services',{method:'GET',eoParams:{project:systemId, keyword:searchWord},eoTransformKeys:['partition_id','service_type','api_num','create_time','update_time']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setOriginTableListDataSource(data.services) - setTableListDataSource(selectedPartition.length > 0 ? data.services.filter((x:MyServiceTableListItem)=>x.partition.filter((x:EntityItem)=>selectedPartition.includes(x.id)).length > 0):data.services) - setInit((prev)=>prev ? false : prev) - setTableHttpReload(false) - return {data:data.services, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - const handlePartitionSelectedChange = (e:string[])=>{ - setSelectedPartition(e) - setTableHttpReload(false) - pageListRef.current?.reload() - } - - useEffect(() => { - setBreadcrumb([ - { - title:内部数据服务 - }, - { - title:'提供的服务列表' - } - ]) - manualReloadTable() - }, [systemId]); - - - const openDrawer = (type:'add'|'api',entity?:MyServiceTableListItem)=>{ - if(type !== 'add'){ - setCurService(entity) - setEditDrawerOpen(true) - }else{ - setOpen(true) - } - } - - const newColumns = useMemo(() => { - const columns = [...SYSTEM_MYSERVICE_TABLE_COLUMNS, ...operation]; - - return columns.map(column => { - if (column.dataIndex === 'status') { - return { - ...column, - render: (_:unknown,entity:MyServiceTableListItem) => - handleChangeServiceStatus(entity,checked)} onClick={(checked, e)=>e?.stopPropagation()} /> - }; - } - - return column; - }); - }, []); - - const handleChangeServiceStatus = (entity:MyServiceTableListItem,checked:boolean)=>{ - setSwitchLoading(prev => {prev.add(entity.id);return prev}) - fetchData>(`project/service/${checked?'enable':'disable'}`,{method:'PUT',eoParams:{service:entity.id,project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - manualReloadTable() - }else{ - message.error(msg || '操作失败') - } - }).finally(()=>{setSwitchLoading(prev => {prev.delete(entity.id); return prev})}) - } - - return ( - <> - getMyServiceList()} - dataSource={tableListDataSource} - columns = {newColumns} - addNewBtnTitle="添加服务" - addNewBtnAccess="project.mySystem.service.add" - tableClickAccess="project.mySystem.service.view" - beforeSearchNode={[ } - // onSearch={handleTest} - /> - - { - apiDetail?.match && apiDetail.match?.length > 0 && - - } - - { - apiDetail?.proxy && Object.keys(apiDetail?.proxy).length > 0 && - - } - - {apiDetail && } - - // testClick(apiDocs.id)} entity={doc} /> - }]} - activeKey={activeKey} - onChange={(val)=>{setActiveKey(val as string[])}} - /> - - ))} - - - {/*
-
-

状态码

- -
*/} - - - - ) -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/subSubscribe/SubSubscribeApprovalDetailModalContent.tsx b/frontend/packages/core/src/pages/system/subSubscribe/SubSubscribeApprovalDetailModalContent.tsx deleted file mode 100644 index 9100a99..0000000 --- a/frontend/packages/core/src/pages/system/subSubscribe/SubSubscribeApprovalDetailModalContent.tsx +++ /dev/null @@ -1,108 +0,0 @@ -/* - * @Date: 2024-04-19 15:22:46 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-05 15:15:29 - * @FilePath: \frontend\packages\core\src\pages\system\subSubscribe\SubSubscribeApprovalDetailModalContent.tsx - */ -import { App, Form, Row, Col, Checkbox, Input } from "antd" -import { forwardRef, useImperativeHandle, useEffect } from "react" -import WithPermission from "@common/components/aoplatform/WithPermission" -import { BasicResponse, STATUS_CODE } from "@common/const/const" -import { useFetch } from "@common/hooks/http" -import { SYSTEM_SUBSCRIBE_APPROVAL_DETAIL_LIST } from "../../../const/system/const" -import { SubSubscribeApprovalModalHandle, SubSubscribeApprovalModalProps } from "../../../const/system/type" -import { FieldType } from "../../../const/user/types" - -export const SubSubscribeApprovalModalContent = forwardRef((props, ref) => { - const { message } = App.useApp() - const {data, type, systemId} = props - const [form] = Form.useForm(); - const {fetchData} = useFetch() - - const reApply:()=>Promise = ()=>{ - return new Promise((resolve, reject)=>{ - if(type === 'view'){ - resolve(true) - return - } - form.validateFields().then((value)=>{ - fetchData>('catalogue/service/subscribe',{method: 'POST',eoBody:({partitions:value.partitions,service:data!.service.id, applications:[systemId], reason:value.reason})}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - useImperativeHandle(ref, ()=>({ - reApply - }) - ) - - useEffect(()=>{ - form.setFieldsValue({...data,partitions:data?.partition?.map((x:{id:string})=>x.id)}) - },[]) - - - return ( -
- -
- - {SYSTEM_SUBSCRIBE_APPROVAL_DETAIL_LIST?.map((x)=>{ - if(x.dataType === 'checkbox'){ - return( - - className="mb-btnbase" - label={x.title} - name="partitions" - rules={[{ required: true, message: '必填项' }]} - > - ({label:x.name,value:x.id}))} - /> - - ) - } - return ( - -
{x.title}: - {/* {showData(x)} */} - {x.nested ? data?.[x.key]?.[x.nested] : ( (data as {[k:string]:unknown})?.[x.key] || '-')} - ) - })} - - - label="申请原因" - name="reason" - > - - - - label="审核意见" - name="opinion" - > - - - - - - ) -}) \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/subSubscribe/SystemInsideSubService.tsx b/frontend/packages/core/src/pages/system/subSubscribe/SystemInsideSubService.tsx deleted file mode 100644 index f750eae..0000000 --- a/frontend/packages/core/src/pages/system/subSubscribe/SystemInsideSubService.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import PageList from "@common/components/aoplatform/PageList.tsx" -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {FC, ReactNode, useEffect, useMemo, useRef, useState} from "react"; -import {Link, useNavigate, useParams} from "react-router-dom"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {App, Divider, Drawer} from "antd"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { SimpleMemberItem } from "@common/const/type.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import { RouterParams } from "@core/components/aoplatform/RenderRoutes.tsx"; -import { SubSubscribeApprovalModalHandle, SystemSubServiceTableListItem } from "../../../const/system/type.ts"; -import { SYSTEM_SUBSERVICE_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import { SubSubscribeApprovalModalContent } from "./SubSubscribeApprovalDetailModalContent.tsx"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { PERMISSION_DEFINITION } from "@common/const/permissions.ts"; -import { checkAccess } from "@common/utils/permission.ts"; -import { SubscribeApprovalInfoType } from "@common/const/approval/type.tsx"; -import SubServiceDetail from "./SubServiceDetail.tsx"; - -const SystemInsideSubService:FC = ()=>{ - const [searchWord, setSearchWord] = useState('') - const navigate = useNavigate(); - const { setBreadcrumb } = useBreadcrumb() - const { modal,message } = App.useApp() - // const [confirmLoading, setConfirmLoading] = useState(false); - const pageListRef = useRef(null); - const {fetchData} = useFetch() - const [init, setInit] = useState(true) - const [tableListDataSource, setTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const {systemId,orgId, teamId} = useParams(); - const subSubscribeRef = useRef(null) - const [memberValueEnum, setMemberValueEnum] = useState<{[k:string]:{text:string}}>({}) - const {accessData} = useGlobalContext() - const [drawerOpen, setDrawerOpen] = useState(false) - const [curSubService, setCurSubService] = useState() - const getSubServiceList = ()=>{ - - if(!tableHttpReload){ - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - - return fetchData>('project/subscriptions',{method:'GET',eoParams:{project:systemId,keyword:searchWord},eoTransformKeys:['apply_status','create_time']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTableListDataSource(data.subscriptions) - setInit((prev)=>prev ? false : prev) - setTableHttpReload(false) - return {data:data.subscriptions, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - const handlerService = (type:'reApply'|'delete'|'cancelSub'|'cancelApply',entity:SystemSubServiceTableListItem)=>{ - let url:string - let method:string - let eoParams:{[k:string]:string|number} - switch (type){ - case 'reApply': - url = 'project/subscription/cancel_apply' - method = 'POST' - break - case 'delete': - url = 'project/subscription' - method = 'DELETE' - eoParams = {subscription:entity.id!,project:systemId!} - break - case 'cancelSub': - url = 'project/subscription/cancel' - eoParams = {subscription:entity.id!,project:systemId!} - method = 'POST' - break - case 'cancelApply': - url = 'project/subscription/cancel/application' - eoParams = {application:entity.id!,project:systemId!} - method = 'POST' - break - } - return new Promise((resolve, reject)=>{ - fetchData>(url,{method,eoParams}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - - const isActionAllowed = (type:'view'|'cancelSub'|'cancelApply'|'delete'|'reApply') => { - const actionToPermissionMap = { - 'view': 'viewApproval', - 'cancelSub': 'cancelSubscribe', - 'cancelApply': 'cancelApply', - 'reApply': 'subscribe', - 'delete': 'delete' - }; - - const action = actionToPermissionMap[type]; - const permission = `project.mySystem.subservice.${action}` as keyof typeof PERMISSION_DEFINITION[0]; - - return !checkAccess(permission, accessData); - }; - - - const openDrawer = (entity:SystemSubServiceTableListItem)=>{ - setCurSubService(entity) - setDrawerOpen(true) - } - - const openModal = async (type:'view'|'cancelSub'|'cancelApply'|'delete'|'reApply',entity:SystemSubServiceTableListItem)=>{ - //console.log(type,entity) - let title:string = '' - let content:string|ReactNode = '' - switch (type){ - case 'view': - case 'reApply':{ - message.loading('正在加载数据') - const {code,data,msg} = await fetchData>('project/subscription/approval',{method:'GET',eoParams:{subscription:entity!.id, project:systemId},eoTransformKeys:['apply_project','apply_team','apply_time','approval_time']}) - message.destroy() - if(code === STATUS_CODE.SUCCESS){ - title=type === 'view' ? '审批详情':'重新申请' - content = ; - }else{ - message.error(msg || '操作失败') - return - } - break; - } - case 'cancelSub': - title='取消订阅' - content='请确认是否取消订阅?' - break; - case 'cancelApply': - title='取消申请' - content='请确认是否取消申请?' - break; - case 'delete': - title='删除' - content='该数据删除后将无法找回,请确认是否删除?' - break; - } - - modal.confirm({ - title, - content, - onOk:()=>{ - if(type === 'reApply'){ - return subSubscribeRef.current?.reApply().then((res)=>{ - if(res === true) manualReloadTable() - }) - } - if(type !== 'view'){ - return handlerService(type,entity).then((res)=>{if(res === true) manualReloadTable()}) - } - }, - okText:type === 'reApply' ? '重新申请' :'确认', - okButtonProps:{ - disabled : isActionAllowed(type) - }, - cancelText:'取消', - closable:true, - icon:<>, - width:600 - }) - } - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 194, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: SystemSubServiceTableListItem) => [ - {openDrawer(entity)}} btnTitle="查看"/>, - ...(entity.applyStatus === 2 ? [ - , - {openModal('view',entity)}} btnTitle="审批详情"/>, - , - {openModal('cancelSub',entity)}} btnTitle="取消订阅"/> - ]:[]), - ...( entity.applyStatus === 1? [ - , - {openModal('cancelApply',entity)}} btnTitle="取消申请"/> - ]:[]), - ...( entity.applyStatus !== 1 && entity.applyStatus !== 2? [ - {openModal('reApply',entity)}} btnTitle="重新申请"/>, - , - {openModal('delete',entity)}} btnTitle="删除"/>]:[]), - ], - } - ] - - useEffect(() => { - setBreadcrumb([ - { - title:内部数据服务 - }, - { - title:'使用的服务列表' - } - ]) - getMemberList() - manualReloadTable() - }, [systemId]); - - const getMemberList = async ()=>{ - setMemberValueEnum({}) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.members?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setMemberValueEnum(tmpValueEnum) - }else{ - message.error(msg || '操作失败') - } - } - - const columns = useMemo(()=>{ - return SYSTEM_SUBSERVICE_TABLE_COLUMNS.map(x=>{if(x.filters &&(x.dataIndex as string[])?.indexOf('applier') !== -1){x.valueEnum = memberValueEnum} return x}) - },[memberValueEnum]) - - return ( - <> - getSubServiceList()} - dataSource={tableListDataSource} - columns = {[...columns,...operation]} - addNewBtnTitle="订阅第三方服务" - addNewBtnAccess="project.mySystem.subservice.subscribe" - searchPlaceholder="输入名称、ID、所属服务、负责人查找服务" - onAddNewBtnClick={()=>{navigate(`/serviceHub/list?callbackUrl=${location.pathname}${location.search}`)}} - tableClickAccess="project.mySystem.subservice.view" - onSearchWordChange={(e)=>{setSearchWord(e.target.value)}} - onChange={() => { - setTableHttpReload(false) - }} - onRowClick={(row:SystemSubServiceTableListItem)=>openDrawer(row)} - /> - {setDrawerOpen(false); setCurSubService(undefined)}} - open={drawerOpen} - footer={null}> - - - - ) - -} -export default SystemInsideSubService \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstream.module.css b/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstream.module.css deleted file mode 100644 index 0ba7650..0000000 --- a/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstream.module.css +++ /dev/null @@ -1,6 +0,0 @@ -.upstream-tabs{ - :global(.ant-tabs-content-holder){ - overflow:auto; - height:100%; - } -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamConfig.tsx b/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamConfig.tsx deleted file mode 100644 index ce78877..0000000 --- a/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamConfig.tsx +++ /dev/null @@ -1,257 +0,0 @@ -import { forwardRef, useEffect, useImperativeHandle, useState} from "react"; -import {App, Button, Divider, Form, FormItemProps, Input, InputNumber, Radio,Select} from "antd"; -import {useParams} from "react-router-dom"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import EditableTableWithModal from "@common/components/aoplatform/EditableTableWithModal.tsx"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import { typeOptions, schemeOptions,balanceOptions,passHostOptions, PROXY_HEADER_CONFIG, SYSTEM_UPSTREAM_GLOBAL_CONFIG_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import { ServiceUpstreamFieldType, NodeItem, ProxyHeaderItem, GlobalNodeItem, SystemInsideUpstreamConfigHandle, SystemInsideUpstreamConfigProps } from "../../../const/system/type.ts"; -import EditableTable from "@common/components/aoplatform/EditableTable.tsx"; -import { v4 as uuidv4} from 'uuid' -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; - - -const SystemInsideUpstreamConfig = forwardRef((props,ref) => { - const {upstreamNameForm,partitionId,setLoading} = props - const { message } = App.useApp() - const { serviceId,systemId } = useParams(); - const [form] = Form.useForm(); - const {fetchData} = useFetch() - const [, forceUpdate] = useState(null); - const [showHost, setShowHost] = useState(false) - - useImperativeHandle(ref, () => ({ - save:onFinish - })); - - const saveUpstream = (value:ServiceUpstreamFieldType)=>{ - value.proxyHeaders ||= [] - if(value.globalConfig?.nodes){ - value.globalConfig.nodes = value.globalConfig.nodes.filter((x:GlobalNodeItem)=>x.address)?.map((x:GlobalNodeItem)=>({address:x.address, weight:x.weight ?? 100})) - } - if(value.tmpConfig?.nodes){ - const clusterConfig:Map = new Map() - value.tmpConfig.nodes.forEach((x:NodeItem)=>{ - if(!x.address) return - if (!clusterConfig.has(x.cluster)) { - clusterConfig.set(x.cluster, { nodes: [] }); - } - clusterConfig.get(x.cluster)!.nodes.push({ address: x.address, weight: x.weight ?? 100 }); - }) - value.config = Array.from(clusterConfig.entries())?.map(([cluster, nodes]) => ({ cluster, nodes: nodes.nodes })); - delete value.tmpConfig; - } - - return fetchData>( - 'project/upstream', - { - method:'PUT', - eoBody:({ - ...value, - name:upstreamNameForm.getFieldValue('name'), - limitPeerSecond:Number(value.limitPeerSecond)||0, - retry:Number(value.retry)||0, - timeout:Number(value.timeout)||0}), - eoParams:{project:systemId}, - eoTransformKeys:['limitPeerSecond','proxyHeaders','optType','globalConfig','passHost','upstreamHost'] - }).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - return Promise.resolve(true) - }else{ - message.error(msg || '操作失败') - return Promise.reject(msg || '操作失败') - } - }).catch((errorInfo)=> {return Promise.reject(errorInfo)}) - } - - const onFinish:()=>Promise = async () => { - try { - form.setFieldValue('partition',partitionId) - await upstreamNameForm.validateFields(); - const value: ServiceUpstreamFieldType = await form.validateFields(); - return saveUpstream(value); - } catch (errorInfo) { - return Promise.reject(errorInfo); - } -}; - // 获取表单默认值 - const getUpstreamInfo = () => { - setLoading(true) - fetchData>('project/upstream',{method:'GET',eoParams:{project:systemId},eoTransformKeys:['limit_peer_second','proxy_headers','opt_type','global_config','pass_host','upstream_host']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setShowHost(data.upstream.passHost == 'rewrite') - if(data.upstream.globalConfig?.nodes){ - data.upstream.globalConfig.nodes.push({_id:uuidv4()}) - } - const addEmptyMergedData:NodeItem[] = [] - // const mergeGlobalData = data.upstream?.config?.default?.length > 0 ? generateResultList(mergedData, data.upstream.config.default):mergedData - setTimeout(()=>{form.setFieldsValue({...data.upstream,partition:partitionId,balance: data.upstream.balance || 'round-robin',limitPeerSecond:data.upstream.limitPeerSecond || 5,timeout:data.upstream.timeout || 10000,proxyHeaders: data.upstream.proxyHeaders || [],retry:data.upstream.retry || 3,config:data.config, tmpConfig:{nodes:addEmptyMergedData}})},0) - upstreamNameForm.setFieldValue('name',data.upstream.name) - }else{ - message.error(msg || '操作失败') - } - }).finally(()=>{ - setLoading(false) - forceUpdate({}) - }) - }; - - // 自定义校验规则 -const globalConfigNodesRule: FormItemProps['rules'] = [ - { - validator: (_, value) => { - if (!value || !Array.isArray(value)) { - return Promise.resolve(); - } - const filteredValue = value.filter((item) => item.address && item.weight!== '' && item.weight!== null); - if (filteredValue.length > 0) { - return Promise.resolve(); - } else { - return Promise.reject(new Error('必填项')); - } - }, - }, - ]; - - useEffect(() => { - form.setFieldsValue({partition:partitionId,driver:'static', scheme:'HTTP', balance:'round-robin',passHost:'pass', limitPeerSecond:5,timeout:10000,retry:3,globalConfig:{nodes:undefined}}); // 清空 initialValues - getUpstreamInfo(); - }, [partitionId]); - - return ( - -
- - - label="环境 ID" - name="partition" - hidden - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - - - label="上游类型" - name="driver" - rules={[{ required: true, message: '必填项' }]} - > - - - - - - label="服务地址" - name={["globalConfig","nodes"]} - tooltip="后端默认使用的IP地址" - rules={[{ required: true, message: '必填项' }, - ...globalConfigNodesRule]} - > - - className="w-[528px]" - configFields={SYSTEM_UPSTREAM_GLOBAL_CONFIG_TABLE_COLUMNS} - /> - - - - label="请求协议" - name="scheme" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="负载均衡" - name="balance" - rules={[{ required: true, message: '必填项' }]} - > - - - - - label="转发 Host" - name="passHost" - rules={[{ required: true, message: '必填项' }]} - > - - - - {showHost && - label="重写域名" - name="upstreamHost" - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - } - - - - - - - label="超时时间" - name="timeout" - rules={[{ required: true, message: '必填项' }]} - > - ms }/> - - - - label="超时重试次数" - name="retry" - rules={[{ required: true, message: '必填项' }]} - > - 次} /> - - - - label="调用频率限制" - name="limitPeerSecond" - rules={[{ required: true, message: '必填项' }]} - > - 次/秒 } /> - - - - label="转发上游请求头" - name="proxyHeaders" - className="mb-0" - > - - className="w-[528px]" - configFields={PROXY_HEADER_CONFIG} - /> - - - - - - -
- ) -}) - -export default SystemInsideUpstreamConfig; \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamList.tsx b/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamList.tsx deleted file mode 100644 index 544fe43..0000000 --- a/frontend/packages/core/src/pages/system/upstream/SystemInsideUpstreamList.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import {Link, useParams} from "react-router-dom"; -import PageList from "@common/components/aoplatform/PageList.tsx"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {App, Divider} from "antd"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { SimpleMemberItem } from "@common/const/type.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import { SystemInsideUpstreamContentHandle, SystemUpstreamTableListItem } from "../../../const/system/type.ts"; -import { SYSTEM_UPSTREAM_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { checkAccess } from "@common/utils/permission.ts"; -import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter.tsx"; -import SystemInsideUpstreamContent from "./SystemInsideUpstreamContent.tsx"; - -const SystemInsideUpstreamList:FC = ()=>{ - const { modal,message } = App.useApp() - const { setBreadcrumb } = useBreadcrumb() - const pageListRef = useRef(null); - const [tableListDataSource, setTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const {fetchData} = useFetch() - const {orgId, teamId, systemId } = useParams() - const [memberValueEnum, setMemberValueEnum] = useState<{[k:string]:{text:string}}>({}) - const {accessData} = useGlobalContext() - const [open, setOpen] = useState(false); - const [curUpstreamId, setCurUpstreamId] = useState() - const drawerFormRef = useRef(null) - - const deleteUpstream = (entity:SystemUpstreamTableListItem)=>{ - return new Promise((resolve, reject)=>{ - fetchData>('project/upstream',{method:'DELETE',eoParams:{upstream:entity!.id,project:systemId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - const openModal = async (entity:SystemUpstreamTableListItem)=>{ - modal.confirm({ - title:'删除', - content:'该数据删除后将无法找回,请确认是否删除?', - onOk:()=> { - return deleteUpstream(entity).then((res)=>{if(res === true) manualReloadTable()}) - }, - width:600, - okText:'确认', - okButtonProps:{ - disabled:!checkAccess('project.mySystem.upstream.delete',accessData) - }, - cancelText:'取消', - closable:true, - icon:<> - }) - } - - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 93, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: SystemUpstreamTableListItem) => [ - {openDrawer(entity.id)}} btnTitle="编辑"/>, - entity.canDelete && , - entity.canDelete && {openModal(entity)}} btnTitle="删除"/>, - ], - } - ] - - const getUpstreamList =(): Promise<{ data: SystemUpstreamTableListItem[], success: boolean }>=> { - if(!tableHttpReload){ - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - return fetchData>('project/upstreams',{method:'GET',eoParams:{project:systemId},eoTransformKeys:['update_time','create_time','can_delete']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTableListDataSource(data.upstreams) - setTableHttpReload(false) - return {data:data.upstreams, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - useEffect(() => { - setBreadcrumb([ - { - title:内部数据服务 - }, - { - title:'上游' - } - ]) - getMemberList() - manualReloadTable() - }, [systemId]); - - const getMemberList = async ()=>{ - setMemberValueEnum({}) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.members?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setMemberValueEnum(tmpValueEnum) - }else{ - message.error(msg || '操作失败') - } - } - - const columns = useMemo(()=>{ - return SYSTEM_UPSTREAM_TABLE_COLUMNS.map(x=>{if(x.filters &&((x.dataIndex as string[])?.indexOf('creator') !== -1 || (x.dataIndex as string[])?.indexOf('updater') !== -1) ){x.valueEnum = memberValueEnum} return x}) - },[memberValueEnum]) - - const openDrawer = (id?:string)=>{ - id === undefined? setOpen(true) : setCurUpstreamId(id) - } - - useEffect(()=>{ - curUpstreamId !== undefined && setOpen(true) - },[curUpstreamId]) - - const onClose = () => { - setOpen(false); - setCurUpstreamId(undefined) - }; - - return ( - <> - getUpstreamList()} - addNewBtnTitle="添加上游" - addNewBtnAccess="project.mySystem.upstream.add" - tableClickAccess="project.mySystem.upstream.edit" - onChange={() => { - setTableHttpReload(false) - }} - onAddNewBtnClick={()=>{ - openDrawer() - }} - onRowClick={(row:SystemUpstreamTableListItem)=>openDrawer(row.id)} - /> - drawerFormRef.current?.save()?.then((res)=>{res && manualReloadTable(); return res})} > - - - - ) - -} -export default SystemInsideUpstreamList \ No newline at end of file diff --git a/frontend/packages/core/src/pages/team/TeamInsideAccess.tsx b/frontend/packages/core/src/pages/team/TeamInsideAccess.tsx deleted file mode 100644 index a2720a3..0000000 --- a/frontend/packages/core/src/pages/team/TeamInsideAccess.tsx +++ /dev/null @@ -1,133 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-04 19:11:43 - * @FilePath: \frontend\packages\core\src\pages\team\TeamInsideAccess.tsx - */ -import {App, Collapse, Empty} from "antd"; -import {AccessMemberList, AccessOptionItem, PermissionListItem} from "../access/AccessList.tsx"; -import styles from "./Team.module.css"; -import {DownOutlined, UpOutlined} from "@ant-design/icons"; -import {useEffect, useRef, useState} from "react"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import {Link, useParams} from "react-router-dom"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {DefaultOptionType} from "antd/es/cascader"; -import { PermissionOptionType } from "../access/AccessPage.tsx"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext.tsx"; - -export default function TeamInsideAccess(){ - const [accessList, setAccessList] = useState>([]) - const { message } = App.useApp() - const {teamId} = useParams(); - const {fetchData} = useFetch() - const { setBreadcrumb} = useBreadcrumb() - const requestState = useRef<{ keyword?: string, promise?: Promise}>({ }); - const [activeKey, setActiveKey] = useState([]) - - const getMemberOptionList = ( keyword?: string): Promise => { - // 如果type或keyword与缓存中的相同,返回缓存的promise - if (requestState.current.keyword === keyword && requestState.current.promise) { - return requestState.current.promise!; - } - - // 创建新的promise并更新引用 - const newPromise = new Promise((resolve, reject)=>{ - fetchData>( - 'team/setting/permission/options', - { method: 'GET', eoParams:{team:teamId,keyword:keyword||""} } - ).then((response) => { - const { code, data, msg } = response; - if (code === STATUS_CODE.SUCCESS) { - resolve(data); - } else { - message.error(msg || '操作失败'); - reject(msg || '操作失败'); - } - }).catch((error) => { - // 处理错误 - reject(error) - throw error; - }); - }) - - // 更新引用 - requestState.current = {keyword, promise: newPromise }; - - // 返回新的promise - return newPromise; - }; - - - const addMember = (value:{[k:string]:unknown})=>{ - //console.log(value) - return fetchData>('team/setting/permission',{method:'POST',eoBody:({...value}),eoParams:{team:teamId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - getAccessList() - return Promise.resolve(true) - }else{ - message.error(msg || '操作失败') - return Promise.reject(msg) - } - }).catch(errInfo=>Promise.reject(errInfo)) - } - - const removeMember :(entity:AccessOptionItem & {access:string})=>Promise = (entity:AccessOptionItem& {access:string})=>{ - return new Promise((resolve, reject)=>{ - fetchData>('team/setting/permission',{method:'DELETE',eoParams:{access:entity.access,key:entity.key,team:teamId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(false) - } - }).catch(()=>reject(false)) - }) - } - - const getAccessList = ()=>{ - fetchData>('team/setting/permissions',{method:'GET',eoParams:{team:teamId}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setAccessList(data.permissions?.map((x:PermissionListItem)=>({ - key:x.access, label:<>{x.name} {x.description}, - children: - })) || []) - setActiveKey(data.permissions?.map((x:PermissionListItem)=>(x.access))) - }else{ - message.error(msg || '操作失败') - } - }) - } - - useEffect(() => { - setBreadcrumb([ - {title:团队}, - {title:'权限'} - ]) - getAccessList() - }, [teamId]); - - return ( -
-

权限设置

-
- { accessList && accessList.length > 0 ? - <> - {setActiveKey(val as string[])}} - expandIcon={({isActive})=>(isActive? : )}/> - :
- } -
-
- ) -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/user/UserList.tsx b/frontend/packages/core/src/pages/user/UserList.tsx deleted file mode 100644 index a692648..0000000 --- a/frontend/packages/core/src/pages/user/UserList.tsx +++ /dev/null @@ -1,328 +0,0 @@ -/* - * @Date: 2024-01-31 15:00:11 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-07 17:36:52 - * @FilePath: \frontend\packages\core\src\pages\user\UserList.tsx - */ -import {App, Button, Modal} from "antd"; -import PageList from "@common/components/aoplatform/PageList.tsx"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import {TransferTableHandle} from "@common/components/aoplatform/TransferTable.tsx"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import MemberTransfer from "@common/components/aoplatform/MemberTransfer.tsx"; -import {useEffect, useMemo, useRef, useState} from "react"; -import {useOutletContext, useParams} from "react-router-dom"; -import {ActionType, ProColumns} from "@ant-design/pro-components"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {EntityItem, MemberItem} from "@common/const/type.ts"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import {useFetch} from "@common/hooks/http.ts"; -import { USER_LIST_COLUMNS } from "../../const/user/const.tsx"; -import { DepartmentListItem } from "../../const/member/type.ts"; -import { handleDepartmentListToFilter } from "@common/utils/dataTransfer.ts"; -import { checkAccess } from "@common/utils/permission.ts"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { ColumnFilterItem } from "antd/es/table/interface"; -import {v4 as uuidv4} from 'uuid' -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; - -type DepartmentWithMemberItem = - DepartmentListItem & {type:'member'|'department', children?: Array< DepartmentListItem & {type:'member'|'department'} | { - id:string, - name:string, - avatar:string, - email:string} & {type:'member'|'department'}> -} - - -export const getDepartmentWithMember = (department:(DepartmentListItem & {type?:'department'|'member'})[],departmentMap:Map) : (DepartmentWithMemberItem | undefined)[] =>{ - return department.map((x:DepartmentListItem & {type?:'department'|'member'})=>{ - const res = ({ - ...x, - key:x.id, - title:x.name, - 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)) -} - -export const addMemberToDepartment = (departmentMap: Map, departmentId: string, member: MemberItem) => { - const members = departmentMap.get(departmentId) || []; - members.push({...member, type: 'member'}); - departmentMap.set(departmentId, members); - } - -const UserList = ()=>{ - const { userGroupId } = useParams(); - const [searchWord, setSearchWord] = useState('') - const { modal,message} = App.useApp() - // const [confirmLoading, setConfirmLoading] = useState(false); - const addRef = useRef>(null) - const [addMemberBtnDisabled, setAddMemberBtnDisabled] = useState(true) - const [init, setInit] = useState(true) - const [tableHttpReload, setTableHttpReload] = useState(true); - const [tableListDataSource, setTableListDataSource] = useState([]); - const {fetchData} = useFetch() - const [allMemberIds,setAllMemberIds] = useState([]) - const [allMemberSelectedDepartIds, setAllMemberSelectedDepartIds] = useState([]) - const {refreshGroup} = useOutletContext<{refreshGroup:()=>void}>() - const [departmentValueEnum,setDepartmentValueEnum] = useState([]) - const [selectableMemberIds,setSelectableMemberIds] = useState>(new Set()) - const [addMemberBtnLoading, setAddMemberBtnLoading] = useState(false) - const [modalVisible, setModalVisible] = useState(false) - const {accessData} = useGlobalContext() - const getUserList = ()=>{ - if(!tableHttpReload){ - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - return fetchData>('user/group/members',{method:'GET',eoParams:{userGroup:userGroupId,keyword:searchWord},eoTransformKeys:['userGroup']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTableListDataSource(data.members) - setInit((prev)=>prev ? false : prev) - setTableHttpReload(false) - if(!searchWord) setAllMemberIds(data.members?.map((x:MemberItem)=>x.id) || []) - return {data:data.members, success: true} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - - const getDepartmentMemberList = () => { - const topDepartmentId:string = uuidv4() - return Promise.all([ - fetchData>('simple/departments', {method:'GET'}), - fetchData>('simple/member', {method:'GET', eoParams:{}, eoTransformKeys:[]}) - ]).then(([departmentResponse, memberResponse])=>{ - const departmentMap = new Map(); - memberResponse.data.members.forEach((member: MemberItem) => { - setSelectableMemberIds((pre)=>{pre.add(member.id);return pre}) - member = {...member, title:member.name, key:member.id} - if (member.department) { - member.department.forEach((department: EntityItem) => { - addMemberToDepartment(departmentMap, department.id, member); - }); - } else { - addMemberToDepartment(departmentMap, '_withoutDepartment', member); - } - }); - - const finalData = departmentResponse.data.department - ? [ - { - id: topDepartmentId, - key:topDepartmentId, - name: departmentResponse.data.department.name, - title:departmentResponse.data.department.name, - children: [ - ...getDepartmentWithMember(departmentResponse.data.department.children, departmentMap), - ...departmentMap.get('_withoutDepartment') || [] - ] - } - ] - : [...departmentMap.get('_withoutDepartment') || []]; - 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]) - } - } - } - if(!finalData[0].children || finalData[0].children.filter(m => allMemberIds.indexOf(m.id) === -1).length === 0){ - setAllMemberSelectedDepartIds((pre)=>[...pre, topDepartmentId]) - } - - return {data:finalData, success: true} - }).catch(()=>({data:[], success:false})) - } - - - const operation:ProColumns[] =[ - { - title: '操作', - key: 'option', - width: 62, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: MemberItem) => [ - {openModal('delete',entity!)}} btnTitle="移除"/> - ], - } - ] - - const treeDisabledData = useMemo(()=>{ return [...allMemberIds,...allMemberSelectedDepartIds]},[allMemberIds,allMemberSelectedDepartIds]) - - const { setBreadcrumb } = useBreadcrumb() - const pageListRef = useRef(null); - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - const addMember = (selectableMemberIds:Set)=>{ - setAddMemberBtnLoading(true) - const keyFromModal = addRef.current?.selectedRowKeys() - const memberKeyFromModal = keyFromModal?.filter(x => allMemberIds.indexOf(x as string) === -1 && selectableMemberIds.has(x)) || []; - return new Promise((resolve, reject)=>{ - fetchData>('user/group/member',{method:'POST',eoParams:{userGroup:userGroupId},eoBody:({ids:Array.from(memberKeyFromModal) || []}),eoTransformKeys:['userGroup']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - manualReloadTable() - refreshGroup && refreshGroup() - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)).finally(()=>setAddMemberBtnLoading(false)) - }) - } - - const deleteUser = (entity:MemberItem)=>{ - return new Promise((resolve, reject)=>{ - fetchData>('user/group/member',{method:'DELETE',eoParams:{userGroup:userGroupId,member:entity!.id},eoTransformKeys:['userGroup']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - - const openModal = (type:'addMember'|'delete',entity?:MemberItem)=>{ - let title:string = '' - let content:string|React.ReactNode = '' - switch (type){ - case 'addMember': - setModalVisible(true) - setAddMemberBtnDisabled(true) - setAddMemberBtnLoading(false) - return; - case 'delete': - title='移除成员' - content=确定删除成员?此操作无法恢复,确认操作? - break; - } - - modal.confirm({ - title, - content, - onOk:()=>{ - return deleteUser(entity!).then((res)=>{if(res === true) {refreshGroup && refreshGroup() ; manualReloadTable()}}) - }, - width:600, - okText:'确认', - cancelText:'取消', - okButtonProps:{ - disabled : !checkAccess( `system.user.member.delete`, accessData) - }, - closable:true, - icon:<>, - }) - } - - useEffect(() => { - !init && manualReloadTable() - }, [userGroupId]); - - useEffect(()=>{ - setBreadcrumb([{ title: '用户组'}]) - getDepartmentList() - },[]) - - - const cleanModalData = ()=>{ - setModalVisible(false);setAddMemberBtnDisabled(true);setAddMemberBtnLoading(false) - } - - const getDepartmentList = async ()=>{ - setDepartmentValueEnum([]) - const {code,data,msg} = await fetchData>('simple/departments',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:ColumnFilterItem[] = [{text:data.department.name, value:data.department.id,children:handleDepartmentListToFilter(data.department.children)}] - setDepartmentValueEnum(tmpValueEnum) - }else{ - message.error(msg || '操作失败') - } - } - - const columns = useMemo(()=>{ - return USER_LIST_COLUMNS.map(x=>{if((x.dataIndex as string[])?.indexOf('department') !== -1 ){ - x.filters = departmentValueEnum - x.onFilter = (value: string, record) => { - return value ? record.department?.filter(x=>x.id === value).length > 0 : true - } - } return x}) - },[departmentValueEnum]) - - return (<>getUserList()} - addNewBtnTitle="添加成员" - searchPlaceholder="输入用户名、邮箱查找成员" - onAddNewBtnClick={() => { - openModal('addMember') - }} - addNewBtnAccess="system.user.member.add" - onSearchWordChange={(e) => { - setSearchWord(e.target.value) - }} - /> - {cleanModalData()}} - maskClosable={false} - footer={[ - , - , - ]} - > - getDepartmentMemberList()} - onSelect={(selectedData: Set) => { - const memberKeyFromModal = Array.from(selectedData)?.filter(x => allMemberIds.indexOf(x) === -1 &&selectableMemberIds.has(x)) || []; - setAddMemberBtnDisabled((memberKeyFromModal.length === 0)); - }} - searchPlaceholder="搜索用户名、邮箱" - /> - - ) - -} -export default UserList; \ No newline at end of file diff --git a/frontend/packages/core/src/pages/user/UserPage.tsx b/frontend/packages/core/src/pages/user/UserPage.tsx deleted file mode 100644 index 876b43a..0000000 --- a/frontend/packages/core/src/pages/user/UserPage.tsx +++ /dev/null @@ -1,264 +0,0 @@ -/* - * @Date: 2024-04-08 15:05:34 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-05 15:17:55 - * @FilePath: \frontend\packages\core\src\pages\user\UserPage.tsx - */ -import {DataNode} from "antd/es/tree"; -import {Outlet, useNavigate, useParams} from "react-router-dom"; -import {forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react"; -import {App, Button, Empty, Form, Input} from "antd"; -import {PlusOutlined} from "@ant-design/icons"; -import styles from '../system/SystemList.module.css' -import {useFetch} from "@common/hooks/http.ts"; -import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; -import { UserGroupModalHandle, UserGroupModalProps, FieldType, UserGroupItem } from "../../const/user/types.ts"; -import { RouterParams } from "@core/components/aoplatform/RenderRoutes.tsx"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { PERMISSION_DEFINITION } from "@common/const/permissions.ts"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { checkAccess } from "@common/utils/permission.ts"; -import GroupTree, { GroupTreeHandle } from "@common/components/aoplatform/GroupTree.tsx"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext.tsx"; - -export const UserGroupModal = forwardRef((props,ref)=>{ - const { message } = App.useApp() - const [form] = Form.useForm(); - const {type,entity} = props - const {fetchData} = useFetch() - - const save:()=>Promise = ()=>{ - //console.log(type) - const url:string = 'user/group' - let method:string - switch (type){ - case 'add': - method = 'POST' - break; - case 'edit': - method = 'PUT' - break; - } - return new Promise((resolve, reject)=>{ - form.validateFields().then((value)=>{ - fetchData>(url,{method,eoBody:({name:value.name}), ...(type ==='edit' ? {eoParams:{userGroup:value.id}}:{}),eoTransformKeys:['userGroup']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - useImperativeHandle(ref, ()=>({ - save - }) - ) - - useEffect(() => { - - if(type === 'edit'){ - form.setFieldsValue(entity) - } - }, []); - - return ( -
- - {type === 'edit' && - - label="ID" - name="id" - hidden - rules={[{ required: true, message: '必填项',whitespace:true }]} - > - - - } - - label="用户组名称" - name="name" - rules={[{ required: true, message: '必填项' ,whitespace:true }]} - > - - - -
) -}) - -const UserPage = ()=>{ - const {modal,message} = App.useApp() - const navigate = useNavigate() - const {fetchData} = useFetch() - const {userGroupId} = useParams() - const [userGroup, setUserGroup] = useState() - const [selectedGroupIds, setSelectedGroupIds] = useState([userGroupId!]) - const {accessData} = useGlobalContext() - const groupRef = useRef(null) - const {setBreadcrumb} = useBreadcrumb() - - - const dropdownMenu = (entity:UserGroupItem) => [ - // { - // key: 'add', - // label: ( - // - // ), - // }, - { - key: 'edit', - label: ( - - ), - }, - { - key: 'delete', - label: ( - - ), - }, - ]; - - const handleEditUserGroup = (type:'rename'|'addChild'|'addPeer',entity:UserGroupItem, name:string)=>{ - const url:string = 'user/group' - let method:string - switch (type){ - case 'rename': - method = 'PUT' - break; - case 'addPeer': - method = 'POST' - break; - } - - return new Promise((resolve, reject)=>{ - return fetchData>(url,{method,eoBody:({name:name}), ...(type ==='rename' ? {eoParams:{userGroup:entity.id}}:{}),eoTransformKeys:['userGroup']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - getUserGroup() - return resolve(true) - }else{ - message.error(msg || '操作失败') - return reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const treeData = useMemo(() => { - const loop = (data: UserGroupItem[]): (DataNode & UserGroupItem)[] => - data?.map((item) => { - return { - ...item, - title:item.name, - key: item.id, - }; - }); - return userGroup ? loop(userGroup) :[]; - }, [userGroup]); - - - const getUserGroup = ()=>{ - setUserGroup([]) - fetchData>('user/groups',{method:'GET',eoTransformKeys:['user_groups']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setUserGroup(data.userGroups) - if(userGroup === undefined) {navigate(`/user/list/${data.userGroups[0].id}`); return} - }else{ - message.error(msg || '操作失败') - return {data:[], success:false} - } - }) - } - - const deleteUserGroup = (id:string)=>{ - return new Promise((resolve, reject)=>{ - fetchData>('user/group',{method:'DELETE',eoParams:{userGroup:id},eoTransformKeys:['userGroup']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || '操作成功!') - resolve(true) - }else{ - message.error(msg || '操作失败') - reject(msg || '操作失败') - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const openModal = (type:'add'|'edit'|'delete',entity?:{id:string, name:string})=>{ - modal.confirm({ - title:'删除', - content:'该数据删除后将无法找回,请确认是否删除?', - onOk:()=>deleteUserGroup(entity!.id!).then((res)=>{if(res === true) getUserGroup()}), - width:600, - okText:'确认', - okButtonProps:{ - disabled : !checkAccess(`system.user.group.${type}` as keyof typeof PERMISSION_DEFINITION[0], accessData) - }, - cancelText:'取消', - closable:true, - icon:<>, - }) - } - - useEffect(() => { - setBreadcrumb([ - {title:'用户组'} - ]) - getUserGroup() - }, []); - - useEffect(()=>{ - userGroupId && setSelectedGroupIds([userGroupId]) - },[userGroupId]) - - return ( -
-
- } - groupData={treeData} - selectedKeys={selectedGroupIds} - addBtnName={<>添加用户组} - addBtnAccess="system.user.group.add" - onSelect={(selectedKeys) => { - navigate(`/user/list/${selectedKeys[0]}`) - }} - treeNameSuffixKey='usage' - dropdownMenu={dropdownMenu} - onEditGroup={handleEditUserGroup} - withMore - placeholder="搜索用户组" - /> -
- {treeData?.length > 0 ?
- getUserGroup()}} /> -
:
} -
) -} -export default UserPage; \ No newline at end of file diff --git a/frontend/packages/market/src/const/serviceHub/type.ts b/frontend/packages/market/src/const/serviceHub/type.ts index 0d612d7..0a3295f 100644 --- a/frontend/packages/market/src/const/serviceHub/type.ts +++ b/frontend/packages/market/src/const/serviceHub/type.ts @@ -15,6 +15,7 @@ export type ServiceBasicInfoType = { tags:EntityItem[] updateTime:string version:string + logo?:string } export type ServiceDetailType = { diff --git a/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx b/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx index 9857ed4..2dc09d0 100644 --- a/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx +++ b/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx @@ -125,10 +125,10 @@ const ServiceHubDetail = ()=>{
{/* {service?.name?.substring(0,1)} */} : undefined} - icon={serviceBasicInfo.logo ? '' :}> + icon={serviceBasicInfo?.logo ? '' :}>

{serviceName}

diff --git a/frontend/packages/market/tailwind.config.js b/frontend/packages/market/tailwind.config.js deleted file mode 100644 index e53065a..0000000 --- a/frontend/packages/market/tailwind.config.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * @Date: 2023-11-27 17:31:44 - * @LastEditors: maggieyyy - * @LastEditTime: 2024-06-05 10:36:11 - * @FilePath: \frontend\packages\market\tailwind.config.js - */ -/** @type {import('tailwindcss').Config} */ - -export default { - important:true, - content: [ - `./index.html`, - `../*/src/**/*.{js,ts,jsx,tsx}`, - ], - theme: { - extend: { - width: { - INPUT_NORMAL: '100%', - // INPUT_NORMAL: '346px', - INPUT_LARGE: '508px', - GROUP: '240px', - SEARCH: '276px', - LOG: '254px' - }, - minHeight:{ - TEXTAREA:'68px' - }, - borderRadius: { - DEFAULT: 'var(--border-radius)', - SEARCH_RADIUS: '50px' - }, - boxShadow:{ - SCROLL: '0 2px 2px #0000000d', - SCROLL_TOP:' 0 -2px 2px -2px var(--border-color)' - }, - colors: { - DISABLE_BG: 'var(--disabled-background-color)', - MAIN_TEXT: 'var(--text-color)', - MAIN_HOVER_TEXT: 'var(--text-hover-color)', - SECOND_TEXT:'var(--disabled-text-color)', - MAIN_BG: 'var(--background-color)', - MENU_BG:'var(--MENU-BG-COLOR)', - 'bar-theme': 'var(--bar-background-color)', - BORDER: 'var(--border-color)', - NAVBAR_BTN_BG: 'var(--item-active-background-color)', - MAIN_DISABLED_BG: 'var(--disabled-background-color)', - theme: 'var(--primary-color)', - DESC_TEXT: 'var(--TITLE_TEXT)', - HOVER_BG: 'var(--item-hover-background-color)', - guide_cluster: '#ee6760', - guide_upstream: '#f9a429', - guide_api: '#71d24d', - guide_publishApi: '#5884ff', - guide_final: '#915bf9', - table_text: 'var(--table-text-color)', - status_success:'#138913', - status_fail:"#ff3b30", - status_update:"#03a9f4", - status_pending:"#ffa500", - status_offline:"#8f8e93", - A_HOVER:'var(--button-primary-hover-background-color)' - }, - spacing: { - mbase: 'var(--FORM_SPAN)', - label: '12px', // 选择器和label之间的间距,待删 - btnbase: 'var(--LAYOUT_MARGIN)', // x方向的间距 - btnybase: 'var(--LAYOUT_MARGIN)', // y轴方向的间距 - btnrbase: '20px', // 页面最右侧边距20px - formtop: 'var(--FORM_SPAN)', - icon: '5px', - blockbase: '40px', - DEFAULT_BORDER_RADIUS: 'var(--border-radius)', - TREE_TITLE:'var(--small-padding) var(--LAYOUT_PADDING);' - }, - borderColor: { - 'color-base': 'var(--border-color)' - } - } - }, - plugins: [], - corePlugins: { - preflight: false, - }, - } - - \ No newline at end of file