diff --git a/api/app/lib/controllers/control/analysis.js b/api/app/lib/controllers/control/analysis.js
index 16dbdbe..b2de347 100644
--- a/api/app/lib/controllers/control/analysis.js
+++ b/api/app/lib/controllers/control/analysis.js
@@ -140,7 +140,7 @@ async function personnelApp (ctx) {
findOptions.where.id = { $in: userInfo.correlationProject }
}
if (pepId) {
- findOptions.where.id = pepId
+ findOptions.where.id = { $in: pepId.split(',') }
}
const proRes = await models.ProjectCorrelation.findAndCountAll(findOptions)
@@ -199,7 +199,8 @@ async function personnelApp (ctx) {
let personnel = userRes.rows.filter(r => r.correlationProject.length > 0)
if (pepId) {
- personnel = personnel.filter(r => r.dataValues.correlationProject.map(v => v.id).includes(Number(pepId)))
+ let pepIds = pepId.split(',')
+ personnel = personnel.filter(r => r.dataValues.correlationProject.map(v => v.id).some(pepId => pepIds.includes(pepId)))
}
ctx.status = 200
diff --git a/api/app/lib/controllers/control/data.js b/api/app/lib/controllers/control/data.js
index fe5e291..0b7d5e4 100644
--- a/api/app/lib/controllers/control/data.js
+++ b/api/app/lib/controllers/control/data.js
@@ -250,7 +250,11 @@ async function getAlarmsHandleStatistics (ctx) {
const models = ctx.fs.dc.models;
const data = await models.AlarmHandleStatistics.findAll({
order: [['time', 'DESC']],
- where: projectCorrelationId ? { projectCorrelationId: projectCorrelationId } : {},
+ where: projectCorrelationId ?
+ {
+ projectCorrelationId: { $in: projectCorrelationId.split(',') }
+ }
+ : {},
limit: 1
})
ctx.status = 200;
@@ -278,8 +282,8 @@ async function getLatestDynamic (ctx) {
if (projectCorrelationId) {//查指定项目,控制台全局切换
where.projectCorrelationId = projectCorrelationId
}
-
-
+
+
let news = await models.LatestDynamicList.findAll({//最新动态
include: [{
model: models.ProjectCorrelation,
@@ -322,7 +326,7 @@ async function getLatestDynamic (ctx) {
}
}
-
+
// EM 推送的特殊处理
@@ -336,7 +340,7 @@ async function getLatestDynamic (ctx) {
}) : []
-
+
for (let { dataValues: p } of emailLogProjectCorrelationRes) {
if (p.pepProjectId) {
@@ -400,7 +404,7 @@ async function getLatestDynamic (ctx) {
confirm//确认
};
} catch (error) {
-
+
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
diff --git a/api/app/lib/controllers/project/group.js b/api/app/lib/controllers/project/group.js
new file mode 100644
index 0000000..be05ecd
--- /dev/null
+++ b/api/app/lib/controllers/project/group.js
@@ -0,0 +1,110 @@
+'use strict';
+const moment = require('moment')
+
+async function groupList (ctx) {
+ try {
+ const { models } = ctx.fs.dc;
+ const { userId } = ctx.fs.api
+ const res = await models.ProjectGroup.findAll({
+ where: {
+ pomsUserId: userId
+ },
+ order: [['id', 'DESC']]
+ })
+
+ ctx.status = 200;
+ ctx.body = res
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = {
+ message: typeof error == 'string' ? error : undefined
+ }
+ }
+}
+
+async function editGroup (ctx) {
+ try {
+ const { models } = ctx.fs.dc;
+ const { userId } = ctx.fs.api
+ const { id, name, pomsProjectIds = [] } = ctx.request.body
+
+ if (!name || !pomsProjectIds || !pomsProjectIds.length) {
+ throw '参数错误!'
+ }
+
+ let repeatNameRes = await models.ProjectGroup.findOne({
+ where: {
+ pomsUserId: userId,
+ name,
+ }
+ })
+ let repeatProjectRes = await models.ProjectGroup.findOne({
+ where: {
+ pomsUserId: userId,
+ pomsProjectIds
+ }
+ })
+ if (repeatNameRes && (!id || (id && repeatNameRes.id != id))) {
+ throw '已有相同名称的分组信息!'
+ }
+ if (repeatProjectRes && (!id || (id && repeatProjectRes.id != id))) {
+ throw '已有相同项目的分组信息!'
+ }
+
+ if (id) {
+ await models.ProjectGroup.update({
+ name,
+ pomsProjectIds,
+ }, {
+ where: {
+ id
+ }
+ })
+ } else {
+ await models.ProjectGroup.create({
+ name,
+ pomsProjectIds,
+ pomsUserId: userId,
+ }, {
+ where: {
+ id
+ }
+ })
+ }
+
+ ctx.status = 204;
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = {
+ message: typeof error == 'string' ? error : undefined
+ }
+ }
+}
+
+async function delGroup (ctx) {
+ try {
+ const { models } = ctx.fs.dc;
+
+ await models.ProjectGroup.destroy({
+ where: {
+ id: ctx.query.groupId
+ }
+ })
+
+ ctx.status = 204;
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = {
+ message: typeof error == 'string' ? error : undefined
+ }
+ }
+}
+
+module.exports = {
+ groupList,
+ editGroup,
+ delGroup,
+};
\ No newline at end of file
diff --git a/api/app/lib/models/project_group.js b/api/app/lib/models/project_group.js
new file mode 100644
index 0000000..66a7336
--- /dev/null
+++ b/api/app/lib/models/project_group.js
@@ -0,0 +1,57 @@
+/* eslint-disable*/
+
+'use strict';
+
+module.exports = dc => {
+ const DataTypes = dc.ORM;
+ const sequelize = dc.orm;
+ const ProjectGroup = sequelize.define("projectGroup", {
+ id: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: true,
+ field: "id",
+ autoIncrement: true,
+ unique: "project_group_id_uindex"
+ },
+ name: {
+ type: DataTypes.STRING,
+ allowNull: true,
+ defaultValue: null,
+ comment: null,
+ primaryKey: false,
+ field: "name",
+ autoIncrement: false
+ },
+ pomsProjectIds: {
+ type: DataTypes.ARRAY(DataTypes.INTEGER),
+ allowNull: false,
+ defaultValue: null,
+ comment: "运维项目id",
+ primaryKey: false,
+ field: "poms_project_ids",
+ autoIncrement: false
+ },
+ pomsUserId: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: false,
+ field: "poms_user_id",
+ autoIncrement: false,
+ references: {
+ key: "id",
+ model: "user"
+ }
+ }
+ }, {
+ tableName: "project_group",
+ comment: "",
+ indexes: []
+ });
+ dc.models.ProjectGroup = ProjectGroup;
+ return ProjectGroup;
+};
\ No newline at end of file
diff --git a/api/app/lib/routes/project/index.js b/api/app/lib/routes/project/index.js
index aa3a5a7..ec18d9e 100644
--- a/api/app/lib/routes/project/index.js
+++ b/api/app/lib/routes/project/index.js
@@ -2,6 +2,7 @@
const project = require('../../controllers/project');
const projectBind = require('../../controllers/project/bind')
+const projectGroup = require('../../controllers/project/group')
module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/project/app_list'] = { content: '获取应用列表', visible: true };
@@ -27,4 +28,15 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/project/structure'] = { content: '获取绑定项目下结构物', visible: true };
router.get('/project/structure', project.strucWithPomsProject);
+
+ //
+
+ app.fs.api.logAttr['GET/project/group'] = { content: '获取项目分组', visible: true };
+ router.get('/project/group', projectGroup.groupList);
+
+ app.fs.api.logAttr['PUT/project/group'] = { content: '编辑项目分组', visible: true };
+ router.put('/project/group', projectGroup.editGroup);
+
+ app.fs.api.logAttr['DEL/project/group'] = { content: '删除项目分组', visible: true };
+ router.delete('/project/group', projectGroup.delGroup);
};
\ No newline at end of file
diff --git a/api/app/lib/utils/dataRange.js b/api/app/lib/utils/dataRange.js
index 407c80e..e6cbfcb 100644
--- a/api/app/lib/utils/dataRange.js
+++ b/api/app/lib/utils/dataRange.js
@@ -28,7 +28,7 @@ module.exports = function (app, opts) {
}
if (pepProjectId) {
// 有 特定的项目id 就按此查询
- findOption.where.id = pepProjectId
+ findOption.where.id = { $in: String(pepProjectId).split(',') }
} else if (!isSuper) {
// 还不是超管或管理员就按关联的项目id的数据范围查
findOption.where.id = { $in: correlationProject }
diff --git a/api/sequelize-automate.config.js b/api/sequelize-automate.config.js
index 8012e75..a4dd7af 100644
--- a/api/sequelize-automate.config.js
+++ b/api/sequelize-automate.config.js
@@ -33,7 +33,7 @@ module.exports = {
dir: './app/lib/models', // 指定输出 models 文件的目录
typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义
emptyDir: false, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir`
- tables: ['workorder'], // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性
+ tables: ['project_group'], // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性
skipTables: [], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性
tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中
ignorePrefix: [], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面
diff --git a/web/client/src/app.jsx b/web/client/src/app.jsx
index b11c920..6d3cfa1 100644
--- a/web/client/src/app.jsx
+++ b/web/client/src/app.jsx
@@ -14,14 +14,15 @@ import Service from './sections/service';
import WorkOrder from './sections/workOrder';
import Means from './sections/means';
import Data from './sections/data';
+import ProjectGroup from './sections/projectGroup';
const App = props => {
- const { projectName } = props
+ const { projectName } = props
- useEffect(() => {
- document.title = projectName;
+ useEffect(() => {
+ document.title = projectName;
- console.log(`
+ console.log(`
_ _
/> フ
| _ _ l
@@ -33,17 +34,18 @@ const App = props => {
| ( ̄ヽ__ヽ_)__)
\二つ
`);
- }, [])
+ }, [])
- return (
-
- )
+ return (
+
+ )
}
export default App;
\ No newline at end of file
diff --git a/web/client/src/layout/components/header/components/customProjGroupModal.jsx b/web/client/src/layout/components/header/components/customProjGroupModal.jsx
new file mode 100644
index 0000000..d660527
--- /dev/null
+++ b/web/client/src/layout/components/header/components/customProjGroupModal.jsx
@@ -0,0 +1,80 @@
+"use strict";
+import React, { useEffect, useState, useRef } from 'react'
+import { connect, createStore } from "react-redux";
+import Immutable from 'immutable';
+import { SplitButtonGroup, Dropdown, Button, Nav, Avatar, Input, useFormApi, Form, Modal } from '@douyinfe/semi-ui';
+import { IconTreeTriangleDown, IconSearch, IconPlus } from '@douyinfe/semi-icons';
+import "../index.less";
+
+const { Option } = Form.Select;
+
+const CustomProjGroupModal = (props) => {
+ const { visible, cancel, editData, pomsList, dispatch, actions } = props
+ const form = useRef();
+
+ return (
+ {
+ e.preventDefault()
+ form.current.validate()
+ .then(values => {
+ console.log(values);
+ let stoData = {
+ ...values,
+ }
+ if (editData) {
+ stoData.id = editData.id
+ }
+ dispatch(actions.projectGroupAC.editProjectGroup(stoData)).then((res) => {
+ if (res.success) {
+ cancel({ refresh: true })
+ form.current?.reset()
+ }
+ })
+ })
+ }}
+ onCancel={(e) => {
+ e.preventDefault()
+ form.current?.reset()
+ cancel()
+ }}
+ closeOnEsc={true}
+ >
+
+
+ {
+ pomsList.map((item, index) => {
+ return (
+
+ )
+ })
+ }
+
+ >
+ )}
+
+
+ )
+}
+
+function mapStateToProps (state) {
+ const { global, auth } = state;
+ return {
+ actions: global.actions,
+ user: auth.user,
+ };
+}
+
+export default connect(mapStateToProps)(CustomProjGroupModal);
diff --git a/web/client/src/layout/components/header/index.jsx b/web/client/src/layout/components/header/index.jsx
index 275f356..43e4b47 100644
--- a/web/client/src/layout/components/header/index.jsx
+++ b/web/client/src/layout/components/header/index.jsx
@@ -3,20 +3,27 @@ import React, { useEffect, useState } from 'react'
import { connect, createStore } from "react-redux";
import Immutable from 'immutable';
import { pepProject } from '../../actions/global';
-import { SplitButtonGroup, Dropdown, Button, Nav, Avatar, Input, Tooltip, Tabs, TabPane } from '@douyinfe/semi-ui';
-import { IconTreeTriangleDown, IconSearch } from '@douyinfe/semi-icons';
+import { SplitButtonGroup, Dropdown, Button, Nav, Avatar, Input, Tooltip, Tabs, TabPane, Space, Popconfirm, Modal } from '@douyinfe/semi-ui';
+import { IconTreeTriangleDown, IconSearch, IconEdit, IconDelete } from '@douyinfe/semi-icons';
+import CustomProjGroupModal from './components/customProjGroupModal'
import PerfectScrollbar from "perfect-scrollbar";
import "./index.less";
let newScrollbar;
const Header = (props) => {
- const { dispatch, history, user, actions, socket, headerItems, tochange } = props;
- const { install } = actions
+ const { dispatch, history, user, actions, socket, headerItems, tochange, projectGroup } = props;
+ const { install, projectGroup: projectGroupAC } = actions
const [pomsList, setPomsList] = useState([])
const [pomsName, setPomsName] = useState('全局')
const [pepProjectId, setPepProjectId] = useState()
const [keyword, setKeyword] = useState('')
const [Scrollbar, setScrollbar] = useState(false)
+ const [prjDropdownVis, setPrjDropdownVis] = useState(false)
+ const [prjDropDownTabKey, setPrjDropDownTabKey] = useState('项目')
+ const [customProjGroupModalVis, setCustomProjGroupModalVis] = useState(false)
+ const [customProjGroupDelPopVis, setCustomProjGroupDelPopVis] = useState(false)
+ const [customProjGroupEditData, setCustomProjGroupEditData] = useState(null)
+
let userRole = user?.pomsUserInfo?.role
let modalRole = []
if (userRole) {
@@ -33,6 +40,10 @@ const Header = (props) => {
if (userRole?.includes('SuperAdmin') || userRole?.includes('admin')) modalRole = headerItems
}
+ const getProjGroup = () => {
+ dispatch(projectGroupAC.getProjectGroup())
+ }
+
useEffect(() => {
if (JSON.parse(sessionStorage.getItem('pomsUser'))?.token) {
dispatch(install.getProjectPoms({ global: 1 })).then((res) => { //获取已绑定项目
@@ -41,6 +52,7 @@ const Header = (props) => {
setPomsList(data)
}
})
+ getProjGroup()
}
}, [])
@@ -60,7 +72,15 @@ const Header = (props) => {
dispatch(pepProject(pepProjectId))
}, [pepProjectId])
-
+ const semiPortalZindex = () => {
+ const semiPortal = document.getElementsByClassName('semi-portal')
+ for (let sp of semiPortal) {
+ if (sp.style.zIndex == 1060) {
+ sp.style.zIndex = 990
+ break
+ }
+ }
+ }
return (
<>
@@ -86,7 +106,11 @@ const Header = (props) => {
logo: (
{
+ // history.push('/projectGroup/static')
+ window.open('/projectGroup/static', '_blank');
+ }}
/>
),
text: (
@@ -97,26 +121,42 @@ const Header = (props) => {
setScrollbar(!Scrollbar)
setKeyword('')
}}
- clickToHide={true}
+ // trigger="click"
+ // clickToHide={true}
+ trigger={'custom'}
+ visible={prjDropdownVis}
+ onClickOutSide={(e) => {
+ if (customProjGroupModalVis || customProjGroupDelPopVis) {
+ return
+ }
+ setPrjDropdownVis(false)
+ }}
+ position="rightBottom"
+ stopPropagation={true}
render={
-
-
+
+ setPrjDropDownTabKey(v)
+ }
+ >
- } onChange={(v) => setKeyword(v)} showClear onClick={(e)=>e.stopPropagation()}>
+ } onChange={(v) => setKeyword(v)} showClear onClick={(e) => e.stopPropagation()}>
{pomsList?.length > 0 ?
pomsList.filter(u => u.pepProjectName?.includes(keyword))?.map(v => {
return
-
{
v.pepProjectName?.length > 15 ? {v.pepProjectName}
}>
{
setPomsName(v.pepProjectName)
setPepProjectId(v.pepProjectId)
+ setPrjDropdownVis(false)
}}>
{v.pepProjectName?.length > 15 ? `${v.pepProjectName?.substr(0, 15)}` : v.pepProjectName}
@@ -125,6 +165,7 @@ const Header = (props) => {
:
{
setPomsName(v.pepProjectName)
setPepProjectId(v.pepProjectId)
+ setPrjDropdownVis(false)
}}>{v.pepProjectName}
}
@@ -135,11 +176,91 @@ const Header = (props) => {
{
setPomsName('全局')
setPepProjectId('')
+ setPrjDropdownVis(false)
}}>全局 } itemKey="全局">
+ {
+ setPepProjectId('')
+ }}>自定义分组 } itemKey="自定义分组">
+
+
+
+ } onChange={(v) => setKeyword(v)} showClear onClick={(e) => e.stopPropagation()}>
+
+
+ {
+ projectGroup.filter(u => u.name?.includes(keyword))?.map(v => {
+ return (
+ {
+ e.stopPropagation()
+ setPomsName(v.name)
+ setPepProjectId(v.pomsProjectIds.join(','))
+ setPrjDropdownVis(false)
+ }}
+ >
+ {
+ v.name?.length > 10 ?
+ {v.name}
}>
+
+ {v.name?.substr(0, 10)}...
+
+
+ :
+
+ {v.name}
+
+ }
+
+ {
+ e.stopPropagation()
+ semiPortalZindex()
+ setCustomProjGroupEditData(v)
+ setCustomProjGroupModalVis(true)
+ }} />
+ {
+ e.stopPropagation()
+ semiPortalZindex()
+ setCustomProjGroupDelPopVis(v.id)
+ Modal.warning({
+ title: '确定删除该自定义分组?', content: '此修改将不可逆',
+ onCancel: () => {
+ setCustomProjGroupDelPopVis(null)
+ },
+ onOk: () => {
+ dispatch(projectGroupAC.delProjectGroup(v.id)).then((res) => {
+ if (res.success) {
+ setCustomProjGroupDelPopVis(null)
+
+ getProjGroup()
+ }
+ })
+ },
+ style: { zIndex: 1090 }
+ });
+ }} />
+
+
+
+ )
+ })
+ }
+
+
- } trigger="click" position="bottomRight">
+ }
+ >
- }>
+ } onClick={() => { setPrjDropdownVis(!prjDropdownVis) }}>
>
@@ -176,7 +297,6 @@ const Header = (props) => {
{ tochange(item) }} />
-
)
}
}) : ""}
@@ -253,17 +373,32 @@ const Header = (props) => {
>
}
/>
+ {
+ {
+ setCustomProjGroupModalVis(false)
+ setCustomProjGroupEditData(null)
+ if (refresh) {
+ getProjGroup()
+ }
+ }}
+ />
+ }
>
);
};
function mapStateToProps (state) {
- const { global, auth, webSocket } = state;
+ const { global, auth, webSocket, projectGroup } = state;
return {
actions: global.actions,
user: auth.user,
socket: webSocket.socket,
+ projectGroup: projectGroup.data || []
};
}
diff --git a/web/client/src/layout/components/header/index.less b/web/client/src/layout/components/header/index.less
index 11a6811..0e23a40 100644
--- a/web/client/src/layout/components/header/index.less
+++ b/web/client/src/layout/components/header/index.less
@@ -1,18 +1,77 @@
-#top-slider{
- .semi-navigation-item-text{
- font-size: 13px;
- color: #F2F3F5;
- }
- .semi-navigation-item-icon{
- color: #F2F3F5;
- }
- .semi-navigation-item-selected{
- background: none;
- }
- .semi-navigation-item{
- margin: 0px;
- }
- .semi-navigation-item-text{
- overflow: inherit;
- }
+#top-slider {
+ .semi-navigation-item-text {
+ font-size: 13px;
+ color: #F2F3F5;
+ }
+
+ .semi-navigation-item-icon {
+ color: #F2F3F5;
+ }
+
+ .semi-navigation-item-selected {
+ background: none;
+ }
+
+ .semi-navigation-item {
+ margin: 0px;
+ }
+
+ .semi-navigation-item-text {
+ overflow: inherit;
+ }
+
+
+}
+
+.customGroupPop {
+ .customGroupItem {
+ position: relative;
+
+ .edit-icon,
+ .del-icon {
+ display: none;
+ cursor: pointer;
+ }
+
+ .del-icon {
+ color: red;
+ }
+
+ &:hover .edit-icon,
+ &:hover .del-icon {
+ display: inline-block;
+ opacity: 1;
+ }
+
+ &:hover .edit-icon {
+ animation: fadeIn 0.3s ease-in-out;
+ }
+
+ &:hover .del-icon {
+ animation: slideIn 0.3s ease-in-out;
+ }
+
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ display: inline-block;
+ opacity: 1;
+ }
+ }
+
+ @keyframes slideIn {
+ from {
+ transform: translateX(-10px);
+ opacity: 0;
+ }
+
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/web/client/src/sections/install/actions/system.js b/web/client/src/sections/install/actions/system.js
index e1ca7b9..da4a446 100644
--- a/web/client/src/sections/install/actions/system.js
+++ b/web/client/src/sections/install/actions/system.js
@@ -3,79 +3,79 @@
import { ApiTable, basicAction } from '$utils'
export function getProjectPoms (query) {//获取已绑定项目
- return (dispatch) => basicAction({
- type: "get",
- dispatch: dispatch,
- actionType: "GET_PROJECT_POMS",
- query: query,
- url: `${ApiTable.getProjectPoms}`,
- msg: { option: "获取已绑定项目" },
- reducer: { name: "ProjectPoms", params: { noClear: true } },
- });
+ return (dispatch) => basicAction({
+ type: "get",
+ dispatch: dispatch,
+ actionType: "GET_PROJECT_POMS",
+ query: query,
+ url: `${ApiTable.getProjectPoms}`,
+ msg: { option: "获取已绑定项目" },
+ reducer: { name: "ProjectPoms", params: { noClear: true } },
+ });
}
export function getProjectAnxincloud (query) {//获取安心云项目
- return (dispatch) => basicAction({
- type: "get",
- dispatch: dispatch,
- actionType: "GET_PROJECT_ANXINCLOUD",
- query: query,
- url: `${ApiTable.getProjectAnxincloud}`,
- msg: { option: "获取安心云项目" },
- reducer: { name: "ProjectAnxincloud", params: { noClear: true } },
- });
+ return (dispatch) => basicAction({
+ type: "get",
+ dispatch: dispatch,
+ actionType: "GET_PROJECT_ANXINCLOUD",
+ query: query,
+ url: `${ApiTable.getProjectAnxincloud}`,
+ msg: { option: "获取安心云项目" },
+ reducer: { name: "ProjectAnxincloud", params: { noClear: true } },
+ });
}
export function getProjectPmanage (query) {//获取PEP项目管理项目
- return (dispatch) => basicAction({
- type: "get",
- dispatch: dispatch,
- actionType: "GET_PROJECT_PMANAGE",
- query: query,
- url: `${ApiTable.getProjectPmanage}`,
- msg: { option: "获取PEP项目管理项目" },
- reducer: { name: "ProjectPmanage", params: { noClear: true } },
- });
+ return (dispatch) => basicAction({
+ type: "get",
+ dispatch: dispatch,
+ actionType: "GET_PROJECT_PMANAGE",
+ query: query,
+ url: `${ApiTable.getProjectPmanage}`,
+ msg: { option: "获取PEP项目管理项目" },
+ reducer: { name: "ProjectPmanage", params: { noClear: true } },
+ });
}
export function getProjectAppList (query) {//获取应用列表
- return (dispatch) => basicAction({
- type: "get",
- dispatch: dispatch,
- actionType: "GET_PROJECT_APPLIST",
- query: query,
- url: `${ApiTable.getProjectAppList}`,
- msg: { option: "获取应用列表" },
- reducer: { name: "ProjectAppList", params: { noClear: true } },
- });
+ return (dispatch) => basicAction({
+ type: "get",
+ dispatch: dispatch,
+ actionType: "GET_PROJECT_APPLIST",
+ query: query,
+ url: `${ApiTable.getProjectAppList}`,
+ msg: { option: "获取应用列表" },
+ reducer: { name: "ProjectAppList", params: { noClear: true } },
+ });
}
export function postProjectBind (data) {//绑定安心云、项目管理项目
- let msg = ''
- if (data) {
- msg = data.msg
- }
- return (dispatch) =>
- basicAction({
- type: "post",
- dispatch: dispatch,
- data,
- actionType: "POST_PROJECT_BIND",
- url: `${ApiTable.postProjectBind}`,
- msg: { option: msg },
- reducer: { name: "" },
- });
+ let msg = ''
+ if (data) {
+ msg = data.msg
+ }
+ return (dispatch) =>
+ basicAction({
+ type: "post",
+ dispatch: dispatch,
+ data,
+ actionType: "POST_PROJECT_BIND",
+ url: `${ApiTable.postProjectBind}`,
+ msg: { option: msg },
+ reducer: { name: "" },
+ });
}
export function deleteProjectBind (data) {//删除安心云、项目管理项目绑定关系
- let bindId = ''
- let msg = ''
- if (data) {
- bindId = data.bindId
- msg = data.msg
- }
- return (dispatch) =>
- basicAction({
- type: "del",
- dispatch: dispatch,
- actionType: "DEL_PROJECT_BIND",
- url: `${ApiTable.deleteProjectBind.replace("{bindId}", bindId)}`,
- msg: { option: msg }, //删除安心云、项目管理项目绑定关系
- reducer: {},
- });
-}
\ No newline at end of file
+ let bindId = ''
+ let msg = ''
+ if (data) {
+ bindId = data.bindId
+ msg = data.msg
+ }
+ return (dispatch) =>
+ basicAction({
+ type: "del",
+ dispatch: dispatch,
+ actionType: "DEL_PROJECT_BIND",
+ url: `${ApiTable.deleteProjectBind.replace("{bindId}", bindId)}`,
+ msg: { option: msg }, //删除安心云、项目管理项目绑定关系
+ reducer: {},
+ });
+}
diff --git a/web/client/src/sections/projectGroup/actions/group.js b/web/client/src/sections/projectGroup/actions/group.js
new file mode 100644
index 0000000..c84e90c
--- /dev/null
+++ b/web/client/src/sections/projectGroup/actions/group.js
@@ -0,0 +1,35 @@
+'use strict';
+
+import { ApiTable, basicAction } from '$utils'
+
+export function getProjectGroup () {
+ return (dispatch) => basicAction({
+ type: "get",
+ dispatch: dispatch,
+ actionType: "GET_PROJECT_GROPUP",
+ url: `${ApiTable.projectGroup}`,
+ msg: { error: "获取项目分组失败" },
+ reducer: { name: "projectGroup", params: { noClear: true } },
+ });
+}
+
+export function editProjectGroup (data) {
+ return (dispatch) => basicAction({
+ type: "put",
+ data,
+ dispatch: dispatch,
+ actionType: "EDIT_PROJECT_GROPUP",
+ url: `${ApiTable.projectGroup}`,
+ msg: { option: (data?.id ? '编辑' : '添加') + "项目分组" },
+ });
+}
+
+export function delProjectGroup (id) {
+ return (dispatch) => basicAction({
+ type: "del",
+ dispatch: dispatch,
+ actionType: "DEL_PROJECT_GROPUP",
+ url: `${ApiTable.projectGroup}?groupId=${id}`,
+ msg: { option: "删除项目分组" },
+ });
+}
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/actions/index.js b/web/client/src/sections/projectGroup/actions/index.js
new file mode 100644
index 0000000..5c08b2d
--- /dev/null
+++ b/web/client/src/sections/projectGroup/actions/index.js
@@ -0,0 +1,7 @@
+'use strict';
+
+import * as group from './group'
+
+export default {
+ ...group
+}
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/containers/index.js b/web/client/src/sections/projectGroup/containers/index.js
new file mode 100644
index 0000000..155d0b1
--- /dev/null
+++ b/web/client/src/sections/projectGroup/containers/index.js
@@ -0,0 +1,4 @@
+'use strict';
+import Static from './static'
+
+export { Static };
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/containers/static.jsx b/web/client/src/sections/projectGroup/containers/static.jsx
new file mode 100644
index 0000000..83ec969
--- /dev/null
+++ b/web/client/src/sections/projectGroup/containers/static.jsx
@@ -0,0 +1,23 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { connect } from 'react-redux';
+import { Skeleton, Button, Pagination, Form, Popconfirm, Table, Toast } from '@douyinfe/semi-ui';
+import moment from "moment";
+
+const Static = (props) => {
+
+ return (
+
+
+
+ )
+}
+
+function mapStateToProps (state) {
+ const { auth, global, } = state;
+ return {
+ user: auth.user,
+ actions: global.actions,
+ };
+}
+
+export default connect(mapStateToProps)(Static);
diff --git a/web/client/src/sections/projectGroup/index.js b/web/client/src/sections/projectGroup/index.js
new file mode 100644
index 0000000..799cdfa
--- /dev/null
+++ b/web/client/src/sections/projectGroup/index.js
@@ -0,0 +1,15 @@
+'use strict';
+
+import reducers from './reducers';
+import routes from './routes';
+import actions from './actions';
+import { getNavItem } from './nav-item';
+
+export default {
+ key: 'projectGroup',
+ name: '项目分组',
+ reducers: reducers,
+ routes: routes,
+ actions: actions,
+ getNavItem: getNavItem
+};
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/nav-item.jsx b/web/client/src/sections/projectGroup/nav-item.jsx
new file mode 100644
index 0000000..1ede9db
--- /dev/null
+++ b/web/client/src/sections/projectGroup/nav-item.jsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { IconCode } from '@douyinfe/semi-icons';
+
+export function getNavItem (user, dispatch) {
+ return (
+ [
+
+ ]
+ );
+}
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/reducers/index.js b/web/client/src/sections/projectGroup/reducers/index.js
new file mode 100644
index 0000000..7ed1088
--- /dev/null
+++ b/web/client/src/sections/projectGroup/reducers/index.js
@@ -0,0 +1,5 @@
+'use strict';
+
+export default {
+
+}
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/routes.js b/web/client/src/sections/projectGroup/routes.js
new file mode 100644
index 0000000..4dc94b3
--- /dev/null
+++ b/web/client/src/sections/projectGroup/routes.js
@@ -0,0 +1,11 @@
+import { Static } from './containers';
+
+export default [{
+ type: 'outer',
+ route: {
+ path: '/projectGroup/static',
+ key: 'projectGroup',
+ breadcrumb: '项目集',
+ component: Static,
+ }
+}];
\ No newline at end of file
diff --git a/web/client/src/sections/projectGroup/style.less b/web/client/src/sections/projectGroup/style.less
new file mode 100644
index 0000000..e69de29
diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js
index 60f33ec..dbb5801 100644
--- a/web/client/src/utils/webapi.js
+++ b/web/client/src/utils/webapi.js
@@ -33,6 +33,8 @@ export const ApiTable = {
getProjectAppList: 'project/app_list',//获取应用列表
deleteProjectBind: 'project/bind/{bindId}',//删除安心云、项目管理项目绑定关系
+ //项目分组
+ projectGroup: 'project/group',
//告警
getProjectPoms: 'project/poms', //获取已绑定项目