24 | );
25 | }
26 | }
27 |
28 | export default CLContentCard;
29 |
--------------------------------------------------------------------------------
/backend/src/components/CLContentCard.less:
--------------------------------------------------------------------------------
1 | .cardtitle{
2 | font-size: 15px;
3 | }
4 |
5 | .carddivier{
6 | width: 100%;
7 | height: 1px;
8 | background-color: #ECECEC;
9 | margin-top: 10px;
10 | margin-bottom: 10px;
11 | }
12 |
13 | .close{
14 | display: -webkit-flex; /* Safari */
15 | display: flex;
16 | justify-content:flex-end;
17 | }
--------------------------------------------------------------------------------
/backend/src/components/CLContentCardWithClose.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Icon,
4 | Row,
5 | Col
6 | } from 'antd';
7 | import styles from './CLContentCard.less';
8 |
9 | class CLContentCardWithClose extends React.Component {
10 |
11 | static defaultProps = {
12 | minHeight: 737,
13 | };
14 |
15 | constructor() {
16 | super();
17 | };
18 |
19 | render() {
20 | const minHeight = this.props.minHeight;
21 | const mHeight = parseInt(minHeight);
22 | return (
23 |
24 |
25 |
26 |
27 | {this.props.title}
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 | {this.props.children}
39 |
40 |
41 | );
42 | }
43 | }
44 |
45 | export default CLContentCardWithClose;
--------------------------------------------------------------------------------
/backend/src/components/CLForm.less:
--------------------------------------------------------------------------------
1 | .formItemContainer{
2 | margin-top: 10px;
3 | margin-bottom: 10px;
4 | font-size: 14px;
5 | }
6 |
7 | .formItemTitle{
8 | margin-top:5px;
9 | margin-bottom:5px;
10 | }
--------------------------------------------------------------------------------
/backend/src/components/CLSimditor.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Simditor from 'simditor';
4 | require('simditor/styles/simditor.css');
5 |
6 | class CLSimditor extends React.Component{
7 |
8 | constructor(props) {
9 | super(props);
10 | }
11 |
12 | componentWillReceiveProps(nextProps) {
13 | this.setState(nextProps);
14 |
15 | const value = nextProps.value;
16 | if (value) {
17 |
18 | if (this.getValue() !== value){
19 | this.editor.setValue(value);
20 | }
21 | }
22 | };
23 |
24 |
25 |
26 | componentDidMount() {
27 | this.initEditor();
28 | }
29 |
30 | initEditor = ()=>{
31 | var textbox = ReactDOM.findDOMNode(this.refs.textarea);
32 | this.editor = new Simditor({
33 | textarea: textbox,
34 | toolbar:[
35 | 'title','bold','italic','underline','strikethrough','fontScale','color',
36 | 'ol' , 'ul' , 'blockquote','code' , 'table','link','image','hr' , 'indent',
37 | 'outdent','alignment'
38 | ],
39 | upload:{
40 | url:"/api/media/simditorUploadImage",
41 | params: null,
42 | connectionCount: 3,
43 | leaveConfirm: 'Uploading is in progress, are you sure to leave this page?'
44 | }
45 | });
46 | this.editor.on('valuechanged', this._handleValueChange);
47 | };
48 |
49 | getValue = () => {
50 | return this.editor ? this.editor.getValue() : '';
51 | };
52 |
53 | _handleValueChange = (e) => {
54 | var changeFun = this.props.onValueChange;
55 | changeFun(this.getValue());
56 | };
57 |
58 | render(){
59 | return(
60 |
61 |
62 |
63 | );
64 | }
65 | }
66 |
67 | export default CLSimditor;
--------------------------------------------------------------------------------
/backend/src/components/CLTableViewCell.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {
4 | Table,Icon,Input
5 | } from 'antd';
6 |
7 | class CLTableViewCell extends React.Component {
8 | state = {
9 | value: this.props.value,
10 | editable: false,
11 | }
12 | handleChange = (e) => {
13 | const value = e.target.value;
14 | this.setState({ value });
15 | }
16 | check = () => {
17 | this.setState({ editable: false });
18 | if (this.props.onChange) {
19 | this.props.onChange(this.state.value);
20 | }
21 | }
22 | edit = () => {
23 | this.setState({ editable: true });
24 | }
25 | render() {
26 | const { value, editable } = this.state;
27 | return (
28 |
29 | {
30 | editable ?
31 |
32 |
37 |
42 |
43 | :
44 |
45 | {value || ' '}
46 |
51 |
52 | }
53 |
54 | );
55 | }
56 | }
57 |
58 | export default CLTableViewCell;
--------------------------------------------------------------------------------
/backend/src/components/CLTopMenu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './CLTopMenu.less';
3 |
4 | const CLTopMenu = ({isOnFoucs,icon,title,onClickMenu}) => {
5 | return
onClickMenu()} className={isOnFoucs? styles.menuContainerFoucs: styles.menuContainerNormal}>
6 | {title}
7 |
8 | }
9 |
10 | export default CLTopMenu;
11 |
--------------------------------------------------------------------------------
/backend/src/components/CLTopMenu.less:
--------------------------------------------------------------------------------
1 | .menuContainerNormal {
2 | background-color: #fff;
3 | height: 64px;
4 | display: -webkit-flex; /* Safari */
5 | display: flex;
6 | align-items:center;
7 | padding:15px;
8 | border-top: 3px solid #fff;
9 | cursor:pointer;
10 | }
11 |
12 | .menuContainerFoucs {
13 | // background-color: #e2edf5;
14 | height: 64px;
15 | display: -webkit-flex; /* Safari */
16 | display: flex;
17 | align-items:center;
18 | border-top: 3px solid #0083CD;
19 | padding:15px;
20 | cursor:pointer;
21 | }
22 |
23 | .menuTitleNormal{
24 | font-size: 15px;
25 | color:#969aa7;
26 | }
27 |
28 | .menuTitleFoucs{
29 | font-size: 15px;
30 | color:#969aa7;
31 | }
32 |
33 | .topMenuCotainer{
34 | display: -webkit-flex; /* Safari */
35 | display: flex;
36 | flex:1;
37 | align-items:center;
38 | flex-direction: row ;
39 | }
--------------------------------------------------------------------------------
/backend/src/components/CLTopMenus.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './CLTopMenu.less';
3 | import CLTopMenu from 'components/CLTopMenu'
4 |
5 | class CLTopMenus extends React.Component{
6 |
7 | constructor(props){
8 | super(props)
9 | this.state = {
10 | selectMenu:-1,
11 | }
12 | }
13 |
14 | onClickMenu = (id,i) => {
15 | this.setState({selectMenu:i});
16 | this.props.onClickMenu(id);
17 | }
18 |
19 | render() {
20 | return
21 | {this.props.menus.map((item,i) => {
22 | return {this.onClickMenu(item.id,i)}}
26 | title={item.title} />
27 | })}
28 |
29 | }
30 |
31 | }
32 |
33 | export default CLTopMenus;
34 |
35 |
36 |
--------------------------------------------------------------------------------
/backend/src/components/CLTree.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Tree
4 | } from 'antd';
5 | const TreeNode = Tree.TreeNode;
6 | import fetchUtil from '../libs/fetchUtil';
7 |
8 | function setLeaf(treeData, curKey, level) {
9 | const loopLeaf = (data, lev) => {
10 | const l = lev - 1;
11 | data.forEach((item) => {
12 | if ((item.key.length > curKey.length) ? item.key.indexOf(curKey) !== 0 :
13 | curKey.indexOf(item.key) !== 0) {
14 | return;
15 | }
16 | if (item.children) {
17 | loopLeaf(item.children, l);
18 | } else if (l < 1) {
19 | item.isLeaf = true;
20 | }
21 | });
22 | };
23 | loopLeaf(treeData, level + 1);
24 | }
25 |
26 | function getNewTreeData(treeData, curKey, child, level) {
27 | const loop = (data) => {
28 | data.forEach((item) => {
29 | if (item.children) {
30 | loop(item.children);
31 | } else {
32 | if (curKey.indexOf(item.key) === 0) {
33 | item.children = child;
34 | }
35 | }
36 | });
37 | };
38 | loop(treeData);
39 | setLeaf(treeData, curKey, level);
40 | }
41 |
42 | class CLTree extends React.Component {
43 |
44 | static defaultProps = {
45 | rootKey: '-1',
46 | };
47 |
48 | constructor() {
49 | super();
50 | this.state = {
51 | treeData: []
52 | };
53 | };
54 |
55 | componentDidMount() {
56 | var self = this;
57 | const rootKey = self.props.rootKey;
58 | this.setState({
59 | treeData: [{
60 | name: '根目录',
61 | key: rootKey
62 | }],
63 | });
64 | };
65 |
66 | generateTreeNodes = (treeLoadData) => {
67 | var titleKey = this.props.treeNode.title;
68 | var keyKey = this.props.treeNode.key;
69 | const arr = [];
70 | var count = treeLoadData.length;
71 | for (let i = 0; i < count; i++) {
72 | var item = treeLoadData[i];
73 | var name = item[titleKey];
74 | var key = item[keyKey];
75 | arr.push({
76 | name: name,
77 | key: key
78 | });
79 | }
80 | return arr;
81 | };
82 |
83 | onLoadData = (treeNode) => {
84 | return new Promise((resolve) => {
85 | const treeUrl = `${this.props.treeUrl}?pid=${treeNode.props.eventKey}`;
86 | fetchUtil.get(treeUrl)
87 | .then((d) => {
88 | const treeData = [...this.state.treeData];
89 | getNewTreeData(treeData, treeNode.props.eventKey, this.generateTreeNodes(d), 1);
90 | this.setState({
91 | treeData
92 | });
93 | resolve();
94 | }, e => {
95 |
96 | });
97 | });
98 | };
99 |
100 | render() {
101 | const loop = data => data.map((item) => {
102 | if (item.children) {
103 | return
{loop(item.children)};
104 | }
105 | return
;
106 | });
107 | const treeNodes = loop(this.state.treeData);
108 | return (
109 |
110 | {treeNodes}
111 |
112 | );
113 | }
114 | }
115 |
116 | export default CLTree;
--------------------------------------------------------------------------------
/backend/src/components/CLTreeSelect.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {TreeSelect} from 'antd';
3 | import fetchUtil from '../libs/fetchUtil';
4 |
5 | class CLTreeSelect extends React.Component {
6 |
7 | static defaultProps = {
8 | rootKey: '-1',
9 | };
10 |
11 | constructor(props) {
12 | super(props);
13 |
14 | this.state = {
15 | treeData: [],
16 | };
17 |
18 | this.treeNode = props.treeNode;
19 | this.treeUrl = props.treeUrl;
20 | };
21 |
22 | componentWillReceiveProps(nextProps) {
23 | this.setState(nextProps);
24 | };
25 |
26 | componentDidMount() {
27 | const self = this;
28 | const rootKey = "" + self.props.rootKey;
29 | fetchUtil.get(this.treeUrl)
30 | .then((d)=>{
31 | const treeData = self.loopTreeData(d,rootKey);
32 | self.setState({
33 | treeData: [{
34 | label:"根",
35 | value:rootKey,
36 | key:rootKey,
37 | children:treeData
38 | }],
39 | });
40 | },e =>{
41 |
42 | });
43 |
44 | };
45 |
46 | loopTreeData = (data, pid) => {
47 | let result = [], temp;
48 | for (var i = 0; i < data.length; i++) {
49 | const treeData = data[i];
50 | const treeDataName = treeData[this.treeNode.title];
51 | const treeDataKey = ""+treeData[this.treeNode.key];
52 | const treeDataPkey = ""+treeData[this.treeNode.pkey];
53 |
54 | if (treeDataPkey === pid) {
55 | let obj = {label: treeDataName, value: treeDataKey, key: treeDataKey};
56 | temp = this.loopTreeData(data, treeDataKey);
57 | if (temp.length > 0) {
58 | obj.children = temp;
59 | }
60 | result.push(obj);
61 | }
62 | }
63 |
64 | return result;
65 | };
66 |
67 | treeSelect = (info, node) => {
68 | var treeNodeSelect = this.props.onTreeNodeSelect;
69 | var treeSelectFormTitle = this.props.treeSelectFormTitle;
70 | var treeSelectFormValue = this.props.treeSelectFormValue;
71 | treeNodeSelect(info, node, treeSelectFormTitle, treeSelectFormValue);
72 | };
73 |
74 |
75 | render() {
76 | var treeData = this.state.treeData;
77 | let value;
78 | if (this.props.value){
79 | value = ""+this.props.value;
80 | }
81 |
82 | const tProps = {
83 | treeData,
84 | value: value,
85 | placeholder: '请选择',
86 | onSelect: this.treeSelect,
87 | };
88 |
89 | return (
90 |
91 | );
92 | }
93 | }
94 |
95 | export default CLTreeSelect;
96 |
--------------------------------------------------------------------------------
/backend/src/components/CLUploadFiles.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button,Upload,Icon} from 'antd';
3 | import {StringUtil} from '../libs/common';
4 | import {constant} from '../libs/constant';
5 |
6 | class CLUploadFiles extends React.Component{
7 |
8 | constructor(props){
9 | super(props);
10 | this.state = {
11 | fileList: []
12 | };
13 |
14 | var defaultFileList = props.value;
15 |
16 | if (defaultFileList){
17 | const files = this.convertValueToFileList(defaultFileList);
18 | this.state = {fileList:files};
19 | }
20 | }
21 |
22 | componentWillReceiveProps(nextProps) {
23 | this.setState(nextProps);
24 | var defaultFileList = nextProps.value;
25 |
26 | if (defaultFileList){
27 | const files = this.convertValueToFileList(defaultFileList);
28 | this.setState({fileList:files});
29 | }
30 | };
31 |
32 | convertValueToFileList = (defaultFileList) =>{
33 | //获取图片列表 start
34 | var files = [];
35 |
36 | if (defaultFileList != undefined) {
37 | defaultFileList.split(";").map(function (val, index) {
38 | var fileurl = val;
39 | files.push(
40 | {
41 | uid: index,
42 | name: val,
43 | status: 'done',
44 | url: fileurl,
45 | }
46 | )
47 | });
48 | }
49 | //获取图片列表 end
50 |
51 | return files;
52 |
53 | }
54 |
55 | handleChange = (info)=> {
56 |
57 | var onFilesChangeSuccess = this.props.onFilesChangeSuccess;
58 | var formItem = this.props.formItem;
59 |
60 | var self = this;
61 | let fileList = info.fileList;
62 |
63 | var fileurls = "";
64 |
65 | // 2. 读取远程路径并显示链接
66 | fileList = fileList.map((file) => {
67 | if (file.response) {
68 | // 组件会将 file.url 作为链接进行展示
69 | file.url = file.response.url;
70 | }
71 |
72 | if (fileurls=="") {
73 | fileurls += file.url;
74 | }else{
75 | fileurls += ";" + file.url;
76 | }
77 | return file;
78 | });
79 |
80 |
81 | fileurls = StringUtil.replaceAll(fileurls,constant.urlPrex,"");
82 |
83 | onFilesChangeSuccess(formItem,fileurls);
84 |
85 | // 3. 按照服务器返回信息筛选成功上传的文件
86 | fileList = fileList.filter((file) => {
87 | if (file.response) {
88 | return file.response.status === 'success';
89 | }
90 | return true;
91 | });
92 | this.setState({ fileList });
93 | };
94 |
95 | render() {
96 | const uploadProps = {
97 | action: '/api/media/uploadFiles',
98 | fileList:this.state.fileList,
99 | onChange: this.handleChange,
100 | multiple: true
101 | };
102 |
103 | return (
104 |
105 |
108 |
109 | );
110 | }
111 | };
112 |
113 | export default CLUploadFiles;
114 |
--------------------------------------------------------------------------------
/backend/src/components/CLUploadImage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Upload,Icon,message} from 'antd';
3 | import {constant} from '../libs/constant';
4 |
5 | class CLUploadImage extends React.Component{
6 |
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | fileList: []
11 | };
12 |
13 | var defaultFileList = props.value;
14 |
15 | if (defaultFileList){
16 | const files = this.convertValueToFileList(defaultFileList);
17 | this.state = {fileList:files};
18 | }
19 | };
20 |
21 | componentWillReceiveProps(nextProps) {
22 | this.setState(nextProps);
23 |
24 | var defaultFileList = nextProps.value;
25 |
26 | if (defaultFileList){
27 | const files = this.convertValueToFileList(defaultFileList);
28 | this.setState({fileList:files});
29 | }
30 | };
31 |
32 | convertValueToFileList = (defaultFileList) =>{
33 | //获取图片列表 start
34 | var files = [];
35 |
36 | if (defaultFileList != undefined) {
37 | defaultFileList.split(";").map(function (val, index) {
38 | var fileurl = val;
39 | console.log("图片地址"+fileurl);
40 | files.push(
41 | {
42 | uid: index,
43 | name: val,
44 | status: 'done',
45 | url: fileurl,
46 | }
47 | )
48 | });
49 | }
50 | //获取图片列表 end
51 |
52 | return files;
53 |
54 | }
55 |
56 | handleChange = (info) => {
57 |
58 | var onUploadSuccess = this.props.onUploadSuccess;
59 | var formItem = this.props.formItem;
60 |
61 | var self = this;
62 | let fileList = info.fileList;
63 | fileList = fileList.slice(-1);
64 |
65 |
66 | if (info.file.status === 'uploading') {
67 | }
68 | if (info.file.status === 'done') {
69 |
70 | fileList = fileList.map((file) => {
71 | if (file.response) {
72 | // 组件会将 file.url 作为链接进行展示
73 | file.url = file.response.url;
74 | onUploadSuccess(formItem,file.url);
75 | }
76 | return file;
77 | });
78 | } else if (info.file.status === 'error') {
79 |
80 | } else if (info.file.status === 'removed'){
81 | onUploadSuccess(formItem,'');
82 | }
83 |
84 | self.setState({ fileList });
85 | };
86 |
87 | render() {
88 | const uploadProps = {
89 | action: '/api/media/upload',
90 | listType: 'picture-card',
91 | fileList:this.state.fileList,
92 | onChange: this.handleChange,
93 | name:'pic'
94 | };
95 |
96 | return (
97 |
98 |
99 | 上传照片
100 |
101 | );
102 | }
103 | };
104 |
105 | export default CLUploadImage;
106 |
--------------------------------------------------------------------------------
/backend/src/components/CLUploadImageToQiniu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Upload,Icon,message} from 'antd';
3 | import {constant} from 'utils/constant';
4 |
5 | import fetchUtil from 'utils/fetchUtil';
6 |
7 | import {Qiniu} from 'utils/qiniuUtil'
8 |
9 | import request from 'superagent-bluebird-promise'
10 | import moment from 'moment';
11 |
12 | class CLUploadImageToQiniu extends React.Component{
13 |
14 | constructor(props) {
15 | super(props);
16 | this.state = {
17 | fileList: []
18 | };
19 |
20 | this.uploadUrl = 'http://upload.qiniu.com'
21 | if (window.location.protocol === 'https:') {
22 | this.uploadUrl = 'https://up.qbox.me/'
23 | }
24 |
25 | var defaultFileList = props.value;
26 |
27 | if (defaultFileList){
28 | const files = this.convertValueToFileList(defaultFileList);
29 | this.state = {fileList:files};
30 | }
31 | };
32 |
33 | componentWillReceiveProps(nextProps) {
34 | this.setState(nextProps);
35 |
36 | var defaultFileList = nextProps.value;
37 |
38 | if (defaultFileList){
39 | const files = this.convertValueToFileList(defaultFileList);
40 | this.setState({fileList:files});
41 | }
42 | };
43 |
44 | convertValueToFileList = (defaultFileList) =>{
45 | //获取图片列表 start
46 | var files = [];
47 |
48 | if (defaultFileList != undefined) {
49 | defaultFileList.split(";").map(function (val, index) {
50 | var fileurl = val;
51 | files.push(
52 | {
53 | uid: index,
54 | name: val,
55 | status: 'done',
56 | url: fileurl,
57 | }
58 | )
59 | });
60 | }
61 | //获取图片列表 end
62 |
63 | return files;
64 |
65 | }
66 |
67 | _customRequest = (options) => {
68 | console.log(options.file);
69 | fetchUtil.get(`/api/zhende/qiniu/token`)
70 | .then((rs) => {
71 | this.uploadFile(options.file,rs.data.token);
72 | }, e => {
73 | });
74 | }
75 |
76 | uploadFile = (file,token) => {
77 | var self = this;
78 |
79 | var onUploadSuccess = this.props.onUploadSuccess;
80 | var formItem = this.props.formItem;
81 |
82 | if (!file || file.size === 0) return null;
83 |
84 | const time = moment()
85 | const timeString = time.format("YYYYMMDDHHmmss");
86 |
87 | var key = "shop/"+timeString+".jpg";
88 |
89 | var r = request
90 | .post(this.uploadUrl)
91 | .field('key', key)
92 | .field('token', token)
93 | .field('x:filename', file.name)
94 | .field('x:size', file.size)
95 | .attach('file', file, file.name)
96 | .set('Accept', 'application/json')
97 | .then(function(res) {
98 | onUploadSuccess(formItem,"https://appimage.1688zdw.com/"+key);
99 | file.url = "https://appimage.1688zdw.com/"+key;
100 | let fileList = [file];
101 | self.setState({ fileList });
102 | }, function(error) {
103 | console.log(error);
104 | });
105 | }
106 |
107 | render() {
108 | const uploadProps = {
109 | action: '/api/media/uploadToQiniu',
110 | listType: 'picture-card',
111 | fileList:this.state.fileList,
112 | customRequest:this._customRequest,
113 | name:'pic'
114 | };
115 |
116 | return (
117 |
118 |
119 | 上传照片
120 |
121 | );
122 | }
123 | };
124 |
125 | export default CLUploadImageToQiniu;
126 |
--------------------------------------------------------------------------------
/backend/src/components/LmmTableViewSearch.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Form, Row, Col, Input, Button, Icon } from 'antd';
3 | const FormItem = Form.Item;
4 |
5 | import styles from './LmmTableViewSearch.less'
6 |
7 | class LmmTableViewSearchForm extends React.Component {
8 |
9 | constructor(props){
10 | super(props);
11 | this.searchValues = {} ;
12 | this.state = {
13 | expand: false,
14 | }
15 | }
16 |
17 | handleSearch = (e) => {
18 | e.preventDefault();
19 | this.props.form.validateFields((err, values) => {
20 | console.log('Received values of form: ', values);
21 | console.log(values);
22 | this.props.searchAction(values);
23 | });
24 | }
25 |
26 | handleReset = () => {
27 | this.props.form.resetFields();
28 | }
29 |
30 | toggle = () => {
31 | const { expand } = this.state;
32 | this.setState({ expand: !expand });
33 | }
34 |
35 | // To generate mock Form.Item
36 | getFields() {
37 | let fieldCount = this.props.searchFields.length;
38 | const count = this.state.expand ? fieldCount : 3;
39 | const { getFieldDecorator } = this.props.form;
40 | const children = [];
41 |
42 | const formItemLayout = {
43 | labelCol: { span: 4 },
44 | wrapperCol: { span: 20 },
45 | } ;
46 |
47 | let i = 0;
48 | for (let searchField of this.props.searchFields){
49 | children.push(
50 |
51 |
55 | {getFieldDecorator(`${searchField.attr}`)(
56 |
57 | )}
58 |
59 |
60 | );
61 | i++;
62 | }
63 | return children;
64 | }
65 |
66 | render() {
67 | return (
68 |
86 | );
87 | }
88 | }
89 |
90 | const LmmTableViewSearch = Form.create()(LmmTableViewSearchForm);
91 |
92 | export default LmmTableViewSearch;
93 |
94 |
95 |
--------------------------------------------------------------------------------
/backend/src/components/LmmTableViewSearch.less:
--------------------------------------------------------------------------------
1 | .ant-advanced-search-form {
2 | padding: 24px;
3 | background: #fbfbfb;
4 | border: 1px solid #d9d9d9;
5 | border-radius: 6px;
6 | }
7 |
8 | .ant-advanced-search-form .ant-form-item {
9 | display: flex;
10 | }
11 |
12 | .ant-advanced-search-form .ant-form-item-control-wrapper {
13 | flex: 1;
14 | }
--------------------------------------------------------------------------------
/backend/src/favicon.ico:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/backend/src/img/LOGO.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/LOGO.jpg
--------------------------------------------------------------------------------
/backend/src/img/LOGO.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/LOGO.png
--------------------------------------------------------------------------------
/backend/src/img/account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/account.png
--------------------------------------------------------------------------------
/backend/src/img/activity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/activity.png
--------------------------------------------------------------------------------
/backend/src/img/bg1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/bg1.jpg
--------------------------------------------------------------------------------
/backend/src/img/config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/config.png
--------------------------------------------------------------------------------
/backend/src/img/head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/head.png
--------------------------------------------------------------------------------
/backend/src/img/imgtag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/imgtag.png
--------------------------------------------------------------------------------
/backend/src/img/order.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/order.png
--------------------------------------------------------------------------------
/backend/src/img/rightTo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/rightTo.png
--------------------------------------------------------------------------------
/backend/src/img/sep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/sep.png
--------------------------------------------------------------------------------
/backend/src/img/shop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/shop.png
--------------------------------------------------------------------------------
/backend/src/img/text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/text.png
--------------------------------------------------------------------------------
/backend/src/img/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/backend/src/img/user.png
--------------------------------------------------------------------------------
/backend/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/backend/src/layouts/BaseLayout/ListWithTreeLayout.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/27.
3 | */
4 | import React from 'react';
5 | import {
6 | Row,
7 | Col,
8 | } from 'antd';
9 | import styles from "./ListWithTreeLayout.less";
10 | import CLTree from "../../components/CLTree";
11 |
12 | class ListWithTreeLayout extends React.Component {
13 | render() {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 | {this.props.treeTitle}
21 |
22 | {this.props.treeTitleDes}
23 |
24 |
25 |
27 |
28 |
29 |
30 | {this.props.children}
31 |
32 |
33 |
34 | )
35 | }
36 | }
37 |
38 | export default ListWithTreeLayout;
--------------------------------------------------------------------------------
/backend/src/layouts/BaseLayout/ListWithTreeLayout.less:
--------------------------------------------------------------------------------
1 | .operateDiv{
2 | margin-top: 15px;
3 | margin-bottom: 15px;
4 | }
5 |
6 | .treeLayout {
7 | width: 100%;
8 | background-color: white;
9 | overflow: hidden;
10 | margin-bottom: -10000px;
11 | padding-bottom: 10000px;
12 | border-right: 2px solid #eeeeee;
13 | }
14 |
15 | .treeLayout .treeTitle{
16 | border-bottom: 1px solid #e9e9e9;
17 | font-size:15px;
18 | padding: 24px;
19 | }
20 |
21 | .treeLayout .treeDes{
22 | font-size:12px;
23 | margin-top: 5px;
24 | color: gray;
25 | }
--------------------------------------------------------------------------------
/backend/src/layouts/MainLayout/MainLayout.less:
--------------------------------------------------------------------------------
1 | body{
2 | height:100%;
3 | }
4 |
5 | .aside {
6 | position: relative;
7 | min-height: 100%;
8 | }
9 |
10 | .logo {
11 | width: 150px;
12 | height: 64px;
13 | display: -webkit-flex; /* Safari */
14 | display: flex;
15 | flex-direction: row ;
16 | align-items: center;
17 | //border-radius: 6px;
18 | //margin: 16px 24px 16px 28px;
19 | }
20 |
21 | .logo .img{
22 | width:30px;
23 | height: 30px;
24 | margin-left: 15px;
25 | margin-right: 10px;
26 | }
27 |
28 | .aside .logo .logoItem{
29 | display: -webkit-flex; /* Safari */
30 | display: flex;
31 | align-items:center;
32 | font-weight: bold;
33 | font-size: 20px;
34 | color: white;
35 | cursor: pointer;
36 | }
37 |
38 | .logoText{
39 | font-size: 15px;
40 | color: #000;
41 | }
42 |
43 | .logoText2{
44 | font-size: 12px;
45 | color: #eee;
46 | }
47 |
48 | .sider {
49 | width: 100%;
50 | background: #fff;
51 | border-right:1px solid #eee;
52 | overflow: hidden;
53 | margin-bottom: -10000px;
54 | padding-bottom: 10000px;
55 | }
56 |
57 | .header {
58 | display: -webkit-flex; /* Safari */
59 | display: flex;
60 | background-color: #fff;
61 | flex-direction: row;
62 | justify-content: space-between;
63 | box-shadow: 0 0 10px #deeaf4;
64 | border-bottom: 1px solid #deeaf4;
65 | }
66 |
67 | .headerleft {
68 | display: -webkit-flex; /* Safari */
69 | display: flex;
70 | flex-direction: row;
71 | }
72 |
73 | .aside .headerRight {
74 | height: 64px;
75 | display: -webkit-flex; /* Safari */
76 | display: flex;
77 | justify-content:flex-end;
78 | }
79 |
80 | .aside .headerRight .headItem{
81 | display: -webkit-flex; /* Safari */
82 | display: flex;
83 | align-items:center;
84 | margin-right: 10px;
85 | margin-left: 10px;
86 | border-radius:50%; overflow:hidden;
87 | color: black;
88 | }
89 |
90 | .logoContainer {
91 | height: 64px;
92 | }
93 |
94 |
95 | .aside .headerRight .headItemImg{
96 | width: 30px;
97 | height: 30px;
98 | border-radius:50%; overflow:hidden;
99 | }
100 |
101 | .aside .footer {
102 | height: 64px;
103 | line-height: 64px;
104 | text-align: center;
105 | font-size: 12px;
106 | color: #999;
107 | background: #fff;
108 | border-top: 1px solid #e9e9e9;
109 | width: 100%;
110 | }
111 |
112 | .rootMenuTitle{
113 | font-family:"Times New Roman",Georgia,Serif;
114 | font-size: 14px;
115 | }
--------------------------------------------------------------------------------
/backend/src/libs/common.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jf on 16/1/14.
3 | */
4 | class StringUtil {
5 | static replaceAll(s,s1,s2){
6 | return s.replace(new RegExp(s1,"gm"),s2);
7 | }
8 | }
9 |
10 | export {StringUtil};
11 |
--------------------------------------------------------------------------------
/backend/src/libs/constant.js:
--------------------------------------------------------------------------------
1 | var constant = {};
2 |
3 | constant.urlPrex = "http://localhost";
4 |
5 | export {constant};
--------------------------------------------------------------------------------
/backend/src/libs/fetchUtil.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/20.
3 | */
4 | import fetch from 'isomorphic-fetch';
5 |
6 | const fetchUtil = {};
7 |
8 | fetchUtil.post = async (url,params) => {
9 | try {
10 |
11 | const token = sessionStorage.getItem('token');
12 | let headers = {};
13 | if (token != undefined){
14 | headers = {
15 | "Content-Type": "application/json",
16 | "Accept": "application/json",
17 | "Authorization":"Bearer "+token,
18 | }
19 | }else{
20 | headers = {
21 | "Content-Type": "application/json",
22 | "Accept": "application/json"
23 | }
24 | }
25 |
26 | let response = await fetch(url, {
27 | method: 'POST',
28 | headers: headers,
29 | body: JSON.stringify(params)
30 | });
31 | let data = await response.json();
32 | if (response.status === 200) {
33 | if (data.success){
34 | return data.data;
35 | }else{
36 | throw new Error(data.msg);
37 | }
38 | } else {
39 | throw new Error(response.status);
40 | }
41 | } catch (e) {
42 | throw new Error("网络请求异常");
43 | }
44 | };
45 |
46 | fetchUtil.get = async (url) => {
47 | try {
48 |
49 | const token = sessionStorage.getItem('token');
50 | let headers = {};
51 | if (token != undefined){
52 | headers = {
53 | "Content-Type": "application/json",
54 | "Accept": "application/json",
55 | "Authorization":"Bearer "+token,
56 | }
57 | }else{
58 | headers = {
59 | "Content-Type": "application/json",
60 | "Accept": "application/json"
61 | }
62 | }
63 |
64 | let response = await fetch(url, {
65 | method: 'GET',
66 | headers: headers,
67 | });
68 | let data = await response.json();
69 | if (response.status === 200) {
70 | if (data.success){
71 | return data.data;
72 | }else{
73 | throw new Error(data.msg);
74 | }
75 | } else {
76 | throw new Error(response.status);
77 | }
78 | } catch (e) {
79 | throw new Error("网络请求异常");
80 | }
81 | };
82 |
83 | fetchUtil.requestZhenDe = (apiUrl,params,method) => {
84 | let data = {
85 | url:apiUrl,
86 | params:params
87 | }
88 |
89 | let requestUrl = "";
90 | if (method == "get"){
91 | requestUrl = "/api/zhende/common/get";
92 | }else if (method == "post"){
93 | requestUrl = "/api/zhende/common/post";
94 | }
95 |
96 | return fetchUtil.post(requestUrl,data)
97 | }
98 |
99 | export default fetchUtil;
100 |
--------------------------------------------------------------------------------
/backend/src/libs/react-dom.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ReactDOM v15.1.0
3 | *
4 | * Copyright 2013-present, Facebook, Inc.
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree. An additional grant
9 | * of patent rights can be found in the PATENTS file in the same directory.
10 | *
11 | */
12 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e(require("react"));else if("function"==typeof define&&define.amd)define(["react"],e);else{var f;f="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,f.ReactDOM=e(f.React)}}(function(e){return e.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED});
--------------------------------------------------------------------------------
/backend/src/page/frame/FrameRoleMenu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button, Input, Form, Modal,Tree,Table} from 'antd';
3 | const createForm = Form.create;
4 | const FormItem = Form.Item;
5 | const TreeNode = Tree.TreeNode;
6 |
7 | import {getAllRoleMenu,configRoleMenu} from '../../actions/frameRoleAction'
8 |
9 | class FrameRoleMenu extends React.Component{
10 |
11 | constructor(props) {
12 | super(props);
13 |
14 | this.state = {
15 | defaultKeys:props.defaultKeys,
16 | };
17 | this.chooseRoleId = props.chooseRoleId;
18 | this.selectKeys=`${props.defaultKeys}`;
19 | }
20 |
21 | componentWillReceiveProps(nextProps) {
22 | this.setState(nextProps);
23 | this.chooseRoleId = nextProps.chooseRoleId;
24 | this.selectKeys=`${nextProps.defaultKeys}`;
25 | }
26 |
27 | componentDidMount() {
28 | this.props.dispatch(getAllRoleMenu());
29 | }
30 |
31 | handleOk = ()=> {
32 | this.props.dispatch(configRoleMenu(this.chooseRoleId,this.selectKeys));
33 | };
34 |
35 | handleCancel = ()=> {
36 | this.props.onClose();
37 | };
38 |
39 | rowKey = (record)=> {
40 | return record.menuId;
41 | };
42 |
43 | rowOnChange = (selectedRowKeys, selectedRows)=> {
44 | this.selectKeys = `${selectedRowKeys}`;
45 | this.setState({defaultKeys:selectedRowKeys})
46 | };
47 |
48 |
49 | render() {
50 | const columns = [{
51 | title: '菜单名称',
52 | dataIndex: 'name',
53 | key: 'name',
54 | }];
55 |
56 | var rowSelection = {
57 | selectedRowKeys:this.state.defaultKeys,
58 | onChange:this.rowOnChange,
59 | };
60 |
61 | return (
62 |
63 |
返 回 , ]}>
67 |
70 |
71 |
72 | );
73 | }
74 | }
75 |
76 | export default FrameRoleMenu;
77 |
--------------------------------------------------------------------------------
/backend/src/page/frame/FrameUserRole.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button, Input, Form, Modal,Tree,Table} from 'antd';
3 | const createForm = Form.create;
4 | const FormItem = Form.Item;
5 | const TreeNode = Tree.TreeNode;
6 | import {getAllUserRole,configUserRole} from '../../actions/userAction';
7 |
8 | class FrameUserRole extends React.Component{
9 |
10 | constructor(props) {
11 | super(props);
12 | this.state = {
13 | defaultKeys:props.defaultKeys,
14 | };
15 | this.chooseUserId = props.chooseUserId;
16 | this.selectKeys=`${props.defaultKeys}`;
17 | }
18 |
19 | componentWillReceiveProps(nextProps) {
20 | this.setState(nextProps);
21 | this.chooseUserId = nextProps.chooseUserId;
22 | this.selectKeys=`${nextProps.defaultKeys}`;
23 | }
24 |
25 | componentDidMount() {
26 | this.props.dispatch(getAllUserRole());
27 | }
28 |
29 | handleOk = ()=> {
30 | this.props.dispatch(configUserRole(this.chooseUserId,this.selectKeys));
31 | };
32 |
33 | handleCancel = ()=> {
34 | this.props.onClose();
35 | };
36 |
37 | rowKey = (record)=> {
38 | return record.roleId;
39 | };
40 |
41 | rowOnChange = (selectedRowKeys, selectedRows)=> {
42 | this.selectKeys = `${selectedRowKeys}`;
43 | this.setState({defaultKeys:selectedRowKeys})
44 | };
45 |
46 | render() {
47 | const columns = [{
48 | title: '角色名称',
49 | dataIndex: 'name',
50 | key: 'name',
51 | }];
52 |
53 | var rowSelection = {
54 | selectedRowKeys:this.state.defaultKeys,
55 | onChange:this.rowOnChange,
56 | };
57 |
58 | return (
59 |
60 |
返 回 , ]}>
64 |
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 | export default FrameUserRole;
74 |
--------------------------------------------------------------------------------
/backend/src/page/index/index.less:
--------------------------------------------------------------------------------
1 |
2 | :global {
3 | html, body, #root {
4 | height: 100%;
5 | }
6 | body {
7 | background: #fafafa;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/backend/src/page/index/main.js:
--------------------------------------------------------------------------------
1 | import './index.less';
2 | import ReactDOM from 'react-dom';
3 | import React from 'react';
4 | import Routes from '../../routes/index';
5 |
6 | ReactDOM.render(
, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/backend/src/page/info/InfoAdd.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import CLForm from '../../components/CLForm';
3 | import CLContentCard from '../../components/CLContentCard';
4 | import { message } from 'antd';
5 | import { connect } from 'react-redux'
6 | import {replace} from 'react-router-redux'
7 |
8 | import {infoAdd} from '../../actions/infoAction'
9 |
10 | @connect(state => ({
11 | infoData:state.info.formData,
12 | formedit:state.info.formedit
13 | }))
14 | class InfoAdd extends React.Component{
15 | constructor(props) {
16 | super(props);
17 | this.state = {
18 | edit: false,
19 | formData:{}
20 | }
21 | }
22 |
23 | onSubmitSuccess = (e)=> {
24 | message.info('保存成功');
25 | const {dispatch} = this.props;
26 | dispatch(replace('/info/infoList'));
27 | dispatch(infoAdd());
28 | };
29 |
30 | render(){
31 | const formItems = [
32 | {
33 | type:"TreeSelect",
34 | title:"类别",
35 | arrname:"categoryId",
36 | treeUrl:"/api/infoCategory/listByPid",
37 | treeSelectFormValue:"categoryId",
38 | treeSelectFormTitle:"categoryName",
39 | treeNode:{
40 | title: 'categoryName',
41 | key: 'categoryId',
42 | pkey:'pCategoryId'
43 | },
44 | require:true
45 | },
46 | {
47 | type:"Input",
48 | title:"标题",
49 | arrname:"topic",
50 | require:true
51 | },
52 | {
53 | type:"Input",
54 | title:"城市",
55 | arrname:"city",
56 | require:true
57 | },
58 | {
59 | type:"Input",
60 | title:"跳转地址",
61 | arrname:"url",
62 | require:true
63 | },
64 | {
65 | type:"Input",
66 | title:"描述",
67 | arrname:"infoDes"
68 | },
69 | {
70 | type:"UploadImg",
71 | title:"缩略图",
72 | arrname:"headImage",
73 | require:true
74 | },
75 | {
76 | type:"Editor",
77 | title:"内容",
78 | arrname:"content",
79 | require:true
80 | }
81 | ];
82 |
83 | const formProps = {
84 | edit:this.props.formedit,
85 | formData:this.props.infoData,
86 | formItems:formItems,
87 | onSubmitSuccess:this.onSubmitSuccess,
88 | updateUrl:'/api/info/update',
89 | addUrl:'/api/info/add'
90 | };
91 |
92 | return(
93 |
94 |
95 |
96 | );
97 | }
98 | }
99 |
100 | export default InfoAdd;
--------------------------------------------------------------------------------
/backend/src/page/signIn.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './signIn.less';
3 | import { message ,Spin} from 'antd';
4 | import userLoginAction from '../actions/loginAction';
5 | import { connect } from 'react-redux'
6 |
7 | @connect(
8 | state => ({
9 | loginState: state.login.loginState,
10 | })
11 | )
12 | class SignIn extends React.Component{
13 |
14 | static contextTypes = {
15 | router: React.PropTypes.object.isRequired
16 | };
17 |
18 | handleSubmit = (e) => {
19 | e.preventDefault();
20 |
21 | var username = this.refs.name.value
22 | var password = this.refs.pass.value
23 |
24 | const { dispatch } = this.props
25 | dispatch(userLoginAction(username,password));
26 | };
27 |
28 |
29 | render() {
30 |
31 | let loading = false;
32 | if (this.props.loginState==="no"){
33 | loading=false;
34 | }else if(this.props.loginState==="start"){
35 | loading=true;
36 | }else if(this.props.loginState==="success"){
37 | loading=false;
38 | }else if(this.props.loginState==="fail"){
39 | loading=false;
40 | }
41 |
42 | return
43 |
44 |
45 | 后台管理登录
46 |
51 |
52 |
53 |
54 | }
55 | }
56 |
57 | export default SignIn;
58 |
59 |
--------------------------------------------------------------------------------
/backend/src/page/signIn.less:
--------------------------------------------------------------------------------
1 | .container {
2 | position: relative;
3 | top: 25%;
4 | z-index: 1001;
5 | width: 450px;
6 | margin: auto;
7 | padding: 30px 40px 40px;
8 | border-radius: 10px;
9 | background-color: #fff;
10 | }
11 |
12 | .container h2{
13 | margin: 0 0 25px;
14 | font-size: 25px;
15 | font-weight: 400;
16 | text-align: center;
17 | color: #323a45;
18 | }
19 |
20 | .container button{
21 | width: 100%;
22 | height: 45px;
23 | border: none;
24 | background-color: #323a45;
25 | color: #fff;
26 | font-size: 24px;
27 | border-radius: 24px;
28 | cursor: pointer;
29 | margin-left: auto;
30 | margin-right: auto;
31 | transition: opacity .2s ease;
32 | }
33 |
34 | .LoginContainer{
35 | position: absolute;
36 | width: 100%;
37 | height: 100%;
38 | background-image: url('../img/bg1.jpg');
39 | background-repeat: no-repeat;
40 | background-size:100% 100%;
41 | }
42 |
43 | :-moz-placeholder {
44 | color: #c9c9c9 !important;
45 | font-size: 13px;
46 | }
47 |
48 | ::-webkit-input-placeholder {
49 | color: #ccc;
50 | font-size: 13px;
51 | }
52 |
53 | .input[type=text], input[type=password] {
54 | margin-bottom: 20px;
55 | padding: 0 10px;
56 | width: 100%;
57 | height: 50px;
58 | font-family: 'Lucida Grande', Tahoma, Verdana, sans-serif;
59 | font-size: 14px;
60 | color: #404040;
61 | background: white;
62 | border: 1px solid;
63 | border-color: #c4c4c4 #d1d1d1 #d4d4d4;
64 | border-radius: 2px;
65 | -moz-outline-radius: 3px;
66 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12);
67 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12);
68 | }
69 | .input[type=text]:focus, input[type=password]:focus {
70 | border-color: #7dc9e2;
71 | outline-color: #dceefc;
72 | outline-offset: 0;
73 | }
74 |
75 | .input[type=submit] {
76 | padding: 0 18px;
77 | height: 29px;
78 | font-size: 12px;
79 | font-weight: bold;
80 | color: #527881;
81 | text-shadow: 0 1px #e3f1f1;
82 | background: #cde5ef;
83 | border: 1px solid;
84 | border-color: #b4ccce #b3c0c8 #9eb9c2;
85 | border-radius: 16px;
86 | outline: 0;
87 | -webkit-box-sizing: content-box;
88 | -moz-box-sizing: content-box;
89 | box-sizing: content-box;
90 | background-image: -webkit-linear-gradient(top, #edf5f8, #cde5ef);
91 | background-image: -moz-linear-gradient(top, #edf5f8, #cde5ef);
92 | background-image: -o-linear-gradient(top, #edf5f8, #cde5ef);
93 | background-image: linear-gradient(to bottom, #edf5f8, #cde5ef);
94 | -webkit-box-shadow: inset 0 1px white, 0 1px 2px rgba(0, 0, 0, 0.15);
95 | box-shadow: inset 0 1px white, 0 1px 2px rgba(0, 0, 0, 0.15);
96 | }
97 | .input[type=submit]:active {
98 | background: #cde5ef;
99 | border-color: #9eb9c2 #b3c0c8 #b4ccce;
100 | -webkit-box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.2);
101 | box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.2);
102 | }
103 |
104 | .lt-ie9 .input[type=text], .lt-ie9 input[type=password] {
105 | line-height: 34px;
106 | }
107 |
--------------------------------------------------------------------------------
/backend/src/page/style/pageStyle.less:
--------------------------------------------------------------------------------
1 | .operateDiv{
2 | margin-top: 15px;
3 | margin-bottom: 15px;
4 | }
5 |
6 | .treeLayout {
7 | width: 100%;
8 | background-color: white;
9 | overflow: hidden;
10 | margin-bottom: -10000px;
11 | padding-bottom: 10000px;
12 | border-right: 2px solid #eeeeee;
13 | }
14 |
15 | .treeLayout .treeTitle{
16 | border-bottom: 1px solid #e9e9e9;
17 | font-size:15px;
18 | padding: 24px;
19 | }
20 |
21 | .treeLayout .treeDes{
22 | font-size:12px;
23 | margin-top: 5px;
24 | color: gray;
25 | }
--------------------------------------------------------------------------------
/backend/src/reducers/common/formReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/20.
3 | */
4 | import {
5 | FORM_ADD,FORM_HIDE,FORM_EDIT
6 | } from '../../actions/common/commonActionType'
7 |
8 | const initState = {
9 | visible:false,
10 | formdata:{},
11 | formedit:false,
12 | }
13 |
14 | export default (state = initState, action) => {
15 | switch (action.type) {
16 | case FORM_ADD:
17 | return action.payload;
18 | case FORM_EDIT:
19 | return action.payload;
20 | case FORM_HIDE:
21 | return action.payload;
22 | default:
23 | return state
24 | }
25 | };
--------------------------------------------------------------------------------
/backend/src/reducers/common/tableReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/20.
3 | */
4 | import {
5 | TABLE_LOADING,TABLE_NORMAL,TABLE_DATASOURCE
6 | } from '../../actions/common/commonActionType'
7 |
8 | const initState = {
9 | payload:{
10 | loading:false,
11 | dataSource:[],
12 | total:0,
13 | }
14 | }
15 |
16 | export default (state = initState, action) => {
17 | switch (action.type) {
18 | case TABLE_LOADING:
19 | return Object.assign({},state,action.payload);
20 | case TABLE_NORMAL:
21 | return Object.assign({},state,action.payload);
22 | case TABLE_DATASOURCE:
23 | return Object.assign({},state,action.payload);
24 | default:
25 | return state
26 | }
27 | };
--------------------------------------------------------------------------------
/backend/src/reducers/frameMenuReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/21.
3 | */
4 | import {
5 | MENU_LIST
6 | } from '../actions/actionType'
7 |
8 | const initState = {
9 | menulist:[],
10 | total:0
11 | }
12 |
13 | export default (state=initState , action) =>{
14 | switch (action.type) {
15 | case MENU_LIST:
16 | return Object.assign({},state,action.payload);
17 | default:
18 | return state;
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/backend/src/reducers/frameRoleReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/21.
3 | */
4 | import {
5 | ROLE_LIST,ROLE_MENU_FORM_SHOW,ROLE_MENU_FORM_HIDE,ROLE_MENU_FORM_LOADING,ROLE_MENU_ALL
6 | } from '../actions/actionType'
7 |
8 | const initState = {
9 | rolelist:[],
10 | total:0
11 | }
12 |
13 | export default (state=initState , action) =>{
14 | switch (action.type) {
15 | case ROLE_LIST:
16 | return Object.assign({},state,{
17 | rolelist:action.payload.dataSource,
18 | total:action.payload.total,
19 | });
20 | case ROLE_MENU_FORM_SHOW:
21 | return Object.assign({},state,action.payload);
22 | case ROLE_MENU_FORM_HIDE:
23 | return Object.assign({},state,action.payload);
24 | case ROLE_MENU_FORM_LOADING:
25 | return Object.assign({},state,action.payload);
26 | case ROLE_MENU_ALL:
27 | return Object.assign({},state,action.payload);
28 | default:
29 | return state;
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/backend/src/reducers/infoCReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/27.
3 | */
4 | import {
5 | INFOC_LIST
6 | } from '../actions/actionType'
7 |
8 | const initState = {
9 | formData:{},
10 | infoCList:[],
11 | total:0,
12 | }
13 |
14 | export default (state=initState, action) => {
15 | switch (action.type) {
16 | case INFOC_LIST:
17 | return Object.assign({},state,{
18 | infoCList:action.payload.dataSource,
19 | total:action.payload.total,
20 | });
21 |
22 | default:
23 | return state
24 | }
25 | };
--------------------------------------------------------------------------------
/backend/src/reducers/infoReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/27.
3 | */
4 | import {
5 | INFO_ADD,INFO_EDIT,INFO_LIST
6 | } from '../actions/actionType'
7 |
8 | const initState = {
9 | formData:{},
10 | infoList:[],
11 | total:0,
12 | }
13 |
14 | export default (state=initState, action) => {
15 | switch (action.type) {
16 | case INFO_ADD:
17 | return Object.assign({},state,action.payload);
18 | case INFO_EDIT:
19 | return Object.assign({},state,action.payload);
20 | case INFO_LIST:
21 | return Object.assign({},state,{
22 | infoList:action.payload.dataSource,
23 | total:action.payload.total,
24 | });
25 |
26 | default:
27 | return state
28 | }
29 | };
--------------------------------------------------------------------------------
/backend/src/reducers/loginReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/19.
3 | */
4 | import {
5 | LOGIN_AJAX_START,LOGIN_SUCCESS,LOGIN_FAILURE
6 | } from '../actions/actionType'
7 |
8 | export default (state = {loginState:"no", msg:""}, action) => {
9 | switch (action.type) {
10 | case LOGIN_AJAX_START:
11 | return action.payload;
12 | case LOGIN_SUCCESS:
13 | return action.payload;
14 | case LOGIN_FAILURE:
15 | return action.payload;
16 | default:
17 | return state
18 | }
19 | };
--------------------------------------------------------------------------------
/backend/src/reducers/userReducer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/20.
3 | */
4 | import {
5 | USER_LIST,USER_ROLE_FORM_HIDE,USER_ROLE_FORM_SHOW,USER_ROLE_ALL,USER_ROLE_FORM_LOADING
6 | } from '../actions/actionType'
7 |
8 | const initState = {
9 | userlist:[],
10 | total:0
11 | }
12 |
13 | export default (state=initState, action) => {
14 | switch (action.type) {
15 | case USER_LIST:
16 | return Object.assign({},state,action.payload);
17 | case USER_ROLE_FORM_SHOW:
18 | return Object.assign({},state,action.payload);
19 | case USER_ROLE_FORM_HIDE:
20 | return Object.assign({},state,action.payload);
21 | case USER_ROLE_ALL:
22 | return Object.assign({},state,action.payload);
23 | case USER_ROLE_FORM_LOADING:
24 | return Object.assign({},state,action.payload);
25 | default:
26 | return state
27 | }
28 | };
--------------------------------------------------------------------------------
/backend/src/routes/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { Router, Route,hashHistory} from 'react-router';
3 | import { syncHistoryWithStore } from 'react-router-redux'
4 | import { Provider } from 'react-redux';
5 |
6 | import store from './store';
7 |
8 | import App from '../layouts/MainLayout/MainLayout';
9 | import SignIn from '../page/signIn';
10 |
11 |
12 | import Users from '../page/frame/Users';
13 | import CLFrameMenu from '../page/frame/FrameMenu';
14 | import CLFrameRole from '../page/frame/FrameRole';
15 | import InfoList from '../page/info/InfoList';
16 | import InfoAdd from '../page/info/InfoAdd';
17 | import InfoCategory from '../page/info/InfoCategory';
18 |
19 | function requireAuth(nextState, replace) {
20 | var islogin = sessionStorage.getItem('login');
21 | if(islogin == 'true'){
22 |
23 | }else{
24 | replace('/user/login')
25 | }
26 | }
27 |
28 |
29 | store.subscribe(() =>
30 | console.log(store.getState())
31 | );
32 |
33 | const history = syncHistoryWithStore(hashHistory, store);
34 |
35 | const Routes = () =>
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | ;
55 |
56 | Routes.propTypes = {
57 | history: PropTypes.any,
58 | };
59 |
60 | export default Routes;
61 |
--------------------------------------------------------------------------------
/backend/src/routes/store.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/19.
3 | */
4 |
5 | import {combineReducers ,createStore,applyMiddleware} from 'redux'
6 | import {routerReducer,routerMiddleware } from 'react-router-redux'
7 |
8 | //通用
9 | import table from "../reducers/common/tableReducer";
10 | import form from "../reducers/common/formReducer";
11 |
12 | //框架相关
13 | import login from "../reducers/loginReducer";
14 | import user from "../reducers/userReducer";
15 | import menu from "../reducers/frameMenuReducer";
16 | import role from "../reducers/frameRoleReducer";
17 |
18 | //业务相关
19 | import info from "../reducers/infoReducer";
20 | import infoc from "../reducers/infoCReducer";
21 |
22 | import {hashHistory} from 'react-router';
23 | import thunk from 'redux-thunk'
24 |
25 | const rootReducer = combineReducers({
26 | form,
27 | table,
28 | login,
29 | user,
30 | menu,
31 | role,
32 | info,
33 | infoc,
34 | routing: routerReducer
35 | });
36 |
37 | const routermiddleware = routerMiddleware(hashHistory)
38 |
39 | const middleware = [ thunk,routermiddleware ]
40 |
41 | const store = createStore(
42 | rootReducer,
43 | applyMiddleware(...middleware)
44 | );
45 |
46 | export default store;
--------------------------------------------------------------------------------
/backend/tools/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path'),
4 | utils = require('./utils'),
5 | __basename = path.dirname(__dirname),
6 | __env = process.env.NODE_ENV;
7 |
8 | let defaultPath = "//localhost:9000/";
9 | let cdn = "//localhost:9000/";
10 |
11 | if (__env == "__PROD__") {
12 | defaultPath = "//localhost:9000/page/";
13 | cdn = "//localhost:9000/page/";
14 | }
15 |
16 | /**
17 | * [config basic configuration]
18 | * @type {Object}
19 | */
20 |
21 | var config = {
22 | env: __env,
23 | webpack: {
24 | path: {
25 | src: path.resolve(__basename, "src"),
26 | dev: path.resolve(__basename, "dev"),
27 | pub: path.resolve(__basename, "pub"),
28 | },
29 | defaultPath: defaultPath,
30 | cdn: cdn,
31 | hash: "[hash:6]",
32 | chunkhash: "[chunkhash:6]",
33 | imghash: "",
34 | contenthash: "[contenthash:6]",
35 | },
36 | gulp: {
37 | path: {
38 | src: path.resolve(__basename, "src"),
39 | dev: path.resolve(__basename, "dev"),
40 | pub: path.resolve(__basename, "pub"),
41 | offline: path.resolve(__basename, "offline"),
42 | },
43 | },
44 | server: { // webpack开发环境服务器配置
45 | port: 9000, // port for local server
46 | hostDirectory: "/page/" // http://host/hostDirectory/
47 | },
48 | };
49 |
50 | // 自动扫描html
51 | config.webpack.html = utils.getHtmlFile(config.webpack.path.src);
52 | // 根据约定,自动扫描js entry,约定是src/page/xxx/main.js 或 src/page/xxx/main.jsx
53 | /**
54 | 当前获取结果
55 | {
56 | 'js/index': [path.join(configWebpack.path.src, "/page/index/main.js")],
57 | 'js/spa': [path.join(configWebpack.path.src, "/page/spa/main.js")],
58 | 'js/pindex': [path.join(configWebpack.path.src, "/page/pindex/main.jsx")],
59 | }
60 | */
61 | config.webpack.entry = utils.getJsFile(config.webpack.path.src, 'page', 'main', ['js', 'jsx']);
62 |
63 | // 合图配置
64 | config.gulp.sprites = {
65 | tplpath: path.resolve(__basename, "tools/sprite-template/less.template.handlebars"),
66 | imgPath: '../../css/sprites/',
67 | imgName: 'sprites.png',
68 | cssName: 'sprites.scss',
69 | imgDest: config.gulp.path.src + '/css/sprites/',
70 | cssDest: config.gulp.path.src + '/css/sprites/',
71 | };
72 |
73 | module.exports = config;
74 |
--------------------------------------------------------------------------------
/backend/tools/gulpfile.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var gulp = require("gulp");
3 | var run = require('run-sequence');
4 | var merge = require('merge-stream');
5 | var replace = require('gulp-replace');
6 | var gutil = require('gulp-util');
7 |
8 | // 合图
9 | var spritesmith = require('gulp.spritesmith-multi');
10 | var config = require('./config.js');
11 |
12 | gulp.task('sprites', function (cb) {
13 | var spriteData = gulp.src(config.gulp.path.src + '/img/sprites/**/*.png')
14 | // .on('data', function(files) {
15 | // gutil.log(gutil.colors.green("sprites start: " + files.path));
16 | // })
17 | .pipe(spritesmith({
18 | spritesmith: function(options) {
19 | options.imgPath = config.gulp.sprites.imgPath + options.imgName;
20 |
21 | options.cssName = options.cssName.replace('.css', '.less');
22 | // customized generated css template
23 | options.cssTemplate = config.gulp.sprites.tplpath; //'./sprite-template/less.template.handlebars';
24 |
25 | }
26 | }))
27 | // .on('finish', function() {
28 | // gutil.log(gutil.colors.green("sprites done"));
29 | // });
30 |
31 | // Pipe image stream through image optimizer and onto disk
32 | var imgStream = spriteData.img
33 | // DEV: We must buffer our stream into a Buffer for `imagemin`
34 | .pipe(gulp.dest(config.gulp.sprites.imgDest));
35 |
36 | // Pipe CSS stream through CSS optimizer and onto disk
37 | var cssStream = spriteData.css
38 | .pipe(gulp.dest(config.gulp.sprites.cssDest));
39 |
40 | // Return a merged stream to handle both `end` events
41 | return merge(imgStream, cssStream);
42 | });
43 |
44 | gulp.task('dist', ['sprites'], function(cb) {
45 | cb();
46 | });
47 |
48 | gulp.task('default', function() {
49 | run('dist');
50 | });
51 |
52 | run('default');
--------------------------------------------------------------------------------
/backend/tools/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs'),
4 | path = require('path');
5 |
6 | module.exports = {
7 | /**
8 | * get html files automatically
9 | * @param {String} srcPath [directory contains html files]
10 | * @return {Array} [array of html files path]
11 | */
12 | getHtmlFile: function(srcPath) {
13 | // read html filename from
14 | let srcFiles = fs.readdirSync(srcPath);
15 |
16 | srcFiles = srcFiles.filter((item, index) => {
17 | return !!~item.indexOf('.html');
18 | });
19 |
20 | srcFiles = srcFiles.map((item, index) => {
21 | return item.replace('.html', '');
22 | });
23 |
24 | return srcFiles;
25 | },
26 | /**
27 | * get js files automatically
28 | * @param {String} srcPath [directory contains js files]
29 | * @param {String} jsDirectory [js directory]
30 | * @param {String} fileName [js filename]
31 | * @param {Array} extensions [possiable js extension]
32 | * @return {Object} [Object of js files path]
33 | */
34 | getJsFile: function(srcPath, jsDirectory, fileName, extensions) {
35 | let jsFileArray = {};
36 | //read js filename
37 | let srcFiles = fs.readdirSync(path.join(srcPath, jsDirectory));
38 |
39 | srcFiles = srcFiles.filter((item, index) => {
40 | return item !== 'common';
41 | });
42 |
43 | srcFiles.map((item, index) => {
44 | extensions.map((ext, index) => {
45 | let jsPath = path.join(srcPath, jsDirectory, item, 'main.' + ext);
46 | if (fs.existsSync(jsPath)) {
47 | jsFileArray['js/' + item] = [jsPath];
48 | }
49 | });
50 | });
51 |
52 | // console.log(jsFileArray);
53 | return jsFileArray;
54 | }
55 | };
--------------------------------------------------------------------------------
/backend/tools/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var webpack = require('webpack'),
4 | config = require('./config'),
5 | isProduction = (config.env === '__PROD__'),
6 | gutil = require('gulp-util');
7 |
8 |
9 | if (isProduction) {
10 | var compiler = webpack(require('./webpack.pub'));
11 | compiler.run(function(err, stats) {
12 | if (!err) {
13 | gutil.log('[webpack:pub]', stats.toString({
14 | chunks: false, // Makes the build much quieter
15 | colors: true
16 | }));
17 | }
18 | else {
19 | console.log(err);
20 | }
21 | });
22 | }
23 | else {
24 | require('./webpack.server');
25 | }
--------------------------------------------------------------------------------
/backend/tools/webpack.server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 | var webpack = require('webpack');
4 | var webpackDevMiddleware = require("webpack-dev-middleware");
5 | var webpackHotMiddleware = require("webpack-hot-middleware");
6 | var proxy = require('proxy-middleware');
7 |
8 | var webpackConfig = require("./webpack.dev.js"),
9 | config = require("./config.js");
10 | var port = config.server.port;
11 |
12 | for (var key in webpackConfig.entry) {
13 | webpackConfig.entry[key].unshift('webpack-hot-middleware/client');
14 | }
15 |
16 | var compiler = webpack(webpackConfig);
17 | app.use(webpackDevMiddleware(compiler, {
18 | hot: true,
19 | // historyApiFallback: false,
20 | noInfo: true,
21 | stats: {
22 | colors: true
23 | },
24 | }));
25 | app.use(webpackHotMiddleware(compiler));
26 | // 前端转发
27 | app.use(config.server.hostDirectory, proxy('http://localhost:' + port));
28 | //后台转发
29 | // app.use('/api/', proxy('http://localhost:8080/api'));
30 | app.use('/api/', proxy('http://localhost:7001/api'));
31 |
32 | app.listen(port, function(err) {
33 | if (err) {
34 | console.error(err);
35 | }
36 | else {
37 | console.info("Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port);
38 | }
39 | });
--------------------------------------------------------------------------------
/doc/form表单.md:
--------------------------------------------------------------------------------
1 | ### form表单熟悉
2 |
3 | ```
4 | const formProps = {
5 | visible: this.props.formVisible,
6 | edit: this.props.formedit,
7 | formData: this.props.formdata,
8 | formItems: formItems,
9 | formValueName:"title",//title:使用lable的值作为form表单的值,使用value的值作为form表单的值
10 | onClose: this.formClose,
11 | dateFormatList: ['start', 'end'],//需要格式化的字段名
12 | deleteFormItemList:['createAt'],//需要删除的字段名
13 | updateUrl: '/api/zhende/activity/update',
14 | addUrl: '/api/zhende/activity/add'
15 | };
16 |
17 | ```
18 |
19 | ### formItems 属性
20 |
21 | 树结构
22 |
23 | ```
24 |
25 | {
26 | type: "TreeSelect",
27 | title: "选择区域",
28 | arrname: "area",
29 | treeUrl: "/api/zhende/area/listByPid",
30 | treeSelectFormTitle: "name",//title复值给表单哪个key
31 | treeSelectFormValue:"",//value复值给表单哪个key
32 | formValueName:"title",//希望使用title作为表单的值
33 | rootKey:"101",
34 | treeNode: {
35 | title: 'name',
36 | key: 'name',
37 | pkey: 'pid'
38 | },
39 | require: true
40 | },
41 |
42 | ```
43 |
44 | 文本
45 |
46 | ```
47 | {
48 | type: "Input",
49 | title: "菜单名称",
50 | arrname: "name",
51 | require: true
52 | },
53 |
54 | ```
55 |
56 | 下拉选择
57 |
58 | ```
59 |
60 | {
61 | type: "Select",
62 | title: "活动类别",
63 | arrname: "activityType",
64 | require: true,
65 | selectOptions:[
66 | {name:"新人大礼包",
67 | value:"0",},
68 | {name:"周期性活动礼包",
69 | value:"1",}
70 | ],
71 | },
72 |
73 | ```
74 |
75 | 下拉选择(多选)
76 |
77 | ```
78 |
79 | {
80 | type: "MutiSelect",
81 | title: "活动类别",
82 | arrname: "activityType",
83 | require: true,
84 | selectOptions:[
85 | {name:"新人大礼包",
86 | value:"0",},
87 | {name:"周期性活动礼包",
88 | value:"1",}
89 | ],
90 | },
91 |
92 | ```
93 |
94 | 时间
95 |
96 | ```
97 | {
98 | type: "DatePicker",
99 | title: "活动开始时间",
100 | arrname: "start",
101 | require: true
102 | }
103 |
104 | ```
105 |
106 |
107 | ## 操作
108 |
109 | ```
110 | showForm = () => {
111 | const {
112 | dispatch
113 | } = this.props;
114 | dispatch(formAdd());
115 | };
116 |
117 | deleteHandle = (record) => {
118 | const currentCityName = this.props.currentCityName;
119 | const self = this;
120 | const {
121 | dispatch
122 | } = this.props;
123 | return function() {
124 | confirm({
125 | title: '提示',
126 | content: '确认删除?',
127 | onOk() {
128 | dispatch(deleteActivity(record.id,currentCityName));
129 | },
130 | onCancel() {}
131 | });
132 | };
133 | };
134 |
135 | editHandle = (record, index) => {
136 | const {
137 | dispatch
138 | } = this.props;
139 | return function() {
140 | dispatch(formEdit(record));
141 | };
142 | };
143 |
144 | formClose = (d) => {
145 | const {
146 | dispatch
147 | } = this.props;
148 | dispatch(formHide());
149 | if (d) {
150 | dispatch(getList(1));
151 | }
152 | };
153 |
154 | ```
--------------------------------------------------------------------------------
/doc/table控件.md:
--------------------------------------------------------------------------------
1 | ### 使用curd控件
2 |
3 | ```
4 | import React from 'react';
5 | import LmmTableView from 'components/LmmTableView'
6 | import moment from 'moment'
7 |
8 | class TradeList extends React.Component {
9 |
10 | constructor() {
11 | super();
12 | }
13 |
14 | render() {
15 |
16 | const self = this;
17 |
18 | let columns = [
19 | {
20 | title: '姓名',
21 | dataIndex: 'name',
22 | key: 'name',
23 | minWidth: '100'
24 | },
25 | {
26 | title: '交易号',
27 | dataIndex: 'tradeNo',
28 | key: 'tradeNo',
29 | minWidth: '100'
30 | },
31 | {
32 | title: '交易时间',
33 | key: 'tradedAt',
34 | minWidth: '100',
35 | render: function(text, record, index) {
36 | let timeString = moment(record.tradedAt).format('YYYY-MM-DD HH:mm:ss');
37 | return
38 | {timeString}
39 |
;
40 | }
41 | },
42 | {
43 | title: '状态',
44 | key: 'state',
45 | minWidth: '100',
46 | render: function(text, record, index) {
47 | let divtext = '待支付';
48 | if (record.state == 1){
49 | divtext = '待支付'
50 | }else if (record.state == 2){
51 | divtext = '已支付'
52 | }
53 | return
54 | {divtext}
55 |
;
56 | }
57 | },
58 |
59 | ];
60 |
61 | let searchFields = [{
62 | title:'用户名',
63 | attr:'name',
64 | type:'input'
65 | },{
66 | title:'交易号',
67 | attr:'tradeNo',
68 | type:'input'
69 | }]
70 |
71 | let tableProps = {
72 | title:'交易',
73 | columns:columns,
74 | searchFields:searchFields,
75 | apiList:'/api/b/trade/alltrade',//必须返回rows,count两个参数,get方法
76 | }
77 |
78 | return (
79 |
80 |
81 |
82 | );
83 | }
84 | }
85 |
86 | export default TradeList;
87 |
88 |
89 | ```
--------------------------------------------------------------------------------
/eggserver/README.md:
--------------------------------------------------------------------------------
1 | # LmmEggFrame
2 |
3 | Lmm后台管理
4 |
5 | ## QuickStart
6 |
7 |
8 |
9 | see [egg docs][egg] for more detail.
10 |
11 | ### Development
12 |
13 | ```bash
14 | $ npm i
15 | $ npm run dev
16 | $ open http://localhost:7001/
17 | ```
18 |
19 | ### Deploy
20 |
21 | ```bash
22 | $ npm start
23 | $ npm stop
24 | ```
25 |
26 | ### npm scripts
27 |
28 | - Use `npm run lint` to check code style.
29 | - Use `npm test` to run unit test.
30 | - Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
31 |
32 |
33 | [egg]: https://eggjs.org
--------------------------------------------------------------------------------
/eggserver/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # LmmEggFrame
2 |
3 | Lmm后台管理
4 |
5 | ## 快速入门
6 |
7 |
8 |
9 | 如需进一步了解,参见 [egg 文档][egg]。
10 |
11 | ### 本地开发
12 |
13 | ```bash
14 | $ npm i
15 | $ npm run dev
16 | $ open http://localhost:7001/
17 | ```
18 |
19 | ### 部署
20 |
21 | ```bash
22 | $ npm start
23 | $ npm stop
24 | ```
25 |
26 | ### 单元测试
27 |
28 | - [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。
29 | - 断言库非常推荐使用 [power-assert]。
30 | - 具体参见 [egg 文档 - 单元测试](https://eggjs.org/zh-cn/core/unittest)。
31 |
32 | ### 内置指令
33 |
34 | - 使用 `npm run lint` 来做代码风格检查。
35 | - 使用 `npm test` 来执行单元测试。
36 | - 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod) 。
37 |
38 |
39 | [egg]: https://eggjs.org
40 |
--------------------------------------------------------------------------------
/eggserver/app/controller/menu.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('../core/base_controller');
4 |
5 | class MenuController extends Controller {
6 | async list() {
7 | const {ctx,app} = this;
8 | var q = ctx.query;
9 | var rows = await ctx.service.menu.getMenusPage(q.pmenuId,q.page,q.size);
10 | var count = await ctx.service.menu.getMenusCount(q.pmenuId);
11 |
12 | this.success({"rows":rows,
13 | "count":count})
14 | }
15 |
16 | async listByPid() {
17 | const {ctx,app} = this;
18 | var q = ctx.query;
19 | var rows = await ctx.service.menu.getMenuByPid(q.pid);
20 | this.success(rows);
21 | }
22 |
23 | async allList() {
24 | const {ctx,app} = this;
25 | var q = ctx.query;
26 | var rows = await ctx.service.menu.getAllMenu();
27 | this.success(rows);
28 | }
29 |
30 | async add() {
31 | const {ctx,app} = this;
32 | var menu = ctx.request.body;
33 | var success = await ctx.service.menu.add('fmenu',menu);
34 | this.success({ success : true,});
35 | }
36 |
37 | async delete() {
38 | const {ctx,app} = this;
39 | var q = ctx.query;
40 | var id = q.id;
41 | var success = await ctx.service.menu.delete('fmenu',{menuId:id});
42 | this.success({ success : true,});
43 | }
44 |
45 | async update() {
46 | const {ctx,app} = this;
47 | var menu = ctx.request.body;
48 | var success = await ctx.service.menu.update('fmenu',menu,{menuId:menu.menuId});
49 | this.success({ success : true,});
50 | }
51 |
52 | }
53 |
54 | module.exports = MenuController;
--------------------------------------------------------------------------------
/eggserver/app/controller/role.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | const Controller = require('../core/base_controller');
5 |
6 | class RoleController extends Controller {
7 | async list() {
8 | const {ctx,app} = this;
9 | var q = ctx.query;
10 | var rows = await ctx.service.role.getRolesPage(q.proleId,q.page,q.size);
11 | var count = await ctx.service.role.getRolesCount(q.proleId);
12 |
13 | this.success({"rows":rows,
14 | "count":count})
15 | }
16 |
17 | async listByPid() {
18 | const {ctx,app} = this;
19 | var q = ctx.query;
20 | var rows = await ctx.service.role.getRoleByPid(q.pid);
21 | this.success(rows);
22 | }
23 |
24 | async allList() {
25 | const {ctx,app} = this;
26 | var q = ctx.query;
27 | var rows = await ctx.service.role.getAllRoles();
28 |
29 | this.success(rows);
30 | }
31 |
32 | async add() {
33 | const {ctx,app} = this;
34 | var role = ctx.request.body;
35 | var success = await ctx.service.role.add('frole',role);
36 |
37 | ctx.body = {
38 | success : true,
39 | };
40 |
41 | this.success({ success : true,});
42 | }
43 |
44 | async delete() {
45 | const {ctx,app} = this;
46 | var q = ctx.query;
47 | var id = q.id;
48 | var success = await ctx.service.role.delete('frole',{roleId:id});
49 | this.success({ success : true,});
50 | }
51 |
52 | async update() {
53 | const {ctx,app} = this;
54 | var role = ctx.request.body;
55 | var success = await ctx.service.role.update('frole',role,{roleId:role.roleId});
56 | this.success({ success : true,});
57 | }
58 |
59 | async configRoleMenu() {
60 | const {ctx,app} = this;
61 | var roleMenuFormData = ctx.request.body;
62 | await ctx.service.role.configRoleMenu(roleMenuFormData);
63 | ctx.body = {
64 | success : true,
65 | };
66 | }
67 |
68 | async getRoleMenus() {
69 | const {ctx,app} = this;
70 | var q = ctx.query;
71 | var rows = await ctx.service.role.getRoleMenus(q.roleId);
72 | this.success(rows)
73 | }
74 |
75 | }
76 |
77 | module.exports = RoleController;
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/eggserver/app/controller/upload.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const sendToWormhole = require('stream-wormhole');
3 | const Controller = require('egg').Controller;
4 | const fs = require('fs');
5 | const mkdirp = require('mkdirp');
6 |
7 | class UploaderController extends Controller {
8 | async upload() {
9 | const ctx = this.ctx;
10 | const stream = await ctx.getFileStream();
11 | const name = path.basename(stream.filename);
12 |
13 | let now = new Date();
14 | let today = path.join(now.getFullYear().toString(), (now.getMonth() + 1).toString(), now.getDay().toString(),"/");
15 | let folder = path.join(this.app.config.upload.localFilePrex, today);
16 | // let filename = now.getTime() + '__' + name;
17 | let filename = now.getTime() + '.jpg';
18 |
19 | try {
20 | fs.accessSync(folder, fs.constants.W_OK);
21 | } catch (err) {
22 | mkdirp.sync(folder);
23 | } finally {
24 |
25 | }
26 |
27 | const fileAbsoluteName = folder + filename;
28 |
29 | var fileWriteStream = fs.createWriteStream(fileAbsoluteName);
30 | stream.pipe(fileWriteStream);
31 | fileWriteStream.on('close',function(){
32 | console.log('copy over');
33 | });
34 |
35 | let url = `${this.app.config.upload.remoteFilePrex}` + today + filename;
36 |
37 | ctx.body = {
38 | "status": "success",
39 | "url": url
40 | };
41 |
42 | }
43 | }
44 |
45 | module.exports = UploaderController;
--------------------------------------------------------------------------------
/eggserver/app/controller/user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('../core/base_controller');
4 |
5 | class UserController extends Controller {
6 |
7 | async login() {
8 | const {ctx,app} = this;
9 | const username = ctx.request.body.username;
10 | const password = ctx.request.body.password;
11 |
12 | var loginsuccess = false;
13 | var user = await ctx.service.user.getUserByUserName(username);
14 | var menus = [];
15 | if (user!=undefined) {
16 | if(user.loginPasw == password){
17 | loginsuccess = true;
18 | if (username=='admin') {
19 | menus = await ctx.service.menu.getAllMenu(user.userId);
20 | }else{
21 | menus = await ctx.service.user.getUserMenus(user.userId);
22 | }
23 | } else {
24 | loginsuccess = false;
25 | }
26 | } else {
27 | loginsuccess = false;
28 | }
29 |
30 | let token = undefined;
31 | if (user != undefined){
32 | token = app.jwt.sign({userId:user.userId}, app.config.jwt.secret,{expiresIn:app.config.jwt.expiresIn});
33 | }
34 |
35 | if (loginsuccess){
36 | this.success({
37 | token:token,
38 | name:user.name,
39 | menus:menus
40 | });
41 | }else{
42 | this.error("登录密码错误");
43 | }
44 |
45 |
46 | }
47 |
48 | async list(){
49 | const ctx = this.ctx;
50 | var q = ctx.query;
51 | var rows = await ctx.service.user.getUsersPage(q.page,q.size);
52 | var count = await ctx.service.user.getUsersCount();
53 |
54 | this.success({"rows":rows,
55 | "count":count})
56 | }
57 |
58 | async add(){
59 | const ctx = this.ctx;
60 | var user = ctx.request.body;
61 | await ctx.service.user.add('fuser',user);
62 | this.success({})
63 | }
64 |
65 | async delete(){
66 | const ctx = this.ctx;
67 | var q = ctx.query;
68 | var userId = q.userId;
69 |
70 | await ctx.service.user.delete('fuser',{userId:userId})
71 | this.success({})
72 | }
73 |
74 | async update(){
75 | const ctx = this.ctx;
76 | var user = ctx.request.body;
77 | await ctx.service.user.update('fuser',user,{userId:user.userId});
78 | this.success({})
79 | }
80 |
81 | async configUserRole(){
82 | const ctx = this.ctx;
83 | var userRoleFormData = ctx.request.body;
84 | await ctx.service.user.configUserRole(userRoleFormData);
85 | this.success({})
86 | }
87 |
88 | async getUserRoles(){
89 | const ctx = this.ctx;
90 | var q = ctx.query;
91 | var rows = await ctx.service.user.getUserRoles(q.userId);
92 | this.success(rows);
93 | }
94 |
95 | async getUserMenus(){
96 | const ctx = this.ctx;
97 | var q = ctx.query;
98 | var rows = await ctx.service.user.getUserMenus(q.userId);
99 | this.success(rows);
100 | }
101 |
102 | }
103 |
104 | module.exports = UserController;
--------------------------------------------------------------------------------
/eggserver/app/core/base_controller.js:
--------------------------------------------------------------------------------
1 | const { Controller } = require('egg');
2 | class BaseController extends Controller {
3 | get user() {
4 | return this.ctx.session.user;
5 | }
6 |
7 | success(data) {
8 | this.ctx.body = {
9 | success: true,
10 | data,
11 | msg:"",
12 | };
13 | }
14 |
15 | error(msg) {
16 | this.ctx.body = {
17 | success: false,
18 | data:'',
19 | msg
20 | };
21 | }
22 |
23 | notFound(msg) {
24 | msg = msg || 'not found';
25 | this.ctx.throw(404, msg);
26 | }
27 | }
28 | module.exports = BaseController;
--------------------------------------------------------------------------------
/eggserver/app/core/base_service.js:
--------------------------------------------------------------------------------
1 | const Service = require('egg').Service;
2 | class BaseService extends Service {
3 |
4 | async query(sqlString){
5 | return await this.app.mysql.query(sqlString);
6 | }
7 |
8 | async delete(tableName,params) {
9 | const result = await this.app.mysql.delete(tableName, params);
10 | return result;
11 | }
12 |
13 | async add(tableName,data){
14 | const result = await this.app.mysql.insert(tableName, data);
15 | const insertSuccess = result.affectedRows === 1;
16 | return insertSuccess;
17 | }
18 |
19 | async update(tableName,data,whereParams){
20 | const result = await this.app.mysql.update(tableName,data, {
21 | where:whereParams,
22 | });
23 | const updateSuccess = result.affectedRows === 1;
24 | return updateSuccess;
25 | }
26 |
27 | async updateNormal(tableName,data){
28 | const result = await this.app.mysql.update(tableName,data);
29 | const updateSuccess = result.affectedRows === 1;
30 | return updateSuccess;
31 | }
32 | }
33 |
34 | module.exports = BaseService;
--------------------------------------------------------------------------------
/eggserver/app/graphql/common/resolver.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | Date: require('./scalars/date'), // eslint-disable-line
4 | };
5 |
--------------------------------------------------------------------------------
/eggserver/app/graphql/common/scalars/date.js:
--------------------------------------------------------------------------------
1 | const { GraphQLScalarType } = require('graphql');
2 | const { Kind } = require('graphql/language');
3 |
4 | module.exports = new GraphQLScalarType({
5 | name: 'Date',
6 | description: 'Date custom scalar type',
7 | parseValue(value) {
8 | return new Date(value);
9 | },
10 | serialize(value) {
11 | return value.getTime();
12 | },
13 | parseLiteral(ast) {
14 | if (ast.kind === Kind.INT) {
15 | return parseInt(ast.value, 10);
16 | }
17 | return null;
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/eggserver/app/graphql/common/schema.graphql:
--------------------------------------------------------------------------------
1 | scalar Date
2 |
3 |
--------------------------------------------------------------------------------
/eggserver/app/graphql/menu/connector.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | class MenuConnector {
3 | constructor(ctx) {
4 | this.ctx = ctx;
5 | }
6 | async getMenuList(pmenuId,page,size) {
7 | return await this.ctx.service.menu.getMenusPage(pmenuId,page,size);
8 | }
9 |
10 | async getMenuCount(pmenuId) {
11 | let count = await this.ctx.service.menu.getMenusCount(pmenuId);
12 | return count;
13 | }
14 |
15 | async getAllMenu() {
16 | return await this.ctx.service.menu.getAllMenu();
17 | }
18 |
19 | }
20 |
21 | module.exports = MenuConnector;
--------------------------------------------------------------------------------
/eggserver/app/graphql/menu/resolver.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | Query: {
4 | menu(root,{pmenuId,page,size} ,ctx) {
5 | let menuList = ctx.connector.menu.getMenuList(pmenuId,page,size);
6 | let menuCount = ctx.connector.menu.getMenuCount(pmenuId);
7 |
8 | return {
9 | count:menuCount,
10 | menulist:menuList,
11 | };
12 | },
13 |
14 | allmenu(root,{},ctx){
15 | let menuList = ctx.connector.menu.getAllMenu();
16 | return menuList;
17 | }
18 | },
19 |
20 | Mutation: {
21 | createMenu(root, {
22 | menuInput
23 | }, ctx) {
24 | ctx.service.menu.add('fmenu',{
25 | name:menuInput.name,
26 | icon:menuInput.icon,
27 | pmenuId:menuInput.pmenuId,
28 | orderNum:menuInput.orderNum,
29 | tourl:menuInput.tourl
30 | });
31 | return true;
32 | },
33 |
34 | deleteMenu(root, {
35 | menuId
36 | }, ctx) {
37 | ctx.service.menu.delete('fmenu',{menuId:menuId})
38 | return true;
39 | },
40 |
41 | updateMenu(root, {
42 | menuId,menuInput
43 | }, ctx) {
44 | ctx.service.menu.update('fmenu',menuInput,{menuId:menuId});
45 | return true;
46 | },
47 | },
48 | };
--------------------------------------------------------------------------------
/eggserver/app/graphql/menu/schema.graphql:
--------------------------------------------------------------------------------
1 |
2 | type Menu {
3 | menuId: Int!
4 | name: String!
5 | menuKey: String!
6 | pmenuId: Int!
7 | orderNum:Int!
8 | tourl:String!
9 | tag:String!
10 | icon:String
11 | }
12 |
13 | type MenuList {
14 | count: Int!
15 | menulist: [Menu]!
16 | }
17 |
18 | input MenuInput {
19 | name: String!
20 | menuKey: String
21 | pmenuId: Int!
22 | orderNum:Int!
23 | tourl:String!
24 | tag:String
25 | icon:String
26 | }
27 |
--------------------------------------------------------------------------------
/eggserver/app/graphql/mutation/schema.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | type Mutation {
4 |
5 | # User
6 | createUser (userInput: UserInput!): User
7 | updateUser (userId: Int!, userInput: UserInput!): User
8 | deleteUser (userId: Int!): User
9 |
10 | configUserRole (userId: Int!, userRoles: String!): Boolean
11 |
12 | # Menu
13 | createMenu (menuInput: MenuInput!): Boolean
14 | updateMenu (menuId: Int!, menuInput: MenuInput!): Boolean
15 | deleteMenu (menuId: Int!): Boolean
16 |
17 | # Role
18 | createRole (roleInput: RoleInput!): Boolean
19 | updateRole (roleId: Int!, roleInput: RoleInput!): Boolean
20 | deleteRole (roleId: Int!): Boolean
21 | configRoleMenu (roleId: Int!, roleMenus: String!): Boolean
22 | }
--------------------------------------------------------------------------------
/eggserver/app/graphql/query/schema.graphql:
--------------------------------------------------------------------------------
1 |
2 | type Query {
3 | user(page: Int!,size: Int!): UserList!
4 | userRoles(userId : Int!) : [UserRole]!
5 |
6 | menu(pmenuId:Int,page: Int!,size: Int!): MenuList!
7 | allmenu : [Menu]!
8 |
9 | role(proleId:Int,page: Int!,size: Int!): RoleList!
10 | allrole : [Role]!
11 | roleMenus(roleId: Int!) : [RoleMenu]!
12 | }
--------------------------------------------------------------------------------
/eggserver/app/graphql/role/connector.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | class RoleConnector {
3 | constructor(ctx) {
4 | this.ctx = ctx;
5 | }
6 | async getRoleList(proleId,page,size) {
7 | return await this.ctx.service.role.getRolesPage(proleId,page,size);
8 | }
9 |
10 | async getRoleCount(proleId) {
11 | let count = await this.ctx.service.role.getRolesCount(proleId);
12 | return count;
13 | }
14 |
15 | async getAllRoles() {
16 | return await this.ctx.service.role.getAllRoles();
17 | }
18 |
19 | async getRoleMenus(roleId) {
20 | return await this.ctx.service.role.getRoleMenus(roleId);
21 | }
22 |
23 | }
24 |
25 | module.exports = RoleConnector;
--------------------------------------------------------------------------------
/eggserver/app/graphql/role/resolver.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | Query: {
4 | role(root,{proleId,page,size} ,ctx) {
5 | let roleList = ctx.connector.role.getRoleList(proleId,page,size);
6 | let roleCount = ctx.connector.role.getRoleCount(proleId);
7 |
8 | return {
9 | count:roleCount,
10 | rolelist:roleList,
11 | };
12 | },
13 |
14 | allrole(root,{},ctx){
15 | let roleList = ctx.connector.role.getAllRoles();
16 | return roleList;
17 | },
18 |
19 | roleMenus(root,{roleId} ,ctx) {
20 | let roleMenus = ctx.connector.role.getRoleMenus(roleId);
21 | return roleMenus;
22 | },
23 | },
24 |
25 | Mutation: {
26 | createRole(root, {
27 | roleInput
28 | }, ctx) {
29 | ctx.service.role.add('frole',{
30 | name:roleInput.name,
31 | proleId:roleInput.proleId,
32 | });
33 | return true;
34 | },
35 |
36 | deleteRole(root, {
37 | roleId
38 | }, ctx) {
39 | ctx.service.role.delete('frole',{roleId:roleId})
40 | return true;
41 | },
42 |
43 | updateRole(root, {
44 | roleId,roleInput
45 | }, ctx) {
46 | ctx.service.role.update('frole',roleInput,{roleId:roleId});
47 | return true;
48 | },
49 |
50 | configRoleMenu(root, {
51 | roleId,
52 | roleMenus
53 | }, ctx) {
54 | let data = {
55 | roleId:roleId,
56 | menus:roleMenus
57 | }
58 | ctx.service.role.configRoleMenu(data);
59 | return true;
60 | },
61 | },
62 | };
--------------------------------------------------------------------------------
/eggserver/app/graphql/role/schema.graphql:
--------------------------------------------------------------------------------
1 |
2 | type Role {
3 | roleId: Int!
4 | name: String!
5 | proleId: Int!
6 | }
7 |
8 | type RoleList {
9 | count: Int!
10 | rolelist: [Role]!
11 | }
12 |
13 | type RoleMenu {
14 | menuId:Int!
15 | }
16 |
17 | input RoleInput {
18 | name: String!
19 | proleId: Int!
20 | }
21 |
--------------------------------------------------------------------------------
/eggserver/app/graphql/user/connector.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | class UserConnector {
3 | constructor(ctx) {
4 | this.ctx = ctx;
5 | }
6 | async getUserList(page,size) {
7 | return await this.ctx.service.user.getUsersPage(page,size);
8 | }
9 |
10 | async getUserCount() {
11 | let count = await this.ctx.service.user.getUsersCount();
12 | return count;
13 | }
14 |
15 | async getUserRoles(userId) {
16 | let list = await this.ctx.service.user.getUserRoles(userId);
17 | return list;
18 | }
19 |
20 | }
21 |
22 | module.exports = UserConnector;
--------------------------------------------------------------------------------
/eggserver/app/graphql/user/resolver.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | Query: {
4 | user(root,{page,size} ,ctx) {
5 | let userlist = ctx.connector.user.getUserList(page,size);
6 | let userCount = ctx.connector.user.getUserCount();
7 |
8 | return {
9 | count:userCount,
10 | userlist:userlist,
11 | };
12 | },
13 |
14 | userRoles(root,{userId} ,ctx) {
15 | let userRole = ctx.connector.user.getUserRoles(userId);
16 | return userRole;
17 | },
18 |
19 | },
20 |
21 | Mutation: {
22 | createUser(root, {
23 | userInput
24 | }, ctx) {
25 | ctx.service.user.add('fuser',{
26 | loginName:userInput.loginName,
27 | loginPasw:userInput.loginPasw,
28 | name:userInput.name
29 | });
30 | return {loginName:""};
31 | },
32 |
33 | deleteUser(root, {
34 | userId
35 | }, ctx) {
36 | ctx.service.user.delete('fuser',{userId:userId})
37 | return {loginName:""};
38 | },
39 |
40 | updateUser(root, {
41 | userId,userInput
42 | }, ctx) {
43 | ctx.service.user.update('fuser',userInput,{userId:userId});
44 | return {loginName:""};
45 | },
46 |
47 | configUserRole(root, {
48 | userId,
49 | userRoles
50 | }, ctx) {
51 | let data = {
52 | userId:userId,
53 | roles:userRoles
54 | }
55 | ctx.service.user.configUserRole(data);
56 | return true;
57 | },
58 |
59 | },
60 | };
--------------------------------------------------------------------------------
/eggserver/app/graphql/user/schema.graphql:
--------------------------------------------------------------------------------
1 |
2 | type User {
3 | userId: Int!
4 | loginName: String!
5 | loginPasw: String!
6 | name: String!
7 | }
8 |
9 | type UserList {
10 | count: Int!
11 | userlist: [User]!
12 | }
13 |
14 | type UserRole {
15 | roleId:Int!
16 | }
17 |
18 | input UserInput {
19 | loginName: String!
20 | loginPasw: String!
21 | name: String!
22 | }
23 |
--------------------------------------------------------------------------------
/eggserver/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | require('./router/qiniu')(app);
8 | require('./router/user')(app);
9 | require('./router/menu')(app);
10 | require('./router/role')(app);
11 | require('./router/upload')(app);
12 | };
13 |
--------------------------------------------------------------------------------
/eggserver/app/router/menu.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | // app.router.get('/api/menu/list', app.jwt,app.controller.menu.list);
3 | // app.router.get('/api/menu/listByPid', app.jwt,app.controller.menu.listByPid);
4 | // app.router.get('/api/menu/allList', app.jwt,app.controller.menu.allList);
5 | // app.router.post('/api/menu/add', app.jwt,app.controller.menu.add);
6 | // app.router.get('/api/menu/delete', app.jwt,app.controller.menu.delete);
7 | // app.router.post('/api/menu/update',app.jwt, app.controller.menu.update);
8 |
9 | app.router.get('/api/menu/list',app.controller.menu.list);
10 | app.router.get('/api/menu/listByPid',app.controller.menu.listByPid);
11 | app.router.get('/api/menu/allList',app.controller.menu.allList);
12 | app.router.post('/api/menu/add',app.controller.menu.add);
13 | app.router.get('/api/menu/delete',app.controller.menu.delete);
14 | app.router.post('/api/menu/update', app.controller.menu.update);
15 | };
--------------------------------------------------------------------------------
/eggserver/app/router/qiniu.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | module.exports = app => {
4 | app.router.post('/api/qiniu', app.controller.qiniu.qiniuUploadStream);
5 | };
--------------------------------------------------------------------------------
/eggserver/app/router/role.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | app.router.get('/api/role/list', app.jwt,app.controller.role.list);
3 | app.router.get('/api/role/listByPid', app.jwt,app.controller.role.listByPid);
4 | app.router.get('/api/role/allList', app.jwt,app.controller.role.allList);
5 | app.router.post('/api/role/add', app.jwt,app.controller.role.add);
6 | app.router.get('/api/role/delete', app.jwt,app.controller.role.delete);
7 | app.router.post('/api/role/update',app.jwt, app.controller.role.update);
8 | app.router.post('/api/role/configRoleMenu',app.jwt, app.controller.role.configRoleMenu);
9 | app.router.get('/api/role/getRoleMenus',app.jwt, app.controller.role.getRoleMenus);
10 | };
--------------------------------------------------------------------------------
/eggserver/app/router/upload.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | app.router.post('/api/upload',app.controller.upload.upload);
3 | };
--------------------------------------------------------------------------------
/eggserver/app/router/user.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | app.router.post('/api/auth/login', app.controller.user.login);
3 | app.router.get('/api/user/list', app.jwt,app.controller.user.list);
4 | app.router.post('/api/user/add', app.jwt,app.controller.user.add);
5 | app.router.get('/api/user/delete', app.jwt,app.controller.user.delete);
6 | app.router.post('/api/user/update', app.jwt,app.controller.user.update);
7 | app.router.post('/api/user/configUserRole', app.jwt,app.controller.user.configUserRole);
8 | app.router.get('/api/user/getUserRoles', app.jwt,app.controller.user.getUserRoles);
9 | app.router.get('/api/user/getUserMenus', app.jwt,app.controller.user.getUserMenus);
10 | };
--------------------------------------------------------------------------------
/eggserver/app/service/menu.js:
--------------------------------------------------------------------------------
1 | const Service = require('../core/base_service');
2 |
3 | class MenuService extends Service {
4 | async getMenusPage(pmenuId,page,size){
5 |
6 | let params = {};
7 |
8 | var page = parseInt(page);
9 | var size = parseInt(size);
10 |
11 | var start = (page-1)*size;
12 |
13 | if (pmenuId != undefined && pmenuId != '') {
14 | params.pmenuId = pmenuId;
15 | };
16 |
17 | var rows = await this.app.mysql.select('fmenu', {
18 | where: params,
19 | orders: [['orderNum','desc']],
20 | limit: size,
21 | offset: start,
22 | });
23 |
24 | return rows;
25 | }
26 |
27 | async getMenusCount(pmenuId) {
28 |
29 | let sqlString = `select count(1) as cnt from fmenu where 1=1 `;
30 | if (pmenuId != undefined && pmenuId != '') {
31 | sqlString += ` and pmenuId = ${pmenuId} `;
32 | };
33 |
34 | let rows = await this.app.mysql.query(sqlString);
35 |
36 | let count = 0 ;
37 | if (rows.length > 0){
38 | count = rows[0].cnt;
39 | }
40 |
41 | return count;
42 | }
43 |
44 | async getMenuByPid(pmenuId){
45 | var sqlString = `select * from fmenu where 1=1 `;
46 | if (pmenuId != undefined && pmenuId != '') {
47 | sqlString += ` and pmenuId=${pmenuId} `;
48 | };
49 | let rows = await this.app.mysql.query(sqlString);
50 | return rows;
51 | }
52 |
53 | async getAllMenu(){
54 | var rows = await this.app.mysql.select('fmenu', {
55 | orders: [['orderNum','desc']],
56 | });
57 | return rows;
58 | }
59 |
60 | }
61 |
62 | module.exports = MenuService;
--------------------------------------------------------------------------------
/eggserver/app/service/role.js:
--------------------------------------------------------------------------------
1 | const Service = require('../core/base_service');
2 |
3 | class RoleService extends Service {
4 |
5 | async getRolesPage(proleId,page,size){
6 |
7 | let params = {};
8 |
9 | if (proleId != undefined && proleId != '') {
10 | params.proleId = proleId;
11 | };
12 |
13 | var pageInt = parseInt(page);
14 | var sizeInt = parseInt(size);
15 |
16 | var start = (page-1)*size;
17 |
18 | var rows = await this.app.mysql.select('frole', {
19 | where: params,
20 | limit: size,
21 | offset: start,
22 | });
23 |
24 | return rows;
25 | }
26 |
27 | async getAllRoles() {
28 | var rows = await this.app.mysql.select('frole');
29 | return rows;
30 | }
31 |
32 | async getRolesCount(proleId) {
33 | let sqlString = `select count(1) as cnt from frole where 1=1 `;
34 | if (proleId != undefined && proleId != '') {
35 | sqlString += ` and proleId = ${proleId} `;
36 | };
37 |
38 | let rows = await this.app.mysql.query(sqlString);
39 |
40 | let count = 0 ;
41 | if (rows.length > 0){
42 | count = rows[0].cnt;
43 | }
44 |
45 | return count;
46 | }
47 |
48 | async getRoleByPid (proleId) {
49 | let params = {};
50 | if (proleId != undefined && proleId != '') {
51 | params.proleId = proleId;
52 | }
53 |
54 | let rows = await this.app.mysql.select('frole',
55 | {where:params});
56 | return rows;
57 | }
58 |
59 |
60 | async configRoleMenu(data){
61 | var menus = data.menus ;
62 | await this.query(`delete from froleMenu where roleId = ${data.roleId} `);
63 | if (menus!=undefined && menus != ""){
64 | var menuArray = menus.split(",");
65 | for(var i = 0 ; i< menuArray.length ; i ++){
66 | var menuId = menuArray[i];
67 | if (parseInt(menuId) != -1 ) {
68 | var insertsql = `INSERT INTO froleMenu(menuId, roleId) SELECT ${menuId}, ${data.roleId} FROM DUAL WHERE NOT EXISTS(SELECT * FROM froleMenu WHERE menuId =${menuId} and roleId =${data.roleId} )`;
69 | await this.query(insertsql);
70 | }
71 | }
72 | }
73 | }
74 |
75 | async getRoleMenus (roleId) {
76 | let params = {};
77 | if (roleId != undefined && roleId != '') {
78 | params.roleId = roleId;
79 | };
80 |
81 | const rows = await this.app.mysql.select('froleMenu',{
82 | where:params,
83 | columns: ['menuId'],
84 | })
85 | return rows;
86 | }
87 |
88 | }
89 |
90 | module.exports = RoleService;
--------------------------------------------------------------------------------
/eggserver/app/service/user.js:
--------------------------------------------------------------------------------
1 | const Service = require('../core/base_service');
2 |
3 | class UserService extends Service {
4 |
5 | async checkUser(username,password){
6 |
7 | var loginsuccess = false;
8 |
9 | var user = await this.app.mysql.select('fuser', { // 搜索 post 表
10 | loginName: username, // 返回数据量
11 | });
12 |
13 | // var menus = [];
14 | // if (user!=undefined) {
15 | // if(user.loginPasw == password){
16 | // loginsuccess = true;
17 | // if (username=='admin') {
18 | // menus = await menuService.getAllMenu(user.userId);
19 | // }else{
20 | // menus = await userService.getUserMenus(user.userId);
21 | // }
22 | // } else {
23 | // loginsuccess = false;
24 | // }
25 | // } else {
26 | // loginsuccess = false;
27 | // }
28 |
29 | // var token = jwt.sign(user, tokenConfig.JWT_SECRET,{expiresIn:tokenConfig.JWT_expiresIn});
30 |
31 | return user;
32 | }
33 |
34 | async getUsersPage(page,size) {
35 |
36 | var page = parseInt(page);
37 | var size = parseInt(size);
38 |
39 | var start = (page-1)*size;
40 | var end = page*size;
41 |
42 | const users = await this.app.mysql.select('fuser', { // 搜索 post 表
43 | limit: size, // 返回数据量
44 | offset: start, // 数据偏移量
45 | });
46 |
47 | return users;
48 | }
49 |
50 | async getUserByUserName (username) {
51 | const row = await this.app.mysql.get('fuser',{loginName:username});
52 | return row;
53 | }
54 |
55 | async getUsersCount(){
56 | var sqlString = `select count(1) as cnt from fuser `;
57 |
58 | let countRows = await this.query(sqlString);
59 | let count = 0;
60 | if (countRows != undefined){
61 | count = countRows[0].cnt;
62 | }
63 |
64 | return count;
65 | }
66 |
67 | async configUserRole(data){
68 | var roles = data.roles ;
69 | await this.query(`delete from fuserrole where userId = ${data.userId} `);
70 | if (roles!=undefined && roles != ""){
71 | var roleArray = roles.split(",");
72 | for(var i = 0 ; i< roleArray.length ; i ++){
73 | var roleId = roleArray[i];
74 | if (parseInt(roleId) != -1 ) {
75 | var insertsql = `INSERT INTO fuserrole(userId, roleId) SELECT ${data.userId}, ${roleId} FROM DUAL WHERE NOT EXISTS(SELECT * FROM fuserrole WHERE userId =${data.userId} and roleId =${roleId} )`;
76 | await this.query(insertsql);
77 | }
78 | }
79 | }
80 | }
81 |
82 | async getUserRoles(userId) {
83 |
84 | let params = {};
85 | if (userId != undefined && userId != '') {
86 | params.userId = userId;
87 | }
88 |
89 | const rows = await this.app.mysql.select('fuserrole',{
90 | where:params,
91 | columns:['roleId']
92 | })
93 |
94 | return rows;
95 | }
96 |
97 |
98 | async getUserMenus(userId) {
99 | var sqlString = `select distinct m.* from fmenu m inner join frolemenu rm on m.menuId = rm.menuId where rm.roleId in
100 | (select r.roleId from frole r inner join fuserrole ur on r.roleId = ur.roleId where ur.userId = ${userId}) order by m.orderNum `;
101 |
102 | console.log(sqlString);
103 | var rows = await this.query(sqlString);
104 | return rows;
105 | }
106 |
107 | }
108 |
109 | module.exports = UserService;
110 |
--------------------------------------------------------------------------------
/eggserver/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '8'
4 |
5 | install:
6 | - ps: Install-Product node $env:nodejs_version
7 | - npm i npminstall && node_modules\.bin\npminstall
8 |
9 | test_script:
10 | - node --version
11 | - npm --version
12 | - npm run test
13 |
14 | build: off
15 |
--------------------------------------------------------------------------------
/eggserver/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = exports = {};
5 |
6 | // use for cookie sign key, should change to your own and keep security
7 | config.keys = appInfo.name + '_1520384613004_1138';
8 |
9 | // add your config here
10 | config.middleware = [ 'graphql' ];
11 |
12 | config.upload = {
13 | localFilePrex: '/Users/chenliang/website/',
14 | remoteFilePrex: 'http://localhost:7002/',
15 | qiniuCdn:'http://ybimage.atogether.com/',
16 | }
17 |
18 | config.security = {
19 | csrf: {
20 | enable: false,
21 | },
22 | }
23 |
24 | config.jwt = {
25 | secret: 'frameAntDesignToken',
26 | expiresIn: "30m",
27 | enable: true, // default is false
28 | match: ['/api/menu/*','/graphql'], // �optional
29 | // match: ['/api/menu/*'], // �optional
30 | };
31 |
32 | config.mysql = {
33 | // 单数据库信息配置
34 | client: {
35 | // host
36 | host: '114.80.200.31',
37 | // 端口号
38 | port: '3306',
39 | // 用户名
40 | user: 'root',
41 | // 密码
42 | password: '11111',
43 | // 数据库名
44 | database: 'tyh_qx',
45 | },
46 | // 是否加载到 app 上,默认开启
47 | app: true,
48 | // 是否加载到 agent 上,默认关闭
49 | agent: false,
50 | };
51 |
52 | config.graphql = {
53 | router: '/graphql',
54 | // 是否加载到 app 上,默认开启
55 | app: true,
56 | // 是否加载到 agent 上,默认关闭
57 | agent: false,
58 | // 是否加载开发者工具 graphiql, 默认开启。路由同 router 字段。使用浏览器打开该可见。
59 | graphiql: true,
60 | // graphQL 路由前的拦截器
61 | onPreGraphQL: function* (ctx) {},
62 | // 开发工具 graphiQL 路由前的拦截器,建议用于做权限操作(如只提供开发者使用)
63 | onPreGraphiQL: function* (ctx) {},
64 | };
65 |
66 | return config;
67 | };
--------------------------------------------------------------------------------
/eggserver/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // had enabled by egg
4 | // exports.static = true;
5 |
6 | exports.mysql = {
7 | enable: true,
8 | package: 'egg-mysql',
9 | };
10 |
11 | exports.jwt = {
12 | enable: true,
13 | package: 'egg-jwt',
14 | };
15 |
16 | exports.graphql = {
17 | enable: true,
18 | package: 'egg-graphql',
19 | };
--------------------------------------------------------------------------------
/eggserver/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "LmmEggFrame",
3 | "version": "1.0.0",
4 | "description": "Lmm后台管理",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^2.2.1",
8 | "egg-graphql": "^2.1.0",
9 | "egg-jwt": "^2.2.1",
10 | "egg-mysql": "^3.0.0",
11 | "egg-scripts": "^2.5.0",
12 | "graphql": "^0.13.2",
13 | "mkdirp": "^0.5.1",
14 | "qiniu": "^7.2.1",
15 | "stream-wormhole": "^1.0.3"
16 | },
17 | "devDependencies": {
18 | "autod": "^3.0.1",
19 | "autod-egg": "^1.0.0",
20 | "egg-bin": "^4.3.5",
21 | "egg-ci": "^1.8.0",
22 | "egg-mock": "^3.14.0",
23 | "eslint": "^4.11.0",
24 | "eslint-config-egg": "^6.0.0",
25 | "webstorm-disable-index": "^1.2.0"
26 | },
27 | "engines": {
28 | "node": ">=8.9.0"
29 | },
30 | "scripts": {
31 | "start": "egg-scripts start --daemon --title=egg-server-LmmEggFrame",
32 | "stop": "egg-scripts stop --title=egg-server-LmmEggFrame",
33 | "dev": "egg-bin dev",
34 | "debug": "egg-bin debug",
35 | "test": "npm run lint -- --fix && npm run test-local",
36 | "test-local": "egg-bin test",
37 | "cov": "egg-bin cov",
38 | "lint": "eslint .",
39 | "ci": "npm run lint && npm run cov",
40 | "autod": "autod"
41 | },
42 | "ci": {
43 | "version": "8"
44 | },
45 | "repository": {
46 | "type": "git",
47 | "url": ""
48 | },
49 | "author": "陈靓",
50 | "license": "MIT"
51 | }
52 |
--------------------------------------------------------------------------------
/eggserver/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app, assert } = require('egg-mock/bootstrap');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 |
7 | it('should assert', function* () {
8 | const pkg = require('../../../package.json');
9 | assert(app.config.keys.startsWith(pkg.name));
10 |
11 | // const ctx = app.mockContext({});
12 | // yield ctx.service.xx();
13 | });
14 |
15 | it('should GET /', () => {
16 | return app.httpRequest()
17 | .get('/')
18 | .expect('hi, egg')
19 | .expect(200);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/img/b1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/b1.png
--------------------------------------------------------------------------------
/img/configproxy.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/configproxy.jpeg
--------------------------------------------------------------------------------
/img/database.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/database.png
--------------------------------------------------------------------------------
/img/login.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/login.jpeg
--------------------------------------------------------------------------------
/img/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/login.png
--------------------------------------------------------------------------------
/img/main.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/main.jpeg
--------------------------------------------------------------------------------
/img/page1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/page1.jpeg
--------------------------------------------------------------------------------
/img/page2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/page2.jpeg
--------------------------------------------------------------------------------
/img/startproject.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/startproject.jpeg
--------------------------------------------------------------------------------
/img/tiaoshi.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/tiaoshi.jpeg
--------------------------------------------------------------------------------
/img/webpackserverconfig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenliang2016/CLReactAntDesign/445318d8ce9e38d4c150351628ca2dedc677384c/img/webpackserverconfig.png
--------------------------------------------------------------------------------
/koaFrame.md:
--------------------------------------------------------------------------------
1 | # CLReactAntDesign介绍
2 | * CLReactAntDesign是基于[AntDesign2.0+](https://ant.design/)开发的后端页面例子,
3 | * 整合react,react-router,react-redux,react-router-redux。进行页面状态控制
4 | * 实用fetch进行页面请求,最终生成静态页面,实现前后端完全分离
5 | * 附带使用koa实现的后端接口 //住server下面是koa写的接口,目前框架不使用此接口,仅供想学习koa的同学参考参考接口
6 | * 新版本使用egg实现后端接口
7 |
8 | # 开发环境
9 | * 基于node8.0+进行开发
10 |
11 | # 目录介绍
12 | * backend:基于AntDesign使用的后端SPA。
13 | * server:后端koa搭建的服务接口,主要包括,菜单管理,角色管理,用户管理,信息发布。 //目前废弃不再使用
14 | * eggserver:后端使用egg搭建服务接口
15 |
16 | 使用前,调整mysql数据库。使用 clantd.sql修改数据库。
17 |
18 | # 工程运行
19 | 进入到backend目录,编译运行前端框架
20 |
21 | ## 安装
22 |
23 | 安装node依赖
24 |
25 | ```
26 | npm install
27 |
28 | ```
29 |
30 | ## 开发环境
31 |
32 | 开发使用webpack进行编译,并使用webpack.server启动一个服务器,进行页面的访问,
33 |
34 | 使用前,配置webpack.server,修改接口的转发。主要是调整端口,如果接口端口不冲突,不需要调整。
35 |
36 | 
37 |
38 | 如上图,
39 |
40 | 前端转发,即今天服务器地址,默认端口port是9000,所以请求页面的默认地址是localhost:9000/index.html或localhost:9000
41 |
42 | 后端转发,为接口转发的时候,映射的地址。根据server工程设置的端口定,默认有两个,一个是请求常用接口,一个是登录验证。可视情况做相应调整
43 |
44 | 启动
45 |
46 | ```
47 | npm run dev
48 |
49 | ```
50 |
51 | ## 生产环境
52 |
53 | ```
54 | npm run pub
55 |
56 | ```
57 |
58 | 执行上述命令,会生成相应的文件到根目录下的pub文件夹,直接放服务器中使用即可。
59 |
60 | 生产环境,建议使用ngnix部署,直接配置静态文件目录,放目录下,使用ngnix进行接口转发。解决跨域问题。
61 |
62 | # 后端工程启动
63 |
64 | 后端工程主要提供了一些基础的接口。使用egg来开发。利用JWT整合token机制。
65 |
66 |
67 | ## 安装
68 |
69 | 使用clantd.sql进行数据库的安装,
70 |
71 | 进入到eggserver文件夹下,
72 |
73 | ### 修改数据库配置文件
74 |
75 | 修改eggserver/config/config.default.js下的数据库配置文件
76 |
77 | 
78 |
79 | 安装依赖
80 |
81 | ```
82 | npm install
83 |
84 | ```
85 |
86 | ## 启动开发
87 |
88 | ```
89 | npm run dev
90 |
91 | ```
92 |
93 | ## 后台部署
94 |
95 | ```
96 | npm start //开始
97 | npm stop //stop
98 |
99 | ```
100 |
101 |
102 | # 展示
103 | 访问地址 localhost:9000 登录用户名密码,admin/123
104 |
105 | 
106 |
107 | 
--------------------------------------------------------------------------------
/server/config/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by chenliang on 2017/1/12.
3 | */
4 | const path = require('path');
5 | const _ = require('lodash');
6 | const env = process.env.NODE_ENV || 'development';
7 |
8 | const defaults = {
9 | upload:{
10 | localFilePrex:'/Users/chenliang/website/upload/',//上传的图片位置
11 | downloadFilePrex:'http://localhost/upload/',
12 | },
13 | database:{
14 | host: '127.0.0.1',
15 | user: 'root',
16 | password: '11111',
17 | port: '3306',
18 | database: 'lmmFrame',
19 | },
20 | tokenConfig:{
21 | JWT_SECRET:"frameAntDesignToken",
22 | JWT_expiresIn:"30m"
23 | }
24 | };
25 |
26 | //正式环境参数不同的情况下修改对应参数
27 | const specific = {
28 | test: {},
29 | production: {
30 | upload:{
31 | localFilePrex:'/Users/chenliang/website/upload/',//上传的图片位置
32 | downloadFilePrex:'http://localhost/upload/',
33 | },
34 | database:{
35 | host: 'rm-uf69e0aq27f1zj341o.mysql.rds.aliyuncs.com',
36 | user: 'zhendedev',
37 | password: 'Zhendedev123456',
38 | port: '3306',
39 | database: 'framework',
40 | },
41 | loggers: {
42 | console: {
43 | level: 'info'
44 | }
45 | }
46 | }
47 | };
48 |
49 | const finallyOpts = _.defaultsDeep(specific[env], defaults);
50 |
51 | module.exports = finallyOpts;
--------------------------------------------------------------------------------
/server/database/mysqlUtil.js:
--------------------------------------------------------------------------------
1 | var wrapper = require('co-mysql'),
2 | mysql = require('mysql');
3 |
4 | var config = require('../config/config');
5 |
6 | var options = {
7 | host: config.database.host,
8 | user: config.database.user,
9 | password: config.database.password,
10 | port: config.database.port,
11 | database: config.database.database,
12 | };
13 |
14 | var pool = mysql.createPool(options),
15 | p = wrapper(pool);
16 |
17 | module.exports = p;
18 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "entry": {},
4 | "dependencies": {
5 | "co": "^4.6.0",
6 | "co-busboy": "^1.3.1",
7 | "co-mysql": "^1.0.0",
8 | "es3ify-loader": "^0.2.0",
9 | "history": "^2.0.1",
10 | "isomorphic-fetch": "^2.2.1",
11 | "js-cookie": "^2.1.1",
12 | "jsonwebtoken": "^7.4.1",
13 | "koa": "^2.0.0",
14 | "koa-body": "^2.0.0",
15 | "koa-bodyparser": "^4.2.0",
16 | "koa-convert": "^1.2.0",
17 | "koa-json": "^2.0.2",
18 | "koa-jwt": "^2.2.4",
19 | "koa-router": "^7.0.1",
20 | "koa-static": "^3.0.0",
21 | "lodash": "^4.15.0",
22 | "memory-cache": "^0.1.6",
23 | "mysql": "^2.10.0",
24 | "reqwest": "^2.0.5",
25 | "mkdirp": "^0.5.1",
26 | "stream-wormhole": "^1.0.3"
27 | },
28 | "scripts": {
29 | "start": "nodemon --harmony server.js"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/server/process.json:
--------------------------------------------------------------------------------
1 | {
2 | "apps": [
3 | {
4 | "name": "zhende-admin",
5 | "script": "server.js",
6 | "interpreter_args": "--harmony",
7 | "instances": "0",
8 | "exec_mode": "cluster",
9 | "merge_logs": true,
10 | "log_date_format": "YYYY-MM-DD HH:mm Z",
11 | "env": {
12 | "PORT": 8082
13 | }
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/server/routers/api/frame/auth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by chenliang on 16/1/4.
3 | */
4 |
5 | const Router = require('koa-router');
6 | const router = new Router();
7 |
8 | var config = require('../../../config/config');
9 | var tokenConfig = config.tokenConfig
10 |
11 | var jwt = require('jsonwebtoken');
12 |
13 | var userService = require('../../../service/frame/userService');
14 | var menuService = require('../../../service/frame/menuService');
15 |
16 | router.post('/login', async (ctx) => {
17 | const username = ctx.request.body.username;
18 | const password = ctx.request.body.password;
19 | var loginsuccess = false;
20 | var user = await userService.getUserByUserName(username);
21 | var menus = [];
22 | if (user!=undefined) {
23 | if(user.loginPasw == password){
24 | loginsuccess = true;
25 | if (username=='admin') {
26 | menus = await menuService.getAllMenu(user.userId);
27 | }else{
28 | menus = await userService.getUserMenus(user.userId);
29 | }
30 | } else {
31 | loginsuccess = false;
32 | }
33 | } else {
34 | loginsuccess = false;
35 | }
36 |
37 | var token = jwt.sign(user, tokenConfig.JWT_SECRET,{expiresIn:tokenConfig.JWT_expiresIn});
38 |
39 | ctx.body = {
40 | success : loginsuccess,
41 | data:{
42 | token:token,
43 | name:user.name
44 | },
45 | menus:menus,
46 | };
47 | })
48 |
49 |
50 |
51 | module.exports = router;
52 |
--------------------------------------------------------------------------------
/server/routers/api/frame/menu.js:
--------------------------------------------------------------------------------
1 | var Router = require('koa-router');
2 | var router = new Router();
3 |
4 | var menuService = require('../../../service/frame/menuService');
5 |
6 | router.get('/list', async (ctx) => {
7 | var q = ctx.query;
8 | var rows = await menuService.getMenusPage(q.pmenuId,q.page,q.size);
9 | var count = await menuService.getMenusCount(q.pmenuId);
10 |
11 | ctx.body = {"rows":rows,
12 | "count":count};
13 | });
14 |
15 | router.get('/listByPid',async (ctx) => {
16 | var q = ctx.query;
17 | var rows = await menuService.getMenuByPid(q.pid);
18 | ctx.body = rows;
19 | });
20 |
21 | router.get('/allList', async (ctx) => {
22 | var q = ctx.query;
23 | var rows = await menuService.getAllMenu();
24 | ctx.body = rows;
25 | });
26 |
27 | router.post('/add', async (ctx) => {
28 | var menu = ctx.request.body;
29 | await menuService.addNew(menu);
30 | ctx.body = {
31 | success : true,
32 | };
33 | });
34 |
35 | router.get('/delete', async (ctx) => {
36 | var q = ctx.query;
37 | var id = q.id;
38 | await menuService.delete(id);
39 | ctx.body = {
40 | success : true,
41 | };
42 | });
43 |
44 | router.post('/update', async (ctx) => {
45 | var menu = ctx.request.body;
46 | await menuService.update(menu);
47 | ctx.body = {
48 | success : true,
49 | };
50 | });
51 |
52 |
53 | module.exports = router;
54 |
--------------------------------------------------------------------------------
/server/routers/api/frame/role.js:
--------------------------------------------------------------------------------
1 | var Router = require('koa-router');
2 | var router = new Router();
3 |
4 | var roleService = require('../../../service/frame/roleService');
5 |
6 | router.get('/list', async (ctx) => {
7 | var q = ctx.query;
8 | var rows = await roleService.getRolesPage(q.proleId,q.page,q.size);
9 | var count = await roleService.getRolesCount(q.proleId);
10 |
11 | ctx.body = {"rows":rows,
12 | "count":count};
13 | });
14 |
15 | router.get('/listByPid',async (ctx) => {
16 | var q = ctx.query;
17 | var rows = await roleService.getRoleByPid(q.pid);
18 | ctx.body = rows;
19 | });
20 |
21 | router.get('/allList', async (ctx) => {
22 | var q = ctx.query;
23 | var rows = await roleService.getAllRoles();
24 |
25 | ctx.body = rows;
26 | });
27 |
28 | router.post('/add', async (ctx) =>{
29 | var role = ctx.request.body;
30 | await roleService.addNew(role);
31 | ctx.body = {
32 | success : true,
33 | };
34 | });
35 |
36 | router.get('/delete', async (ctx) => {
37 | var q = ctx.query;
38 | var id = q.id;
39 | await roleService.delete(id);
40 | ctx.body = {
41 | success : true,
42 | };
43 | });
44 |
45 | router.post('/update', async (ctx) => {
46 | var role = ctx.request.body;
47 | await roleService.update(role);
48 | ctx.body = {
49 | success : true,
50 | };
51 | });
52 |
53 | router.post('/configRoleMenu', async (ctx) => {
54 | var roleMenuFormData = ctx.request.body;
55 | await roleService.configRoleMenu(roleMenuFormData);
56 | ctx.body = {
57 | success : true,
58 | };
59 | });
60 |
61 | router.get('/getRoleMenus', async (ctx) => {
62 | var q = ctx.query;
63 | var rows = await roleService.getRoleMenus(q.roleId);
64 | ctx.body = rows;
65 | });
66 |
67 | module.exports = router;
68 |
--------------------------------------------------------------------------------
/server/routers/api/frame/user.js:
--------------------------------------------------------------------------------
1 | var Router = require('koa-router');
2 | var router = new Router();
3 |
4 | var p = require('../../../database/mysqlUtil');
5 | var userService = require('../../../service/frame/userService');
6 |
7 | router.get('/list', async (ctx) =>{
8 | var q = ctx.query;
9 | var rows = await userService.getUsersPage(q.page,q.size);
10 | var count = await userService.getUsersCount();
11 |
12 | ctx.body = {"rows":rows,
13 | "count":count};
14 | });
15 |
16 | router.post('/add', async (ctx) =>{
17 | var user = ctx.request.body;
18 | await userService.addNew(user);
19 | ctx.body = {
20 | success : true,
21 | };
22 | });
23 |
24 | router.get('/delete', async (ctx) =>{
25 |
26 | var q = ctx.query;
27 | var userId = q.userId;
28 |
29 | await userService.delete(userId);
30 | ctx.body = {
31 | success : true,
32 | };
33 | });
34 |
35 | router.post('/update', async (ctx) =>{
36 | var user = ctx.request.body;
37 | await userService.update(user);
38 | ctx.body = {
39 | success : true,
40 | };
41 | });
42 |
43 | router.post('/configUserRole', async (ctx) =>{
44 | var userRoleFormData = ctx.request.body;
45 | await userService.configUserRole(userRoleFormData);
46 | ctx.body = {
47 | success : true,
48 | };
49 | });
50 |
51 | router.get('/getUserRoles', async (ctx) =>{
52 | var q = ctx.query;
53 | var rows = await userService.getUserRoles(q.userId);
54 | ctx.body = rows;
55 | });
56 |
57 | router.get('/getUserMenus', async (ctx) =>{
58 | var q = ctx.query;
59 | var rows = await userService.getUserMenus(q.userId);
60 | ctx.body = rows;
61 | })
62 |
63 | module.exports = router;
64 |
--------------------------------------------------------------------------------
/server/routers/api/index.js:
--------------------------------------------------------------------------------
1 | var config = require('../../config/config');
2 | var tokenConfig = config.tokenConfig
3 | var jwt = require('koa-jwt');
4 |
5 | const Router = require('koa-router');
6 |
7 | const api_user = require("./frame/user");
8 | const api_menu = require("./frame/menu");//菜单
9 | const api_role = require("./frame/role");//角色管理
10 | const api_auth = require("./frame/auth");
11 |
12 | const api_media = require("./media");
13 |
14 | const api_infoCategory = require('./info/infoCategory');
15 | const api_info = require('./info/info');
16 |
17 | const noAuthRouter = new Router();
18 |
19 | const needAuthRouter = new Router();
20 |
21 | module.exports = (app) => {
22 | noAuthRouter.use('/api/auth', api_auth.routes());
23 | noAuthRouter.use('/api/media', api_media.routes());
24 |
25 | needAuthRouter.use('/api/menu', api_menu.routes());
26 | needAuthRouter.use('/api/role', api_role.routes());
27 | needAuthRouter.use('/api/user', api_user.routes());
28 |
29 | needAuthRouter.use('/api/infoCategory', api_infoCategory.routes());
30 | needAuthRouter.use('/api/info', api_info.routes());
31 |
32 | app.use(noAuthRouter.routes());
33 |
34 | app.use(jwt({ secret: tokenConfig.JWT_SECRET }));
35 |
36 | app.use(needAuthRouter.routes());
37 | };
--------------------------------------------------------------------------------
/server/routers/api/info/info.js:
--------------------------------------------------------------------------------
1 | var Router = require('koa-router');
2 | var router = new Router();
3 |
4 | var infoService = require('../../../service/info/infoService');
5 |
6 | router.get('/list', async (ctx) =>{
7 | var q = ctx.query;
8 | var rows = await infoService.getInfoPage(q.categoryId,q.page,q.size);
9 | var count = await infoService.getInfoCount(q.categoryId);
10 |
11 | ctx.body = {"rows":rows,
12 | "count":count};
13 | });
14 |
15 | router.get('/detail' ,async (ctx) => {
16 | var q = ctx.query;
17 | var info = await infoService.getInfoById(q.infoId);
18 | ctx.body = {"info":info};
19 | });
20 |
21 | router.post('/add', async (ctx) =>{
22 | var info = ctx.request.body;
23 | await infoService.addNew(info);
24 | ctx.body = {
25 | success : true,
26 | };
27 | });
28 |
29 | router.get('/delete', async (ctx) =>{
30 | var q = ctx.query;
31 | var id = q.id;
32 | await infoService.delete(id);
33 | ctx.body = {
34 | success : true,
35 | };
36 | });
37 |
38 | router.post('/update', async (ctx) =>{
39 | var info = ctx.request.body;
40 | await infoService.update(info);
41 | ctx.body = {
42 | success : true,
43 | };
44 | });
45 |
46 |
47 | module.exports = router;
48 |
--------------------------------------------------------------------------------
/server/routers/api/info/infoCategory.js:
--------------------------------------------------------------------------------
1 | var Router = require('koa-router');
2 | var router = new Router();
3 |
4 | var infoCategoryService = require('../../../service/info/infoCategoryService');
5 |
6 | router.get('/list', async (ctx) => {
7 | var q = ctx.query;
8 | var rows = await infoCategoryService.getInfoCategoryPage(q.pCategoryId,q.page,q.size);
9 | var count = await infoCategoryService.getInfoCategorysCount(q.pCategoryId);
10 |
11 | ctx.body = {"rows":rows,
12 | "count":count};
13 | });
14 |
15 | router.get('/listByPid',async (ctx) =>{
16 | var q = ctx.query;
17 | var rows = await infoCategoryService.getInfoCategoryByPid(q.pid);
18 | ctx.body = rows;
19 | });
20 |
21 | router.get('/allList', async (ctx) => {
22 | var q = ctx.query;
23 | var rows = await infoCategoryService.getAllCategory();
24 | ctx.body = rows;
25 | });
26 |
27 | router.post('/add', async (ctx) =>{
28 | var infoC = ctx.request.body;
29 | await infoCategoryService.addNew(infoC);
30 | ctx.body = {
31 | success : true,
32 | };
33 | });
34 |
35 | router.get('/delete', async (ctx) =>{
36 | var q = ctx.query;
37 | var id = q.id;
38 | await infoCategoryService.delete(id);
39 | ctx.body = {
40 | success : true,
41 | };
42 | });
43 |
44 | router.post('/update', async (ctx) =>{
45 | var infoc = ctx.request.body;
46 | await infoCategoryService.update(infoc);
47 | ctx.body = {
48 | success : true,
49 | };
50 | });
51 |
52 |
53 | module.exports = router;
54 |
--------------------------------------------------------------------------------
/server/routers/api/media.js:
--------------------------------------------------------------------------------
1 | var Router = require('koa-router');
2 | var router = new Router();
3 |
4 | var parse = require('co-busboy');
5 | var os = require('os');
6 | var path = require('path');
7 | var fs = require('fs');
8 |
9 | var config = require('../../config/config')
10 |
11 | router.post('/upload', async (ctx) => {
12 | let files = ctx.request.body.files;
13 | let returnpath = "";
14 |
15 | if (files) {
16 | Object.keys(files).forEach(key => {
17 | let file = files[key];
18 | let path = file.path;
19 | returnpath = config.upload.downloadFilePrex + path.replace(config.upload.localFilePrex, '').replace(/\\/g, '/');
20 | });
21 | }
22 | ctx.body = {
23 | "status": "success",
24 | "url": returnpath
25 | };
26 | });
27 |
28 | router.post('/simditorUploadImage', async (ctx) => {
29 | let files = ctx.request.body.files;
30 | let returnpath = "";
31 |
32 | if (files) {
33 | Object.keys(files).forEach(key => {
34 | let file = files[key];
35 | let path = file.path;
36 | returnpath = config.upload.downloadFilePrex + path.replace(config.upload.localFilePrex, '').replace(/\\/g, '/');
37 | });
38 | }
39 |
40 | ctx.body = {
41 | "success": true,
42 | "msg": "",
43 | "file_path": returnpath
44 | };
45 | });
46 |
47 | router.post('/uploadFiles', async (ctx) => {
48 |
49 | let files = ctx.request.body.files;
50 | let returnpath = "";
51 |
52 | if (files) {
53 | Object.keys(files).forEach(key => {
54 | let file = files[key];
55 | let path = file.path;
56 |
57 | let fileUrl = config.upload.downloadFilePrex + path.replace(config.upload.localFilePrex, '').replace(/\\/g, '/');
58 |
59 | if (returnpath == "") {
60 | returnpath += fileUrl;
61 | } else {
62 | returnpath += ";" + fileUrl;
63 | }
64 | });
65 | }
66 |
67 | ctx.body = {
68 | status: "success",
69 | url: returnpath
70 | };
71 | });
72 |
73 |
74 | module.exports = router;
--------------------------------------------------------------------------------
/server/routers/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (app) => {
2 | require('./api')(app);
3 | };
4 |
--------------------------------------------------------------------------------
/server/routers/mapi/info/minfo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by cl on 2016/10/9.
3 | */
4 | var Router = require('koa-router');
5 | var router = new Router({prefix: '/api/m/info'});
6 |
7 | var infoService = require('../../../service/info/infoService');
8 |
9 | router.get('/list', function* (next){
10 | var q = this.request.query;
11 | var rows = yield infoService.getInfoPageByCategoryName(q.categoryName,q.page,q.size);
12 |
13 | yield this.body = {ret:200,
14 | data:rows,msg:""};
15 | });
16 |
17 | router.get('/detail' ,function * (next) {
18 | var q = this.request.query;
19 | var info = yield infoService.getInfoById(q.infoId);
20 | yield this.body = {ret:200,
21 | data:info,msg:""};
22 | });
23 |
24 | module.exports = router;
25 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | // require("babel-core/register");
2 | // require("babel-polyfill");
3 | // set babel in entry file
4 |
5 | 'use strict';
6 |
7 | const http = require('http');
8 | const json = require('koa-json');
9 | const bodyParser = require('koa-bodyparser');
10 | const staticDir = require('koa-static');
11 | const body = require('koa-body');
12 | const convert = require('koa-convert')
13 | const path = require('path');
14 | const fs = require('fs');
15 | const mkdirp = require('mkdirp');
16 |
17 | const port = process.env.PORT || '8080'
18 | const Koa = require('koa');
19 | const app = new Koa();
20 |
21 | const server = http.createServer(app.callback());
22 |
23 | var router = require("./routers");
24 |
25 | const config = require('./config/config')
26 |
27 | app.use(json({pretty: false, param: 'pretty'}));
28 |
29 | app.use(staticDir(__dirname + '/../dist'));
30 | app.use(staticDir(__dirname + '/public'));
31 |
32 | app.use(body({
33 | multipart: true,
34 | formidable: {
35 | multiples: true,
36 | uploadDir: config.upload.localFilePrex,
37 | maxFieldsSize: 1024 * 10, // max file size: 10m
38 | onFileBegin: (name, file) => {
39 | let now = new Date();
40 | let today = path.join(now.getFullYear().toString(), (now.getMonth() + 1).toString(), now.getDay().toString());
41 | let folder = path.join(config.upload.localFilePrex, today);
42 | let filename = now.getTime() + '__' + file.name;
43 |
44 | try {
45 | fs.accessSync(folder, fs.constants.W_OK);
46 | } catch (err) {
47 | mkdirp.sync(folder);
48 | } finally {
49 | file.path = path.join(folder, filename);
50 | }
51 | }
52 | }
53 | }));
54 |
55 | app.use(bodyParser());
56 |
57 | router(app);
58 |
59 | server.listen(port, () => {
60 | console.log(`app started in ${port}`);
61 | });
62 |
--------------------------------------------------------------------------------
/server/service/frame/menuService.js:
--------------------------------------------------------------------------------
1 | var p = require('../../database/mysqlUtil');
2 |
3 | var menuService = {};
4 |
5 | menuService.getMenusPage = async (pmenuId,page,size) => {
6 | var sqlString = `select * from fmenu where 1=1 `;
7 | if (pmenuId != undefined && pmenuId != '') {
8 | sqlString += ` and pmenuId = ${pmenuId} `;
9 | };
10 |
11 | var pageInt = parseInt(page);
12 | var sizeInt = parseInt(size);
13 |
14 | var start = (page-1)*size;
15 |
16 | sqlString += ' order by orderNum ';
17 |
18 | sqlString += ' limit ' +start +','+size;
19 |
20 | var rows = await p.query(sqlString);
21 | return rows;
22 | }
23 |
24 | menuService.getMenusCount = async (pmenuId) => {
25 | var sqlString = `select count(1) as cnt from fmenu where 1=1 `;
26 | if (pmenuId != undefined && pmenuId != '') {
27 | sqlString += ` and pmenuId = ${pmenuId} `;
28 | };
29 |
30 | var count = await p.query(sqlString);
31 | return count[0].cnt;
32 | }
33 |
34 | menuService.getMenuByPid = async (pmenuId) => {
35 | var sqlString = `select * from fmenu where 1=1 `;
36 | if (pmenuId != undefined && pmenuId != '') {
37 | sqlString += ` and pmenuId=${pmenuId} `;
38 | };
39 | var rows = await p.query(sqlString);
40 | return rows;
41 | }
42 |
43 | menuService.getAllMenu = async () => {
44 | var sqlString = `select * from fmenu where 1=1 order by orderNum`;
45 | var rows = await p.query(sqlString);
46 | return rows;
47 | }
48 |
49 | menuService.delete = async (menuId) => {
50 | await p.query(`delete from fmenu where menuId = ${menuId} `);
51 | }
52 |
53 | menuService.addNew = async (data) => {
54 | var sqlString = `insert into fmenu (name,menuKey,tourl,orderNum,pmenuId,tag)
55 | value("${data.name}","${data.menuKey}","${data.tourl}",${data.orderNum},${data.pmenuId},"${data.tag}")`;
56 | await p.query(sqlString);
57 | }
58 |
59 | menuService.update = async (data) => {
60 | await p.query(`update fmenu set name = "${data.name}",
61 | menuKey = "${data.menuKey}", orderNum = ${data.orderNum} ,
62 | pmenuId = ${data.pmenuId} ,
63 | tourl = "${data.tourl}",
64 | tag = "${data.tag}" where menuId = ${data.menuId}`);
65 | }
66 |
67 | module.exports = menuService;
--------------------------------------------------------------------------------
/server/service/frame/roleService.js:
--------------------------------------------------------------------------------
1 | var p = require('../../database/mysqlUtil');
2 |
3 | var roleService = {};
4 |
5 | roleService.getRolesPage = async (proleId,page,size) => {
6 | var sqlString = `select * from frole where 1=1 `;
7 | if (proleId != undefined && proleId != '') {
8 | sqlString += ` and proleId = ${proleId} `;
9 | };
10 |
11 | var pageInt = parseInt(page);
12 | var sizeInt = parseInt(size);
13 |
14 | var start = (page-1)*size;
15 |
16 | sqlString += ' limit ' +start +','+size;
17 |
18 | var rows = await p.query(sqlString);
19 | return rows;
20 | }
21 |
22 | roleService.getAllRoles = async () => {
23 | var sqlString = `select * from frole where 1=1 `;
24 | var rows = await p.query(sqlString);
25 | return rows;
26 | }
27 |
28 | roleService.getRolesCount = async (proleId) => {
29 | var sqlString = `select count(1) as cnt from frole where 1=1 `;
30 | if (proleId != undefined && proleId != '') {
31 | sqlString += ` and proleId = ${proleId} `;
32 | };
33 |
34 | var count = await p.query(sqlString);
35 | return count[0].cnt;
36 | }
37 |
38 | roleService.getRoleByPid = async (proleId) => {
39 | var sqlString = `select * from frole where 1=1 `;
40 | if (proleId != undefined && proleId != '') {
41 | sqlString += ` and proleId=${proleId} `;
42 | };
43 | var rows = await p.query(sqlString);
44 | return rows;
45 | }
46 |
47 | roleService.delete = async (roleId) => {
48 | await p.query(`delete from frole where roleId = ${roleId} `);
49 | }
50 |
51 | roleService.addNew = async (data) => {
52 | var sqlString = `insert into frole (name,proleId)
53 | value("${data.name}",${data.proleId})`;
54 | await p.query(sqlString);
55 | }
56 |
57 | roleService.update = async (data) => {
58 | await p.query(`update frole set name = "${data.name}",proleId = ${data.proleId} where roleId = ${data.roleId}`);
59 | }
60 |
61 | roleService.configRoleMenu = async (data) => {
62 | var menus = data.menus ;
63 | await p.query(`delete from froleMenu where roleId = ${data.roleId} `);
64 | if (menus!=undefined && menus != ""){
65 | var menuArray = menus.split(",");
66 | for(var i = 0 ; i< menuArray.length ; i ++){
67 | var menuId = menuArray[i];
68 | if (parseInt(menuId) != -1 ) {
69 | var insertsql = `INSERT INTO froleMenu(menuId, roleId) SELECT ${menuId}, ${data.roleId} FROM DUAL WHERE NOT EXISTS(SELECT * FROM froleMenu WHERE menuId =${menuId} and roleId =${data.roleId} )`;
70 | await p.query(insertsql);
71 | }
72 | }
73 | }
74 | }
75 |
76 | roleService.getRoleMenus = async (roleId) => {
77 | var sqlString = `select menuId from froleMenu where 1=1 `;
78 | if (roleId != undefined && roleId != '') {
79 | sqlString += ` and roleId=${roleId} `;
80 | };
81 | var rows = await p.query(sqlString);
82 | return rows;
83 | }
84 |
85 | module.exports = roleService;
86 |
--------------------------------------------------------------------------------
/server/service/frame/userService.js:
--------------------------------------------------------------------------------
1 | var p = require('../../database/mysqlUtil');
2 |
3 | var userService = {};
4 |
5 | userService.getUsersPage = async (page,size) => {
6 | var page = parseInt(page);
7 | var size = parseInt(size);
8 |
9 | var start = (page-1)*size;
10 | var end = page*size;
11 |
12 | var rows = await p.query('select * from fuser limit ' +start +','+end);
13 |
14 | return rows;
15 | }
16 |
17 | userService.getUserByUserName = async (username) => {
18 | var rows = await p.query('select * from fuser where loginName ="'+username+'"');
19 | if (rows.length>0){
20 | return rows[0];
21 | }
22 | return undefined;
23 | }
24 |
25 | userService.delete = async (userId) => {
26 | await p.query(`delete from fuser where userId = ${userId} `);
27 | }
28 |
29 | userService.addNew = async (data) => {
30 | var sqlString = `insert into fuser (loginName,loginPasw,name)
31 | value("${data.loginName}","${data.loginPasw}","${data.name}")`;
32 | await p.query(sqlString);
33 | }
34 |
35 | userService.update = async (data) => {
36 | await p.query(`update fuser set loginName = "${data.loginName}",
37 | loginPasw = "${data.loginPasw}",
38 | name = "${data.name}" where userId = ${data.userId}`);
39 | }
40 |
41 | userService.getUsersCount = async () => {
42 | var sqlString = `select count(1) as cnt from fuser `;
43 | var count = await p.query(sqlString);
44 | return count[0].cnt;
45 | }
46 |
47 | userService.configUserRole = async (data) => {
48 | var roles = data.roles ;
49 | await p.query(`delete from fuserrole where userId = ${data.userId} `);
50 | if (roles!=undefined && roles != ""){
51 | var roleArray = roles.split(",");
52 | for(var i = 0 ; i< roleArray.length ; i ++){
53 | var roleId = roleArray[i];
54 | if (parseInt(roleId) != -1 ) {
55 | var insertsql = `INSERT INTO fuserrole(userId, roleId) SELECT ${data.userId}, ${roleId} FROM DUAL WHERE NOT EXISTS(SELECT * FROM fuserrole WHERE userId =${data.userId} and roleId =${roleId} )`;
56 | await p.query(insertsql);
57 | }
58 | }
59 | }
60 | }
61 |
62 | userService.getUserRoles = async (userId) => {
63 | var sqlString = `select roleId from fuserrole where 1=1 `;
64 | if (userId != undefined && userId != '') {
65 | sqlString += ` and userId=${userId} `;
66 | };
67 | var rows = await p.query(sqlString);
68 | return rows;
69 | }
70 |
71 | userService.getUserMenus = async (userId) => {
72 | var sqlString = `select distinct m.* from fmenu m inner join frolemenu rm on m.menuId = rm.menuId where rm.roleId in
73 | (select r.roleId from frole r inner join fuserrole ur on r.roleId = ur.roleId where ur.userId = ${userId}) order by m.orderNum `;
74 | var rows = await p.query(sqlString);
75 | return rows;
76 | }
77 |
78 | module.exports = userService;
79 |
--------------------------------------------------------------------------------
/server/service/info/infoCategoryService.js:
--------------------------------------------------------------------------------
1 | var p = require('../../database/mysqlUtil');
2 |
3 | var infoCategoryService = {};
4 |
5 | infoCategoryService.getInfoCategoryPage = async (pCategoryId,page,size) => {
6 | var sqlString = `select * from finfocategory where 1=1 `;
7 | if (pCategoryId != undefined && pCategoryId != '') {
8 | sqlString += ` and pCategoryId = ${pCategoryId} `;
9 | };
10 |
11 | var pageInt = parseInt(page);
12 | var sizeInt = parseInt(size);
13 |
14 | var start = (page-1)*size;
15 |
16 | sqlString += ' order by orderNum ';
17 |
18 | sqlString += ' limit ' +start +','+size;
19 |
20 | var rows = await p.query(sqlString);
21 | return rows;
22 | }
23 |
24 | infoCategoryService.getInfoCategorysCount = async (pCategoryId) => {
25 | var sqlString = `select count(1) as cnt from finfocategory where 1=1 `;
26 | if (pCategoryId != undefined && pCategoryId != '') {
27 | sqlString += ` and pCategoryId = ${pCategoryId} `;
28 | };
29 |
30 | var count = await p.query(sqlString);
31 | return count[0].cnt;
32 | }
33 |
34 | infoCategoryService.getInfoCategoryByPid = async (pCategoryId) => {
35 | var sqlString = `select * from finfocategory where 1=1 `;
36 | if (pCategoryId != undefined && pCategoryId != '') {
37 | sqlString += ` and pCategoryId=${pCategoryId} `;
38 | };
39 | var rows = await p.query(sqlString);
40 | return rows;
41 | }
42 |
43 | infoCategoryService.getAllCategory = async () => {
44 | var sqlString = `select * from finfocategory where 1=1 order by orderNum`;
45 | var rows = await p.query(sqlString);
46 | return rows;
47 | }
48 |
49 | infoCategoryService.delete = async (categoryId) => {
50 | await p.query(`delete from finfocategory where categoryId = ${categoryId} `);
51 | }
52 |
53 | infoCategoryService.addNew = async (data) => {
54 | var sqlString = `insert into finfocategory (categoryName,orderNum,pCategoryId)
55 | value("${data.categoryName}",${data.orderNum},${data.pCategoryId})`;
56 | await p.query(sqlString);
57 | }
58 |
59 | infoCategoryService.update = async (data) => {
60 | await p.query(`update finfocategory set categoryName = "${data.categoryName}",
61 | orderNum = ${data.orderNum}, pCategoryId = ${data.pCategoryId} where categoryId = ${data.categoryId} `);
62 | }
63 |
64 | module.exports = infoCategoryService;
--------------------------------------------------------------------------------
/server/service/info/infoService.js:
--------------------------------------------------------------------------------
1 | var p = require('../../database/mysqlUtil');
2 |
3 | var infoService = {};
4 |
5 | infoService.getInfoPage = async (categoryId,page,size) => {
6 | var sqlString = `select infoId,createDate,infoDes,categoryName,topic,url,city,categoryId from finfo where 1=1 `;
7 | if (categoryId != undefined && categoryId != '') {
8 | sqlString += ` and categoryId = ${categoryId} `;
9 | };
10 |
11 | var pageInt = parseInt(page);
12 | var sizeInt = parseInt(size);
13 |
14 | var start = (page-1)*size;
15 |
16 | sqlString += ' order by createDate desc';
17 |
18 | sqlString += ' limit ' +start +','+size;
19 |
20 | var rows = await p.query(sqlString);
21 | return rows;
22 | }
23 |
24 | infoService.getInfoPageByCategoryName = async (categoryName,page,size) => {
25 | var sqlString = `select infoId,createDate,updateDate,categoryName,topic,url,city,categoryId,headImage from finfo where 1=1 `;
26 | if (categoryName != undefined && categoryName != '') {
27 | sqlString += ` and categoryName = '${categoryName}' `;
28 | };
29 |
30 | var pageInt = parseInt(page);
31 | var sizeInt = parseInt(size);
32 |
33 | var start = (page-1)*size;
34 |
35 | sqlString += ' order by createDate desc';
36 |
37 | sqlString += ' limit ' +start +','+size;
38 |
39 | var rows = await p.query(sqlString);
40 | return rows;
41 | }
42 |
43 | infoService.getInfoCount = async (categoryId) => {
44 | var sqlString = `select count(1) as cnt from finfo where 1=1 `;
45 | if (categoryId != undefined && categoryId != '') {
46 | sqlString += ` and categoryId = ${categoryId} `;
47 | };
48 |
49 | var count = await p.query(sqlString);
50 | return count[0].cnt;
51 | }
52 |
53 | infoService.getInfoByCid = async (categoryId) => {
54 | var sqlString = `select * from finfo where 1=1 `;
55 | if (categoryId != undefined && categoryId != '') {
56 | sqlString += ` and categoryId=${categoryId} `;
57 | };
58 | var rows = await p.query(sqlString);
59 | return rows;
60 | }
61 |
62 | infoService.getInfoById = async (infoId) => {
63 | var sqlString = `select * from finfo where 1=1 `;
64 | if (infoId != undefined && infoId != '') {
65 | sqlString += ` and infoId=${infoId} `;
66 | };
67 | var rows = await p.query(sqlString);
68 | if (rows.length>0){
69 | return rows[0];
70 | }
71 | return undefined;
72 | }
73 |
74 | infoService.delete = async (infoId) => {
75 | await p.query(`delete from finfo where infoId = ${infoId} `);
76 | }
77 |
78 | infoService.addNew = async (data) => {
79 | var sqlString = `insert into finfo (createDate,updateDate,categoryName,topic,content,url,headImage,infoDes,city,categoryId)
80 | value(now(),now(),'${data.categoryName}','${data.topic}','${data.content}','${data.url}','${data.headImage}','${data.infoDes}','${data.city}',${data.categoryId})`;
81 | await p.query(sqlString);
82 | }
83 |
84 | infoService.update = async (data) => {
85 | await p.query(`update finfo set categoryName = "${data.categoryName}",
86 | topic = '${data.topic}', content = '${data.content}', url = '${data.url}', headImage = '${data.headImage}'
87 | , infoDes = '${data.infoDes}', city = '${data.city}', categoryId = ${data.categoryId} where infoId=${data.infoId}` );
88 | }
89 |
90 | module.exports = infoService;
--------------------------------------------------------------------------------