diff --git a/scaleph-dao/src/main/java/cn/sliew/scaleph/dao/entity/master/resource/ResourceJar.java b/scaleph-dao/src/main/java/cn/sliew/scaleph/dao/entity/master/resource/ResourceJar.java
index aa4a6e076..efb540509 100644
--- a/scaleph-dao/src/main/java/cn/sliew/scaleph/dao/entity/master/resource/ResourceJar.java
+++ b/scaleph-dao/src/main/java/cn/sliew/scaleph/dao/entity/master/resource/ResourceJar.java
@@ -36,9 +36,6 @@ public class ResourceJar extends BaseDO {
private static final long serialVersionUID = 1L;
- @TableField("`group`")
- private String group;
-
@TableField("file_name")
private String fileName;
diff --git a/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/resource/ResourceJarMapper.xml b/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/resource/ResourceJarMapper.xml
index 2364ba333..6e7d0f43b 100644
--- a/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/resource/ResourceJarMapper.xml
+++ b/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/resource/ResourceJarMapper.xml
@@ -26,7 +26,6 @@
-
@@ -35,7 +34,7 @@
id, creator, create_time, editor, update_time,
- `group`, file_name, `path`, remark
+ file_name, `path`, remark
diff --git a/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/security/SecUserRoleMapper.xml b/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/security/SecUserRoleMapper.xml
index 614cfd678..bad8979d4 100644
--- a/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/security/SecUserRoleMapper.xml
+++ b/scaleph-dao/src/main/resources/cn/sliew/scaleph/dao/mapper/master/security/SecUserRoleMapper.xml
@@ -37,7 +37,7 @@
sec_user t1
JOIN sec_user_role t2 ON t1.id = t2.user_id
WHERE
- t2.role_id = 1
+ t2.role_id = #{roleId}
AND t1.`status` = #{status}
diff --git a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/convert/JarConvert.java b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/convert/JarConvert.java
index f9926b77d..fe2133e56 100644
--- a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/convert/JarConvert.java
+++ b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/convert/JarConvert.java
@@ -35,8 +35,7 @@ public interface JarConvert extends BaseConvert {
default JarListParam convert(ResourceListParam param) {
JarListParam target = BeanUtil.copy(param, new JarListParam());
- target.setGroup(param.getLabel());
- target.setFileName(param.getName());
+ target.setFileName(param.getLabel());
return target;
}
diff --git a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/impl/JarServiceImpl.java b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/impl/JarServiceImpl.java
index 3d30430dc..675fa17c8 100644
--- a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/impl/JarServiceImpl.java
+++ b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/impl/JarServiceImpl.java
@@ -80,7 +80,6 @@ public Page list(JarListParam param) throws IOException {
final Page page = jarMapper.selectPage(
new Page<>(param.getCurrent(), param.getPageSize()),
Wrappers.lambdaQuery(ResourceJar.class)
- .eq(StringUtils.hasText(param.getGroup()), ResourceJar::getGroup, param.getGroup())
.like(StringUtils.hasText(param.getFileName()), ResourceJar::getFileName, param.getFileName()));
Page result =
new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
@@ -101,7 +100,7 @@ public void upload(JarUploadParam param, MultipartFile file) throws IOException
String fileName = file.getOriginalFilename();
Path path = null;
try (InputStream inputStream = file.getInputStream()) {
- path = fileSystemService.upload(inputStream, getJarPath(param.getGroup(), fileName));
+ path = fileSystemService.upload(inputStream, getJarPath(fileName));
}
ResourceJar record = new ResourceJar();
BeanUtils.copyProperties(param, record);
@@ -134,11 +133,10 @@ public void delete(Long id) throws IOException {
jarMapper.deleteById(id);
}
- private String getJarPath(String group, String fileName) {
- return String.format("%s/%s/%s", getJarRootPath(), group, fileName);
+ private String getJarPath(String fileName) {
+ return String.format("%s/%s", getJarRootPath(), fileName);
}
-
private String getJarRootPath() {
return "jar";
}
diff --git a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarListParam.java b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarListParam.java
index 4ae6c32d8..27d553528 100644
--- a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarListParam.java
+++ b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarListParam.java
@@ -27,9 +27,6 @@
@EqualsAndHashCode(callSuper = true)
public class JarListParam extends PaginationParam {
- @Schema(description = "jar group")
- private String group;
-
@Schema(description = "文件名称。支持模糊匹配")
private String fileName;
diff --git a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarUploadParam.java b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarUploadParam.java
index 127599d71..11ec99ef2 100644
--- a/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarUploadParam.java
+++ b/scaleph-resource/src/main/java/cn/sliew/scaleph/resource/service/param/JarUploadParam.java
@@ -21,15 +21,9 @@
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
-import javax.validation.constraints.NotBlank;
-
@Data
public class JarUploadParam {
-
- @NotBlank
- @Schema(description = "jar group")
- private String group;
-
+
@Schema(description = "备注")
private String remark;
}
diff --git a/scaleph-ui-react/config/routes.ts b/scaleph-ui-react/config/routes.ts
index 1fcc0a931..a68cb2902 100644
--- a/scaleph-ui-react/config/routes.ts
+++ b/scaleph-ui-react/config/routes.ts
@@ -150,6 +150,13 @@ export default [
pCode: PRIVILEGE_CODE.workspaceClusterConfigShow,
access: 'normalRouteFilter'
},
+ {
+ path: '/workspace/flink/kubernetes/template/steps',
+ exact: true,
+ component: './Project/Workspace/Kubernetes/Template/Steps',
+ pCode: PRIVILEGE_CODE.workspaceClusterConfigShow,
+ access: 'normalRouteFilter'
+ },
{
path: '/workspace/flink/kubernetes/template/detail',
exact: true,
diff --git a/scaleph-ui-react/src/locales/zh-CN/pages/base.ts b/scaleph-ui-react/src/locales/zh-CN/pages/base.ts
index 2ff2fae0e..a7bc0531b 100644
--- a/scaleph-ui-react/src/locales/zh-CN/pages/base.ts
+++ b/scaleph-ui-react/src/locales/zh-CN/pages/base.ts
@@ -14,6 +14,16 @@ export default {
'app.common.operate.label': '操作',
'app.common.operate.success': '操作成功',
'app.common.operate.new.label': '新增',
+ 'app.common.operate.new.roles': '分配角色',
+ 'app.common.operate.new.rolesUser': '角色分配用户',
+ 'app.common.operate.new.rolesWeb': '角色配置web资源',
+ 'app.common.operate.new.user': '配置用户',
+ 'app.common.operate.new.webs': '配置web资源',
+ 'app.common.operate.new.accreditUser': '已授权用户',
+ 'app.common.operate.new.accreditRoles': '已授权角色',
+ 'app.common.operate.new.notAccreditUser': '未授权用户',
+ 'app.common.operate.new.notAccreditRoles': '未授权角色',
+ 'app.common.operate.new.assets': '权限配置',
'app.common.operate.new.success': '新增成功',
'app.common.operate.new.failure': '新增失败',
'app.common.operate.new.directive': '没有?去创建',
diff --git a/scaleph-ui-react/src/locales/zh-CN/pages/project.ts b/scaleph-ui-react/src/locales/zh-CN/pages/project.ts
index a6c40469c..d06611bde 100644
--- a/scaleph-ui-react/src/locales/zh-CN/pages/project.ts
+++ b/scaleph-ui-react/src/locales/zh-CN/pages/project.ts
@@ -818,11 +818,12 @@ export default {
// Sql
'pages.project.di.step.sql.query': 'SQL',
- 'pages.project.flink.kubernetes.deployment.template': 'Deployment Template',
- 'pages.project.flink.kubernetes.deployment.template.name': '名称',
- 'pages.project.flink.kubernetes.deployment.template.deploymentKind': '部署模式',
- 'pages.project.flink.kubernetes.deployment.template.namespace': 'Namespace',
- 'pages.project.flink.kubernetes.deployment.template.define': '模板定义',
+ 'pages.project.flink.kubernetes.template': 'Template',
+ 'pages.project.flink.kubernetes.template.name': '名称',
+ 'pages.project.flink.kubernetes.template.deploymentKind': '部署模式',
+ 'pages.project.flink.kubernetes.template.namespace': 'Namespace',
+ 'pages.project.flink.kubernetes.template.detail': '模板详情',
+ 'pages.project.flink.kubernetes.template.step.base': '基础信息',
'pages.project.flink.kubernetes.template.step.advanced.configOptions': 'ConfigOption',
'pages.project.flink.kubernetes.template.step.advanced.configOptions.key': 'Config',
'pages.project.flink.kubernetes.template.step.advanced.configOptions.value': 'Value',
diff --git a/scaleph-ui-react/src/locales/zh-CN/pages/resource.ts b/scaleph-ui-react/src/locales/zh-CN/pages/resource.ts
index 9ba8a5ad3..b1972973f 100644
--- a/scaleph-ui-react/src/locales/zh-CN/pages/resource.ts
+++ b/scaleph-ui-react/src/locales/zh-CN/pages/resource.ts
@@ -21,7 +21,6 @@ export default {
'YARN 上传 core-site.xml 和 hdfs-site.xml, ' +
'Kubernetes 上传 kubeconfig 文件',
'pages.resource.jar': '公共 Jar',
- 'pages.resource.jar.group': 'Group',
'pages.resource.jar.file': 'Jar',
'pages.resource.jar.fileName': '文件名',
'pages.resource.jar.path': '存储路径',
diff --git a/scaleph-ui-react/src/models/project/workspace/kubernetes/template/flinkKubernetesTemplateDetail.ts b/scaleph-ui-react/src/models/project/workspace/kubernetes/template/flinkKubernetesTemplateDetail.ts
new file mode 100644
index 000000000..552ea1cd0
--- /dev/null
+++ b/scaleph-ui-react/src/models/project/workspace/kubernetes/template/flinkKubernetesTemplateDetail.ts
@@ -0,0 +1,55 @@
+import {WsFlinkKubernetesTemplate} from "@/services/project/typings";
+import { Reducer, Effect } from "umi";
+import {WsFlinkKubernetesTemplateService} from "@/services/project/WsFlinkKubernetesTemplateService";
+import YAML from "yaml";
+
+export interface StateType {
+ template: WsFlinkKubernetesTemplate,
+ templateYaml: string
+ templateYamlWithDefault: string
+}
+
+export interface ModelType {
+ namespace: string;
+
+ state: StateType;
+
+ effects: {
+ queryTemplate: Effect;
+ };
+
+ reducers: {
+ updateTemplate: Reducer;
+ };
+}
+
+const model: ModelType = {
+ namespace: "flinkKubernetesTemplateDetail",
+
+ state: {
+ template: null,
+ templateYaml: null,
+ templateYamlWithDefault: null
+ },
+
+ effects: {
+ *editTemplate({ payload }, { call, put }) {
+ const { data } = yield call(WsFlinkKubernetesTemplateService.asYaml, payload);
+ const response = yield call(WsFlinkKubernetesTemplateService.asYamlWithDefault, payload);
+ yield put({ type: 'updateTemplate', payload: {template: payload, templateYaml: YAML.stringify(data), templateYamlWithDefault: YAML.stringify(response.data)} });
+ },
+ },
+
+ reducers: {
+ updateTemplate(state, { payload }) {
+ return {
+ ...state,
+ template: payload.template,
+ templateYaml: payload.templateYaml,
+ templateYamlWithDefault: payload.templateYamlWithDefault,
+ };
+ },
+ },
+};
+
+export default model;
diff --git a/scaleph-ui-react/src/models/project/workspace/kubernetes/template/flinkKubernetesTemplateSteps.ts b/scaleph-ui-react/src/models/project/workspace/kubernetes/template/flinkKubernetesTemplateSteps.ts
new file mode 100644
index 000000000..0e17e8ebd
--- /dev/null
+++ b/scaleph-ui-react/src/models/project/workspace/kubernetes/template/flinkKubernetesTemplateSteps.ts
@@ -0,0 +1,55 @@
+import {WsFlinkKubernetesTemplate} from "@/services/project/typings";
+import { Reducer, Effect } from "umi";
+import {WsFlinkKubernetesTemplateService} from "@/services/project/WsFlinkKubernetesTemplateService";
+import YAML from "yaml";
+
+export interface StateType {
+ template: WsFlinkKubernetesTemplate,
+ templateYaml: string
+ templateYamlWithDefault: string
+}
+
+export interface ModelType {
+ namespace: string;
+
+ state: StateType;
+
+ effects: {
+ queryTemplate: Effect;
+ };
+
+ reducers: {
+ updateTemplate: Reducer;
+ };
+}
+
+const model: ModelType = {
+ namespace: "flinkKubernetesTemplateSteps",
+
+ state: {
+ template: null,
+ templateYaml: null,
+ templateYamlWithDefault: null
+ },
+
+ effects: {
+ *editTemplate({ payload }, { call, put }) {
+ const { data } = yield call(WsFlinkKubernetesTemplateService.asYaml, payload);
+ const response = yield call(WsFlinkKubernetesTemplateService.asYamlWithDefault, payload);
+ yield put({ type: 'updateTemplate', payload: {template: payload, templateYaml: YAML.stringify(data), templateYamlWithDefault: YAML.stringify(response.data)} });
+ },
+ },
+
+ reducers: {
+ updateTemplate(state, { payload }) {
+ return {
+ ...state,
+ template: payload.template,
+ templateYaml: payload.templateYaml,
+ templateYamlWithDefault: payload.templateYamlWithDefault,
+ };
+ },
+ },
+};
+
+export default model;
diff --git a/scaleph-ui-react/src/models/useMainSize.ts b/scaleph-ui-react/src/models/useMainSize.ts
new file mode 100644
index 000000000..07436b494
--- /dev/null
+++ b/scaleph-ui-react/src/models/useMainSize.ts
@@ -0,0 +1,26 @@
+import { useLayoutEffect, useState } from "react";
+import { throttle } from "lodash";
+
+export default (mainCl = ".ant-pro-basicLayout-content") => {
+ const [container, setContainer] = useState<{ height: number; width: number }>({
+ width: 100,
+ height: 100
+ });
+ // const mainCl = '.ant-pro-basicLayout-content';
+ useLayoutEffect(() => {
+ const handler = throttle(() => {
+ const rt = document.querySelector(mainCl)?.getBoundingClientRect();
+ setContainer({
+ height: rt?.height,
+ width: rt?.width
+ });
+ }, 100);
+ handler();
+ window.addEventListener("resize", handler, false);
+ return () => {
+ window.removeEventListener("resize", handler, false);
+ };
+ }, []);
+
+ return container;
+};
diff --git a/scaleph-ui-react/src/pages/Admin/Resource/Web/components/TransferTable.tsx b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/TransferTable.tsx
new file mode 100644
index 000000000..2ae7fb9a3
--- /dev/null
+++ b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/TransferTable.tsx
@@ -0,0 +1,56 @@
+import { Table, Transfer } from 'antd';
+import { difference } from 'lodash'; // 注意这里改为大写的Difference
+import React from 'react';
+
+// 定义组件的Props类型
+interface Props {
+ leftColumns: any[]; // 左侧表格列配置数组
+ rightColumns: any[]; // 右侧表格列配置数组
+ containerHeight: number; // 容器高度
+}
+
+// 使用React.FC声明函数组件,并传入Props类型
+const TableTransfer: React.FC = ({ leftColumns, rightColumns, ...restProps }) => (
+
+ {({
+ direction,
+ filteredItems,
+ onItemSelectAll,
+ onItemSelect,
+ selectedKeys: listSelectedKeys,
+ disabled: listDisabled,
+ }) => {
+ const columns = direction === 'left' ? leftColumns : rightColumns;
+ // 表格行选择配置
+ const rowSelection = {
+ onSelectAll(selected: boolean, selectedRows: any[]) {
+ const treeSelectedKeys = selectedRows.map(({ key }) => key);
+ const diffKeys = selected
+ ? difference(treeSelectedKeys, listSelectedKeys)
+ : difference(listSelectedKeys, treeSelectedKeys);
+ onItemSelectAll(diffKeys, selected);
+ },
+ onSelect: ({ id }: { id: string }, selected: boolean) => {
+ onItemSelect(id, selected);
+ },
+ selectedRowKeys: listSelectedKeys,
+ };
+
+ return (
+
+ );
+ }}
+
+);
+export default React.memo(TableTransfer);
diff --git a/scaleph-ui-react/src/pages/Admin/Resource/Web/components/WebAssugnRoles.tsx b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/WebAssugnRoles.tsx
new file mode 100644
index 000000000..7550f0aef
--- /dev/null
+++ b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/WebAssugnRoles.tsx
@@ -0,0 +1,170 @@
+import mainHeight from '@/models/useMainSize';
+import { SecResourceWeb } from '@/services/admin/typings';
+import { AuthService } from '@/services/auth';
+import { Button, Card, Form, message, Modal, Space } from 'antd';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useIntl } from 'umi';
+import TableTransfer from './TransferTable';
+
+// 定义组件 Props 类型
+interface ModalFormParentProps {
+ data: T;
+ visible: boolean;
+ onVisibleChange?: (visible: boolean) => void;
+ onCancel: () => void;
+ onOK?: (values: any) => void;
+}
+
+const WebResourceForm: React.FC> = ({
+ data,
+ visible,
+ onVisibleChange,
+ onCancel,
+}) => {
+ const intl = useIntl();
+ const [form] = Form.useForm();
+ const containerInfo = mainHeight('.ant-layout-content');
+ const [roleLists, setRoleLists] = useState([]);
+
+ // 角色表格列配置
+ const tableColumns = [
+ {
+ dataIndex: 'name',
+ title: '角色名称',
+ width: 300,
+ },
+ {
+ dataIndex: 'desc',
+ title: '描述',
+ width: 300,
+ },
+ ];
+
+ // 角色类型定义
+ interface Role {
+ id: string;
+ name: string;
+ resourceAuthorized: number;
+ checkOut?: number;
+ }
+
+ // 合并数组
+ function mergeArrays(array1: Role[], array2: Role[]): Role[] {
+ array1.forEach((obj, index) => {
+ obj.checkOut = 0;
+ });
+ array2.forEach((obj, index) => {
+ obj.checkOut = 1;
+ });
+ return [...array1, ...array2];
+ }
+
+ // 异步获取数据
+ const fetchData = useCallback(async () => {
+ try {
+ const res1 = await AuthService.unauthorizedRoles({ resourceWebId: data?.id });
+ const res2 = await AuthService.authorizedRoles({ resourceWebId: data?.id });
+ if (res1?.records && res2?.records) {
+ const mergedArray = mergeArrays(res1.records, res2.records);
+ setRoleLists(mergedArray);
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }, [data]);
+
+ useEffect(() => {
+ if (data) {
+ fetchData();
+ }
+ }, [data, fetchData]);
+
+ // 页面标题
+ const returnTitle = useMemo(() => {
+ return (
+
+ {` ${intl.formatMessage({ id: `menu.${data?.name}` })}-资源分配详情`}
+
+ );
+ }, [data, intl]);
+
+ // 获取选中角色的 id 数组
+ const originTargetKeys = useMemo(() => {
+ return roleLists?.filter((item) => item.checkOut === 1).map((item) => item.id);
+ }, [roleLists]);
+
+ // 过滤方法
+ const handleFilter = useCallback((inputValue, item) => {
+ return item?.name.indexOf(inputValue) !== -1;
+ }, []);
+
+ // 角色转移事件处理
+ const handleChange = useCallback(
+ async (targetKeys, direction, moveKeys) => {
+ const roleIds = moveKeys.map((item: string | number) => +item);
+ const params = {
+ resourceWebId: data?.id,
+ roleIds: roleIds,
+ };
+ if (direction === 'right') {
+ // 绑定角色资源
+ await AuthService.resourceWebRoles(params).then((res) => {
+ if (res?.success) {
+ message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2);
+ }
+ });
+ } else {
+ // 删除绑定的角色资源
+ await AuthService.resourceWebRolesDelete(params).then((res) => {
+ message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2);
+ });
+ }
+ fetchData();
+ },
+ [data, fetchData, intl],
+ );
+
+ return (
+
+ {intl.formatMessage({ id: 'app.common.operate.close.label' })}
+ ,
+ ]}
+ >
+
+
+ record.id}
+ onChange={handleChange}
+ filterOption={handleFilter}
+ listStyle={{
+ width: 500,
+ }}
+ leftColumns={tableColumns}
+ rightColumns={tableColumns}
+ />
+
+
+
+ );
+};
+
+export default WebResourceForm;
diff --git a/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx b/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx
index d50592fe2..f21ddd1e9 100644
--- a/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx
+++ b/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx
@@ -1,9 +1,10 @@
import { PRIVILEGE_CODE } from '@/constant';
+import WebAssugnRoles from '@/pages/Admin/Resource/Web/components/WebAssugnRoles';
import WebResourceForm from '@/pages/Admin/Resource/Web/components/WebResourceForm';
import { PrivilegeService } from '@/services/admin/privilege.service';
import { ResourceWebService } from '@/services/admin/resourceWeb.service';
import { SecResourceWeb } from '@/services/admin/typings';
-import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
+import { DeleteOutlined, EditOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons';
import { ActionType, ProColumns, ProFormInstance, ProTable } from '@ant-design/pro-components';
import { Button, message, Modal, Space, Tag, Tooltip } from 'antd';
import { isEmpty } from 'lodash';
@@ -21,6 +22,10 @@ const WebResourceWeb: React.FC = () => {
parent: SecResourceWeb;
data: SecResourceWeb;
}>({ visiable: false, parent: {}, data: {} });
+ const [webAssignRoles, setWebAssignRoles] = useState<{
+ visiable: boolean;
+ data: SecResourceWeb;
+ }>({ visiable: false, parent: {}, data: {} });
const onExpand = (expanded: boolean, record: SecResourceWeb) => {
if (expanded && record.children && isEmpty(record.children)) {
@@ -44,6 +49,9 @@ const WebResourceWeb: React.FC = () => {
{
title: intl.formatMessage({ id: 'pages.admin.resource.web.name' }),
dataIndex: 'name',
+ // render: (dom, entity) => {
+ // return intl.formatMessage({ id: `menu.${entity?.name}` });
+ // },
},
{
title: intl.formatMessage({ id: 'pages.admin.resource.web.path' }),
@@ -91,12 +99,22 @@ const WebResourceWeb: React.FC = () => {
title: intl.formatMessage({ id: 'app.common.operate.label' }),
dataIndex: 'actions',
align: 'center',
- width: 120,
+ width: 160,
fixed: 'right',
valueType: 'option',
render: (_, record) => (
<>
+ {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && (
+
+ }
+ onClick={() => setWebAssignRoles({ visiable: true, data: record })}
+ />
+
+ )}
{access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && (
,
+ ]}
+ >
+
+
+ record.id}
+ onChange={handleChange}
+ filterOption={handleFilter}
+ listStyle={{
+ width: 500,
+ }}
+ leftColumns={tableColumns}
+ rightColumns={tableColumns}
+ />
+
+
+
+ );
+};
+
+export default WebResourceForm;
diff --git a/scaleph-ui-react/src/pages/Admin/Role/index.tsx b/scaleph-ui-react/src/pages/Admin/Role/index.tsx
index 5b34a7ab9..e1b98455d 100644
--- a/scaleph-ui-react/src/pages/Admin/Role/index.tsx
+++ b/scaleph-ui-react/src/pages/Admin/Role/index.tsx
@@ -1,13 +1,21 @@
-import {useAccess, useIntl} from "umi";
-import React, {useRef, useState} from "react";
-import {Button, message, Modal, Space, Tag, Tooltip} from "antd";
-import {DeleteOutlined, EditOutlined} from "@ant-design/icons";
-import {ActionType, ProColumns, ProFormInstance, ProFormSelect, ProTable} from "@ant-design/pro-components";
-import {DICT_TYPE, PRIVILEGE_CODE} from "@/constant";
-import {SecRole} from "@/services/admin/typings";
-import {RoleService} from "@/services/admin/role.service";
-import RoleForm from "@/pages/Admin/Role/components/RoleForm";
-import {DictDataService} from "@/services/admin/dictData.service";
+import { DICT_TYPE, PRIVILEGE_CODE } from '@/constant';
+import RoleForm from '@/pages/Admin/Role/components/RoleForm';
+import { DictDataService } from '@/services/admin/dictData.service';
+import { RoleService } from '@/services/admin/role.service';
+import { SecRole } from '@/services/admin/typings';
+import { DeleteOutlined, EditOutlined, FormOutlined, SelectOutlined } from '@ant-design/icons';
+import {
+ ActionType,
+ ProColumns,
+ ProFormInstance,
+ ProFormSelect,
+ ProTable,
+} from '@ant-design/pro-components';
+import { Button, message, Modal, Space, Tag, Tooltip } from 'antd';
+import React, { useRef, useState } from 'react';
+import { useAccess, useIntl } from 'umi';
+import WebAssugnRoles from './components/WebAssugnRoles';
+import ResourceWebs from './components/ResourceWebs';
const RoleWeb: React.FC = () => {
const intl = useIntl();
@@ -18,27 +26,37 @@ const RoleWeb: React.FC = () => {
const [roleFormData, setRoleFormData] = useState<{
visiable: boolean;
data: SecRole;
- }>({visiable: false, data: {}});
+ }>({ visiable: false, data: {} });
+
+ const [webAssignRoles, setWebAssignRoles] = useState<{
+ visiable: boolean;
+ data: SecRole;
+ }>({ visiable: false, parent: {}, data: {} });
+
+ const [resourceWebs, setResourceWebs] = useState<{
+ visiable: boolean;
+ data: SecRole;
+ }>({ visiable: false, parent: {}, data: {} });
const tableColumns: ProColumns[] = [
{
- title: intl.formatMessage({id: 'pages.admin.role.name'}),
+ title: intl.formatMessage({ id: 'pages.admin.role.name' }),
dataIndex: 'name',
- width: 200
+ width: 200,
},
{
- title: intl.formatMessage({id: 'pages.admin.role.code'}),
+ title: intl.formatMessage({ id: 'pages.admin.role.code' }),
dataIndex: 'code',
hideInSearch: true,
- width: 200
+ width: 200,
},
{
- title: intl.formatMessage({id: 'pages.admin.role.type'}),
+ title: intl.formatMessage({ id: 'pages.admin.role.type' }),
dataIndex: 'type',
render: (dom, entity) => {
- return ({entity.type?.label})
+ return {entity.type?.label};
},
- renderFormItem: (item, {defaultRender, ...rest}, form) => {
+ renderFormItem: (item, { defaultRender, ...rest }, form) => {
return (
{
/>
);
},
- width: 200
+ width: 200,
},
{
- title: intl.formatMessage({id: 'pages.admin.role.status'}),
+ title: intl.formatMessage({ id: 'pages.admin.role.status' }),
dataIndex: 'status',
render: (dom, entity) => {
- return ({entity.status?.label})
+ return {entity.status?.label};
},
- renderFormItem: (item, {defaultRender, ...rest}, form) => {
+ renderFormItem: (item, { defaultRender, ...rest }, form) => {
return (
{
/>
);
},
- width: 200
+ width: 200,
},
{
- title: intl.formatMessage({id: 'app.common.data.remark'}),
+ title: intl.formatMessage({ id: 'app.common.data.remark' }),
dataIndex: 'remark',
hideInSearch: true,
width: 180,
},
{
- title: intl.formatMessage({id: 'app.common.data.createTime'}),
+ title: intl.formatMessage({ id: 'app.common.data.createTime' }),
dataIndex: 'createTime',
hideInSearch: true,
width: 180,
},
{
- title: intl.formatMessage({id: 'app.common.data.updateTime'}),
+ title: intl.formatMessage({ id: 'app.common.data.updateTime' }),
dataIndex: 'updateTime',
hideInSearch: true,
width: 180,
},
{
- title: intl.formatMessage({id: 'app.common.operate.label'}),
+ title: intl.formatMessage({ id: 'app.common.operate.label' }),
dataIndex: 'actions',
align: 'center',
width: 120,
@@ -94,34 +112,60 @@ const RoleWeb: React.FC = () => {
render: (_, record) => (
<>
+ {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && (
+
+ }
+ onClick={() => setWebAssignRoles({ visiable: true, data: record })}
+ />
+
+ )}
+ {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && (
+
+ }
+ onClick={() => setResourceWebs({ visiable: true, data: record })}
+ />
+
+ )}
{access.canAccess(PRIVILEGE_CODE.roleEdit) && (
-
+
)}
{access.canAccess(PRIVILEGE_CODE.roleDelete) && (
-
+
),
],
}}
- pagination={{showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10}}
+ pagination={{ showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10 }}
rowSelection={{
fixed: true,
onChange: (selectedRowKeys, selectedRows, info) => setSelectedRows(selectedRows),
@@ -202,17 +250,38 @@ const RoleWeb: React.FC = () => {
{roleFormData.visiable && (
setRoleFormData({visiable: false, data: {}})}
+ onCancel={() => setRoleFormData({ visiable: false, data: {} })}
onVisibleChange={(visiable) => {
- setRoleFormData({visiable: visiable, data: {}});
+ setRoleFormData({ visiable: visiable, data: {} });
actionRef.current?.reload();
}}
data={roleFormData.data}
/>
)}
+ {webAssignRoles.visiable && (
+ setWebAssignRoles({ visiable: false, data: {} })}
+ onVisibleChange={(visiable) => {
+ setWebAssignRoles({ visiable: visiable, data: {} });
+ actionRef.current?.reload();
+ }}
+ data={webAssignRoles.data}
+ />
+ )}
+ {resourceWebs.visiable && (
+ setResourceWebs({ visiable: false, data: {} })}
+ onVisibleChange={(visiable) => {
+ setResourceWebs({ visiable: visiable, data: {} });
+ actionRef.current?.reload();
+ }}
+ data={resourceWebs.data}
+ />
+ )}
);
-
-}
+};
export default RoleWeb;
diff --git a/scaleph-ui-react/src/pages/Admin/User/components/UserRoles.tsx b/scaleph-ui-react/src/pages/Admin/User/components/UserRoles.tsx
new file mode 100644
index 000000000..09f8369fb
--- /dev/null
+++ b/scaleph-ui-react/src/pages/Admin/User/components/UserRoles.tsx
@@ -0,0 +1,172 @@
+import mainHeight from '@/models/useMainSize';
+import TableTransfer from '@/pages/Admin/Resource/Web/components/TransferTable';
+import { SecResourceWeb } from '@/services/admin/typings';
+import { AuthService } from '@/services/auth';
+import { Button, Card, Form, message, Modal, Space } from 'antd';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useIntl } from 'umi';
+
+// 定义组件 Props 类型
+interface ModalFormParentProps {
+ data: T;
+ visible: boolean;
+ onVisibleChange?: (visible: boolean) => void;
+ onCancel: () => void;
+ onOK?: (values: any) => void;
+}
+
+const WebResourceForm: React.FC> = ({
+ data,
+ visible,
+ onVisibleChange,
+ onCancel,
+}) => {
+ const intl = useIntl();
+ const [form] = Form.useForm();
+ const containerInfo = mainHeight('.ant-layout-content');
+ const [roleLists, setRoleLists] = useState([]);
+
+ // 角色表格列配置
+ const tableColumns = [
+ {
+ dataIndex: 'name',
+ title: '角色名称',
+ width: 300,
+ },
+ {
+ dataIndex: 'status.label',
+ title: '角色状态',
+ width: 300,
+ render: (text: any, record: { status: { label: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined; }; }) => (
+ {record.status.label}
+ ),
+ },
+ ];
+
+ // 角色类型定义
+ interface Role {
+ id: string;
+ name: string;
+ resourceAuthorized: number;
+ checkOut?: number;
+ }
+
+ // 合并数组
+ function mergeArrays(array1: any, array2: any): any {
+ array1.forEach((obj: { checkOut: number; }, index: any) => {
+ obj.checkOut = 0;
+ });
+ array2.forEach((obj: { checkOut: number; }, index: any) => {
+ obj.checkOut = 1;
+ });
+ return [...array1, ...array2];
+ }
+ // 异步获取数据
+ const fetchData = useCallback(async () => {
+ try {
+ const res1 = await AuthService.requestUnauthorizedRoles({ userId: data?.id });
+ const res2 = await AuthService.requestUserAuthorizedRoles({ userId: data?.id });
+ if (res1 && res2) {
+ const mergedArray = mergeArrays(res1, res2);
+ setRoleLists(mergedArray);
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }, [data]);
+
+ useEffect(() => {
+ if (data) {
+ fetchData();
+ }
+ }, [data, fetchData]);
+
+ // 页面标题
+ const returnTitle = useMemo(() => {
+ return (
+
+ {` ${intl.formatMessage({ id: `menu.${data?.userName}` })}-${intl.formatMessage({ id: 'app.common.operate.new.roles' })}`}
+
+ );
+ }, [data, intl]);
+
+ // 获取选中角色的 id 数组
+ const originTargetKeys = useMemo(() => {
+ return roleLists?.filter((item) => item.checkOut === 1).map((item) => item.id);
+ }, [roleLists]);
+
+ // 过滤方法
+ const handleFilter = useCallback((inputValue, item) => {
+ return item?.name.indexOf(inputValue) !== -1;
+ }, []);
+
+ // 角色转移事件处理
+ const handleChange = useCallback(
+ async (targetKeys, direction, moveKeys) => {
+ const roleIds = moveKeys.map((item: string | number) => +item);
+ const params = {
+ userId: data?.id,
+ roleIds: roleIds,
+ };
+ if (direction === 'right') {
+ // 批量为角色绑定用户
+ await AuthService.requestUserRoles(params).then((res) => {
+ if (res?.success) {
+ message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2);
+ }
+ });
+ } else {
+ // 批量为角色解除用户绑定
+ await AuthService.requestDeleteUserRoles(params).then((res) => {
+ message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2);
+ });
+ }
+ fetchData();
+ },
+ [data, fetchData, intl],
+ );
+
+ return (
+
+ {intl.formatMessage({ id: 'app.common.operate.close.label' })}
+ ,
+ ]}
+ >
+
+
+ record.id}
+ onChange={handleChange}
+ filterOption={handleFilter}
+ listStyle={{
+ width: 500,
+ }}
+ leftColumns={tableColumns}
+ rightColumns={tableColumns}
+ />
+
+
+
+ );
+};
+
+export default WebResourceForm;
diff --git a/scaleph-ui-react/src/pages/Admin/User/index.tsx b/scaleph-ui-react/src/pages/Admin/User/index.tsx
index 6dcb4247c..ca7b9b90b 100644
--- a/scaleph-ui-react/src/pages/Admin/User/index.tsx
+++ b/scaleph-ui-react/src/pages/Admin/User/index.tsx
@@ -1,19 +1,20 @@
-import {useAccess, useIntl} from 'umi';
-import React, {useEffect, useRef, useState} from 'react';
-import {Button, Card, Col, Input, List, message, Modal, Row, Space, Tabs, Tag, Tooltip, Tree, Typography,} from 'antd';
-import {EditOutlined, RedoOutlined, StopOutlined, UserSwitchOutlined,} from '@ant-design/icons';
-import {ActionType, ProColumns, ProFormInstance, ProFormSelect, ProTable} from '@ant-design/pro-components';
-import {TreeNode} from '@/app.d';
-import {DICT_TYPE, PRIVILEGE_CODE} from '@/constant';
-import {DeptService} from '@/services/admin/dept.service';
-import {DictDataService} from '@/services/admin/dictData.service';
-import {RoleService} from '@/services/admin/role.service';
-import {SecDept, SecRole, SecUser} from '@/services/admin/typings';
-import {UserService} from '@/services/admin/user.service';
+import { useAccess, useIntl } from 'umi';
+import React, { useEffect, useRef, useState } from 'react';
+import { Button, Card, Col, Input, List, message, Modal, Row, Space, Tabs, Tag, Tooltip, Tree, Typography, } from 'antd';
+import { EditOutlined, RedoOutlined, StopOutlined, UserSwitchOutlined, FormOutlined } from '@ant-design/icons';
+import { ActionType, ProColumns, ProFormInstance, ProFormSelect, ProTable } from '@ant-design/pro-components';
+import { TreeNode } from '@/app.d';
+import { DICT_TYPE, PRIVILEGE_CODE } from '@/constant';
+import { DeptService } from '@/services/admin/dept.service';
+import { DictDataService } from '@/services/admin/dictData.service';
+import { RoleService } from '@/services/admin/role.service';
+import { SecDept, SecRole, SecUser } from '@/services/admin/typings';
+import { UserService } from '@/services/admin/user.service';
import DeptGrant from './components/DeptGrant';
import RoleForm from './components/RoleForm';
import RoleGrant from './components/RoleGrant';
import UserForm from './components/UserForm';
+import UserRoles from './components/UserRoles';
import styles from './index.less';
const User: React.FC = () => {
@@ -47,15 +48,19 @@ const User: React.FC = () => {
visible: false,
data: {},
});
+ const [webAssignRoles, setWebAssignRoles] = useState<{
+ visiable: boolean;
+ data: SecRole;
+ }>({ visiable: false, parent: {}, data: {} });
const tableColumns: ProColumns[] = [
{
- title: intl.formatMessage({id: 'pages.admin.user.type'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.type' }),
dataIndex: 'type',
render: (dom, entity) => {
return ({entity.type?.label})
},
- renderFormItem: (item, {defaultRender, ...rest}, form) => {
+ renderFormItem: (item, { defaultRender, ...rest }, form) => {
return (
{
width: 200
},
{
- title: intl.formatMessage({id: 'pages.admin.user.userName'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.userName' }),
dataIndex: 'userName',
},
{
- title: intl.formatMessage({id: 'pages.admin.user.nickName'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.nickName' }),
dataIndex: 'nickName',
},
{
- title: intl.formatMessage({id: 'pages.admin.user.email'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.email' }),
dataIndex: 'email',
hideInSearch: true
},
{
- title: intl.formatMessage({id: 'pages.admin.user.phone'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.phone' }),
dataIndex: 'phone',
hideInSearch: true
},
{
- title: intl.formatMessage({id: 'pages.admin.user.gender'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.gender' }),
dataIndex: 'gender',
hideInSearch: true,
render: (text, record, index) => {
@@ -93,12 +98,12 @@ const User: React.FC = () => {
},
},
{
- title: intl.formatMessage({id: 'pages.admin.user.status'}),
+ title: intl.formatMessage({ id: 'pages.admin.user.status' }),
dataIndex: 'userStatus',
render: (text, record, index) => {
return ({record.status?.label})
},
- renderFormItem: (item, {defaultRender, ...rest}, form) => {
+ renderFormItem: (item, { defaultRender, ...rest }, form) => {
return (
{
}
},
{
- title: intl.formatMessage({id: 'app.common.operate.label'}),
+ title: intl.formatMessage({ id: 'app.common.operate.label' }),
dataIndex: 'actions',
align: 'center',
width: 120,
@@ -118,15 +123,26 @@ const User: React.FC = () => {
render: (_, record) => (
<>
+ {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && (
+
+ }
+ onClick={() => setWebAssignRoles({ visiable: true, data: record })}
+ />
+
+ )}
+
{access.canAccess(PRIVILEGE_CODE.userEdit) && (
-
+
}
+ icon={}
disabled={record.type.value == '0' || record.status.value == '2'}
onClick={() => {
- setUserFormData({visible: true, data: record});
+ setUserFormData({ visible: true, data: record });
}}
>
@@ -134,23 +150,23 @@ const User: React.FC = () => {
{record.userStatus?.value?.substring(0, 1) != '9' &&
access.canAccess(PRIVILEGE_CODE.userDelete) && (
-
+
}
+ icon={}
disabled={record.type.value == '0' || record.status.value == '2'}
onClick={() => {
Modal.confirm({
- title: intl.formatMessage({id: 'app.common.operate.forbid.confirm.title'}),
- content: intl.formatMessage({id: 'app.common.operate.forbid.confirm.content'}),
- okText: intl.formatMessage({id: 'app.common.operate.confirm.label'}),
- okButtonProps: {danger: true},
- cancelText: intl.formatMessage({id: 'app.common.operate.cancel.label'}),
+ title: intl.formatMessage({ id: 'app.common.operate.forbid.confirm.title' }),
+ content: intl.formatMessage({ id: 'app.common.operate.forbid.confirm.content' }),
+ okText: intl.formatMessage({ id: 'app.common.operate.confirm.label' }),
+ okButtonProps: { danger: true },
+ cancelText: intl.formatMessage({ id: 'app.common.operate.cancel.label' }),
onOk() {
UserService.deleteUserRow(record).then((d) => {
if (d.success) {
- message.success(intl.formatMessage({id: 'app.common.operate.forbid.success'}));
+ message.success(intl.formatMessage({ id: 'app.common.operate.forbid.success' }));
actionRef.current?.reload();
}
});
@@ -162,21 +178,21 @@ const User: React.FC = () => {
)}
{record.userStatus?.value?.substring(0, 1) == '9' &&
access.canAccess(PRIVILEGE_CODE.userDelete) && (
-
+
}
+ icon={}
onClick={() => {
let user: SecUser = {
userName: record.userName,
id: record.id,
- userStatus: {value: '10', label: ''},
+ userStatus: { value: '10', label: '' },
email: record.email,
};
UserService.updateUser(user).then((resp) => {
if (resp.success) {
- message.success(intl.formatMessage({id: 'app.common.operate.success'}));
+ message.success(intl.formatMessage({ id: 'app.common.operate.success' }));
actionRef.current?.reload();
}
});
@@ -245,7 +261,7 @@ const User: React.FC = () => {
}}
>
{access.canAccess(PRIVILEGE_CODE.roleSelect) && (
-
+
{
actionRef.current?.reload();
}}
>
-
+
{item.name}
{item.showOpIcon && (
{access.canAccess(PRIVILEGE_CODE.roleGrant) && (
-
+
}
+ icon={}
onClick={() => {
- setRoleGrantData({visible: true, data: item});
+ setRoleGrantData({ visible: true, data: item });
}}
>
@@ -293,16 +309,16 @@ const User: React.FC = () => {
)}
{access.canAccess(PRIVILEGE_CODE.deptSelect) && (
-
+
{
setDeptTreeList([...deptTreeList]);
}}
>
-
+
{node.title}
{node.showOpIcon && (
{access.canAccess(PRIVILEGE_CODE.deptGrant) && (
-
+
}
+ icon={}
onClick={() => {
- setDeptGrantData({visible: true, data: node.origin});
+ setDeptGrantData({ visible: true, data: node.origin });
}}
>
@@ -370,12 +386,12 @@ const User: React.FC = () => {
- headerTitle={intl.formatMessage({id: 'pages.admin.user'})}
+ headerTitle={intl.formatMessage({ id: 'pages.admin.user' })}
search={{
labelWidth: 'auto',
- span: {xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4},
+ span: { xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4 },
}}
- scroll={{x: 800}}
+ scroll={{ x: 800 }}
rowKey="id"
actionRef={actionRef}
formRef={formRef}
@@ -387,10 +403,10 @@ const User: React.FC = () => {
key="new"
type="primary"
onClick={() => {
- setUserFormData({visible: true, data: {}});
+ setUserFormData({ visible: true, data: {} });
}}
>
- {intl.formatMessage({id: 'app.common.operate.new.label'})}
+ {intl.formatMessage({ id: 'app.common.operate.new.label' })}
),
access.canAccess(PRIVILEGE_CODE.userDelete) && (
@@ -400,15 +416,15 @@ const User: React.FC = () => {
disabled={selectedRows.length < 1}
onClick={() => {
Modal.confirm({
- title: intl.formatMessage({id: 'app.common.operate.forbid.confirm.title'}),
- content: intl.formatMessage({id: 'app.common.operate.forbid.confirm.content'}),
- okText: intl.formatMessage({id: 'app.common.operate.confirm.label'}),
- okButtonProps: {danger: true},
- cancelText: intl.formatMessage({id: 'app.common.operate.cancel.label'}),
+ title: intl.formatMessage({ id: 'app.common.operate.forbid.confirm.title' }),
+ content: intl.formatMessage({ id: 'app.common.operate.forbid.confirm.content' }),
+ okText: intl.formatMessage({ id: 'app.common.operate.confirm.label' }),
+ okButtonProps: { danger: true },
+ cancelText: intl.formatMessage({ id: 'app.common.operate.cancel.label' }),
onOk() {
UserService.deleteUserBatch(selectedRows).then((d) => {
if (d.success) {
- message.success(intl.formatMessage({id: 'app.common.operate.forbid.success'}));
+ message.success(intl.formatMessage({ id: 'app.common.operate.forbid.success' }));
actionRef.current?.reload();
}
});
@@ -416,7 +432,7 @@ const User: React.FC = () => {
});
}}
>
- {intl.formatMessage({id: 'app.common.operate.forbid.label'})}
+ {intl.formatMessage({ id: 'app.common.operate.forbid.label' })}
),
],
@@ -429,7 +445,7 @@ const User: React.FC = () => {
roleId: selectRole,
});
}}
- pagination={{showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10}}
+ pagination={{ showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10 }}
rowSelection={{
fixed: true,
onChange(selectedRowKeys, selectedRows, info) {
@@ -444,10 +460,10 @@ const User: React.FC = () => {
{
- setRoleFormData({visible: false, data: {}});
+ setRoleFormData({ visible: false, data: {} });
}}
onVisibleChange={(visible) => {
- setRoleFormData({visible: visible, data: {}});
+ setRoleFormData({ visible: visible, data: {} });
refreshRoles();
}}
data={roleFormData.data}
@@ -457,10 +473,10 @@ const User: React.FC = () => {
{
- setRoleGrantData({visible: false, data: {}});
+ setRoleGrantData({ visible: false, data: {} });
}}
onVisibleChange={(visible) => {
- setRoleGrantData({visible: visible, data: {}});
+ setRoleGrantData({ visible: visible, data: {} });
}}
data={roleGrantData.data}
>
@@ -469,10 +485,10 @@ const User: React.FC = () => {
{
- setDeptGrantData({visible: false, data: {}});
+ setDeptGrantData({ visible: false, data: {} });
}}
onVisibleChange={(visible) => {
- setDeptGrantData({visible: visible, data: {}});
+ setDeptGrantData({ visible: visible, data: {} });
}}
data={deptGrantData.data}
/>
@@ -481,15 +497,26 @@ const User: React.FC = () => {
{
- setUserFormData({visible: false, data: {}});
+ setUserFormData({ visible: false, data: {} });
}}
onVisibleChange={(visible) => {
- setUserFormData({visible: visible, data: {}});
+ setUserFormData({ visible: visible, data: {} });
actionRef.current?.reload();
}}
data={userFormData.data}
>
) : null}
+ {webAssignRoles.visiable && (
+ setWebAssignRoles({ visiable: false, data: {} })}
+ onVisibleChange={(visiable) => {
+ setWebAssignRoles({ visiable: visiable, data: {} });
+ actionRef.current?.reload();
+ }}
+ data={webAssignRoles.data}
+ />
+ )}
);
};
diff --git a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/DeploymentTemplateForm.tsx b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/DeploymentTemplateForm.tsx
index 42719af7a..b4a73f8e6 100644
--- a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/DeploymentTemplateForm.tsx
+++ b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/DeploymentTemplateForm.tsx
@@ -1,21 +1,19 @@
import {useIntl} from "umi";
import React from "react";
import {Form, message, Modal} from "antd";
-import {ProForm, ProFormDigit, ProFormRadio, ProFormSelect, ProFormText} from "@ant-design/pro-components";
+import {ProForm, ProFormDigit, ProFormRadio, ProFormText, ProFormTextArea} from "@ant-design/pro-components";
import {ModalFormProps} from '@/app.d';
import {WsFlinkKubernetesTemplate} from "@/services/project/typings";
-import {
- WsFlinkKubernetesTemplateService
-} from "@/services/project/WsFlinkKubernetesTemplateService";
+import {WsFlinkKubernetesTemplateService} from "@/services/project/WsFlinkKubernetesTemplateService";
import {DICT_TYPE, WORKSPACE_CONF} from "@/constant";
import {DictDataService} from "@/services/admin/dictData.service";
const DeploymentTemplateForm: React.FC> = ({
- data,
- visible,
- onVisibleChange,
- onCancel
- }) => {
+ data,
+ visible,
+ onVisibleChange,
+ onCancel
+ }) => {
const intl = useIntl();
const [form] = Form.useForm();
const projectId = localStorage.getItem(WORKSPACE_CONF.projectId);
@@ -26,9 +24,9 @@ const DeploymentTemplateForm: React.FC
title={
data.id
? intl.formatMessage({id: 'app.common.operate.edit.label'}) +
- intl.formatMessage({id: 'pages.project.flink.kubernetes.deployment.template'})
+ intl.formatMessage({id: 'pages.project.flink.kubernetes.template'})
: intl.formatMessage({id: 'app.common.operate.new.label'}) +
- intl.formatMessage({id: 'pages.project.flink.kubernetes.deployment.template'})
+ intl.formatMessage({id: 'pages.project.flink.kubernetes.template'})
}
width={580}
destroyOnClose={true}
@@ -72,22 +70,22 @@ const DeploymentTemplateForm: React.FC
DictDataService.listDictDataByType2(DICT_TYPE.deploymentKind)}
/>
-
diff --git a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Detail/Advanced/AdvancedBasic.tsx b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Detail/Advanced/AdvancedBasic.tsx
index 36dc79780..cabab286d 100644
--- a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Detail/Advanced/AdvancedBasic.tsx
+++ b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Detail/Advanced/AdvancedBasic.tsx
@@ -26,7 +26,7 @@ const AdvancedBasic: React.FC = () => {
name="image"
label={'image'}
colProps={{span: 10, offset: 1}}
- initialValue={"flink:1.16"}
+ initialValue={"flink:1.18"}
/>
{
{label: 'YAML', key: 'yaml', children: },
]
return (
-
+
{intl.formatMessage({id: 'app.common.operate.cancel.label'})}
diff --git a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Steps/BaseStepForm.tsx b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Steps/BaseStepForm.tsx
new file mode 100644
index 000000000..6832b384f
--- /dev/null
+++ b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Steps/BaseStepForm.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import {ProCard, ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea} from "@ant-design/pro-components";
+import {useIntl} from "umi";
+import {DICT_TYPE} from "@/constant";
+import {DictDataService} from "@/services/admin/dictData.service";
+
+const FlinkKubernetesTemplateBase: React.FC = () => {
+ const intl = useIntl();
+
+ return (
+
+
+
+ DictDataService.listDictDataByType2(DICT_TYPE.deploymentKind)}
+ />
+
+
+
+ );
+}
+
+export default FlinkKubernetesTemplateBase;
diff --git a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Steps/index.tsx b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Steps/index.tsx
new file mode 100644
index 000000000..1efb5c334
--- /dev/null
+++ b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/Steps/index.tsx
@@ -0,0 +1,86 @@
+import {connect, history, useIntl} from "umi";
+import React, {useRef} from "react";
+import {ProCard, ProFormInstance, StepsForm} from "@ant-design/pro-components";
+import {WORKSPACE_CONF} from "@/constant";
+import {WsDorisTemplate, WsFlinkKubernetesTemplate} from "@/services/project/typings";
+import {WsDorisTemplateService} from "@/services/project/WsDorisTemplateService";
+import FlinkKubernetesTemplateBase from "@/pages/Project/Workspace/Kubernetes/Template/Steps/BaseStepForm";
+
+const FlinkKubernetesTemplateSteps: React.FC = (props: any) => {
+ const intl = useIntl();
+ const formRef = useRef();
+ const localProjectId = localStorage.getItem(WORKSPACE_CONF.projectId);
+
+ const onBaseStepFinish = (values: Record) => {
+ const template: WsFlinkKubernetesTemplate = {
+ projectId: localProjectId,
+ deploymentKind: values.deploymentKind,
+ name: values.name,
+ namespace: values.namespace,
+ remark: values.remark,
+ }
+ editDorisTemplate(template)
+ return Promise.resolve(true)
+ }
+
+ const onComponentStepFinish = (values: Record) => {
+ try {
+ const template: WsDorisTemplate = WsDorisTemplateService.formatData(props.dorisTemplateSteps.template, values)
+ editDorisTemplate(template)
+ } catch (unused) {
+ }
+ return Promise.resolve(true)
+ }
+
+ const editDorisTemplate = (template: WsDorisTemplate) => {
+ props.dispatch({
+ type: 'flinkKubernetesTemplateSteps/editTemplate',
+ payload: template
+ })
+ }
+
+ const onAllFinish = (values: Record) => {
+ return WsDorisTemplateService.add(props.dorisTemplateSteps.template).then((response) => {
+ if (response.success) {
+ history.back()
+ }
+ })
+ }
+
+ return (
+
+
+
+
+
+ {/**/}
+ {/* */}
+ {/**/}
+ {/**/}
+ {/* */}
+ {/**/}
+
+
+ )
+}
+
+const mapModelToProps = ({flinkKubernetesTemplateSteps}: any) => ({flinkKubernetesTemplateSteps})
+export default connect(mapModelToProps)(FlinkKubernetesTemplateSteps);
diff --git a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/index.tsx b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/index.tsx
index 50146b105..efd4d9623 100644
--- a/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/index.tsx
+++ b/scaleph-ui-react/src/pages/Project/Workspace/Kubernetes/Template/index.tsx
@@ -25,11 +25,11 @@ const FlinkKubernetesDeploymentTemplateWeb: React.FC = () => {
const tableColumns: ProColumns[] = [
{
- title: intl.formatMessage({id: 'pages.project.flink.kubernetes.deployment.template.name'}),
+ title: intl.formatMessage({id: 'pages.project.flink.kubernetes.template.name'}),
dataIndex: 'name'
},
{
- title: intl.formatMessage({id: 'pages.project.flink.kubernetes.deployment.template.deploymentKind'}),
+ title: intl.formatMessage({id: 'pages.project.flink.kubernetes.template.deploymentKind'}),
dataIndex: 'deploymentKind',
width: 150,
render: (dom, entity) => {
@@ -46,7 +46,7 @@ const FlinkKubernetesDeploymentTemplateWeb: React.FC = () => {
}
},
{
- title: intl.formatMessage({id: 'pages.project.flink.kubernetes.deployment.template.namespace'}),
+ title: intl.formatMessage({id: 'pages.project.flink.kubernetes.template.namespace'}),
dataIndex: 'namespace',
hideInSearch: true,
width: 150
@@ -90,7 +90,7 @@ const FlinkKubernetesDeploymentTemplateWeb: React.FC = () => {
)}
{access.canAccess(PRIVILEGE_CODE.datadevJobEdit) && (
-
+
{
key="new"
type="primary"
onClick={() => {
- setDeploymentTemplateFormData({visiable: true, data: {}});
+ history.push("/workspace/flink/kubernetes/template/steps")
}}
>
{intl.formatMessage({id: 'app.common.operate.new.label'})}
diff --git a/scaleph-ui-react/src/pages/Resource/Jar/components/JarForm.tsx b/scaleph-ui-react/src/pages/Resource/Jar/components/JarForm.tsx
index c14986c5b..266ae05ab 100644
--- a/scaleph-ui-react/src/pages/Resource/Jar/components/JarForm.tsx
+++ b/scaleph-ui-react/src/pages/Resource/Jar/components/JarForm.tsx
@@ -1,7 +1,7 @@
import {useIntl} from 'umi';
import {useState} from 'react';
import {Form, message, Modal, UploadFile, UploadProps} from 'antd';
-import {ProForm, ProFormDigit, ProFormText, ProFormUploadButton} from '@ant-design/pro-components';
+import {ProForm, ProFormDigit, ProFormTextArea, ProFormUploadButton} from '@ant-design/pro-components';
import {ModalFormProps} from '@/app.d';
import {ResourceJarService} from '@/services/resource/jar.service';
import {Jar, JarUploadParam} from '@/services/resource/typings';
@@ -72,11 +72,6 @@ const JarForm: React.FC> = ({data, visible, onVisibleChange,
>
-
> = ({data, visible, onVisibleChange,
fieldProps={props}
rules={[{required: true}]}
/>
- {
@@ -17,42 +17,38 @@ const JarResource: React.FC = () => {
const [jarFormData, setJarData] = useState<{
visiable: boolean;
data: Jar;
- }>({ visiable: false, data: {} });
+ }>({visiable: false, data: {}});
const tableColumns: ProColumns[] = [
{
- title: intl.formatMessage({ id: 'pages.resource.jar.group' }),
- dataIndex: 'group',
- },
- {
- title: intl.formatMessage({ id: 'pages.resource.fileName' }),
+ title: intl.formatMessage({id: 'pages.resource.fileName'}),
dataIndex: 'fileName',
width: 280,
},
{
- title: intl.formatMessage({ id: 'pages.resource.path' }),
+ title: intl.formatMessage({id: 'pages.resource.path'}),
dataIndex: 'path',
hideInSearch: true,
},
{
- title: intl.formatMessage({ id: 'app.common.data.remark' }),
+ title: intl.formatMessage({id: 'app.common.data.remark'}),
dataIndex: 'remark',
hideInSearch: true,
},
{
- title: intl.formatMessage({ id: 'app.common.data.createTime' }),
+ title: intl.formatMessage({id: 'app.common.data.createTime'}),
dataIndex: 'createTime',
hideInSearch: true,
width: 180,
},
{
- title: intl.formatMessage({ id: 'app.common.data.updateTime' }),
+ title: intl.formatMessage({id: 'app.common.data.updateTime'}),
dataIndex: 'updateTime',
hideInSearch: true,
width: 180,
},
{
- title: intl.formatMessage({ id: 'app.common.operate.label' }),
+ title: intl.formatMessage({id: 'app.common.operate.label'}),
dataIndex: 'actions',
align: 'center',
width: 120,
@@ -62,32 +58,32 @@ const JarResource: React.FC = () => {
<>
{access.canAccess(PRIVILEGE_CODE.datadevResourceDownload) && (
-
+
}
+ icon={}
onClick={() => ResourceJarService.download(record)}
/>
)}
{access.canAccess(PRIVILEGE_CODE.datadevResourceDelete) && (
-
+
}
+ icon={}
onClick={() => {
Modal.confirm({
- title: intl.formatMessage({ id: 'app.common.operate.delete.confirm.title' }),
+ title: intl.formatMessage({id: 'app.common.operate.delete.confirm.title'}),
content: intl.formatMessage({id: 'app.common.operate.delete.confirm.content'}),
- okText: intl.formatMessage({ id: 'app.common.operate.confirm.label' }),
- okButtonProps: { danger: true },
- cancelText: intl.formatMessage({ id: 'app.common.operate.cancel.label' }),
+ okText: intl.formatMessage({id: 'app.common.operate.confirm.label'}),
+ okButtonProps: {danger: true},
+ cancelText: intl.formatMessage({id: 'app.common.operate.cancel.label'}),
onOk() {
ResourceJarService.deleteOne(record).then((d) => {
if (d.success) {
- message.success(intl.formatMessage({ id: 'app.common.operate.delete.success' }));
+ message.success(intl.formatMessage({id: 'app.common.operate.delete.success'}));
actionRef.current?.reload();
}
});
@@ -108,7 +104,7 @@ const JarResource: React.FC = () => {
search={{
labelWidth: 'auto',
- span: { xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4 },
+ span: {xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4},
}}
rowKey="id"
actionRef={actionRef}
@@ -124,9 +120,9 @@ const JarResource: React.FC = () => {
setJarData({ visiable: true, data: {} })}
+ onClick={() => setJarData({visiable: true, data: {}})}
>
- {intl.formatMessage({ id: 'app.common.operate.upload.label' })}
+ {intl.formatMessage({id: 'app.common.operate.upload.label'})}
),
access.canAccess(PRIVILEGE_CODE.datadevResourceDelete) && (
@@ -136,15 +132,15 @@ const JarResource: React.FC = () => {
disabled={selectedRows.length < 1}
onClick={() => {
Modal.confirm({
- title: intl.formatMessage({ id: 'app.common.operate.delete.confirm.title' }),
+ title: intl.formatMessage({id: 'app.common.operate.delete.confirm.title'}),
content: intl.formatMessage({id: 'app.common.operate.delete.confirm.content'}),
- okText: intl.formatMessage({ id: 'app.common.operate.confirm.label' }),
- okButtonProps: { danger: true },
- cancelText: intl.formatMessage({ id: 'app.common.operate.cancel.label' }),
+ okText: intl.formatMessage({id: 'app.common.operate.confirm.label'}),
+ okButtonProps: {danger: true},
+ cancelText: intl.formatMessage({id: 'app.common.operate.cancel.label'}),
onOk() {
ResourceJarService.deleteBatch(selectedRows).then((d) => {
if (d.success) {
- message.success(intl.formatMessage({ id: 'app.common.operate.delete.success' }));
+ message.success(intl.formatMessage({id: 'app.common.operate.delete.success'}));
actionRef.current?.reload();
}
});
@@ -152,12 +148,12 @@ const JarResource: React.FC = () => {
});
}}
>
- {intl.formatMessage({ id: 'app.common.operate.delete.label' })}
+ {intl.formatMessage({id: 'app.common.operate.delete.label'})}
),
],
}}
- pagination={{ showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10 }}
+ pagination={{showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10}}
rowSelection={{
fixed: true,
onChange(selectedRowKeys, selectedRows, info) {
@@ -171,10 +167,10 @@ const JarResource: React.FC = () => {
{
- setJarData({ visiable: false, data: {} });
+ setJarData({visiable: false, data: {}});
}}
onVisibleChange={(visiable) => {
- setJarData({ visiable: visiable, data: {} });
+ setJarData({visiable: visiable, data: {}});
actionRef.current?.reload();
}}
data={jarFormData.data}
diff --git a/scaleph-ui-react/src/services/auth.ts b/scaleph-ui-react/src/services/auth.ts
index b8425839e..07d3ae4db 100644
--- a/scaleph-ui-react/src/services/auth.ts
+++ b/scaleph-ui-react/src/services/auth.ts
@@ -63,4 +63,112 @@ export const AuthService = {
params: { token: token },
});
},
+
+ unauthorizedRoles: async (param: any) => {
+ return request>('/api/admin/authorize/resource-web/unauthorized-roles', {
+ method: 'GET',
+ params: param,
+ });
+ },
+ authorizedRoles: async (param: any) => {
+ return request>('/api/admin/authorize/resource-web/authorized-roles', {
+ method: 'GET',
+ params: param,
+ });
+ },
+ resourceWebRoles: async (param: any) => {
+ return request>('/api/admin/authorize/resource-web/roles', {
+ method: 'PUT',
+ data: param,
+ });
+ },
+ resourceWebRolesDelete: async (param: any) => {
+ return request>('/api/admin/authorize/resource-web/roles', {
+ method: 'DELETE',
+ data: param,
+ });
+ },
+ //查询角色绑定用户列表
+ requestAuthorizedUsers: async (param: any) => {
+ return request>('/api/admin/authorize/role/authorized-users', {
+ method: 'GET',
+ params: param,
+ });
+ },
+ //查询角色未绑定用户列表
+ requestUnauthorizedUsers: async (param: any) => {
+ return request>('/api/admin/authorize/role/unauthorized-users', {
+ method: 'GET',
+ params: param,
+ });
+ },
+ //批量为角色绑定用户
+ rolesUser: async (param: any) => {
+ return request>('/api/admin/authorize/role/users', {
+ method: 'PUT',
+ data: param,
+ });
+ },
+ //批量为角色解除用户绑定
+ deleteRolesUser: async (param: any) => {
+ return request>('/api/admin/authorize/role/users', {
+ method: 'DELETE',
+ data: param,
+ });
+ },
+
+ //查询用户未绑定角色列表
+ requestUnauthorizedRoles: async (param: any) => {
+ return request>('/api/admin/authorize/user/unauthorized-roles', {
+ method: 'GET',
+ params: param,
+ });
+ },
+ //查询角色绑定用户列表
+ requestUserAuthorizedRoles: async (param: any) => {
+ return request>('/api/admin/authorize/user/authorized-roles', {
+ method: 'GET',
+ params: param,
+ });
+ },
+
+ //批量为用户绑定角色
+ requestUserRoles: async (param: any) => {
+ return request>('/api/admin/authorize/user/roles', {
+ method: 'PUT',
+ data: param,
+ });
+ },
+
+ //批量为用户解除角色绑定
+ requestDeleteUserRoles: async (param: any) => {
+ return request>('/api/admin/authorize/user/roles', {
+ method: 'DELETE',
+ data: param,
+ });
+ },
+
+ //查询所有 资源-web 和指定角色绑定状态
+ requestResourceWebs: async (param: any) => {
+ return request>('/api/admin/authorize/role/resource-webs', {
+ method: 'GET',
+ params: param,
+ });
+ },
+
+ //批量为角色绑定 资源-web
+ requestRoleResourceWebs: async (param: any) => {
+ return request>('/api/admin/authorize/role/resource-webs', {
+ method: 'PUT',
+ data: param,
+ });
+ },
+
+ //批量为角色解除 资源-web 绑定
+ requestDeleteRoleResourceWebs: async (param: any) => {
+ return request>('/api/admin/authorize/role/resource-webs', {
+ method: 'DELETE',
+ data: param,
+ });
+ },
};
diff --git a/scaleph-ui-react/src/services/resource/jar.service.ts b/scaleph-ui-react/src/services/resource/jar.service.ts
index 666505a39..b7e2b9dcf 100644
--- a/scaleph-ui-react/src/services/resource/jar.service.ts
+++ b/scaleph-ui-react/src/services/resource/jar.service.ts
@@ -29,7 +29,6 @@ export const ResourceJarService = {
upload: async (uploadParam: JarUploadParam) => {
const formData = new FormData();
- formData.append('group', uploadParam.group);
formData.append('file', uploadParam.file);
if (uploadParam.remark) {
formData.append('remark', uploadParam.remark);
diff --git a/scaleph-ui-react/src/services/resource/typings.d.ts b/scaleph-ui-react/src/services/resource/typings.d.ts
index 0a23ac0fb..9679e08ab 100644
--- a/scaleph-ui-react/src/services/resource/typings.d.ts
+++ b/scaleph-ui-react/src/services/resource/typings.d.ts
@@ -8,7 +8,6 @@ export type ResourceListParam = QueryParam & {
export type Jar = {
id?: number;
- group?: string;
fileName?: string;
path?: string;
remark?: string;
@@ -17,12 +16,10 @@ export type Jar = {
}
export type JarListParam = QueryParam & {
- group?: string;
fileName?: string;
}
export type JarUploadParam = QueryParam & {
- group?: string;
file: File;
remark?: String;
}
diff --git a/scaleph-ui-react/src/typings.d.ts b/scaleph-ui-react/src/typings.d.ts
index cb2b0295f..73f1ad1a6 100644
--- a/scaleph-ui-react/src/typings.d.ts
+++ b/scaleph-ui-react/src/typings.d.ts
@@ -22,3 +22,4 @@ declare module 'bizcharts-plugin-slider';
declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined;
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | 'dist' | false;
+declare module 'monaco-editor/esm/vs/basic-languages/sql/sql';
diff --git a/tools/docker/mysql/init.d/scaleph-master-mysql.sql b/tools/docker/mysql/init.d/scaleph-master-mysql.sql
index 3d737db09..ab47023ae 100644
--- a/tools/docker/mysql/init.d/scaleph-master-mysql.sql
+++ b/tools/docker/mysql/init.d/scaleph-master-mysql.sql
@@ -75,7 +75,6 @@ DROP TABLE IF EXISTS resource_jar;
CREATE TABLE resource_jar
(
id bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
- `group` varchar(255) NOT NULL COMMENT 'jar group',
file_name varchar(255) NOT NULL COMMENT '文件名称',
path varchar(255) NOT NULL COMMENT '存储路径',
remark varchar(255) DEFAULT NULL COMMENT '备注',
diff --git a/tools/docker/mysql/init.d/scaleph-security-mysql.sql b/tools/docker/mysql/init.d/scaleph-security-mysql.sql
index aaba0a229..e07a9afef 100644
--- a/tools/docker/mysql/init.d/scaleph-security-mysql.sql
+++ b/tools/docker/mysql/init.d/scaleph-security-mysql.sql
@@ -571,6 +571,10 @@ INSERT INTO `sec_resource_web`(`id`, `type`, `pid`, `name`, `path`, `redirect`,
`creator`, `editor`)
VALUES (71, '2', 64, '', '/workspace/doris/instance/detail', NULL, NULL, NULL,
'./Project/Workspace/Doris/Instance/Detail', NULL, 'sys', 'sys');
+INSERT INTO `sec_resource_web` (`id`, `type`, `pid`, `name`, `path`, `redirect`, `layout`, `icon`, `component`,
+ `remark`, `creator`, `editor`)
+VALUES (72, '2', 21, NULL, '/workspace/flink/kubernetes/template/steps', NULL, NULL, NULL,
+ './Project/Workspace/Kubernetes/Template/Steps', NULL, 'sys', 'sys');
drop table if exists sec_resource_web_role;
create table sec_resource_web_role