diff --git a/package.json b/package.json
index 0edc5e0..70e0cc6 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"react-dom": "15.0.2",
"react-hot-loader": "1.3.0",
"react-router": "2.0.1",
+ "reqwest": "^2.0.5",
"strip-loader": "0.1.2",
"style-loader": "0.13.1",
"stylelint": "6.6.0",
diff --git a/src/components/App/index.js b/src/components/App/index.js
deleted file mode 100644
index edf889c..0000000
--- a/src/components/App/index.js
+++ /dev/null
@@ -1,112 +0,0 @@
-import React from 'react';
-import {Spin, message} from 'antd';
-import Header from '../Header';
-import Footer from '../Footer';
-import Sidebar from '../Sidebar';
-import Login from '../Login';
-import Breadcrumb from '../Breadcrumb';
-import './index.less';
-import globalConfig from 'config.js';
-import ajax from '../../utils/ajax';
-import Logger from '../../utils/Logger';
-
-const logger = Logger.getLogger('App');
-
-/**
- * App组件
- * 定义整个页面的布局
- */
-class App extends React.Component {
-
- // 全局的状态
- state = {
- loading: true, // 是否在loading状态
- login: false, // 是否登录
- userName: '未登录', // 登录后的用户名
- };
-
- componentWillMount() {
- logger.debug('mount and add styles');
- // 为了兼容登录组件
- document.body.style.background = 'white'; // FIXME: gross hack
- }
-
- componentDidMount() {
- if (!this.state.login) {
- const hide = message.loading('正在获取用户信息...', 0);
-
- // 先去服务端验证下, 说不定已经登录了
- ajax.get(`${globalConfig.getAPIPath()}${globalConfig.login.getCurrentUser}`).end((err, res) => {
-
- // 注意这里, debug模式下每次刷新都必须重新登录
- if (ajax.isSuccess(res) && !globalConfig.debug) {
- hide();
- this.loginSuccess(res.body.data);
- } else {
- // 如果服务端说没有登录, 就要跳转到sso或者登录界面
- if (globalConfig.isSSO()) {
- // debug模式不支持调试单点登录
- // 因为没有单点登录的地址啊...跳不回来
- hide();
- logger.debug('not login, redirect to SSO login page');
- const redirect = encodeURIComponent(window.location.href);
- window.location.href = `${globalConfig.login.sso}${redirect}`;
- } else {
- hide();
- message.error('获取用户信息失败, 请重新登录');
- logger.debug('not login, redirect to Login component');
- this.setState({loading: false, login: false});
- }
- }
- });
- }
- }
-
- // 登录成功后的回调
- loginSuccess = (name, showMsg) => {
- logger.debug('callback logingSuccess, name = %s', name);
- if (showMsg)
- message.success('登录成功');
- document.body.style.background = 'white'; // FIXME: gross hack
- this.setState({loading: false, login: true, userName: name});
- }
-
- render() {
- // 显示一个加载中
- if (this.state.loading) {
- return
;
- }
-
- // 跳转到登录界面
- if (!this.state.login) {
- return ;
- }
-
- return (
-
- {/*整个页面被一个ant-layout-aside的div包围, 分为sidebar/header/footer/content等几部分*/}
-
-
-
-
- );
- }
-}
-
-export default App;
diff --git a/src/components/App/index.less b/src/components/App/index.less
deleted file mode 100644
index 44aff70..0000000
--- a/src/components/App/index.less
+++ /dev/null
@@ -1,154 +0,0 @@
-/*定义整体layout的样式, 直接从antd官网copy的, 稍微修改了一些*/
-/*我本来想把样式拆到各个模块去, 但是太麻烦了...*/
-
-.ant-layout-aside {
- position: relative;
- height: 100%;
-}
-
-.ant-layout-aside .ant-layout-logo {
- width: 200px;
- height: 32px;
- background: #333;
- border-radius: 6px;
- margin: 16px 8px 16px 12px;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside-collapse .ant-layout-logo {
- width: 32px;
- margin: 16px;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside .ant-layout-sider {
- width: 224px;
- background: #404040;
- position: absolute;
- overflow: auto;
- padding-bottom: 24px;
- height: 100%;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside-collapse .ant-layout-sider {
- width: 64px;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside .ant-layout-sider > .ant-menu {
- margin-bottom: 20px;
-}
-
-.ant-layout-aside .ant-layout-sider > .ant-menu > .ant-menu-item {
- margin: 16px 0;
-}
-
-.ant-layout-aside .ant-layout-sider > .ant-menu > .ant-menu-item .nav-text {
- vertical-align: baseline;
- display: inline-block;
-}
-
-.ant-layout-aside .ant-layout-sider > .ant-menu > .ant-menu-item > .anticon {
- transition: font-size .3s;
-}
-
-.ant-layout-aside-collapse .ant-layout-sider > .ant-menu > .ant-menu-item {
- transition: all 0s ease;
-}
-
-.ant-layout-aside-collapse .ant-layout-sider > .ant-menu > .ant-menu-item > .anticon {
- font-size: 16px;
- display: inline-block;
-}
-
-.ant-layout-aside-collapse .ant-layout-sider > .ant-menu > .ant-menu-item .nav-text {
- display: none;
-}
-
-.ant-layout-aside-collapse .ant-layout-sider > .ant-menu > .ant-menu-item:hover {
- background: #2db7f5;
- color: #fff;
- transition: all 0s ease;
-}
-
-.ant-layout-aside-collapse .ant-layout-sider > .ant-menu > .ant-menu-item:hover .nav-text {
- display: inline-block;
- vertical-align: top;
- background: #2db7f5;
- color: #fff;
- padding-right: 16px;
- border-radius: 0 5px 5px 0;
-}
-
-/* 实际使用中需要改成 position: fixed */
-.ant-layout-aside .ant-aside-action {
- height: 42px;
- width: 224px;
- position: absolute;
- bottom: 0;
- background: #656565;
- color: #fff;
- text-align: center;
- line-height: 42px;
- cursor: pointer;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside-collapse .ant-aside-action {
- width: 64px;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside .ant-layout-header {
- background: #fff;
- height: 48px;
- border-bottom: 1px solid #e9e9e9;
-}
-
-.ant-layout-aside .ant-layout-breadcrumb {
- margin: 7px 0 -17px 24px;
-}
-
-.ant-layout-aside .ant-layout-main {
- margin-left: 224px;
- transition: all 0.3s ease;
- overflow: auto;
- height: 100%;
-}
-
-.ant-layout-aside-collapse .ant-layout-main {
- margin-left: 64px;
- transition: all 0.3s ease;
-}
-
-.ant-layout-aside .ant-layout-container {
- margin: 24px 16px;
-}
-
-.ant-layout-aside .ant-layout-content {
- background: #fff;
- padding: 24px;
-}
-
-.ant-layout-aside .ant-layout-footer {
- height: 64px;
- line-height: 64px;
- text-align: center;
- font-size: 12px;
- color: #999;
- background: #fff;
- border-top: 1px solid #e9e9e9;
- width: 100%;
-}
-
-// 为了在屏幕中间显示一个loading
-.center-div {
- position: absolute; /*绝对定位*/
- top: 50%; /* 距顶部50%*/
- left: 50%; /* 距左边50%*/
- height: 2px;
- margin-top: -1px; /*margin-top为height一半的负值*/
- width: 2px;
- margin-left: -1px; /*margin-left为width一半的负值*/
-}
diff --git a/src/components/Breadcrumb/index.js b/src/components/Breadcrumb/index.js
index 297cee5..0f4432d 100644
--- a/src/components/Breadcrumb/index.js
+++ b/src/components/Breadcrumb/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import {Breadcrumb, Icon} from 'antd';
import items from 'menu.js';
-import Logger from '../../utils/Logger';
+import Logger from '../../utils/logger';
const Item = Breadcrumb.Item;
const logger = Logger.getLogger('Breadcrumb');
diff --git a/src/components/DBTable/InnerForm.js b/src/components/DBTable/InnerForm.js
deleted file mode 100644
index 3d9cf4d..0000000
--- a/src/components/DBTable/InnerForm.js
+++ /dev/null
@@ -1,449 +0,0 @@
-import React from 'react';
-import {
- Form,
- Input,
- Row,
- Col,
- Button,
- DatePicker,
- Select,
- Icon,
- Radio,
- InputNumber,
- Checkbox,
- message,
- Upload,
- notification
-} from 'antd';
-import globalConfig from 'config.js';
-import Logger from '../../utils/Logger';
-
-const FormItem = Form.Item;
-const RadioGroup = Radio.Group;
-const CheckboxGroup = Checkbox.Group;
-const Option = Select.Option;
-
-const logger = Logger.getLogger('InnerForm');
-
-/**
- * 内部表单组件
- */
-class InnerForm extends React.Component {
-
- // 本来想在初始化时解析schema, 结果发现不行
- // 解析schema的过程还是改到render里了
-
- /**
- * 辅助函数, 将一个input元素包装下
- *
- * @param formItem
- * @param field
- * @returns {XML}
- */
- colWrapper = (formItem, field) => {
- //const {getFieldProps, getFieldError, isFieldValidating} = this.props.form;
- return (
-
-
- {formItem}
-
-
- );
- }
-
- /**
- * 将schema中的一列转换为下拉框
- *
- * @param field
- */
- transformSelect = (field) => {
- // TODO: 这里是否要做schema校验
- const options = [];
- const {getFieldProps} = this.props.form;
-
- logger.debug('transform field %o to Select component', field);
- field.options.forEach((option) => {
- options.push();
- });
-
- return this.colWrapper((
-
- ), field);
- }
-
- /**
- * 将schema中的一列转换为单选框
- *
- * @param field
- */
- transformRadio = (field) => {
- const options = [];
- const {getFieldProps} = this.props.form;
-
- logger.debug('transform field %o to Radio component', field);
- field.options.forEach((option) => {
- options.push({option.value});
- });
-
- return this.colWrapper((
-
- {options}
-
- ), field);
- }
-
- /**
- * 将schema中的一列转换为checkbox
- *
- * @param field
- */
- transformCheckbox = (field) => {
- const options = [];
- const {getFieldProps} = this.props.form;
-
- logger.debug('transform field %o to Checkbox component', field);
- field.options.forEach((option) => {
- options.push({label: option.value, value: option.key});
- });
-
- return this.colWrapper((
-
- ), field);
- }
-
- /**
- * 转换为下拉多选框
- *
- * @param field
- * @returns {XML}
- */
- transformMultiSelect = (field) => {
- const options = [];
- const {getFieldProps} = this.props.form;
-
- logger.debug('transform field %o to MultipleSelect component', field);
- field.options.forEach((option) => {
- options.push();
- });
-
- return this.colWrapper((
-
- ), field);
- }
-
- /**
- * 将schema中的一列转换为普通输入框
- *
- * @param field
- * @returns {XML}
- */
- transformNormal = (field) => {
- const {getFieldProps} = this.props.form;
- switch (field.dataType) {
- case 'int':
- logger.debug('transform field %o to integer input component', field);
- return this.colWrapper((
-
- ), field);
- case 'float':
- logger.debug('transform field %o to float input component', field);
- return this.colWrapper((
-
- ), field);
- case 'datetime':
- logger.debug('transform field %o to datetime input component', field);
- return this.colWrapper((
-
- ), field);
- default: // 默认就是普通的输入框
- logger.debug('transform field %o to varchar input component', field);
- return this.colWrapper((
-
- ), field);
- }
- }
-
- /**
- * 也是个辅助函数, 由于是范围查询, 输入的formItem是两个, 一个用于begin一个用于end
- *
- * @param beginFormItem
- * @param endFormItem
- * @param field
- * @returns {XML}
- */
- betweenColWrapper = (beginFormItem, endFormItem, field) => {
- // 布局真是个麻烦事
- // col内部又用了一个row做布局
- // const {getFieldProps} = this.props.form;
- return (
-
-
-
-
- {beginFormItem}
-
-
-
-
- {endFormItem}
-
-
-
-
- );
- }
-
- /**
- * between类型比较特殊, 普通元素每个宽度是8, int和float的between元素宽度也是8, 但datetime类型的between元素宽度是16
- * 否则排版出来不能对齐, 太丑了, 逼死强迫症
- * 而且普通的transform函数返回是一个object, 而这个函数返回是一个array, 就是因为datetime的between要占用两列
- *
- * @param field
- */
- transformBetween = (field) => {
- const cols = [];
- let beginFormItem;
- let endFormItem;
- const {getFieldProps} = this.props.form;
-
- switch (field.dataType) {
- case 'int':
- logger.debug('transform field %o to integer BETWEEN component', field);
- beginFormItem = ();
- endFormItem = ();
- cols.push(this.betweenColWrapper(beginFormItem, endFormItem, field));
- break;
- case 'float':
- logger.debug('transform field %o to float BETWEEN component', field);
- beginFormItem = ();
- endFormItem = ();
- cols.push(this.betweenColWrapper(beginFormItem, endFormItem, field));
- break;
- // datetime类型的between要占用两个Col
- // 不写辅助函数了, 直接这里写jsx吧...
- case 'datetime':
- logger.debug('transform field %o to datetime BETWEEN component', field);
- cols.push(
-
-
-
-
-
- );
- cols.push(
-
-
-
- );
- break;
- default:
- // 理论上来说不会出现这种情况
- logger.error('unknown dataType: %s', field.dataType);
- }
- return cols;
- }
-
- /**
- * 表单的查询条件不能直接传给后端, 要处理一下
- *
- * @param oldObj
- * @returns {{}}
- */
- filterQueryObj(oldObj) {
- // 将提交的值中undefined的去掉
- const newObj = {};
- for (const key in oldObj) {
- if (oldObj[key]) {
- // 对于js的日期类型, 要转换成字符串再传给后端
- if (oldObj[key] instanceof Date) {
- newObj[key] = oldObj[key].format('yyyy-MM-dd HH:mm:ss');
- } else {
- newObj[key] = oldObj[key];
- }
- }
- }
- logger.debug('old queryObj: %o, new queryObj %o', oldObj, newObj);
- return newObj;
- }
-
- /**
- * 处理表单提交
- *
- * @param e
- */
- handleSubmit = (e) => {
- e.preventDefault();
-
- const oldObj = this.props.form.getFieldsValue();
- const newObj = this.filterQueryObj(oldObj);
-
- // 还是要交给上层组件处理, 因为要触发table组件的状态变化...
- this.props.parentHandleSubmit(newObj);
- }
-
- handleReset = (e) => {
- e.preventDefault();
- this.props.form.resetFields();
- }
-
- /**
- * 处理数据导入
- */
- handleImport = (info) => {
- logger.debug('upload status: %s', info.file.status);
- // 正在导入时显示一个提示信息
- if (info.file.status === 'uploading') {
- if (!this.hideLoading) {
- let hide = message.loading('正在导入...');
- this.hideLoading = hide;
- }
- }
- // 导入完成, 无论成功或失败, 必须给出提示, 并且要用户手动关闭
- else if (info.file.status === 'error') {
- this.hideLoading();
- this.hideLoading = undefined;
- notification.error({
- message: '导入失败',
- description: '文件上传失败, 请联系管理员',
- duration: 0,
- });
- }
- // done的情况下还要判断返回值
- else if (info.file.status === 'done') {
- this.hideLoading();
- this.hideLoading = undefined;
- logger.debug('upload result %o', info.file.response);
- if (!info.file.response.success) {
- notification.error({
- message: '导入失败',
- description: `请联系管理员, 错误信息: ${info.file.response.message}`,
- duration: 0,
- });
- } else {
- notification.success({
- message: '导入成功',
- description: info.file.response.data,
- duration: 0,
- });
- }
- }
- }
-
- /**
- * 处理数据导出
- * 本质上也是提交表单, 跟handleSubmit有点类似
- * 但不用再提交给上层组件处理了, 因为不需要改变表格组件的状态
- */
- handleExport = (e) => {
- e.preventDefault();
-
- const oldObj = this.props.form.getFieldsValue();
- const newObj = this.filterQueryObj(oldObj);
-
- // 导出前必须选定了一些查询条件, 不允许导出全表
- // 防止误操作
- if (Object.keys(newObj).length === 0) {
- message.warning('导出时查询条件不能为空', 4.5);
- return;
- }
-
- // ajax是不能处理下载请求的, 必须交给浏览器自己去处理
- // 坏处是我就不知道用户的下载是否成功了
- const url = `${globalConfig.getAPIPath()}/${this.props.tableName}/export`;
- window.open(`${url}?q=${encodeURIComponent(JSON.stringify(newObj))}`); // 注意url编码
- }
-
- render() {
- const rows = [];
- let cols = [];
-
- // 参见antd的布局, 每行被分为24个格子
- // 普通的字段每个占用8格, between类型的字段每个占用16格
- let spaceLeft = 24;
- this.props.schema.forEach((field)=> {
- // 当前列需要占用几个格子? 普通的都是8, 只有datetime between是16
- let spaceNeed = 8;
- if (field.showType === 'between' && field.dataType === 'datetime') {
- spaceNeed = 16;
- }
-
- // 如果当前行空间不足, 就换行
- if (spaceLeft < spaceNeed) {
- rows.push({cols}
);
- cols = []; // 不知array有没有clear之类的方法
- spaceLeft = 24; // 剩余空间重置
- }
-
- // 开始push各种FormItem
- switch (field.showType) {
- case 'select':
- cols.push(this.transformSelect(field));
- break;
- case 'radio':
- cols.push(this.transformRadio(field));
- break;
- case 'checkbox':
- cols.push(this.transformCheckbox(field));
- break;
- case 'multiSelect':
- cols.push(this.transformMultiSelect(field));
- break;
- case 'between':
- for (const col of this.transformBetween(field)) { // between类型比较特殊, 返回的是一个数组
- cols.push(col)
- }
- break;
- default:
- cols.push(this.transformNormal(field));
- }
-
- spaceLeft -= spaceNeed;
- });
-
- // 别忘了最后一行
- if (cols.length > 0) {
- rows.push({cols}
);
- }
-
- // 上传相关配置
- const uploadProps = {
- name: 'file',
- action: `${globalConfig.getAPIPath()}/${this.props.tableName}/import`,
- showUploadList: false,
- onChange: this.handleImport,
- };
-
- // 表单的前面是一堆输入框, 最后一行是按钮
- return (
-
- );
- }
-
-}
-
-InnerForm = Form.create()(InnerForm); // antd中的表单组件还要这么包装一层
-
-export default InnerForm;
diff --git a/src/components/DBTable/InnerPagination.js b/src/components/DBTable/InnerPagination.js
deleted file mode 100644
index da016c4..0000000
--- a/src/components/DBTable/InnerPagination.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import {Pagination, Select} from 'antd';
-
-/**
- * 内部分页器组件
- */
-class InnerPagination extends React.Component {
-
- render() {
- // 有些状态要传到父组件中去处理
- return (
-
-
`每页${this.props.pageSize}条, 共 ${total} 条`}
- pageSize={this.props.pageSize} defaultCurrent={1}
- current={this.props.currentPage}
- onChange={this.props.parentHandlePageChange}
- />
-
- );
- }
-
-}
-
-export default InnerPagination;
diff --git a/src/components/DBTable/InnerTable.js b/src/components/DBTable/InnerTable.js
deleted file mode 100644
index ee88c02..0000000
--- a/src/components/DBTable/InnerTable.js
+++ /dev/null
@@ -1,425 +0,0 @@
-import React from 'react';
-import {
- Form,
- Input,
- Button,
- DatePicker,
- Select,
- Table,
- Icon,
- Radio,
- InputNumber,
- Checkbox,
- Modal,
- message,
- notification,
- Affix
-} from 'antd';
-import globalConfig from 'config.js';
-import Logger from '../../utils/Logger';
-import ajax from '../../utils/ajax';
-
-const FormItem = Form.Item;
-const ButtonGroup = Button.Group;
-
-const logger = Logger.getLogger('InnerTable');
-
-/**
- * 内部表格组件
- */
-class InnerTable extends React.Component {
-
- // 很多时候都要在antd的组件上再包一层
- state = {
- modalVisible: false, // modal是否可见
- modalTitle: '新增', // modal标题
- modalInsert: true, // 当前modal是用来insert还是update
-
- selectedRowKeys: [], // 当前有哪些行被选中, 这里只保存key
- selectedRows: [], // 当前有哪些行被选中, 保存完整数据
- };
-
- /**
- * InnerTable组件的重render有两种可能:
- * 1. 上层组件调用的render方法, 这个时候会触发componentWillReceiveProps方法
- * 2. 自身状态变化引起的重新render
- * 注意区分
- *
- * 对于第一种情况, 要将组件的状态还原到初始状态
- *
- * @param nextProps
- */
- componentWillReceiveProps = (nextProps) => {
- logger.debug('receive new props and try to render, nextProps=%o', nextProps);
- // 其实传入的props和当前的props可能是一样的, 这个方法不会判断修改才触发
- // 要自己判断props是否有变化
-
- // 蛋疼的是, 要区分是上层组件引起的这个方法调用还是InnerTable组件本身引起的
- // 本来自身的变化是不应该触发的, 但不知antd的form组件做了什么, 每次给表单设置值的时候就会触发, 我讨厌黑盒...
- // 利用了一个特性: 如果是上层触发的, tableLoading必定是true
- if (nextProps.tableLoading === true) {
- // 所有状态都要手动还原到初始值
- // 这个方法里setState不会触发render
- this.setState({
- modalVisible: false,
- modalTitle: '新增',
- modalInsert: true,
-
- selectedRowKeys: [],
- selectedRows: [],
- });
- }
- }
-
- /**
- * 点击新增按钮, 弹出一个内嵌表单的modal
- *
- * @param e
- */
- onClickInsert = (e) => {
- e.preventDefault();
- this.props.form.resetFields();
- this.setState({modalVisible: true, modalTitle: '新增', modalInsert: true});
- }
-
- /**
- * 点击更新按钮, 弹出一个内嵌表单的modal
- * 注意区分单条更新和批量更新
- *
- * @param e
- */
- onClickUpdate = (e) => {
- e.preventDefault();
- this.props.form.resetFields();
- const multiSelected = this.state.selectedRowKeys.length > 1; // 是否选择了多项
- // 如果只选择了一项, 就把原来的值填到表单里
- // 否则就只把要更新的主键填到表单里
- if (!multiSelected) {
- logger.debug('update single record, and fill original values');
- this.props.form.setFieldsValue(this.state.selectedRows.pop()); // FIXME: 理论上来说不应该这样去修改state中的值
- } else {
- const tmpObj = {};
- tmpObj[this.primaryKey] = this.state.selectedRowKeys.join(', ');
- logger.debug('update multiple records, keys = %s', tmpObj[this.primaryKey]);
- this.props.form.setFieldsValue(tmpObj);
- }
-
- if (multiSelected) {
- this.setState({modalVisible: true, modalTitle: '批量更新', modalInsert: false});
- } else {
- this.setState({modalVisible: true, modalTitle: '更新', modalInsert: false});
- }
- }
-
- /**
- * 点击删除按钮, 弹出一个确认对话框
- * 注意区分单条删除和批量删除
- *
- * @param e
- */
- onClickDelete = (e) => {
- e.preventDefault();
- Modal.confirm({
- title: this.state.selectedRowKeys.length > 1 ? '确认批量删除' : '确认删除',
- content: `当前被选中的行: ${this.state.selectedRowKeys.join(', ')}`,
- // 这里注意要用箭头函数, 否则this不生效
- onOk: () => {
- this.handleDelete();
- },
- });
- }
-
- /**
- * 隐藏modal
- */
- hideModal = () => {
- this.setState({modalVisible: false});
- }
-
- /**
- * 点击modal中确认按钮的回调
- */
- handleModalOk = () => {
- // 将表单中的undefined去掉
- // 表单传过来的主键是逗号分隔的字符串, 这里转换成数组
- const newObj = {};
- const primaryKeyArray = [];
- const oldObj = this.props.form.getFieldsValue();
- for (const key in oldObj) {
- if (!oldObj[key])
- continue;
-
- if (key === this.primaryKey && typeof oldObj[key] === 'string') {
- for (const str of oldObj[key].split(', ')) {
- // 按schema中的约定, 主键只能是int/varchar
- if (this.primaryKeyType === 'int') {
- primaryKeyArray.push(parseInt(str));
- } else {
- primaryKeyArray.push(str);
- }
- }
- } else {
- newObj[key] = oldObj[key];
- }
- }
- if (this.primaryKey && primaryKeyArray.length > 0) {
- newObj[this.primaryKey] = primaryKeyArray;
- }
- this.hideModal();
- logger.debug('click modal OK and the form obj = %o', newObj);
-
- if (this.state.modalInsert) {
- this.handleInsert(newObj);
- } else {
- this.handleUpdate(newObj);
- }
- }
-
-
- /*下面开始才是真正的数据库操作*/
-
-
- /**
- * 真正去处理新增数据
- */
- handleInsert = (obj) => {
- const url = `${globalConfig.getAPIPath()}/${this.props.tableName}/insert`;
- const hide = message.loading('正在新增...', 0);
- logger.debug('handleInsert: url = %s, obj = %o', url, obj);
-
- ajax.post(url).send(obj).end((err, res) => {
- hide();
- logger.debug('handleInsert: return error = %o, res = %o', err, res);
- // err就是一个字符串
- // res是一个Response对象, 其中的body字段才是服务端真正返回的数据
- if (err || !res.body.success) {
- notification.error({
- message: '新增失败',
- description: err ? '请求insert接口出错, 请联系管理员' : `请联系管理员, 错误信息: ${res.body.message}`,
- duration: 0,
- });
- } else {
- notification.success({
- message: '新增成功',
- description: this.primaryKey ? `新增数据行 主键=${res.body.data[this.primaryKey]}` : '',
- duration: 0,
- });
- }
- });
- }
-
- /**
- * 真正去更新数据
- */
- handleUpdate = (obj) => {
- const keys = obj[this.primaryKey];
- const url = `${globalConfig.getAPIPath()}/${this.props.tableName}/update?keys=${keys instanceof Array ? keys.join(',') : keys}`;
- const hide = message.loading('正在更新...', 0);
- obj[this.primaryKey] = undefined;
-
- logger.debug('handleUpdate: url = %s, obj = %o', url, obj);
-
- ajax.post(url).send(obj).end((err, res) => {
- hide();
- logger.debug('handleUpdate: return error = %o, res = %o', err, res);
-
- if (err || !res.body.success) {
- notification.error({
- message: '更新失败',
- description: err ? '请求update接口出错, 请联系管理员' : `请联系管理员, 错误信息: ${res.body.message}`,
- duration: 0,
- });
- } else {
- notification.success({
- message: '更新成功',
- description: `更新${res.body.data}条数据`,
- duration: 0,
- });
- // 更新数据后, 注意刷新下整个页面
- this.props.refresh();
- }
- });
- }
-
- /**
- * 真正去删除数据
- */
- handleDelete = () => {
- const url = `${globalConfig.getAPIPath()}/${this.props.tableName}/delete?keys=${this.state.selectedRowKeys.join(',')}`;
- const hide = message.loading('正在删除...', 0);
- logger.debug('handleDelete: url = %s', url);
-
- ajax.post(url).end((err, res) => {
- hide();
- logger.debug('handleDelete: return error = %o, res = %o', err, res);
- if (err || !res.body.success) {
- notification.error({
- message: '删除失败',
- description: err ? '请求delete接口出错, 请联系管理员' : `请联系管理员, 错误信息: ${res.body.message}`,
- duration: 0,
- });
- } else {
- notification.success({
- message: '删除成功',
- description: `删除${res.body.data}条数据`,
- duration: 0,
- });
- // 更新数据后, 注意刷新下整个页面
- this.props.refresh();
- }
- });
- }
-
- /**
- * 辅助函数
- *
- * @param formItem
- * @param field
- * @returns {XML}
- */
- colWrapper = (formItem, field) => {
- //const {getFieldProps, getFieldError, isFieldValidating} = this.props.form;
- return (
-
- {formItem}
-
- );
- }
-
- /**
- * 将schema中的一个字段转换为表单的一项
- *
- * @param field
- */
- transFormField = (field) => {
- const {getFieldProps} = this.props.form;
-
- // 对于主键, 直接返回一个不可编辑的textarea
- if (this.primaryKey === field.key) {
- logger.debug('key %o is primary, transform to text area', field);
- return this.colWrapper((
-
- ), field);
- }
-
- switch (field.dataType) {
- case 'int':
- logger.debug('transform field %o to integer input', field);
- return this.colWrapper((
-
- ), field);
- case 'float':
- logger.debug('transform field %o to float input', field);
- return this.colWrapper((
-
- ), field);
- case 'datetime':
- logger.debug('transform field %o to datetime input', field);
- return this.colWrapper((
-
- ), field);
- default: // 默认就是普通的输入框
- logger.debug('transform field %o to varchar input', field);
- return this.colWrapper((
-
- ), field);
- }
- }
-
- /**
- * 处理表格的选择事件
- *
- * @param selectedRowKeys
- * @param selectedRows
- */
- handleSelectChange = (selectedRowKeys, selectedRows) => {
- this.setState({selectedRowKeys, selectedRows});
- }
-
- render() {
- // 解析schema
- const newCols = [];
- this.props.schema.forEach((field) => {
- const col = {};
- col.key = field.key;
- col.dataIndex = field.key;
- col.title = field.title;
- if (field.render) {
- col.render = field.render;
- }
- newCols.push(col);
- // 当前列是否是主键?
- if (field.primary) {
- this.primaryKey = field.key;
- this.primaryKeyType = field.dataType;
- }
- });
-
- // 对数据也要处理一下
- // 每行数据都必须有个key属性, 如果指定了主键, 就以主键为key
- // 否则直接用个自增数字做key
- const newData = [];
- let i = 0;
- this.props.data.forEach((obj) => {
- const newObj = Object.assign({}, obj);
- if (this.primaryKey) {
- newObj.key = obj[this.primaryKey];
- } else {
- newObj.key = i;
- i++;
- }
- newData.push(newObj);
- });
-
- // 生成表单项
- const formItems = [];
- this.props.schema.forEach((field) => {
- formItems.push(this.transFormField(field));
- });
-
- const rowSelection = {
- selectedRowKeys: this.state.selectedRowKeys,
- onChange: this.handleSelectChange,
- };
-
- const hasSelected = this.state.selectedRowKeys.length > 0; // 是否选择
- const multiSelected = this.state.selectedRowKeys.length > 1; // 是否选择了多项
-
- return (
-
-
-
document.getElementById('main-content-div')}>
-
-
- {/* 注意这里, 如果schema中没有定义主键, 不允许update或delete */}
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-
-}
-
-InnerTable = Form.create()(InnerTable);
-
-export default InnerTable;
diff --git a/src/components/DBTable/index.js b/src/components/DBTable/index.js
deleted file mode 100644
index de77996..0000000
--- a/src/components/DBTable/index.js
+++ /dev/null
@@ -1,276 +0,0 @@
-import React from 'react';
-import {message, notification} from 'antd';
-import Error from '../Error';
-import InnerForm from './InnerForm.js';
-import InnerTable from './InnerTable.js';
-import InnerPagination from './InnerPagination.js';
-import './index.less';
-import globalConfig from 'config.js';
-import ajax from '../../utils/ajax';
-import Logger from '../../utils/Logger';
-
-const logger = Logger.getLogger('DBTable');
-
-/**
- * 操作数据库中的一张表的组件, 又可以分为3个组件: 表单+表格+分页器
- */
-class DBTable extends React.Component {
-
- // 代替componentWillMount
- constructor(props) {
- super(props);
- // 组件初始化时尝试获取schema
- this.tryFetchSchema(this.props);
- }
-
- // 父组件要保存子组件的状态...非常蛋疼...
- // 破坏了子组件的"封闭"原则
-
- // 注意: 向父组件传状态, 通过回调函数的形式
- // 从父组件接收状态, 通过props的形式
-
- state = {
- // 表单组件的状态
- queryObj: {}, // 表单中的查询条件
-
- // 表格组件的状态
- data: [], // 表格中显示的数据
- tableLoading: false, // 表格是否是loading状态
-
- // 分页器的状态
- currentPage: 1, // 当前第几页
- pageSize: 50, // pageSize暂时不可修改, 固定50
- total: 0, // 总共有多少条数据
- };
-
- /**
- * 尝试获取某个表的querySchema和dataSchema
- * 无论是从远端获取还是从本地配置读取, 这个方法必须是同步的
- *
- * @param dbName
- * @param tableName
- */
- tryFetchSchema(props) {
- const routes = props.routes;
- // 这个tableName是路由表配置中传过来的
- // 可以用这个方法向组件传值
- const tableName = routes.pop().tableName;
- if (tableName) {
- logger.info('init component DBTable with tableName = %s', tableName);
- } else {
- logger.error('can not find tableName, check your router config');
- this.inited = false; // 是否成功获取schema
- this.errorMsg = '找不到表名, 请检查路由配置'; // 如果没能成功获取schema, 错误信息是什么?
- return;
- }
-
- // 其实很多这种this.xxx变量也可以做成状态, 看情况了
- // 关键是这些变量变化时, 是否要触发重新render?
-
- this.tableName = tableName;
-
- // 尝试加载querySchema
- try {
- this.querySchema = require(`../../schema/${tableName}.querySchema.js`);
- } catch (e) {
- logger.error('load query schema error: %o', e);
- this.inited = false;
- this.errorMsg = `加载${tableName}表的querySchema出错, 请检查配置`;
- return;
- }
-
- // 尝试加载dataSchema
- try {
- this.dataSchema = require(`../../schema/${tableName}.dataSchema.js`);
- } catch (e) {
- logger.error('load data schema error: %o', e);
- this.inited = false;
- this.errorMsg = `加载${tableName}表的dataSchema出错, 请检查配置`;
- return;
- }
-
- // 尝试加载个性化配置, 加载失败也没影响
- try {
- this.tableConfig = require(`../../schema/${tableName}.config.js`);
- } catch (e) {
- logger.warn('can not find config for table %s, use default instead', tableName);
-
- // TODO: 默认配置写在这里
- this.tableConfig = {
- showExport: true, // 显示导出按钮, 默认true
- showImport: true, // 显示导入按钮, 默认true
- }
- }
-
- this.inited = true;
- }
-
- /**
- * 刚进入页面时触发一次查询
- */
- componentDidMount() {
- this.refresh();
- }
-
- // 在react router中切换时, 组件不会重新mount, 只有props会变化
- componentWillReceiveProps = (nextProps) => {
- logger.debug('receive new props and try to render, nextProps = %o', nextProps);
- this.tryFetchSchema(nextProps); // 根据新的props重新获取配置
- // 所有状态都要手动还原到初始值
- // this.setState({
- // queryObj: {},
- // data: [],
- // tableLoading: false,
- // currentPage: 1,
- // pageSize: 50,
- // total: 0,
- // });
-
- // 这种写法和setState有何区别?
- // 似乎setState不是"立即"发生的, 会导致下面refresh时有bug
- this.state.queryObj = {};
- this.state.data = [];
- this.state.tableLoading = false;
- this.state.currentPage = 1;
- this.state.pageSize = 50;
- this.state.total = 0;
-
- // 切换时也要重新查询一次数据
- this.refresh();
- }
-
- /**
- * 切换分页时触发查询
- *
- * @param page
- */
- handlePageChange = (page) => {
- logger.debug('handlePageChange, page = %d', page);
- this.setState({tableLoading: true});
- this.select(this.state.queryObj, page, this.state.pageSize).then((result) => {
- //message.success('查询成功');
- this.setState({
- currentPage: page,
- data: result.data,
- total: result.total,
- tableLoading: false,
- });
- }, this.handleError);
- }
-
- /**
- * 点击提交按钮时触发查询
- *
- * @param queryObj
- */
- handleFormSubmit = (queryObj) => {
- logger.debug('handleFormSubmit, queryObj = %o', queryObj);
- this.setState({tableLoading: true});
- // 这时查询条件已经变了, 要从第一页开始查
- this.select(queryObj, 1, this.state.pageSize).then((result) => {
- //message.success('查询成功');
- this.setState({
- currentPage: 1,
- data: result.data,
- total: result.total,
- tableLoading: false,
- queryObj: queryObj,
- });
- }, this.handleError);
- }
-
- /**
- * 统一处理ajax失败时的回调
- *
- * @param errorMsg
- */
- handleError = (errorMsg) => {
- // 对于错误信息, 要很明显的提示用户, 这个通知框要用户手动关闭
- notification.error({
- message: '出错啦!',
- description: `请联系管理员, 错误信息: ${errorMsg}`,
- duration: 0,
- });
- this.setState({tableLoading: false});
- };
-
- /**
- * 按当前的查询条件重新查询一次
- */
- refresh = () => {
- this.setState({tableLoading: true});
- this.select(this.state.queryObj, this.state.currentPage, this.state.pageSize).then((result) => {
- //message.success('查询成功');
- this.setState({
- data: result.data,
- total: result.total,
- tableLoading: false,
- });
- }, this.handleError);
- }
-
- /**
- * 向服务端发送select请求, 会返回一个promise对象
- *
- * @param queryObj 包含了form中所有的查询条件, 再加上page和pageSize, 后端就能拼成完整的sql
- * @param page
- * @param pageSize
- * @returns {Promise}
- */
- select(queryObj, page, pageSize) {
- const hide = message.loading('正在查询...', 0);
- // superagent请求会直接返回一个promise对象, 但不能直接用, 还是要包装一层
- const tmpObj = Object.assign({}, queryObj); // 创建一个新的临时对象, 其实直接修改queryObj也可以
- tmpObj.page = page;
- tmpObj.pageSize = pageSize;
- const url = `${globalConfig.getAPIPath()}/${this.tableName}/select`; // 拼接要请求的url地址
- logger.debug('select: url = %s, queryObj = %o', url, tmpObj);
-
- // 只是为了试下ES6的Promise特性...其实直接用superagent的API也可以
- const promise = new Promise((resolve, reject) => {
- ajax.post(url).send(tmpObj).end((err, res) => {
- hide();
- // err就是一个字符串
- // res是一个Response对象, 其中的body字段才是服务端真正返回的数据
- if (err || !res.body.success) {
- reject(err ? '请求select接口出错, 请联系管理员' : res.body.message);
- } else {
- resolve(res.body);
- }
- });
- });
-
- return promise;
- }
-
- render() {
- // 如果没能成功加载schema, 显示错误信息
- if (!this.inited) {
- return (
-
- );
- }
-
- // 之前是直接{...this.state}, 感觉会影响效率
- // 父组件传进去的方法名都是parentHandleXXX
-
- // InnerForm和InnerPagination都是无状态的
- // 但InnerTable还是要维护自己的一些状态
-
- return (
-
-
-
-
-
- );
- }
-
-}
-
-export default DBTable;
diff --git a/src/components/DBTable/index.less b/src/components/DBTable/index.less
deleted file mode 100644
index dd923ea..0000000
--- a/src/components/DBTable/index.less
+++ /dev/null
@@ -1,32 +0,0 @@
-.ant-advanced-search-form {
- padding: 16px 8px;
- background: #f8f8f8;
- border: 1px solid #d9d9d9;
- border-radius: 6px;
-}
-
-/* 由于输入标签长度不确定,所以需要微调使之看上去居中 */
-.ant-advanced-search-form > .ant-row {
- position: relative;
- left: -6px;
-}
-
-.ant-advanced-search-form .ant-btn + .ant-btn {
- margin-left: 8px;
-}
-
-/* 我讨厌写css... */
-.db-pagination {
- margin-top: 8px;
- margin-bottom: 8px;
- float: left;
-}
-
-.db-table-button {
- margin-top: 8px;
- margin-bottom: 8px;
-}
-
-.ant-upload {
- margin-left: 8px;
-}
diff --git a/src/components/Login/index.js b/src/components/Login/index.js
deleted file mode 100644
index 3c5cc35..0000000
--- a/src/components/Login/index.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import globalConfig from 'config';
-import ajax from '../../utils/ajax';
-import Logger from '../../utils/Logger';
-import {message} from 'antd';
-import './index.less';
-
-const logger = Logger.getLogger('Login');
-
-/**
- * 定义Login组件
- */
-class Login extends React.Component {
-
- // 这个login组件是直接从网上找的: https://colorlib.com/wp/html5-and-css3-login-forms/
- // 不是react风格...
- // TODO: 以后要把这个login组件改掉
-
- handleSubmit = (e) => {
- e.preventDefault(); // 这个很重要, 防止跳转
- const hide = message.loading('正在验证...', 0);
-
- const username = ReactDOM.findDOMNode(this.refs.user).value;
- const password = ReactDOM.findDOMNode(this.refs.pass).value;
- logger.debug('username = %s, password = %s', username, password);
-
- const button = ReactDOM.findDOMNode(this.refs.button);
- button.setAttribute('disabled', 'true'); // 暂时屏蔽提交按钮, 防止用户重复点击
-
- // 服务端验证
- ajax.post(`${globalConfig.getAPIPath()}${globalConfig.login.validate}`).type('form').send({
- username,
- password,
- }).end((err, res) => {
- hide();
- logger.debug('login validate return: error %o result %o', err, res);
-
- if (ajax.isSuccess(res)) {
- // 如果登录成功, 调用回调函数, 把状态往上层组件传
- if (this.props.loginSuccess)
- this.props.loginSuccess(res.body.data, true);
- else
- message.info(`登录成功, 用户名: ${res.body.data}`);
- } else {
- message.error(`登录失败: ${res.body.message}, 请联系管理员`);
- button.removeAttribute('disabled'); // 登录失败的话, 重新让按钮可用, 让用户重新登录
- }
- });
- }
-
- componentWillMount() {
- logger.debug('mount and add styles');
- document.body.style.background = null;
- }
-
- componentWillUnmount() {
- logger.debug('unmount and clear styles');
- // 组件unmount时设置下样式, 不然其他组件的显示会有问题
- // TODO: 不知道有没有更好的办法
- document.body.style.background = 'white';
- }
-
- render() {
- return (
-
-
-
{globalConfig.name}
-
-
-
- );
- }
-}
-
-export default Login;
diff --git a/src/components/Login/index.less b/src/components/Login/index.less
deleted file mode 100644
index 519fa04..0000000
--- a/src/components/Login/index.less
+++ /dev/null
@@ -1,164 +0,0 @@
-// 都是直接抄来的样式
-// 对我来说就像天书一样好嘛...
-// 这玩意真的是人工手写出来的???
-
-.btn {
- display: inline-block;
- *display: inline;
- *zoom: 1;
- padding: 4px 10px 4px;
- margin-bottom: 0;
- font-size: 13px;
- line-height: 18px;
- color: #333333;
- text-align: center;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
- vertical-align: middle;
- background-color: #f5f5f5;
- background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
- background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: linear-gradient(top, #ffffff, #e6e6e6);
- background-repeat: repeat-x;
- filter: progid:dximagetransform.microsoft.gradient(startColorstr=#ffffff, endColorstr=#e6e6e6, GradientType=0);
- border-color: #e6e6e6 #e6e6e6 #e6e6e6;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- border: 1px solid #e6e6e6;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- cursor: pointer;
- *margin-left: .3em;
-}
-
-.btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] {
- background-color: #e6e6e6;
-}
-
-.btn-large {
- padding: 9px 14px;
- font-size: 15px;
- line-height: normal;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
-}
-
-.btn:hover {
- color: #333333;
- text-decoration: none;
- background-color: #e6e6e6;
- background-position: 0 -15px;
- -webkit-transition: background-position 0.1s linear;
- -moz-transition: background-position 0.1s linear;
- -ms-transition: background-position 0.1s linear;
- -o-transition: background-position 0.1s linear;
- transition: background-position 0.1s linear;
-}
-
-.btn-primary, .btn-primary:hover {
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- color: #ffffff;
-}
-
-.btn-primary.active {
- color: rgba(255, 255, 255, 0.75);
-}
-
-.btn-primary {
- background-color: #4a77d4;
- background-image: -moz-linear-gradient(top, #6eb6de, #4a77d4);
- background-image: -ms-linear-gradient(top, #6eb6de, #4a77d4);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#6eb6de), to(#4a77d4));
- background-image: -webkit-linear-gradient(top, #6eb6de, #4a77d4);
- background-image: -o-linear-gradient(top, #6eb6de, #4a77d4);
- background-image: linear-gradient(top, #6eb6de, #4a77d4);
- background-repeat: repeat-x;
- filter: progid:dximagetransform.microsoft.gradient(startColorstr=#6eb6de, endColorstr=#4a77d4, GradientType=0);
- border: 1px solid #3762bc;
- text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.5);
-}
-
-.btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] {
- filter: none;
- background-color: #4a77d4;
-}
-
-.btn-block {
- width: 100%;
- display: block;
-}
-
-* {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- -o-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-html {
- width: 100%;
- height: 100%;
- overflow: hidden;
-}
-
-body {
- width: 100%;
- height: 100%;
- font-family: 'Open Sans', sans-serif;
- background: #092756;
- background: -moz-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -moz-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -moz-linear-gradient(-45deg, #670d10 0%, #092756 100%);
- background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -webkit-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -webkit-linear-gradient(-45deg, #670d10 0%, #092756 100%);
- background: -o-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -o-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -o-linear-gradient(-45deg, #670d10 0%, #092756 100%);
- background: -ms-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -ms-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -ms-linear-gradient(-45deg, #670d10 0%, #092756 100%);
- background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), linear-gradient(135deg, #670d10 0%, #092756 100%);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3E1D6D', endColorstr='#092756', GradientType=1);
-}
-
-.login {
- position: absolute;
- top: 50%;
- left: 50%;
- margin: -150px 0 0 -150px;
- width: 300px;
- height: 300px;
-}
-
-.login h1 {
- color: #fff;
- text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
- letter-spacing: 1px;
- text-align: center;
- padding-bottom: 15px;
-}
-
-.login-input {
- width: 100%;
- margin-bottom: 10px;
- background: rgba(0, 0, 0, 0.3);
- border: none;
- outline: none;
- padding: 10px;
- font-size: 13px;
- color: #fff;
- text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
- border: 1px solid rgba(0, 0, 0, 0.3);
- border-radius: 4px;
- box-shadow: inset 0 -5px 45px rgba(100, 100, 100, 0.2), 0 1px 1px rgba(255, 255, 255, 0.2);
- -webkit-transition: box-shadow .5s ease;
- -moz-transition: box-shadow .5s ease;
- -o-transition: box-shadow .5s ease;
- -ms-transition: box-shadow .5s ease;
- transition: box-shadow .5s ease;
-}
-
-.login-input:focus {
- box-shadow: inset 0 -5px 45px rgba(100, 100, 100, 0.4), 0 1px 1px rgba(255, 255, 255, 0.2);
-}
diff --git a/src/components/Logo/index.js b/src/components/Logo/index.js
deleted file mode 100644
index 0b98cf7..0000000
--- a/src/components/Logo/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import globalConfig from 'config.js';
-import './index.less';
-
-/**
- * 定义Logo组件
- */
-class Logo extends React.Component {
-
- render() {
- // TODO: 这个logo的样式还是要优化下
- return (
-
-
- {globalConfig.name}
-
-
- );
- }
-
-}
-
-export default Logo;
diff --git a/src/components/Logo/index.less b/src/components/Logo/index.less
deleted file mode 100644
index bedb839..0000000
--- a/src/components/Logo/index.less
+++ /dev/null
@@ -1,6 +0,0 @@
-.logo-text {
- text-align: center;
- font-family: "Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif";
- font-size: 22px;
- color: #2db7f5;
-}
diff --git a/src/components/Sidebar/index.js b/src/components/Sidebar/index.js
index 732775f..0012afa 100644
--- a/src/components/Sidebar/index.js
+++ b/src/components/Sidebar/index.js
@@ -1,8 +1,7 @@
import React from 'react'
import { Link } from 'react-router'
import { Menu, Icon } from 'antd'
-import Logo from '../Logo'
-import Logger from '../../utils/Logger'
+import Logger from '../../utils/logger'
import items from 'menu.js'
const SubMenu = Menu.SubMenu
@@ -47,7 +46,6 @@ const Sider = React.createClass({
},
transFormMenuItem(obj, paths) {
const parentPath = paths.join('/')
- logger.debug('transform %o to path %s', obj, parentPath)
return (