初始化 antd-pro
This commit is contained in:
141
admin-web/src/models/global.js
Normal file
141
admin-web/src/models/global.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import { queryNotices } from '@/services/api';
|
||||
|
||||
export default {
|
||||
namespace: 'global',
|
||||
|
||||
state: {
|
||||
collapsed: false,
|
||||
notices: [],
|
||||
loadedAllNotices: false,
|
||||
},
|
||||
|
||||
effects: {
|
||||
*fetchNotices(_, { call, put, select }) {
|
||||
const data = yield call(queryNotices);
|
||||
const loadedAllNotices = data && data.length && data[data.length - 1] === null;
|
||||
yield put({
|
||||
type: 'setLoadedStatus',
|
||||
payload: loadedAllNotices,
|
||||
});
|
||||
yield put({
|
||||
type: 'saveNotices',
|
||||
payload: data.filter(item => item),
|
||||
});
|
||||
const unreadCount = yield select(
|
||||
state => state.global.notices.filter(item => !item.read).length
|
||||
);
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: data.length,
|
||||
unreadCount,
|
||||
},
|
||||
});
|
||||
},
|
||||
*fetchMoreNotices({ payload }, { call, put, select }) {
|
||||
const data = yield call(queryNotices, payload);
|
||||
const loadedAllNotices = data && data.length && data[data.length - 1] === null;
|
||||
yield put({
|
||||
type: 'setLoadedStatus',
|
||||
payload: loadedAllNotices,
|
||||
});
|
||||
yield put({
|
||||
type: 'pushNotices',
|
||||
payload: data.filter(item => item),
|
||||
});
|
||||
const unreadCount = yield select(
|
||||
state => state.global.notices.filter(item => !item.read).length
|
||||
);
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: data.length,
|
||||
unreadCount,
|
||||
},
|
||||
});
|
||||
},
|
||||
*clearNotices({ payload }, { put, select }) {
|
||||
yield put({
|
||||
type: 'saveClearedNotices',
|
||||
payload,
|
||||
});
|
||||
const count = yield select(state => state.global.notices.length);
|
||||
const unreadCount = yield select(
|
||||
state => state.global.notices.filter(item => !item.read).length
|
||||
);
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: count,
|
||||
unreadCount,
|
||||
},
|
||||
});
|
||||
},
|
||||
*changeNoticeReadState({ payload }, { put, select }) {
|
||||
const notices = yield select(state =>
|
||||
state.global.notices.map(item => {
|
||||
const notice = { ...item };
|
||||
if (notice.id === payload) {
|
||||
notice.read = true;
|
||||
}
|
||||
return notice;
|
||||
})
|
||||
);
|
||||
yield put({
|
||||
type: 'saveNotices',
|
||||
payload: notices,
|
||||
});
|
||||
yield put({
|
||||
type: 'user/changeNotifyCount',
|
||||
payload: {
|
||||
totalCount: notices.length,
|
||||
unreadCount: notices.filter(item => !item.read).length,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
changeLayoutCollapsed(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
collapsed: payload,
|
||||
};
|
||||
},
|
||||
saveNotices(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
notices: payload,
|
||||
};
|
||||
},
|
||||
saveClearedNotices(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
notices: state.notices.filter(item => item.type !== payload),
|
||||
};
|
||||
},
|
||||
pushNotices(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
notices: [...state.notices, ...payload],
|
||||
};
|
||||
},
|
||||
setLoadedStatus(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
loadedAllNotices: payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
subscriptions: {
|
||||
setup({ history }) {
|
||||
// Subscribe history(url) change, trigger `load` action if pathname is `/`
|
||||
return history.listen(({ pathname, search }) => {
|
||||
if (typeof window.ga !== 'undefined') {
|
||||
window.ga('send', 'pageview', pathname + search);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
54
admin-web/src/models/list.js
Normal file
54
admin-web/src/models/list.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { queryFakeList, removeFakeList, addFakeList, updateFakeList } from '@/services/api';
|
||||
|
||||
export default {
|
||||
namespace: 'list',
|
||||
|
||||
state: {
|
||||
list: [],
|
||||
},
|
||||
|
||||
effects: {
|
||||
*fetch({ payload }, { call, put }) {
|
||||
const response = yield call(queryFakeList, payload);
|
||||
yield put({
|
||||
type: 'queryList',
|
||||
payload: Array.isArray(response) ? response : [],
|
||||
});
|
||||
},
|
||||
*appendFetch({ payload }, { call, put }) {
|
||||
const response = yield call(queryFakeList, payload);
|
||||
yield put({
|
||||
type: 'appendList',
|
||||
payload: Array.isArray(response) ? response : [],
|
||||
});
|
||||
},
|
||||
*submit({ payload }, { call, put }) {
|
||||
let callback;
|
||||
if (payload.id) {
|
||||
callback = Object.keys(payload).length === 1 ? removeFakeList : updateFakeList;
|
||||
} else {
|
||||
callback = addFakeList;
|
||||
}
|
||||
const response = yield call(callback, payload); // post
|
||||
yield put({
|
||||
type: 'queryList',
|
||||
payload: response,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
queryList(state, action) {
|
||||
return {
|
||||
...state,
|
||||
list: action.payload,
|
||||
};
|
||||
},
|
||||
appendList(state, action) {
|
||||
return {
|
||||
...state,
|
||||
list: state.list.concat(action.payload),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
78
admin-web/src/models/login.js
Normal file
78
admin-web/src/models/login.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { routerRedux } from 'dva/router';
|
||||
import { stringify } from 'qs';
|
||||
import { fakeAccountLogin, getFakeCaptcha } from '@/services/api';
|
||||
import { setAuthority } from '@/utils/authority';
|
||||
import { getPageQuery } from '@/utils/utils';
|
||||
import { reloadAuthorized } from '@/utils/Authorized';
|
||||
|
||||
export default {
|
||||
namespace: 'login',
|
||||
|
||||
state: {
|
||||
status: undefined,
|
||||
},
|
||||
|
||||
effects: {
|
||||
*login({ payload }, { call, put }) {
|
||||
const response = yield call(fakeAccountLogin, payload);
|
||||
yield put({
|
||||
type: 'changeLoginStatus',
|
||||
payload: response,
|
||||
});
|
||||
// Login successfully
|
||||
if (response.status === 'ok') {
|
||||
reloadAuthorized();
|
||||
const urlParams = new URL(window.location.href);
|
||||
const params = getPageQuery();
|
||||
let { redirect } = params;
|
||||
if (redirect) {
|
||||
const redirectUrlParams = new URL(redirect);
|
||||
if (redirectUrlParams.origin === urlParams.origin) {
|
||||
redirect = redirect.substr(urlParams.origin.length);
|
||||
if (redirect.match(/^\/.*#/)) {
|
||||
redirect = redirect.substr(redirect.indexOf('#') + 1);
|
||||
}
|
||||
} else {
|
||||
window.location.href = redirect;
|
||||
return;
|
||||
}
|
||||
}
|
||||
yield put(routerRedux.replace(redirect || '/'));
|
||||
}
|
||||
},
|
||||
|
||||
*getCaptcha({ payload }, { call }) {
|
||||
yield call(getFakeCaptcha, payload);
|
||||
},
|
||||
|
||||
*logout(_, { put }) {
|
||||
yield put({
|
||||
type: 'changeLoginStatus',
|
||||
payload: {
|
||||
status: false,
|
||||
currentAuthority: 'guest',
|
||||
},
|
||||
});
|
||||
reloadAuthorized();
|
||||
yield put(
|
||||
routerRedux.push({
|
||||
pathname: '/user/login',
|
||||
search: stringify({
|
||||
redirect: window.location.href,
|
||||
}),
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
changeLoginStatus(state, { payload }) {
|
||||
setAuthority(payload.currentAuthority);
|
||||
return {
|
||||
...state,
|
||||
status: payload.status,
|
||||
type: payload.type,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
123
admin-web/src/models/menu.js
Normal file
123
admin-web/src/models/menu.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import memoizeOne from 'memoize-one';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { formatMessage } from 'umi/locale';
|
||||
import Authorized from '@/utils/Authorized';
|
||||
import { menu } from '../defaultSettings';
|
||||
|
||||
const { check } = Authorized;
|
||||
|
||||
// Conversion router to menu.
|
||||
function formatter(data, parentAuthority, parentName) {
|
||||
return data
|
||||
.map(item => {
|
||||
if (!item.name || !item.path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let locale = 'menu';
|
||||
if (parentName) {
|
||||
locale = `${parentName}.${item.name}`;
|
||||
} else {
|
||||
locale = `menu.${item.name}`;
|
||||
}
|
||||
// if enableMenuLocale use item.name,
|
||||
// close menu international
|
||||
const name = menu.disableLocal
|
||||
? item.name
|
||||
: formatMessage({ id: locale, defaultMessage: item.name });
|
||||
const result = {
|
||||
...item,
|
||||
name,
|
||||
locale,
|
||||
authority: item.authority || parentAuthority,
|
||||
};
|
||||
if (item.routes) {
|
||||
const children = formatter(item.routes, item.authority, locale);
|
||||
// Reduce memory usage
|
||||
result.children = children;
|
||||
}
|
||||
delete result.routes;
|
||||
return result;
|
||||
})
|
||||
.filter(item => item);
|
||||
}
|
||||
|
||||
const memoizeOneFormatter = memoizeOne(formatter, isEqual);
|
||||
|
||||
/**
|
||||
* get SubMenu or Item
|
||||
*/
|
||||
const getSubMenu = item => {
|
||||
// doc: add hideChildrenInMenu
|
||||
if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
|
||||
return {
|
||||
...item,
|
||||
children: filterMenuData(item.children), // eslint-disable-line
|
||||
};
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* filter menuData
|
||||
*/
|
||||
const filterMenuData = menuData => {
|
||||
if (!menuData) {
|
||||
return [];
|
||||
}
|
||||
return menuData
|
||||
.filter(item => item.name && !item.hideInMenu)
|
||||
.map(item => check(item.authority, getSubMenu(item)))
|
||||
.filter(item => item);
|
||||
};
|
||||
/**
|
||||
* 获取面包屑映射
|
||||
* @param {Object} menuData 菜单配置
|
||||
*/
|
||||
const getBreadcrumbNameMap = menuData => {
|
||||
const routerMap = {};
|
||||
|
||||
const flattenMenuData = data => {
|
||||
data.forEach(menuItem => {
|
||||
if (menuItem.children) {
|
||||
flattenMenuData(menuItem.children);
|
||||
}
|
||||
// Reduce memory usage
|
||||
routerMap[menuItem.path] = menuItem;
|
||||
});
|
||||
};
|
||||
flattenMenuData(menuData);
|
||||
return routerMap;
|
||||
};
|
||||
|
||||
const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);
|
||||
|
||||
export default {
|
||||
namespace: 'menu',
|
||||
|
||||
state: {
|
||||
menuData: [],
|
||||
breadcrumbNameMap: {},
|
||||
},
|
||||
|
||||
effects: {
|
||||
*getMenuData({ payload }, { put }) {
|
||||
const { routes, authority } = payload;
|
||||
const menuData = filterMenuData(memoizeOneFormatter(routes, authority));
|
||||
const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(menuData);
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: { menuData, breadcrumbNameMap },
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
save(state, action) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
28
admin-web/src/models/project.js
Normal file
28
admin-web/src/models/project.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { queryProjectNotice } from '@/services/api';
|
||||
|
||||
export default {
|
||||
namespace: 'project',
|
||||
|
||||
state: {
|
||||
notice: [],
|
||||
},
|
||||
|
||||
effects: {
|
||||
*fetchNotice(_, { call, put }) {
|
||||
const response = yield call(queryProjectNotice);
|
||||
yield put({
|
||||
type: 'saveNotice',
|
||||
payload: Array.isArray(response) ? response : [],
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
saveNotice(state, action) {
|
||||
return {
|
||||
...state,
|
||||
notice: action.payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
123
admin-web/src/models/setting.js
Normal file
123
admin-web/src/models/setting.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import { message } from 'antd';
|
||||
import defaultSettings from '../defaultSettings';
|
||||
|
||||
let lessNodesAppended;
|
||||
const updateTheme = primaryColor => {
|
||||
// Don't compile less in production!
|
||||
if (APP_TYPE !== 'site') {
|
||||
return;
|
||||
}
|
||||
// Determine if the component is remounted
|
||||
if (!primaryColor) {
|
||||
return;
|
||||
}
|
||||
const hideMessage = message.loading('正在编译主题!', 0);
|
||||
function buildIt() {
|
||||
if (!window.less) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.less
|
||||
.modifyVars({
|
||||
'@primary-color': primaryColor,
|
||||
})
|
||||
.then(() => {
|
||||
hideMessage();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('Failed to update theme');
|
||||
hideMessage();
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
if (!lessNodesAppended) {
|
||||
// insert less.js and color.less
|
||||
const lessStyleNode = document.createElement('link');
|
||||
const lessConfigNode = document.createElement('script');
|
||||
const lessScriptNode = document.createElement('script');
|
||||
lessStyleNode.setAttribute('rel', 'stylesheet/less');
|
||||
lessStyleNode.setAttribute('href', '/color.less');
|
||||
lessConfigNode.innerHTML = `
|
||||
window.less = {
|
||||
async: true,
|
||||
env: 'production',
|
||||
javascriptEnabled: true
|
||||
};
|
||||
`;
|
||||
lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js';
|
||||
lessScriptNode.async = true;
|
||||
lessScriptNode.onload = () => {
|
||||
buildIt();
|
||||
lessScriptNode.onload = null;
|
||||
};
|
||||
document.body.appendChild(lessStyleNode);
|
||||
document.body.appendChild(lessConfigNode);
|
||||
document.body.appendChild(lessScriptNode);
|
||||
lessNodesAppended = true;
|
||||
} else {
|
||||
buildIt();
|
||||
}
|
||||
};
|
||||
|
||||
const updateColorWeak = colorWeak => {
|
||||
document.body.className = colorWeak ? 'colorWeak' : '';
|
||||
};
|
||||
|
||||
export default {
|
||||
namespace: 'setting',
|
||||
state: defaultSettings,
|
||||
reducers: {
|
||||
getSetting(state) {
|
||||
const setting = {};
|
||||
const urlParams = new URL(window.location.href);
|
||||
Object.keys(state).forEach(key => {
|
||||
if (urlParams.searchParams.has(key)) {
|
||||
const value = urlParams.searchParams.get(key);
|
||||
setting[key] = value === '1' ? true : value;
|
||||
}
|
||||
});
|
||||
const { primaryColor, colorWeak } = setting;
|
||||
if (state.primaryColor !== primaryColor) {
|
||||
updateTheme(primaryColor);
|
||||
}
|
||||
updateColorWeak(colorWeak);
|
||||
return {
|
||||
...state,
|
||||
...setting,
|
||||
};
|
||||
},
|
||||
changeSetting(state, { payload }) {
|
||||
const urlParams = new URL(window.location.href);
|
||||
Object.keys(defaultSettings).forEach(key => {
|
||||
if (urlParams.searchParams.has(key)) {
|
||||
urlParams.searchParams.delete(key);
|
||||
}
|
||||
});
|
||||
Object.keys(payload).forEach(key => {
|
||||
if (key === 'collapse') {
|
||||
return;
|
||||
}
|
||||
let value = payload[key];
|
||||
if (value === true) {
|
||||
value = 1;
|
||||
}
|
||||
if (defaultSettings[key] !== value) {
|
||||
urlParams.searchParams.set(key, value);
|
||||
}
|
||||
});
|
||||
const { primaryColor, colorWeak, contentWidth } = payload;
|
||||
if (state.primaryColor !== primaryColor) {
|
||||
updateTheme(primaryColor);
|
||||
}
|
||||
if (state.contentWidth !== contentWidth && window.dispatchEvent) {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}
|
||||
updateColorWeak(colorWeak);
|
||||
window.history.replaceState(null, 'setting', urlParams.href);
|
||||
return {
|
||||
...state,
|
||||
...payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
52
admin-web/src/models/user.js
Normal file
52
admin-web/src/models/user.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { query as queryUsers, queryCurrent } from '@/services/user';
|
||||
|
||||
export default {
|
||||
namespace: 'user',
|
||||
|
||||
state: {
|
||||
list: [],
|
||||
currentUser: {},
|
||||
},
|
||||
|
||||
effects: {
|
||||
*fetch(_, { call, put }) {
|
||||
const response = yield call(queryUsers);
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: response,
|
||||
});
|
||||
},
|
||||
*fetchCurrent(_, { call, put }) {
|
||||
const response = yield call(queryCurrent);
|
||||
yield put({
|
||||
type: 'saveCurrentUser',
|
||||
payload: response,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
save(state, action) {
|
||||
return {
|
||||
...state,
|
||||
list: action.payload,
|
||||
};
|
||||
},
|
||||
saveCurrentUser(state, action) {
|
||||
return {
|
||||
...state,
|
||||
currentUser: action.payload || {},
|
||||
};
|
||||
},
|
||||
changeNotifyCount(state, action) {
|
||||
return {
|
||||
...state,
|
||||
currentUser: {
|
||||
...state.currentUser,
|
||||
notifyCount: action.payload.totalCount,
|
||||
unreadCount: action.payload.unreadCount,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user