feat: user management
This commit is contained in:
parent
45c333cf37
commit
c5443dc9a7
@ -26,7 +26,7 @@ module.exports = Object.assign({}, base, {
|
||||
context: ['/'],
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
target: 'http://localhost:8848',
|
||||
target: 'http://11.239.112.161:8848',
|
||||
pathRewrite: {'^/v1' : '/nacos/v1'}
|
||||
}],
|
||||
disableHostCheck: true,
|
||||
|
@ -27,55 +27,55 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alifd/next-theme-loader": "^1.3.1",
|
||||
"@babel/cli": "^7.2.3",
|
||||
"@babel/core": "^7.2.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.2.3",
|
||||
"@babel/preset-env": "^7.2.3",
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@babel/cli": "^7.7.7",
|
||||
"@babel/core": "^7.7.7",
|
||||
"@babel/plugin-proposal-decorators": "^7.7.4",
|
||||
"@babel/preset-env": "^7.7.7",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"babel-plugin-import": "^1.12.0",
|
||||
"babel-preset-react-app": "^6.1.0",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"copy-webpack-plugin": "^4.6.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^2.0.2",
|
||||
"eslint": "^5.11.0",
|
||||
"eslint-config-ali": "^4.1.0",
|
||||
"eslint-config-prettier": "^3.3.0",
|
||||
"eslint-loader": "^2.1.1",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"babel-preset-react-app": "^9.1.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^5.1.1 ",
|
||||
"cross-env": "^6.0.3",
|
||||
"css-loader": "^3.4.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-ali": "^9.0.2",
|
||||
"eslint-config-prettier": "^6.8.0",
|
||||
"eslint-loader": "^3.0.3",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-prettier": "^3.0.0",
|
||||
"eslint-plugin-react": "^7.11.1",
|
||||
"file-loader": "^2.0.0",
|
||||
"eslint-plugin-react": "^7.17.0",
|
||||
"file-loader": "^5.0.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"husky": "^1.1.4",
|
||||
"lint-staged": "^8.0.4",
|
||||
"mini-css-extract-plugin": "^0.5.0",
|
||||
"node-sass": "^4.11.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.1",
|
||||
"prettier": "1.15.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"uglifyjs-webpack-plugin": "^2.1.0",
|
||||
"url-loader": "^1.1.2",
|
||||
"webpack": "^4.28.2",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"webpack-dev-server": "^3.1.13"
|
||||
"husky": "^3.1.0",
|
||||
"lint-staged": "^9.5.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"prettier": "1.19.1",
|
||||
"sass-loader": "^8.0.0",
|
||||
"style-loader": "^1.1.2",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"url-loader": "^3.0.0",
|
||||
"webpack": "^4.41.4",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-dev-server": "^3.10.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alifd/next": "^1.15.12",
|
||||
"@alifd/next": "^1.17.4",
|
||||
"axios": "^0.18.0",
|
||||
"jquery": "^3.3.1",
|
||||
"moment": "^2.23.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-redux": "^5.1.1",
|
||||
"react-router": "^4.3.1",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-redux": "^7.1.3",
|
||||
"react-router": "^5.1.2",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-router-redux": "^4.0.8",
|
||||
"redux": "^4.0.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"yamljs": "^0.3.0"
|
||||
}
|
||||
|
@ -23,3 +23,9 @@ export const GET_STATE = 'GET_STATE';
|
||||
|
||||
export const GET_SUBSCRIBERS = 'GET_SUBSCRIBERS';
|
||||
export const REMOVE_SUBSCRIBERS = 'REMOVE_SUBSCRIBERS';
|
||||
|
||||
export const UPDATE_USER = 'UPDATE_USER';
|
||||
export const SIGN_IN = 'SIGN_IN';
|
||||
export const USER_LIST = 'USER_LIST';
|
||||
|
||||
export const ROLE_LIST = 'ROLE_LIST';
|
||||
|
@ -12,9 +12,7 @@
|
||||
*/
|
||||
|
||||
import projectConfig from './config';
|
||||
import moment from 'moment';
|
||||
import $ from 'jquery';
|
||||
import i18DocObj from './i18ndoc';
|
||||
|
||||
const global = window;
|
||||
|
||||
@ -205,120 +203,6 @@ const nacosUtils = (function(_global) {
|
||||
};
|
||||
})(global);
|
||||
|
||||
const aliwareIntl = (function(_global) {
|
||||
/**
|
||||
* 国际化构造方法
|
||||
* @param {Object} options 配置信息
|
||||
*/
|
||||
function AliwareI18n(options) {
|
||||
// let currentLocal = options.currentLocal || navigator.language || navigator.userLanguage;
|
||||
|
||||
const nowData = options.locals;
|
||||
this.nowData = nowData;
|
||||
this.setMomentLocale(this.currentLanguageCode);
|
||||
}
|
||||
|
||||
let aliwareLocal = aliwareGetCookieByKeyName('aliyun_lang') || 'zh';
|
||||
let aliwareLocalSite = aliwareGetCookieByKeyName('aliyun_country') || 'cn';
|
||||
aliwareLocal = aliwareLocal.toLowerCase();
|
||||
aliwareLocalSite = aliwareLocalSite.toLowerCase();
|
||||
// 当前语言
|
||||
AliwareI18n.prototype.currentLocal = aliwareLocal;
|
||||
// 当前地区
|
||||
AliwareI18n.prototype.currentSite = aliwareLocalSite;
|
||||
// 当前语言-地区
|
||||
AliwareI18n.prototype.currentLanguageCode =
|
||||
aliwareGetCookieByKeyName('docsite_language') || `${aliwareLocal}-${aliwareLocalSite}`;
|
||||
/**
|
||||
* 通过key获取对应国际化文案
|
||||
* @param {String} key 国际化key
|
||||
*/
|
||||
AliwareI18n.prototype.get = function(key) {
|
||||
return this.nowData[key];
|
||||
};
|
||||
/**
|
||||
* 修改国际化文案数据
|
||||
* @param {String} local 语言信息
|
||||
*/
|
||||
AliwareI18n.prototype.changeLanguage = function(local) {
|
||||
this.nowData = i18DocObj[local] || {};
|
||||
};
|
||||
/**
|
||||
* 数字国际化
|
||||
* @param {Number} num 数字
|
||||
*/
|
||||
AliwareI18n.prototype.intlNumberFormat = function(num) {
|
||||
if (typeof Intl !== 'object' || typeof Intl.NumberFormat !== 'function') {
|
||||
return num;
|
||||
}
|
||||
try {
|
||||
return new Intl.NumberFormat(this.currentLanguageCode).format(num || 0);
|
||||
} catch (error) {
|
||||
return num;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 时间戳格式化
|
||||
* @param {Number} num 时间戳
|
||||
* @param {Object} initOption 配置信息
|
||||
*/
|
||||
AliwareI18n.prototype.intlTimeFormat = function(num = Date.now(), initOption = {}) {
|
||||
try {
|
||||
const date = Object.prototype.toString.call(num) === '[object Date]' ? num : new Date(num);
|
||||
const options = Object.assign(
|
||||
{},
|
||||
{
|
||||
// weekday: "short",
|
||||
hour12: false,
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
second: 'numeric',
|
||||
},
|
||||
initOption
|
||||
);
|
||||
return date.toLocaleDateString(this.currentLanguageCode, options);
|
||||
} catch (error) {
|
||||
return typeof moment === 'function' ? moment(num).format() : '--';
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 获取当前时间格式
|
||||
* @param {String} language 语言信息: zh/en
|
||||
*/
|
||||
AliwareI18n.prototype.getIntlTimeFormat = function(_language) {
|
||||
const language = _language || aliwareLocal;
|
||||
const langObj = {
|
||||
zh: 'YYYY年M月D日 HH:mm:ss',
|
||||
en: 'MMM D, YYYY, h:mm:ss A',
|
||||
default: 'YYYY-MM-DD HH:mm:ss',
|
||||
};
|
||||
return langObj[language] ? langObj[language] : langObj.default;
|
||||
};
|
||||
/**
|
||||
* 设置moment的locale
|
||||
* @param {String} languageCode 语言信息: zh-ch/en-us
|
||||
*/
|
||||
AliwareI18n.prototype.setMomentLocale = function(languageCode) {
|
||||
if (Object.prototype.toString.call(moment) === '[object Function]') {
|
||||
moment.locale(languageCode || this.currentLanguageCode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return new AliwareI18n({
|
||||
currentLocal: `${aliwareLocal}`,
|
||||
locals:
|
||||
i18DocObj[AliwareI18n.prototype.currentLanguageCode] ||
|
||||
i18DocObj['en-us'] ||
|
||||
i18DocObj['zh-cn'] ||
|
||||
{},
|
||||
});
|
||||
})(global);
|
||||
|
||||
/**
|
||||
* 获取url中的参数
|
||||
*/
|
||||
@ -645,7 +529,6 @@ export {
|
||||
nacosEvent,
|
||||
nacosUtils,
|
||||
aliwareGetCookieByKeyName,
|
||||
aliwareIntl,
|
||||
getParams,
|
||||
setParam,
|
||||
setParams,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,9 @@ import ServiceList from './pages/ServiceManagement/ServiceList';
|
||||
import ServiceDetail from './pages/ServiceManagement/ServiceDetail';
|
||||
import SubscriberList from './pages/ServiceManagement/SubscriberList';
|
||||
import ClusterNodeList from './pages/ClusterManagement/ClusterNodeList';
|
||||
import UserManagement from './pages/AuthorityControl/UserManagement';
|
||||
import PermissionsManagement from './pages/AuthorityControl/PermissionsManagement';
|
||||
import RolesManagement from './pages/AuthorityControl/RolesManagement';
|
||||
import Welcome from './pages/Welcome/Welcome';
|
||||
|
||||
import reducers from './reducers';
|
||||
@ -65,10 +68,7 @@ const reducer = combineReducers({
|
||||
|
||||
const store = createStore(
|
||||
reducer,
|
||||
compose(
|
||||
applyMiddleware(thunk),
|
||||
window[REDUX_DEVTOOLS] ? window[REDUX_DEVTOOLS]() : f => f
|
||||
)
|
||||
compose(applyMiddleware(thunk), window[REDUX_DEVTOOLS] ? window[REDUX_DEVTOOLS]() : f => f)
|
||||
);
|
||||
|
||||
const MENU = [
|
||||
@ -89,12 +89,12 @@ const MENU = [
|
||||
{ path: '/serviceDetail', component: ServiceDetail },
|
||||
{ path: '/subscriberList', component: SubscriberList },
|
||||
{ path: '/clusterManagement', component: ClusterNodeList },
|
||||
{ path: '/userManagement', component: UserManagement },
|
||||
{ path: '/rolesManagement', component: RolesManagement },
|
||||
{ path: '/permissionsManagement', component: PermissionsManagement },
|
||||
];
|
||||
|
||||
@connect(
|
||||
state => ({ ...state.locale }),
|
||||
{ changeLanguage }
|
||||
)
|
||||
@connect(state => ({ ...state.locale }), { changeLanguage })
|
||||
class App extends React.Component {
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
|
@ -1217,10 +1217,6 @@ form.vertical-margin-lg .form-group {
|
||||
border-color: #e0e0e0 !important;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.row-bg-green {
|
||||
background-color: #e4fdda;
|
||||
}
|
||||
|
@ -13,506 +13,122 @@
|
||||
|
||||
import React from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ConfigProvider, Icon } from '@alifd/next';
|
||||
import Header from './Header';
|
||||
import $ from 'jquery';
|
||||
import { connect } from 'react-redux';
|
||||
import { setParams } from '../globalLib';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ConfigProvider, Icon, Menu } from '@alifd/next';
|
||||
import Header from './Header';
|
||||
import { getState } from '../reducers/base';
|
||||
import _menu from '../menu';
|
||||
import getMenuData from './menu';
|
||||
|
||||
import './index.scss';
|
||||
const { SubMenu, Item } = Menu;
|
||||
|
||||
@withRouter
|
||||
@connect(
|
||||
state => ({ ...state.locale, ...state.base }),
|
||||
{ getState }
|
||||
)
|
||||
@connect(state => ({ ...state.locale, ...state.base }), { getState })
|
||||
@ConfigProvider.config
|
||||
class MainLayout extends React.Component {
|
||||
static displayName = 'MainLayout';
|
||||
|
||||
static propTypes = {
|
||||
history: PropTypes.object,
|
||||
location: PropTypes.object,
|
||||
locale: PropTypes.object,
|
||||
children: PropTypes.any,
|
||||
history: PropTypes.object,
|
||||
version: PropTypes.any,
|
||||
functionMode: PropTypes.any,
|
||||
getState: PropTypes.func,
|
||||
functionMode: PropTypes.string,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.deepNav = [];
|
||||
this.oneLevelNavArr = {}; // 平行导航map
|
||||
this.state = {
|
||||
navList: [..._menu.data],
|
||||
leftBarClose: false,
|
||||
showLink: null,
|
||||
navRow: [],
|
||||
noChild: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getState();
|
||||
this.refreshNav();
|
||||
}
|
||||
|
||||
goBack() {
|
||||
this.props.history.goBack();
|
||||
}
|
||||
|
||||
nacosToggleNav(id, event) {
|
||||
event.preventDefault();
|
||||
const nowNav = document.getElementById(id);
|
||||
const iconClass = nowNav.querySelector('.iconshow');
|
||||
const subNav = nowNav.querySelector('.subnavlist');
|
||||
const { classList } = iconClass;
|
||||
let tmpClassName = 'iconshow ';
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
if (classList[i] === 'icon-arrow-down') {
|
||||
subNav.style.display = 'none';
|
||||
subNav.className += ' hidden';
|
||||
tmpClassName += 'icon-arrow-right';
|
||||
}
|
||||
if (classList[i] === 'icon-arrow-right') {
|
||||
tmpClassName += 'icon-arrow-down';
|
||||
subNav.className = subNav.className.replace(/hidden/g, '');
|
||||
subNav.style.display = 'block';
|
||||
}
|
||||
}
|
||||
iconClass.className = tmpClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the back button
|
||||
* TODO: this.props.history.goBack(); ???
|
||||
* @param url
|
||||
*/
|
||||
nacosGoBack(url) {
|
||||
const params = window.location.hash.split('?')[1];
|
||||
const urlArr = params.split('&') || [];
|
||||
const queryParams = [];
|
||||
for (let i = 0; i < urlArr.length; i++) {
|
||||
if (
|
||||
urlArr[i].split('=')[0] !== '_k' &&
|
||||
urlArr[i].split('=')[0] !== 'dataId' &&
|
||||
urlArr[i].split('=')[0] !== 'group'
|
||||
) {
|
||||
if (urlArr[i].split('=')[0] === 'searchDataId') {
|
||||
queryParams.push(`dataId=${urlArr[i].split('=')[1]}`);
|
||||
} else if (urlArr[i].split('=')[0] === 'searchGroup') {
|
||||
queryParams.push(`group=${urlArr[i].split('=')[1]}`);
|
||||
} else {
|
||||
queryParams.push(urlArr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('namespace')) {
|
||||
queryParams.push(`namespace=${localStorage.getItem('namespace')}`);
|
||||
}
|
||||
this.props.history.push(`/${url}?${queryParams.join('&')}`);
|
||||
}
|
||||
|
||||
nacosEnterBack() {
|
||||
document.getElementById('backarrow').style.color = '#09c';
|
||||
}
|
||||
|
||||
nacosOutBack() {
|
||||
document.getElementById('backarrow').style.color = '#546478';
|
||||
}
|
||||
|
||||
nacosToggleLeftBar() {
|
||||
if (!this.nacosOutDom) return;
|
||||
if (!this.state.leftBarClose) {
|
||||
// 关闭
|
||||
this.nacosOutDom.className = 'viewFramework-product';
|
||||
this.nacosLeftBarDom.style.width = 0;
|
||||
this.nacosBodyDom.style.left = 0;
|
||||
this.nacosToggleIconDom.style.left = 0;
|
||||
} else {
|
||||
this.nacosOutDom.className = 'viewFramework-product viewFramework-product-col-1';
|
||||
this.nacosLeftBarDom.style.width = '180px';
|
||||
this.nacosBodyDom.style.left = '180px';
|
||||
this.nacosToggleIconDom.style.left = '160px';
|
||||
}
|
||||
|
||||
this.setState({
|
||||
leftBarClose: !this.state.leftBarClose,
|
||||
});
|
||||
}
|
||||
|
||||
navTo(url) {
|
||||
if (url !== '/configdetail' && url !== '/configeditor') {
|
||||
// 二级菜单不清空
|
||||
setParams({
|
||||
dataId: '',
|
||||
group: '',
|
||||
});
|
||||
}
|
||||
|
||||
const params = window.location.hash.split('?')[1];
|
||||
const urlArr = params.split('&') || [];
|
||||
const queryParams = [];
|
||||
for (let i = 0; i < urlArr.length; i++) {
|
||||
if (urlArr[i].split('=')[0] !== '_k') {
|
||||
queryParams.push(urlArr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.props.history.push(`${url}?${queryParams.join('&')}`);
|
||||
const { search } = this.props.location;
|
||||
this.props.history.push([url, search].join(''));
|
||||
}
|
||||
|
||||
nacosSetSpecialNav(item) {
|
||||
item.children.forEach(_item => {
|
||||
const obj = _item;
|
||||
isCurrentPath(url) {
|
||||
const { location } = this.props;
|
||||
return url === location.pathname ? 'current-path' : undefined;
|
||||
}
|
||||
|
||||
if (obj.dontUseChild === true) {
|
||||
obj.parentName = item.title;
|
||||
obj.parentId = item.id;
|
||||
obj.parentPath = `/${item.id}`;
|
||||
this.deepNav.push(obj);
|
||||
}
|
||||
if (_item.children) {
|
||||
this.nacosSetSpecialNav(_item);
|
||||
defaultOpenKeys() {
|
||||
const MenuData = getMenuData(this.props.functionMode);
|
||||
for (let i = 0, len = MenuData.length; i < len; i++) {
|
||||
const { children } = MenuData[i];
|
||||
if (children && children.filter(({ url }) => url === this.props.location.pathname).length) {
|
||||
return String(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isShowGoBack() {
|
||||
const urls = [];
|
||||
const MenuData = getMenuData(this.props.functionMode);
|
||||
MenuData.forEach(item => {
|
||||
if (item.url) urls.push(item.url);
|
||||
if (item.children) item.children.forEach(({ url }) => urls.push(url));
|
||||
});
|
||||
}
|
||||
|
||||
nacosNavAct(serviceName, match, location) {
|
||||
if (!match) {
|
||||
const formatpath = location.pathname.substr(1); // 得到当前路径
|
||||
const nowpathobj = this.oneLevelNavArr[formatpath]; // 根据平行导航匹配父类
|
||||
if (nowpathobj) {
|
||||
if (nowpathobj.parent === serviceName) {
|
||||
// 如果父类等于当前的导航则高亮
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nacosLoopNavDeeply(data, parentServiceName) {
|
||||
// 深度遍历获取所有的导航数据
|
||||
data.forEach(item => {
|
||||
if (item) {
|
||||
const navObj = item;
|
||||
|
||||
const _parentServiceName = item.serviceName;
|
||||
navObj.parentServiceName = parentServiceName;
|
||||
this.oneLevelNavArr[item.serviceName] = navObj; // 得到每一个层级的导航映射
|
||||
if (item.children && item.children.length > 0) {
|
||||
this.nacosLoopNavDeeply(item.children, _parentServiceName);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
activeNav(id) {
|
||||
if (this.preActNav) {
|
||||
this.preActNav.removeClass('active');
|
||||
}
|
||||
const nowNav = $(`#${id}`);
|
||||
nowNav.addClass('active');
|
||||
this.preActNav = nowNav;
|
||||
}
|
||||
|
||||
nacosLoopNav(data, _index = 0, parent) {
|
||||
const { locale = {}, location = {} } = this.props;
|
||||
const { pathname } = location;
|
||||
let index = _index;
|
||||
// 遍历导航,只显示2级
|
||||
const self = this;
|
||||
return data.map(item => {
|
||||
if (!item) return '';
|
||||
index++;
|
||||
if (item.dontUseChild === true) return '';
|
||||
if (item.children && item.children.length > 0) {
|
||||
if (item.isVirtual) {
|
||||
// 如果是虚拟菜单需要增加展开箭头
|
||||
const icon = item.isExtend ? (
|
||||
<span className="icon-arrow-down iconshow" />
|
||||
) : (
|
||||
<span className="icon-arrow-right iconshow" />
|
||||
);
|
||||
const hiddenClass = item.isExtend ? '' : 'hidden';
|
||||
return (
|
||||
<li
|
||||
style={{ display: item.enable ? 'block' : 'none' }}
|
||||
key={`${item.serviceName}`}
|
||||
data-spm-click={`gostr=/aliyun;locaid=${item.serviceName}`}
|
||||
id={`${item.serviceName}`}
|
||||
>
|
||||
<div>
|
||||
<a href="" onClick={this.nacosToggleNav.bind(this, item.serviceName)}>
|
||||
<div className="nav-icon">{icon}</div>
|
||||
<div className="nav-title">{locale[item.serviceName]}</div>
|
||||
</a>
|
||||
</div>
|
||||
<ul className={`subnavlist ${hiddenClass}`}>
|
||||
{self.nacosLoopNav(item.children, index)}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<li
|
||||
className={pathname === `/${item.serviceName}` ? 'selected' : ''}
|
||||
key={`${item.serviceName}`}
|
||||
data-spm-click={`gostr=/aliyun;locaid=${item.serviceName}`}
|
||||
onClick={this.navTo.bind(this, `/${item.serviceName}`)}
|
||||
>
|
||||
<a
|
||||
href="javascript:;"
|
||||
id={`${item.serviceName}`}
|
||||
onClick={this.activeNav.bind(this, `nav${index}`)}
|
||||
>
|
||||
<div className="nav-icon" />
|
||||
<div className="nav-title">{locale[item.serviceName]}</div>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<li
|
||||
className={pathname === `/${item.serviceName}` ? 'selected' : ''}
|
||||
key={`${item.serviceName}`}
|
||||
data-spm-click={`gostr=/aliyun;locaid=${item.serviceName}`}
|
||||
onClick={this.navTo.bind(this, `/${item.serviceName}`)}
|
||||
>
|
||||
<a
|
||||
href={'javascript:;'}
|
||||
id={`${item.serviceName}`}
|
||||
onClick={this.activeNav.bind(this, `nav${index}`)}
|
||||
>
|
||||
<div className="nav-icon" />
|
||||
<div className="nav-title">{locale[item.serviceName]}</div>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
nacosGetNav(navList) {
|
||||
let navRow = ''; // 导航
|
||||
if (navList.length > 0) {
|
||||
navRow = <ul>{this.nacosLoopNav(navList)}</ul>;
|
||||
this.nacosLoopNavDeeply(navList); // 深度遍历导航树获得平行map
|
||||
}
|
||||
return navRow;
|
||||
}
|
||||
|
||||
renderNav() {
|
||||
const { navList } = this.state;
|
||||
this.nacosLeftBarDom = document.getElementById('viewFramework-product-navbar');
|
||||
this.nacosBodyDom = document.getElementById('viewFramework-product-body');
|
||||
this.nacosToggleIconDom = document.getElementById('viewFramework-product-navbar-collapse');
|
||||
this.nacosOutDom = document.getElementById('page-header-mask');
|
||||
const defaultNav = '/configurationManagement';
|
||||
this.props.history.listen(location => {
|
||||
if (this.preSimplePath && this.preSimplePath !== '/') {
|
||||
if (location.pathname.indexOf(this.preSimplePath) !== -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const simplePath = window.location.hash.split('?')[0];
|
||||
const navName = simplePath.substr('2');
|
||||
this.preSimplePath = simplePath;
|
||||
|
||||
if (navName === '') {
|
||||
this.props.history.push(defaultNav);
|
||||
setTimeout(() => {
|
||||
this.activeNav('configurationManagement');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const nowNavObj = this.oneLevelNavArr[navName];
|
||||
if (!nowNavObj) {
|
||||
this.setState({
|
||||
noChild: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const { parentServiceName } = nowNavObj;
|
||||
|
||||
const parentNav = this.oneLevelNavArr[parentServiceName];
|
||||
if (simplePath !== '/' && nowNavObj && parentNav && !parentNav.isVirtual) {
|
||||
this.setState({
|
||||
showLink: (
|
||||
<div>
|
||||
<Icon
|
||||
type="arrow-left"
|
||||
onClick={this.nacosGoBack.bind(this, parentServiceName)}
|
||||
id={'backarrow'}
|
||||
onMouseOver={this.nacosEnterBack.bind(this)}
|
||||
onMouseLeave={this.nacosOutBack.bind(this)}
|
||||
style={{
|
||||
marginLeft: 77,
|
||||
marginTop: 0,
|
||||
fontWeight: 'bold',
|
||||
cursor: 'pointer',
|
||||
color: '#546478',
|
||||
fontSize: '20px',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
|
||||
navRow: <ul>{this.nacosLoopNav([nowNavObj])}</ul>,
|
||||
});
|
||||
setTimeout(() => {
|
||||
const navid = navName;
|
||||
this.activeNav(navid);
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
showLink: null,
|
||||
navRow: <ul>{this.nacosLoopNav(navList)}</ul>,
|
||||
});
|
||||
setTimeout(() => {
|
||||
const navid = navName;
|
||||
this.activeNav(navid);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshNav() {
|
||||
const { navList } = this.state;
|
||||
const { location, history, functionMode } = this.props;
|
||||
const [configUrl, serviceUrl, clusterUrl] = [
|
||||
'/configurationManagement',
|
||||
'/serviceManagement',
|
||||
'/clusterManagement',
|
||||
];
|
||||
this.setState(
|
||||
{
|
||||
navList: navList.map(item => {
|
||||
if (
|
||||
item.serviceName === 'configurationManagementVirtual' &&
|
||||
(functionMode === null || functionMode === 'config')
|
||||
) {
|
||||
item.enable = true;
|
||||
}
|
||||
if (
|
||||
item.serviceName === 'serviceManagementVirtual' &&
|
||||
(functionMode === null || functionMode === 'naming')
|
||||
) {
|
||||
item.enable = true;
|
||||
}
|
||||
if (
|
||||
item.serviceName === 'clusterManagementVirtual' &&
|
||||
(functionMode === null || functionMode === 'cluster')
|
||||
) {
|
||||
item.enable = true;
|
||||
}
|
||||
return item;
|
||||
}),
|
||||
},
|
||||
() => this.setState({ navRow: this.nacosGetNav(navList) }, () => this.renderNav())
|
||||
);
|
||||
if (functionMode === 'config' && location.pathname === serviceUrl) {
|
||||
history.push(configUrl);
|
||||
}
|
||||
if (functionMode === 'naming' && location.pathname === configUrl) {
|
||||
history.push(serviceUrl);
|
||||
}
|
||||
if (functionMode === 'cluster' && location.pathname === clusterUrl) {
|
||||
history.push(clusterUrl);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps() {
|
||||
setTimeout(() => this.refreshNav());
|
||||
return !urls.includes(this.props.location.pathname);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { locale = {}, version } = this.props;
|
||||
const { nacosName, doesNotExist } = locale;
|
||||
const { showLink, navRow, leftBarClose, noChild } = this.state;
|
||||
const { locale = {}, version, functionMode } = this.props;
|
||||
const MenuData = getMenuData(functionMode);
|
||||
return (
|
||||
<div className="viewFramework-product" style={{ top: 66 }}>
|
||||
<>
|
||||
<Header />
|
||||
<div
|
||||
className="viewFramework-product-navbar"
|
||||
style={{ width: 180, marginLeft: 0 }}
|
||||
id="viewFramework-product-navbar"
|
||||
data-spm="acm_nav"
|
||||
>
|
||||
<div className="viewFramework-product-navbar-removed">
|
||||
<div>
|
||||
<div className="product-nav-scene product-nav-main-scene">
|
||||
{showLink ? (
|
||||
<div className="product-nav-icon env" style={{ height: 80, paddingTop: 25 }}>
|
||||
{showLink}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{ textIndent: 0, display: !version ? 'none' : 'block' }}
|
||||
className="product-nav-title"
|
||||
title={nacosName}
|
||||
>
|
||||
<span>{nacosName}</span>
|
||||
<span style={{ marginLeft: 5 }}>{version}</span>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="product-nav-list"
|
||||
style={{ position: 'relative', top: 0, height: '100%' }}
|
||||
>
|
||||
{navRow}
|
||||
</div>
|
||||
<div className="main-container">
|
||||
<div className="left-panel">
|
||||
{this.isShowGoBack() ? (
|
||||
<div className="go-back" onClick={() => this.goBack()}>
|
||||
<Icon type="arrow-left" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="viewFramework-product-navbar-collapse"
|
||||
id="viewFramework-product-navbar-collapse"
|
||||
onClick={this.nacosToggleLeftBar.bind(this)}
|
||||
>
|
||||
<div className="product-navbar-collapse-inner">
|
||||
<div className="product-navbar-collapse-bg" />
|
||||
<div className="product-navbar-collapse">
|
||||
{leftBarClose ? (
|
||||
<span className="icon-collapse-right" style={{ display: 'block' }} />
|
||||
) : (
|
||||
<span className="icon-collapse-left" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="viewFramework-product-body"
|
||||
style={{ marginLeft: 180 }}
|
||||
id="viewFramework-product-body"
|
||||
>
|
||||
<div>
|
||||
{!noChild ? (
|
||||
<div>{this.props.children}</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
height: 300,
|
||||
lineHeight: 300,
|
||||
textAlign: 'center',
|
||||
fontSize: 18,
|
||||
}}
|
||||
>
|
||||
{doesNotExist}
|
||||
</div>
|
||||
<>
|
||||
<h1 className="nav-title">
|
||||
{locale.nacosName}
|
||||
<span>{version}</span>
|
||||
</h1>
|
||||
<Menu
|
||||
defaultOpenKeys={this.defaultOpenKeys()}
|
||||
className="nav-menu"
|
||||
openMode="single"
|
||||
>
|
||||
{MenuData.map((subMenu, idx) =>
|
||||
subMenu.children ? (
|
||||
<SubMenu key={String(idx)} label={locale[subMenu.key]}>
|
||||
{subMenu.children.map((item, i) => (
|
||||
<Item
|
||||
key={[idx, i].join('-')}
|
||||
onClick={() => this.navTo(item.url)}
|
||||
className={this.isCurrentPath(item.url)}
|
||||
>
|
||||
{locale[item.key]}
|
||||
</Item>
|
||||
))}
|
||||
</SubMenu>
|
||||
) : (
|
||||
<Item
|
||||
key={idx}
|
||||
className={['first-menu', this.isCurrentPath(subMenu.url)]
|
||||
.filter(c => c)
|
||||
.join(' ')}
|
||||
onClick={() => this.navTo(subMenu.url)}
|
||||
>
|
||||
{locale[subMenu.key]}
|
||||
</Item>
|
||||
)
|
||||
)}
|
||||
</Menu>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="right-panel">{this.props.children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.header-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
background-color: #fff;
|
||||
}
|
||||
.header-container-primary {
|
||||
background: #252a2f;
|
||||
}
|
||||
@ -1396,5 +1388,62 @@ h6 {
|
||||
}
|
||||
|
||||
.product-nav-list li.selected a {
|
||||
background-color: #F4F6F8;
|
||||
background-color: #f4f6f8;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
height: calc(100vh - 66px);
|
||||
.left-panel,
|
||||
.right-panel {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
.left-panel {
|
||||
width: 180px;
|
||||
background-color: #eaedf1;
|
||||
}
|
||||
.right-panel {
|
||||
width: calc(100% - 180px);
|
||||
padding: 10px;
|
||||
}
|
||||
.nav-title {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 70px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
background-color: #d9dee4;
|
||||
span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
.nav-menu {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
line-height: 40px;
|
||||
div.next-menu-item,
|
||||
.first-menu > .next-menu-item-inner {
|
||||
color: #333;
|
||||
}
|
||||
.next-menu-item-inner {
|
||||
height: 40px;
|
||||
color: #666;
|
||||
}
|
||||
.current-path {
|
||||
background-color: #f2f3f7;
|
||||
}
|
||||
}
|
||||
.go-back {
|
||||
text-align: center;
|
||||
color: rgb(84, 100, 120);
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
padding: 10px 0;
|
||||
margin-top: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
export default function(model) {
|
||||
const configurationMenu = {
|
||||
key: 'configurationManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
key: 'configurationManagement',
|
||||
url: '/configurationManagement',
|
||||
},
|
||||
{
|
||||
key: 'listeningToQuery',
|
||||
url: '/listeningToQuery',
|
||||
},
|
||||
],
|
||||
};
|
||||
return [
|
||||
model === 'naming' ? undefined : configurationMenu,
|
||||
{
|
||||
key: 'serviceManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
key: 'serviceManagement',
|
||||
url: '/serviceManagement',
|
||||
},
|
||||
{
|
||||
key: 'subscriberList',
|
||||
url: '/subscriberList',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'clusterManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
key: 'clusterManagement',
|
||||
url: '/clusterManagement',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'authorityControl',
|
||||
children: [
|
||||
{
|
||||
key: 'userList',
|
||||
url: '/userManagement',
|
||||
},
|
||||
{
|
||||
key: 'roleManagement',
|
||||
url: '/rolesManagement',
|
||||
},
|
||||
{
|
||||
key: 'privilegeManagement',
|
||||
url: '/permissionsManagement',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'namespace',
|
||||
url: '/namespace',
|
||||
},
|
||||
].filter(item => item);
|
||||
}
|
@ -50,6 +50,10 @@ const I18N_CONF = {
|
||||
namespace: 'Namespace',
|
||||
clusterManagementVirtual: 'ClusterManagement',
|
||||
clusterManagement: 'Cluster Node List',
|
||||
authorityControl: 'Authority Control',
|
||||
userList: 'User List',
|
||||
roleManagement: 'Role Management',
|
||||
privilegeManagement: 'Privilege Management',
|
||||
},
|
||||
Password: {
|
||||
passwordNotConsistent: 'The passwords are not consistent',
|
||||
|
@ -50,6 +50,10 @@ const I18N_CONF = {
|
||||
namespace: '命名空间',
|
||||
clusterManagementVirtual: '集群管理',
|
||||
clusterManagement: '节点列表',
|
||||
authorityControl: '权限控制',
|
||||
userList: '用户列表',
|
||||
roleManagement: '角色管理',
|
||||
privilegeManagement: '权限管理',
|
||||
},
|
||||
Password: {
|
||||
passwordNotConsistent: '两次输入密码不一致',
|
||||
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
data: [
|
||||
{
|
||||
enable: false,
|
||||
isExtend: true,
|
||||
name: '配置管理',
|
||||
title: '配置管理',
|
||||
isVirtual: true,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'configurationManagementVirtual',
|
||||
link: 'configurationManagementVirtual',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.configurationManagementVirtual',
|
||||
useRouter: false,
|
||||
id: 'com.alibaba.nacos.page.configurationManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
isExtend: false,
|
||||
name: '配置列表',
|
||||
title: '配置列表',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'configurationManagement',
|
||||
link: 'configurationManagement',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: false,
|
||||
registerName: 'com.alibaba.nacos.page.configurationManagement',
|
||||
useRouter: false,
|
||||
id: 'configurationManagement',
|
||||
children: [
|
||||
{
|
||||
isExtend: false,
|
||||
name: '配置详情',
|
||||
title: '配置详情',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'configdetail',
|
||||
link: 'Configdetail',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: false,
|
||||
registerName: 'com.alibaba.nacos.page.configdetail',
|
||||
useRouter: false,
|
||||
id: 'configdetail',
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '同步配置',
|
||||
title: '同步配置',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'configsync',
|
||||
link: 'configsync',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: true,
|
||||
registerName: 'com.alibaba.nacos.page.configsync',
|
||||
useRouter: false,
|
||||
id: 'configsync',
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '配置编辑',
|
||||
title: '配置编辑',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'configeditor',
|
||||
link: 'configeditor',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.configeditor',
|
||||
useRouter: false,
|
||||
id: 'configeditor',
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '新建配置',
|
||||
title: '新建配置',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'newconfig',
|
||||
link: 'newconfig',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.newconfig',
|
||||
useRouter: false,
|
||||
id: 'newconfig',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '历史版本',
|
||||
title: '历史版本',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
children: [
|
||||
{
|
||||
isExtend: false,
|
||||
name: '配置回滚',
|
||||
title: '配置回滚',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'configRollback',
|
||||
link: 'configRollback',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.configRollback',
|
||||
useRouter: false,
|
||||
id: 'configRollback',
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '历史详情',
|
||||
title: '历史详情',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'historyDetail',
|
||||
link: 'historyDetail',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.historyDetail',
|
||||
useRouter: false,
|
||||
id: 'historyDetail',
|
||||
},
|
||||
],
|
||||
serviceName: 'historyRollback',
|
||||
link: 'historyRollback',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: false,
|
||||
registerName: 'com.alibaba.nacos.page.historyRollback',
|
||||
useRouter: false,
|
||||
id: 'historyRollback',
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '监听查询',
|
||||
title: '监听查询',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'listeningToQuery',
|
||||
link: 'listeningToQuery',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.listeningToQuery',
|
||||
useRouter: false,
|
||||
id: 'listeningToQuery',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
enable: false,
|
||||
isExtend: true,
|
||||
name: '服务管理',
|
||||
title: '服务管理',
|
||||
isVirtual: true,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'serviceManagementVirtual',
|
||||
link: 'serviceManagementVirtual',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.serviceManagementVirtual',
|
||||
useRouter: false,
|
||||
id: 'com.alibaba.nacos.page.serviceManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
isExtend: false,
|
||||
name: '服务列表',
|
||||
title: '服务列表',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'serviceManagement',
|
||||
link: 'serviceManagement',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.serviceManagement',
|
||||
useRouter: false,
|
||||
id: 'serviceManagement',
|
||||
children: [
|
||||
{
|
||||
isExtend: true,
|
||||
name: '服务详情',
|
||||
title: '服务详情',
|
||||
isVirtual: true,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'serviceDetail',
|
||||
link: 'serviceDetail',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.ServiceDetail',
|
||||
useRouter: false,
|
||||
id: 'serviceDetail',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
isExtend: false,
|
||||
name: '订阅者列表',
|
||||
title: '订阅者列表',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'subscriberList',
|
||||
link: 'subscriberList',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.subscriberList',
|
||||
useRouter: false,
|
||||
id: 'subscriberList',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
enable: true,
|
||||
isExtend: false,
|
||||
name: '命名空间',
|
||||
title: '命名空间',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'namespace',
|
||||
link: 'namespace',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: false,
|
||||
registerName: 'com.alibaba.nacos.page.namespace',
|
||||
useRouter: false,
|
||||
id: 'namespace',
|
||||
},
|
||||
{
|
||||
enable: true,
|
||||
isExtend: false,
|
||||
name: '修改密码',
|
||||
title: '修改密码',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'password',
|
||||
link: 'password',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: true,
|
||||
registerName: 'com.alibaba.nacos.page.password',
|
||||
useRouter: false,
|
||||
id: 'password',
|
||||
},
|
||||
{
|
||||
enable: false,
|
||||
isExtend: true,
|
||||
name: '集群管理',
|
||||
title: '集群管理',
|
||||
isVirtual: true,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'clusterManagementVirtual',
|
||||
link: 'clusterManagementVirtual',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.clusterManagementVirtual',
|
||||
useRouter: false,
|
||||
id: 'com.alibaba.nacos.page.clusterManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
isExtend: false,
|
||||
name: '节点状态',
|
||||
title: '节点状态',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'clusterManagement',
|
||||
link: 'clusterManagement',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
registerName: 'com.alibaba.nacos.page.clusterManagement',
|
||||
useRouter: false,
|
||||
id: 'clusterManagement',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
defaultKey: 'configurationManagement',
|
||||
projectName: 'nacos',
|
||||
};
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Button,
|
||||
Field,
|
||||
Form,
|
||||
Grid,
|
||||
Input,
|
||||
Loading,
|
||||
Pagination,
|
||||
Table,
|
||||
ConfigProvider,
|
||||
} from '@alifd/next';
|
||||
|
||||
import './PermissionsManagement.scss';
|
||||
|
||||
@ConfigProvider.config
|
||||
class PermissionsManagement extends React.Component {
|
||||
static displayName = 'UserManagement';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<h1>PermissionsManagement</h1>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PermissionsManagement;
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import PermissionsManagement from './PermissionsManagement';
|
||||
|
||||
export default PermissionsManagement;
|
@ -0,0 +1,7 @@
|
||||
# 权限控制
|
||||
|
||||
> AuthorityControl
|
||||
|
||||
1. UserManagement => 用户管理
|
||||
2. RolesManagement => 角色管理
|
||||
3. PermissionsManagement => 权限管理
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Button,
|
||||
Field,
|
||||
Form,
|
||||
Input,
|
||||
Dialog,
|
||||
Pagination,
|
||||
Table,
|
||||
ConfigProvider,
|
||||
// Field,
|
||||
} from '@alifd/next';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 3 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
@ConfigProvider.config
|
||||
class NewRole extends React.Component {
|
||||
static displayName = 'NewRole';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
};
|
||||
|
||||
check() {
|
||||
const errors = {
|
||||
role: '角色不能为空!',
|
||||
username: '用户名不能为空!',
|
||||
};
|
||||
const vals = ['role', 'username'].map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length === 2) {
|
||||
return vals;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getError } = this.field;
|
||||
const { visible, onOk, onCancel } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title="绑定角色"
|
||||
visible={visible}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label="角色名" required help={getError('role')}>
|
||||
<Input name="role" trim placeholder="Please Enter Role" />
|
||||
</FormItem>
|
||||
<FormItem label="用户名" required help={getError('username')}>
|
||||
<Input name="username" placeholder="Please Enter Username" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewRole;
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Field, Form, Input, Dialog, Pagination, Table, ConfigProvider } from '@alifd/next';
|
||||
import { connect } from 'react-redux';
|
||||
import { getRoles, createRole, deleteRole } from '../../../reducers/authority';
|
||||
import RegionGroup from '../../../components/RegionGroup';
|
||||
import NewRole from './NewRole';
|
||||
|
||||
import './RolesManagement.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 3 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
@connect(state => ({ roles: state.authority.roles }), { getRoles })
|
||||
@ConfigProvider.config
|
||||
class RolesManagement extends React.Component {
|
||||
static displayName = 'RolesManagement';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
roles: PropTypes.object,
|
||||
getRoles: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
pageNo: 1,
|
||||
pageSize: 9,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getRoles();
|
||||
}
|
||||
|
||||
getRoles() {
|
||||
const { pageNo, pageSize } = this.state;
|
||||
this.props
|
||||
.getRoles({ pageNo, pageSize })
|
||||
.then(() => {
|
||||
if (this.state.loading) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
})
|
||||
.catch(() => this.setState({ loading: false }));
|
||||
}
|
||||
|
||||
colseCreateRole() {
|
||||
this.setState({ createRoleVisible: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { roles } = this.props;
|
||||
const { loading, pageSize, pageNo, createRoleVisible, passwordResetUser } = this.state;
|
||||
return (
|
||||
<>
|
||||
<RegionGroup left={'角色管理'} />
|
||||
<div className="filter-panel">
|
||||
<Button
|
||||
type="primary"
|
||||
className="create-user-btn"
|
||||
onClick={() => this.setState({ createRoleVisible: true })}
|
||||
>
|
||||
绑定角色
|
||||
</Button>
|
||||
</div>
|
||||
<Table dataSource={roles.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
|
||||
<Table.Column title="角色名" dataIndex="role" />
|
||||
<Table.Column title="用户名" dataIndex="username" />
|
||||
<Table.Column
|
||||
title="操作"
|
||||
dataIndex="username"
|
||||
cell={(value, index, record) => (
|
||||
<>
|
||||
<Button
|
||||
type="primary"
|
||||
warning
|
||||
onClick={() =>
|
||||
Dialog.confirm({
|
||||
title: '确认',
|
||||
content: '是否要删除该角色?',
|
||||
onOk: () =>
|
||||
deleteRole(record).then(() =>
|
||||
this.setState({ pageNo: 1 }, () => this.getRoles())
|
||||
),
|
||||
})
|
||||
}
|
||||
>
|
||||
刪除
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
{roles.totalCount > pageSize && (
|
||||
<Pagination
|
||||
className="users-pagination"
|
||||
current={pageNo}
|
||||
total={roles.totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={pageNo => this.setState({ pageNo }, () => this.getRoles())}
|
||||
/>
|
||||
)}
|
||||
<NewRole
|
||||
visible={createRoleVisible}
|
||||
onOk={role =>
|
||||
createRole(role).then(res => {
|
||||
this.getRoles();
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.colseCreateRole()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RolesManagement;
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import RolesManagement from './RolesManagement';
|
||||
|
||||
export default RolesManagement;
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Button,
|
||||
Field,
|
||||
Form,
|
||||
Input,
|
||||
Dialog,
|
||||
Pagination,
|
||||
Table,
|
||||
ConfigProvider,
|
||||
// Field,
|
||||
} from '@alifd/next';
|
||||
import './UserManagement.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 3 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
@ConfigProvider.config
|
||||
class NewUser extends React.Component {
|
||||
static displayName = 'NewUser';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
};
|
||||
|
||||
check() {
|
||||
const errors = {
|
||||
username: '用户名不能为空!',
|
||||
password: '密码不能为空!',
|
||||
};
|
||||
const vals = ['username', 'password'].map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length === 2) {
|
||||
return vals;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getError } = this.field;
|
||||
const { visible, onOk, onCancel } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title="创建用户"
|
||||
visible={visible}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label="用户名" required help={getError('username')}>
|
||||
<Input name="username" trim placeholder="Please Enter Username" />
|
||||
</FormItem>
|
||||
<FormItem label="密码" required help={getError('password')}>
|
||||
<Input name="password" htmlType="password" placeholder="Please Enter Password" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewUser;
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Button,
|
||||
Field,
|
||||
Form,
|
||||
Input,
|
||||
Dialog,
|
||||
Pagination,
|
||||
Table,
|
||||
ConfigProvider,
|
||||
// Field,
|
||||
} from '@alifd/next';
|
||||
import './UserManagement.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 3 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
@ConfigProvider.config
|
||||
class PasswordReset extends React.Component {
|
||||
static displayName = 'PasswordReset';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
};
|
||||
|
||||
check() {
|
||||
const errors = { password: '密码不能为空!' };
|
||||
const vals = ['password'].map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length === 1) {
|
||||
return [this.props.username, ...vals];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getError } = this.field;
|
||||
const { username, onOk, onCancel } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title="密码重置"
|
||||
visible={username}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label="用户名" required>
|
||||
<p>{username}</p>
|
||||
</FormItem>
|
||||
<FormItem label="密码" required help={getError('password')}>
|
||||
<Input name="password" htmlType="password" placeholder="Please Enter Password" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PasswordReset;
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Field, Form, Input, Dialog, Pagination, Table, ConfigProvider } from '@alifd/next';
|
||||
import { connect } from 'react-redux';
|
||||
import { getUsers, createUser, deleteUser, passwordReset } from '../../../reducers/authority';
|
||||
import RegionGroup from '../../../components/RegionGroup';
|
||||
import NewUser from './NewUser';
|
||||
import PasswordReset from './PasswordReset';
|
||||
|
||||
import './UserManagement.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 3 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
@connect(state => ({ users: state.authority.users }), { getUsers })
|
||||
@ConfigProvider.config
|
||||
class UserManagement extends React.Component {
|
||||
static displayName = 'UserManagement';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
users: PropTypes.object,
|
||||
getUsers: PropTypes.func,
|
||||
createUser: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
pageNo: 1,
|
||||
pageSize: 9,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getUsers();
|
||||
}
|
||||
|
||||
getUsers() {
|
||||
const { pageNo, pageSize } = this.state;
|
||||
this.props
|
||||
.getUsers({ pageNo, pageSize })
|
||||
.then(() => {
|
||||
if (this.state.loading) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
})
|
||||
.catch(() => this.setState({ loading: false }));
|
||||
}
|
||||
|
||||
colseCreateUser() {
|
||||
this.setState({ createUserVisible: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { users } = this.props;
|
||||
const { loading, pageSize, pageNo, createUserVisible, passwordResetUser } = this.state;
|
||||
return (
|
||||
<>
|
||||
<RegionGroup left={'用户管理'} />
|
||||
<div className="filter-panel">
|
||||
<Button
|
||||
type="primary"
|
||||
className="create-user-btn"
|
||||
onClick={() => this.setState({ createUserVisible: true })}
|
||||
>
|
||||
创建用户
|
||||
</Button>
|
||||
</div>
|
||||
<Table dataSource={users.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
|
||||
<Table.Column title="用户名" dataIndex="username" />
|
||||
<Table.Column
|
||||
title="密码"
|
||||
dataIndex="password"
|
||||
cell={value => value.replace(/\S/g, '*')}
|
||||
/>
|
||||
<Table.Column
|
||||
title="操作"
|
||||
dataIndex="username"
|
||||
cell={username => (
|
||||
<>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.setState({ passwordResetUser: username })}
|
||||
>
|
||||
修改
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
warning
|
||||
onClick={() =>
|
||||
Dialog.confirm({
|
||||
title: '确认',
|
||||
content: '是否要删除该用户?',
|
||||
onOk: () =>
|
||||
deleteUser(username).then(() =>
|
||||
this.setState({ pageNo: 1 }, () => this.getUsers())
|
||||
),
|
||||
})
|
||||
}
|
||||
>
|
||||
刪除
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
{users.totalCount > pageSize && (
|
||||
<Pagination
|
||||
className="users-pagination"
|
||||
current={pageNo}
|
||||
total={users.totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={pageNo => this.setState({ pageNo }, () => this.getUsers())}
|
||||
/>
|
||||
)}
|
||||
<NewUser
|
||||
visible={createUserVisible}
|
||||
onOk={user =>
|
||||
createUser(user).then(res => {
|
||||
this.setState({ pageNo: 1 }, () => this.getUsers());
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.colseCreateUser()}
|
||||
/>
|
||||
<PasswordReset
|
||||
username={passwordResetUser}
|
||||
onOk={user =>
|
||||
passwordReset(user).then(res => {
|
||||
this.getUsers();
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.setState({ passwordResetUser: undefined })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserManagement;
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@import '../authority.scss';
|
||||
|
||||
.users-pagination {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import UserManagement from './UserManagement';
|
||||
|
||||
export default UserManagement;
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.filter-panel {
|
||||
text-align: right;
|
||||
padding: 10px 0;
|
||||
}
|
@ -1095,7 +1095,7 @@ class ConfigurationManagement extends React.Component {
|
||||
render() {
|
||||
const { locale = {} } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<BatchHandle ref={ref => (this.batchHandle = ref)} />
|
||||
<Loading
|
||||
shape={'flower'}
|
||||
@ -1107,7 +1107,7 @@ class ConfigurationManagement extends React.Component {
|
||||
<div className={this.state.hasdash ? 'dash-page-container' : ''}>
|
||||
<div
|
||||
className={this.state.hasdash ? 'dash-left-container' : ''}
|
||||
style={{ position: 'relative', padding: 10 }}
|
||||
style={{ position: 'relative' }}
|
||||
>
|
||||
<div style={{ display: this.inApp ? 'none' : 'block', marginTop: -15 }}>
|
||||
<RegionGroup
|
||||
@ -1359,7 +1359,7 @@ class ConfigurationManagement extends React.Component {
|
||||
)}
|
||||
</div>
|
||||
</Loading>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,3 @@
|
||||
.next-pagination-size-selector{
|
||||
position: static !important;
|
||||
}
|
||||
.next-overlay-inner{
|
||||
top:154px !important;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ class ListeningToQuery extends React.Component {
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div style={{ padding: 10 }}>
|
||||
<>
|
||||
<Loading
|
||||
shape="flower"
|
||||
style={{ position: 'relative' }}
|
||||
@ -320,7 +320,7 @@ class ListeningToQuery extends React.Component {
|
||||
,
|
||||
</div>
|
||||
</Loading>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ class NameSpace extends React.Component {
|
||||
namespaceOperation,
|
||||
} = locale;
|
||||
return (
|
||||
<div style={{ padding: 10 }} className="clearfix">
|
||||
<>
|
||||
<RegionGroup left={namespace} />
|
||||
<div className="fusion-demo">
|
||||
<Loading
|
||||
@ -348,7 +348,7 @@ class NameSpace extends React.Component {
|
||||
<EditorNameSpace ref={this.editgroup} getNameSpaces={this.getNameSpaces.bind(this)} />
|
||||
</Loading>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,8 @@ class Welcome extends React.Component {
|
||||
|
||||
render() {
|
||||
const { functionMode } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{functionMode !== '' && (
|
||||
<Redirect
|
||||
to={`/${functionMode === 'naming' ? 'serviceManagement' : 'configurationManagement'}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const path = functionMode === 'naming' ? 'serviceManagement' : 'configurationManagement';
|
||||
return <>{functionMode !== '' && <Redirect to={`/${path}`} />}</>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Message } from '@alifd/next';
|
||||
import request from '../utils/request';
|
||||
import { UPDATE_USER, SIGN_IN, USER_LIST, ROLE_LIST } from '../constants';
|
||||
|
||||
const initialState = {
|
||||
users: {
|
||||
totalCount: 0,
|
||||
pageNumber: 1,
|
||||
pagesAvailable: 1,
|
||||
pageItems: [],
|
||||
},
|
||||
roles: {},
|
||||
};
|
||||
|
||||
const successMsg = res => {
|
||||
if (res.code === 200) {
|
||||
Message.success(res.message);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户列表
|
||||
* @param {*} params
|
||||
*/
|
||||
const getUsers = params => dispatch =>
|
||||
request.get('v1/auth/users', { params }).then(data => dispatch({ type: USER_LIST, data }));
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
* @param {*} param0
|
||||
*/
|
||||
const createUser = ([username, password]) =>
|
||||
request.post('v1/auth/users', { username, password }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param {*} username
|
||||
*/
|
||||
const deleteUser = username =>
|
||||
request.delete('v1/auth/users', { params: { username } }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
* @param {*} param0
|
||||
*/
|
||||
const passwordReset = ([username, newPassword]) =>
|
||||
request.put('v1/auth/users', { username, newPassword }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
* @param {*} params
|
||||
*/
|
||||
|
||||
const getRoles = params => dispatch =>
|
||||
request.get('v1/auth/roles', { params }).then(data => dispatch({ type: ROLE_LIST, data }));
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
* @param {*} param0
|
||||
*/
|
||||
const createRole = ([role, username]) =>
|
||||
request.post('v1/auth/roles', { role, username }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
* @param {*} param0
|
||||
*/
|
||||
const deleteRole = role =>
|
||||
request.delete('v1/auth/roles', { params: role }).then(res => successMsg(res));
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case USER_LIST:
|
||||
return { ...state, users: { ...action.data } };
|
||||
case ROLE_LIST:
|
||||
return { ...state, roles: { ...action.data } };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { getUsers, createUser, deleteUser, passwordReset, getRoles, createRole, deleteRole };
|
@ -14,5 +14,6 @@
|
||||
import locale from './locale';
|
||||
import base from './base';
|
||||
import subscribers from './subscribers';
|
||||
import authority from './authority';
|
||||
|
||||
export default { locale, base, subscribers };
|
||||
export default { locale, base, subscribers, authority };
|
||||
|
@ -1,4 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import qs from 'qs';
|
||||
import { Message } from '@alifd/next';
|
||||
// import { SUCCESS_RESULT_CODE } from '../constants';
|
||||
|
||||
@ -7,6 +8,21 @@ const API_GENERAL_ERROR_MESSAGE = 'Request error, please try again later!';
|
||||
const request = () => {
|
||||
const instance = axios.create();
|
||||
|
||||
instance.interceptors.request.use(
|
||||
function(config) {
|
||||
if (['post', 'put'].includes(config.method)) {
|
||||
config.data = qs.stringify(config.data);
|
||||
config.headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
};
|
||||
}
|
||||
return config;
|
||||
},
|
||||
function(error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
instance.interceptors.response.use(
|
||||
response => {
|
||||
const { success, resultCode, resultMessage = API_GENERAL_ERROR_MESSAGE } = response.data;
|
||||
|
Loading…
Reference in New Issue
Block a user