105 |
programExperienceStore.openModal('add')}
110 | onKeyDown={this.handleKeyDown}
111 | style={{ marginLeft: '20px' }}
112 | />
113 |
114 | Add Program Experience
115 |
116 |
117 |
118 | {
119 | Object.keys(programExperienceStore.dataSource).map(key => (
120 | -
121 |
122 |
123 |
programExperienceStore.openModal('update',
128 | programExperienceStore.dataSource[key].program_name,
129 | programExperienceStore.dataSource[key].program_url,
130 | programExperienceStore.dataSource[key].program_content,
131 | programExperienceStore.dataSource[key].program_technology_stack,
132 | programExperienceStore.dataSource[key]._id,) /* eslint-disable-line */
133 | }
134 | />
135 | }
138 | onConfirm={() => programExperienceStore.deleteData(programExperienceStore.dataSource[key]._id,)} /* eslint-disable-line */
139 | >
140 |
144 |
145 |
146 |
147 | {programExperienceStore.dataSource[key].program_name}
148 |
149 |
150 |
151 | {programExperienceStore.dataSource[key].program_url}
152 |
153 |
154 | {programExperienceStore.dataSource[key].program_content}
155 |
156 |
157 | {
158 | Object.keys(programExperienceStore.dataSource[key].program_technology_stack).map(tag => (
159 |
160 | {programExperienceStore.dataSource[key].program_technology_stack[tag]}
161 |
162 | ))
163 | }
164 |
165 |
166 | ))
167 | }
168 |
169 |
170 |
171 |
172 | );
173 | }
174 | }
175 |
176 |
177 | export default CV;
178 |
--------------------------------------------------------------------------------
/src/containers/CV/CV.scss:
--------------------------------------------------------------------------------
1 | .cv_wrapper {
2 | display: grid;
3 | grid-template-columns: repeat(2, 1fr);
4 | .add_wrapper {
5 | display: flex;
6 | align-items: center;
7 | .add_intro {
8 | display: inline-block;
9 | margin-left: 20px;
10 | font-size: 18px;
11 | }
12 | }
13 | .work_experience_container {
14 | border-right: 1px solid #ccc;
15 | }
16 | .work_experience_list {
17 | margin-top: 20px;
18 | width: 96%;
19 | .work_experience_item {
20 | margin-bottom: 20px;
21 | padding: 24px;
22 | list-style-type: none;
23 | color: #414a60;
24 | border-radius: 4px;
25 | transition: background-color 500ms linear;
26 | &:hover {
27 | background: #f2f5f9;
28 | transition: background-color 500ms linear;
29 | }
30 | &:hover .operation {
31 | display: inline-block;
32 | }
33 | .operation {
34 | display: none;
35 | float: right;
36 | color: #9fa3b0;
37 | font-size: 18px;
38 | cursor: pointer;
39 | .anticon:hover {
40 | color: #5dd5c8;
41 | }
42 | .anticon:first-child {
43 | margin-right: 16px;
44 | }
45 | }
46 | .enterprise_name {
47 | display: inline-block;
48 | font-size: 15px;
49 | }
50 | .in_service {
51 | display: block;
52 | margin-bottom: 8px;
53 | font-size: 12px;
54 | color: #8d92a1;
55 | }
56 | .position {
57 | font-weight: bold;
58 | }
59 | .work_content {
60 | color: #61687c;
61 | line-height: 24px;
62 | }
63 | .technology_stack {
64 | margin-top: 20px;
65 | .technology_stack_item {
66 | display: inline-block;
67 | font-size: 12px;
68 | line-height: 20px;
69 | color: #9fa3b0;
70 | padding: 0 14px;
71 | margin-top: 10px;
72 | margin-right: 10px;
73 | border: 1px solid #cfd1d7;
74 | border-radius: 50px;
75 | }
76 | }
77 | }
78 | }
79 | .add_btn {
80 | display: inline-block;
81 | position: relative;
82 | width: 48px;
83 | height: 48px;
84 | background: #fff;
85 | border-radius: 50%;
86 | box-shadow: 1px 1px 3px 0 #bbb;
87 | outline: none;
88 | cursor: pointer;
89 | &::after {
90 | position: absolute;
91 | content: '';
92 | width: 24px;
93 | height: 2px;
94 | background: #666;
95 | top: 23px;
96 | left: 12px;
97 | }
98 | &::before {
99 | position: absolute;
100 | content: '';
101 | width: 24px;
102 | height: 2px;
103 | background: #666;
104 | top: 23px;
105 | left: 12px;
106 | transform: rotate(90deg);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/containers/Exception/Exception.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { Button } from 'antd';
4 |
5 | class Exception extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {};
9 | }
10 |
11 |
12 | componentDidMount() {
13 | }
14 |
15 | render() {
16 | const wrapperStyle = {
17 | display: 'flex',
18 | justifyContent: 'space-around',
19 | padding: '100px 320px 0',
20 | };
21 | const figureStyle = {
22 | width: 430,
23 | height: 360,
24 | background: 'url("https://static.yancey.app/404.svg") no-repeat center top',
25 | };
26 | const headerStyle = {
27 | color: '#434e59',
28 | fontSize: 72,
29 | fontWeight: 600,
30 | marginBottom: 16,
31 | };
32 | const introStyle = {
33 | color: 'rgba(0,0,0,.45)',
34 | fontSize: 20,
35 | marginBottom: 16,
36 | };
37 | return (
38 |
42 |
45 |
46 |
49 | 404
50 |
51 |
54 | The Page You Requested Could Not Found.
55 |
56 |
63 |
64 |
65 | );
66 | }
67 | }
68 |
69 |
70 | export default Exception;
71 |
--------------------------------------------------------------------------------
/src/containers/Home/Announcement/Announcement.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { observer, inject } from 'mobx-react';
3 | import {
4 | Table, Button, Modal, Input, Icon, Popconfirm, Row, Col,
5 | } from 'antd';
6 |
7 | import { capitalized } from '../../../util/tools';
8 |
9 | const { Column, ColumnGroup } = Table;
10 |
11 | @inject('announcementStore')
12 | @observer
13 | class Announcement extends Component {
14 | constructor(props) {
15 | super(props);
16 | this.state = {};
17 | }
18 |
19 |
20 | componentDidMount() {
21 | const { announcementStore } = this.props;
22 | announcementStore.getData();
23 | }
24 |
25 | render() {
26 | const { announcementStore } = this.props;
27 | const selectedRowKeysLength = announcementStore.selectedRowKeys.length;
28 | const rowSelection = {
29 | selectedRowKeys: announcementStore.selectedRowKeys,
30 | onChange: announcementStore.onSelectChange,
31 | };
32 | const pagination = {
33 | total: announcementStore.dataSource.length,
34 | showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} items`,
35 | pageSize: 10,
36 | defaultCurrent: 1,
37 | };
38 | return (
39 |
40 |
41 |
55 |
1 ? 'items' : 'item'}?`}
57 | icon={}
58 | onConfirm={() => announcementStore.batchDelete()}
59 | >
60 |
70 |
71 |
72 | {selectedRowKeysLength > 0 ? `Selected ${selectedRowKeysLength} ${selectedRowKeysLength > 1 ? 'items' : 'item'}` : ''}
73 |
74 |
75 | record._id} /* eslint-disable-line */
77 | dataSource={announcementStore.dataSource}
78 | rowSelection={rowSelection}
79 | pagination={pagination}
80 | >
81 |
82 |
87 |
92 | (
96 |
97 | announcementStore.openModal('update', record._id, record.content) /* eslint-disable-line */
104 | }
105 | />
106 | }
109 | onConfirm={() => announcementStore.deleteData(record._id)} /* eslint-disable-line */
110 | >
111 |
117 |
118 |
119 | )}
120 | />
121 |
122 |
123 |
126 |
132 | {announcementStore.modalType === 'add' ? 'Add New' : 'Update The'}
133 | {' '}
134 | Announcement
135 |
136 | )}
137 | width={600}
138 | wrapClassName="reset_modal"
139 | closable={false}
140 | destroyOnClose
141 | visible={announcementStore.showModal}
142 | okButtonProps={{ disabled: !announcementStore.isFilled }}
143 | okText={capitalized(announcementStore.modalType)}
144 | onOk={announcementStore.modalType === 'add' ? () => announcementStore.insertData() : () => announcementStore.modifyData()}
145 | onCancel={announcementStore.closeModal}
146 | >
147 |
148 |
149 |
150 | Announcement Content:
151 |
152 |
153 |
154 | announcementStore.onContentChange(event)}
158 | />
159 |
160 |
161 |
162 |
163 | );
164 | }
165 | }
166 |
167 |
168 | export default Announcement;
169 |
--------------------------------------------------------------------------------
/src/containers/Home/Motto/Motto.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { observer, inject } from 'mobx-react';
3 | import {
4 | Table, Button, Modal, Input, Icon, Popconfirm, Row, Col,
5 | } from 'antd';
6 |
7 | import { capitalized } from '../../../util/tools';
8 |
9 | const { Column, ColumnGroup } = Table;
10 |
11 | @inject('mottoStore')
12 | @observer
13 | class Motto extends Component {
14 | constructor(props) {
15 | super(props);
16 | this.state = {};
17 | }
18 |
19 |
20 | componentDidMount() {
21 | const { mottoStore } = this.props;
22 | mottoStore.getData();
23 | }
24 |
25 | render() {
26 | const { mottoStore } = this.props;
27 | const selectedRowKeysLength = mottoStore.selectedRowKeys.length;
28 | const rowSelection = {
29 | selectedRowKeys: mottoStore.selectedRowKeys,
30 | onChange: mottoStore.onSelectChange,
31 | };
32 | const pagination = {
33 | total: mottoStore.dataSource.length,
34 | showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} items`,
35 | pageSize: 10,
36 | defaultCurrent: 1,
37 | };
38 | return (
39 |
40 |
41 |
55 |
1 ? 'items' : 'item'}?`}
57 | icon={}
58 | onConfirm={() => mottoStore.batchDelete()}
59 | >
60 |
70 |
71 |
72 | {selectedRowKeysLength > 0 ? `Selected ${selectedRowKeysLength} ${selectedRowKeysLength > 1 ? 'items' : 'item'}` : ''}
73 |
74 |
75 | record._id} /* eslint-disable-line */
77 | dataSource={mottoStore.dataSource}
78 | rowSelection={rowSelection}
79 | pagination={pagination}
80 | >
81 |
82 |
87 |
92 | (
96 |
97 | mottoStore.openModal('update', record._id, record.content) /* eslint-disable-line */
104 | }
105 | />
106 | }
109 | onConfirm={() => mottoStore.deleteData(record._id)} /* eslint-disable-line */
110 | >
111 |
117 |
118 |
119 | )}
120 | />
121 |
122 |
123 |
126 |
132 | {mottoStore.modalType === 'add' ? 'Add New' : 'Update The'}
133 | {' '}
134 | Motto
135 |
136 | )}
137 | width={600}
138 | wrapClassName="reset_modal"
139 | closable={false}
140 | destroyOnClose
141 | visible={mottoStore.showModal}
142 | okButtonProps={{ disabled: !mottoStore.isFilled }}
143 | okText={capitalized(mottoStore.modalType)}
144 | onOk={mottoStore.modalType === 'add' ? () => mottoStore.insertData() : () => mottoStore.modifyData()}
145 | onCancel={mottoStore.closeModal}
146 | >
147 |
148 |
149 |
150 | Motto Content:
151 |
152 |
153 |
154 | mottoStore.onContentChange(event)}
158 | />
159 |
160 |
161 |
162 |
163 | );
164 | }
165 | }
166 |
167 |
168 | export default Motto;
169 |
--------------------------------------------------------------------------------
/src/containers/Music/LiveTour/LiveTour.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { observer, inject } from 'mobx-react';
3 | import {
4 | Table, Button, Modal, Input, Icon, Popconfirm, Upload, Row, Col,
5 | } from 'antd';
6 | import {
7 | formatJSONDate, beforeUpload, capitalized, checkWebp, webp, upload,
8 | } from '../../../util/tools';
9 |
10 | const { Column, ColumnGroup } = Table;
11 |
12 | @inject('liveTourStore')
13 | @observer
14 | class Project extends Component {
15 | constructor(props) {
16 | super(props);
17 | this.state = {};
18 | }
19 |
20 | componentDidMount() {
21 | const { liveTourStore } = this.props;
22 | liveTourStore.getData();
23 | }
24 |
25 | render() {
26 | const { liveTourStore } = this.props;
27 | const selectedRowKeysLength = liveTourStore.selectedRowKeys.length;
28 | const rowSelection = {
29 | selectedRowKeys: liveTourStore.selectedRowKeys,
30 | onChange: liveTourStore.onSelectChange,
31 | };
32 | const pagination = {
33 | total: liveTourStore.dataSource.length,
34 | showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} items`,
35 | pageSize: 10,
36 | defaultCurrent: 1,
37 | };
38 | const uploadButton = (
39 |
43 | );
44 | return (
45 |
46 |
47 |
61 |
1 ? 'items' : 'item'}?`}
63 | icon={}
64 | onConfirm={() => liveTourStore.batchDelete()}
65 | >
66 |
76 |
77 |
78 | {selectedRowKeysLength > 0 ? `Selected ${selectedRowKeysLength} ${selectedRowKeysLength > 1 ? 'items' : 'item'}` : ''}
79 |
80 |
81 | record._id} /* eslint-disable-line */
83 | dataSource={liveTourStore.dataSource}
84 | rowSelection={rowSelection}
85 | pagination={pagination}
86 | >
87 |
88 |
93 |
98 | (
102 |
103 |
Modal.info({
110 | width: 740,
111 | iconType: 'zoom-in',
112 | maskClosable: true,
113 | title: 'Look full size picture',
114 | content:
,
121 | })}
122 | />
123 |
124 | )}
125 | />
126 | (
130 |
131 | {formatJSONDate(record.upload_date)}
132 |
133 | )}
134 | />
135 | (
139 |
140 | liveTourStore.openModal('update', record._id, record.title, record.poster) /* eslint-disable-line */
147 | }
148 | />
149 | }
152 | onConfirm={() => liveTourStore.deleteData(record._id)} /* eslint-disable-line */
153 | >
154 |
160 |
161 |
162 | )}
163 | />
164 |
165 |
166 |
169 |
175 | {liveTourStore.modalType === 'add' ? 'Add New' : 'Update The'}
176 | {' '}
177 | Live Tour
178 |
179 | )}
180 | width={600}
181 | wrapClassName="reset_modal"
182 | closable={false}
183 | destroyOnClose
184 | visible={liveTourStore.showModal}
185 | okButtonProps={{ disabled: !liveTourStore.isFilled }}
186 | okText={capitalized(liveTourStore.modalType)}
187 | onOk={liveTourStore.modalType === 'add' ? () => liveTourStore.insertData() : () => liveTourStore.modifyData()}
188 | onCancel={liveTourStore.closeModal}
189 | >
190 |
191 |
192 |
193 | Live Tour Title:
194 |
195 |
196 |
197 | liveTourStore.onTitleChange(event)}
201 | />
202 |
203 |
204 |
205 | Upload Poster:
206 |
207 |
208 |
209 |
210 |
219 | {liveTourStore.poster ?
: uploadButton}
220 |
221 |
222 |
223 |
224 |
225 | );
226 | }
227 | }
228 |
229 |
230 | export default Project;
231 |
--------------------------------------------------------------------------------
/src/containers/Music/Player/player.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | /*# sourceMappingURL=player.css.map */
4 |
--------------------------------------------------------------------------------
/src/containers/Music/Player/player.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "",
4 | "sources": [],
5 | "names": [],
6 | "file": "player.css"
7 | }
--------------------------------------------------------------------------------
/src/containers/Music/Player/player.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yancey-Blog/BLOG_CMS/6ce26e1a910c03b4914ef0d522632f2bfdb90adf/src/containers/Music/Player/player.scss
--------------------------------------------------------------------------------
/src/containers/Overview/OverView.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { Component } from 'react';
3 | import ServerStatus from '../../components/ServerStatus/ServerStatus';
4 | import ArticleStatistics from '../../components/ArticleStatistics/ArticleStatistics';
5 | import './overview.css';
6 |
7 | class OverView extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = {};
11 | }
12 |
13 | componentWillMount() {
14 | }
15 |
16 | componentDidMount() {
17 | }
18 |
19 | componentWillUnmount() {
20 | }
21 |
22 | render() {
23 | return (
24 |
25 |
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 |
33 | export default OverView;
34 |
--------------------------------------------------------------------------------
/src/containers/Overview/overview.css:
--------------------------------------------------------------------------------
1 | .overview_wrapper {
2 | background: #f0f2f5 !important;
3 | padding: 0 !important; }
4 |
5 | /*# sourceMappingURL=overview.css.map */
6 |
--------------------------------------------------------------------------------
/src/containers/Overview/overview.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAAA,iBAAkB;EAChB,UAAU,EAAE,kBAAkB;EAC9B,OAAO,EAAE,YAAY",
4 | "sources": ["overview.scss"],
5 | "names": [],
6 | "file": "overview.css"
7 | }
--------------------------------------------------------------------------------
/src/containers/Overview/overview.scss:
--------------------------------------------------------------------------------
1 | .overview_wrapper {
2 | background: #f0f2f5 !important;
3 | padding: 0 !important;
4 | }
5 |
--------------------------------------------------------------------------------
/src/containers/Page/Login/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Recaptcha from 'react-google-recaptcha';
3 | import './login.css';
4 | import { inject, observer } from 'mobx-react/index';
5 |
6 | @inject('loginStore')
7 | @observer
8 | class Login extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {};
12 | }
13 |
14 | componentDidMount() {
15 | }
16 |
17 | render() {
18 | const { loginStore } = this.props;
19 | window.recaptchaOptions = {
20 | lang: 'ja',
21 | };
22 | const btnStyle = {
23 | background: '#ccc',
24 | boxShadow: '0 0 4px #ccc',
25 | cursor: 'not-allowed',
26 | };
27 | return (
28 |
29 |
30 |
67 |
68 | );
69 | }
70 | }
71 |
72 |
73 | export default Login;
74 |
--------------------------------------------------------------------------------
/src/containers/Page/Login/login.css:
--------------------------------------------------------------------------------
1 | .login_wrapper {
2 | display: flex;
3 | position: relative;
4 | width: 100vw;
5 | height: 100vh;
6 | overflow: hidden;
7 | font-family: Lato, sans-serif; }
8 | .login_wrapper figure {
9 | margin: 0;
10 | padding: 0; }
11 | .login_wrapper .blur_bg {
12 | position: absolute;
13 | top: -4px;
14 | left: -4px;
15 | width: calc(100% + 8px);
16 | height: calc(100% + 8px);
17 | z-index: -1;
18 | background: url(./wew.png) no-repeat center top;
19 | background-size: cover;
20 | -webkit-filter: blur(2px);
21 | filter: blur(2px); }
22 |
23 | .login_container {
24 | width: 372px;
25 | height: 520px;
26 | margin: auto;
27 | padding: 0 35px;
28 | background: rgba(255, 255, 255, 0.45);
29 | border-radius: 6px; }
30 | .login_container .title_img {
31 | width: 200px;
32 | height: 50px;
33 | margin: 25px auto;
34 | background: url("./yancey-official-blog-logo.png") no-repeat center top;
35 | background-size: contain;
36 | text-align: center; }
37 | .login_container .user_input_group {
38 | margin-bottom: 18px; }
39 | .login_container .user_input_group label, .login_container .user_input_group span {
40 | color: #585858;
41 | font-size: 14px;
42 | cursor: pointer; }
43 | .login_container .user_input_group span {
44 | margin-bottom: 10px;
45 | display: inline-block; }
46 | .login_container .user_input_group input {
47 | display: block;
48 | width: 100%;
49 | margin-top: 10px;
50 | border: 1px solid #EAEAEA;
51 | background: none;
52 | padding: 5px 10px;
53 | color: #444;
54 | font-weight: normal;
55 | font-size: 14px;
56 | background: #FFF;
57 | box-shadow: 0 0 0 1000px white inset;
58 | height: 46px;
59 | border-radius: 3px;
60 | outline: none; }
61 | .login_container .user_input_group input:focus {
62 | border: 1px solid #FF5656; }
63 | .login_container .login_btn {
64 | width: 100%;
65 | margin: 16px auto;
66 | border: none;
67 | float: none;
68 | border-radius: 30px;
69 | height: 50px;
70 | font-size: 14px;
71 | text-align: center;
72 | color: #FFF;
73 | background: #FF5656;
74 | font-weight: normal;
75 | cursor: pointer;
76 | box-shadow: none;
77 | text-shadow: none;
78 | letter-spacing: 2px;
79 | outline: none;
80 | transition-property: all;
81 | transition-duration: 0.25s, 0.15s, 0s;
82 | transition-timing-function: cubic-bezier(0.31, 0.32, 0.38, 2), linear, linear;
83 | transition-delay: 0s, 0s, 0.15s;
84 | transform: scale3d(1, 1, 1); }
85 | .login_container .login_btn:hover {
86 | box-shadow: 0 0 4px rgba(241, 39, 66, 0.85);
87 | transform: scale3d(1.05, 1.05, 1); }
88 |
89 |
--------------------------------------------------------------------------------
/src/containers/Page/Login/login.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAAA,cAAe;EACb,OAAO,EAAE,IAAI;EACb,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,KAAK;EACZ,MAAM,EAAE,KAAK;EACb,QAAQ,EAAE,MAAM;EAChB,WAAW,EAAE,gBAAgB;EAC7B,qBAAO;IACL,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,CAAC;EAEZ,uBAAS;IACP,QAAQ,EAAE,QAAQ;IAClB,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,gBAAgB;IACvB,MAAM,EAAE,gBAAgB;IACxB,OAAO,EAAE,EAAE;IACX,UAAU,EAAE,mCAAmC;IAC/C,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,SAAS;IACzB,MAAM,EAAE,SAAS;;AAIrB,gBAAiB;EACf,KAAK,EAAE,KAAK;EACZ,MAAM,EAAE,KAAK;EACb,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,MAAM;EACf,UAAU,EAAE,yBAAyB;EACrC,aAAa,EAAE,GAAG;EAClB,2BAAW;IACT,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,SAAS;IACjB,UAAU,EAAE,2DAA2D;IACvE,eAAe,EAAE,OAAO;IACxB,UAAU,EAAE,MAAM;EAEpB,kCAAkB;IAChB,aAAa,EAAE,IAAI;IACnB,iFAAY;MACV,KAAK,EAAE,OAAO;MACd,SAAS,EAAE,IAAI;MACf,MAAM,EAAE,OAAO;IAEjB,uCAAK;MACH,aAAa,EAAE,IAAI;MACnB,OAAO,EAAE,YAAY;IAEvB,wCAAM;MACJ,OAAO,EAAE,KAAK;MACd,KAAK,EAAE,IAAI;MACX,UAAU,EAAE,IAAI;MAChB,MAAM,EAAE,iBAAiB;MACzB,UAAU,EAAE,IAAI;MAChB,OAAO,EAAE,QAAQ;MACjB,KAAK,EAAE,IAAI;MACX,WAAW,EAAE,MAAM;MACnB,SAAS,EAAE,IAAI;MACf,UAAU,EAAE,IAAI;MAChB,UAAU,EAAE,wBAAwB;MACpC,MAAM,EAAE,IAAI;MACZ,aAAa,EAAE,GAAG;MAClB,OAAO,EAAE,IAAI;MACb,8CAAQ;QACN,MAAM,EAAE,iBAAiB;EAI/B,2BAAW;IACT,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,aAAa,EAAE,IAAI;IACnB,MAAM,EAAE,IAAI;IACZ,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,MAAM;IAClB,KAAK,EAAE,IAAI;IACX,UAAU,EAAE,OAAO;IACnB,WAAW,EAAE,MAAM;IACnB,MAAM,EAAE,OAAO;IACf,UAAU,EAAE,IAAI;IAChB,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,GAAG;IACnB,OAAO,EAAE,IAAI;IACb,mBAAmB,EAAE,8BAA8B;IACnD,mBAAmB,EAAE,gBAAgB;IACrC,0BAA0B,EAAE,iDAAiD;IAC7E,gBAAgB,EAAE,aAAa;IAC/B,SAAS,EAAE,gBAAgB;IAC3B,iCAAQ;MACN,UAAU,EAAE,+BAA0B;MACtC,SAAS,EAAE,sBAAsB",
4 | "sources": ["login.scss"],
5 | "names": [],
6 | "file": "login.css"
7 | }
--------------------------------------------------------------------------------
/src/containers/Page/Login/login.scss:
--------------------------------------------------------------------------------
1 | .login_wrapper {
2 | display: flex;
3 | position: relative;
4 | width: 100vw;
5 | height: 100vh;
6 | overflow: hidden;
7 | font-family: Lato, sans-serif;
8 | figure {
9 | margin: 0;
10 | padding: 0;
11 | }
12 | .blur_bg {
13 | position: absolute;
14 | top: -4px;
15 | left: -4px;
16 | width: calc(100% + 8px);
17 | height: calc(100% + 8px);
18 | z-index: -1;
19 | background: url(./wew.png) no-repeat center top;
20 | background-size: cover;
21 | -webkit-filter: blur(2px);
22 | filter: blur(2px);
23 | }
24 | }
25 |
26 | .login_container {
27 | width: 372px;
28 | height: 520px;
29 | margin: auto;
30 | padding: 0 35px;
31 | background: rgba(255, 255, 255, 0.45);
32 | border-radius: 6px;
33 | .title_img {
34 | width: 200px;
35 | height: 50px;
36 | margin: 25px auto;
37 | background: url("./yancey-official-blog-logo.png") no-repeat center top;
38 | background-size: contain;
39 | text-align: center;
40 | }
41 | .user_input_group {
42 | margin-bottom: 18px;
43 | label, span {
44 | color: #585858;
45 | font-size: 14px;
46 | cursor: pointer;
47 | }
48 | span {
49 | margin-bottom: 10px;
50 | display: inline-block;
51 | }
52 | input {
53 | display: block;
54 | width: 100%;
55 | margin-top: 10px;
56 | border: 1px solid #EAEAEA;
57 | background: none;
58 | padding: 5px 10px;
59 | color: #444;
60 | font-weight: normal;
61 | font-size: 14px;
62 | background: #FFF;
63 | box-shadow: 0 0 0 1000px white inset;
64 | height: 46px;
65 | border-radius: 3px;
66 | outline: none;
67 | &:focus {
68 | border: 1px solid #FF5656;
69 | }
70 | }
71 | }
72 | .login_btn {
73 | width: 100%;
74 | margin: 16px auto;
75 | border: none;
76 | float: none;
77 | border-radius: 30px;
78 | height: 50px;
79 | font-size: 14px;
80 | text-align: center;
81 | color: #FFF;
82 | background: #FF5656;
83 | font-weight: normal;
84 | cursor: pointer;
85 | box-shadow: none;
86 | text-shadow: none;
87 | letter-spacing: 2px;
88 | outline: none;
89 | transition-property: transform, opacity, visibility;
90 | transition-duration: 0.25s, 0.15s, 0s;
91 | transition-timing-function: cubic-bezier(0.31, 0.32, 0.38, 2), linear, linear;
92 | transition-delay: 0s, 0s, 0.15s;
93 | transform: scale3d(1, 1, 1);
94 | &:hover {
95 | box-shadow: 0 0 4px rgba(#F12742, .85);
96 | transform: scale3d(1.05, 1.05, 1);
97 | }
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/src/containers/Page/Login/wew.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yancey-Blog/BLOG_CMS/6ce26e1a910c03b4914ef0d522632f2bfdb90adf/src/containers/Page/Login/wew.png
--------------------------------------------------------------------------------
/src/containers/Page/Login/yancey-official-blog-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yancey-Blog/BLOG_CMS/6ce26e1a910c03b4914ef0d522632f2bfdb90adf/src/containers/Page/Login/yancey-official-blog-logo.png
--------------------------------------------------------------------------------
/src/containers/Setting/Setting.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { observer, inject } from 'mobx-react';
3 | import { Link, Switch, Route } from 'react-router-dom';
4 | import { Menu, Icon } from 'antd';
5 | import UserInfo from '../../components/UserInfo/UserInfo';
6 | import SecurityCenter from '../../components/SecurityCenter/SecurityCenter';
7 | import GlobalConfig from '../../components/GlobalConfig/GlobalConfig';
8 | import Exception from '../Exception/Exception';
9 |
10 | @inject('announcementStore')
11 | @observer
12 | class Setting extends Component {
13 | constructor(props) {
14 | super(props);
15 | this.state = {};
16 | }
17 |
18 |
19 | componentDidMount() {
20 | }
21 |
22 | render() {
23 | const layout = {
24 | display: 'grid',
25 | gridTemplateColumns: '16% 84%',
26 | };
27 | return (
28 |
32 |
33 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 |
74 | export default Setting;
75 |
--------------------------------------------------------------------------------
/src/history.js:
--------------------------------------------------------------------------------
1 | import * as history from 'history';
2 |
3 | const createHistory = history.createBrowserHistory;
4 |
5 | export default createHistory();
6 |
--------------------------------------------------------------------------------
/src/http/AboutApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class AboutApi {
6 | getData = () => GET('/abouts', {});
7 |
8 | insertData = params => POST('/abouts', params);
9 |
10 | modifyData = (id, params) => PUT(`/abouts/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/abouts/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchAbouts', params);
15 | }
16 |
17 | const aboutApi = new AboutApi();
18 |
19 | export default aboutApi;
20 |
--------------------------------------------------------------------------------
/src/http/AnnouncementApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class AnnouncementApi {
6 | getData = () => GET('/announcements', {});
7 |
8 | insertData = params => POST('/announcements', params);
9 |
10 | modifyData = (id, params) => PUT(`/announcements/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/announcements/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchAnnouncements', params);
15 | }
16 |
17 | const announcementApi = new AnnouncementApi();
18 |
19 | export default announcementApi;
20 |
--------------------------------------------------------------------------------
/src/http/ArticleApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class ArticleApi {
6 | getData = () => GET('/articles', {});
7 |
8 | getDataByPage = page => GET(`/articles/page/${page}`, {});
9 |
10 | getDataByTitle = title => GET(`/articlesByTitle?title=${title}`, {});
11 |
12 | getDataByDay = () => GET('/articlesByDay', {});
13 |
14 | getDataByPV = () => GET('/articlesByPV', {});
15 |
16 | getDataByDateRange = (start, end) => GET(`/articlesByDateRange?start=${start}&end=${end}`, {});
17 |
18 | getDataById = id => GET(`articles/${id}`, {});
19 |
20 | insertData = params => POST('/articles', params);
21 |
22 | modifyData = (id, params) => PUT(`/articles/${id}`, params);
23 |
24 | switchStatus = (id, params) => PUT(`/articleStatus/${id}`, params);
25 |
26 | deleteData = id => DELETE(`/articles/${id}`, {});
27 |
28 | batchDeleteData = params => POST('/batchArticles', params);
29 | }
30 |
31 | const articleApi = new ArticleApi();
32 |
33 | export default articleApi;
34 |
--------------------------------------------------------------------------------
/src/http/CoverApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class CoverApi {
6 | getData = () => GET('/covers', {});
7 |
8 | insertData = params => POST('/covers', params);
9 |
10 | modifyData = (id, params) => PUT(`/covers/${id}`, params);
11 |
12 | showData = (id, params) => PUT(`/covers/show/${id}`, params);
13 |
14 | deleteData = id => DELETE(`/covers/${id}`, {});
15 |
16 | batchDeleteData = params => POST('/batchCovers', params);
17 | }
18 |
19 | const coverApi = new CoverApi();
20 |
21 | export default coverApi;
22 |
--------------------------------------------------------------------------------
/src/http/FeaturedRecordApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class FeaturedRecordApi {
6 | getData = () => GET('/featuredRecords', {});
7 |
8 | insertData = params => POST('/featuredRecords', params);
9 |
10 | modifyData = (id, params) => PUT(`/featuredRecords/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/featuredRecords/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchFeaturedRecords', params);
15 | }
16 |
17 | const featuredRecordApi = new FeaturedRecordApi();
18 |
19 | export default featuredRecordApi;
20 |
--------------------------------------------------------------------------------
/src/http/GlobalApi.js:
--------------------------------------------------------------------------------
1 | import { GET, POST, PUT } from '../util/axios';
2 |
3 | class GlobalApi {
4 | getData = () => GET('/globalStatus', {});
5 |
6 | insertFullSiteGrayData = params => POST('/fullSiteGray', params);
7 |
8 | modifyFullSiteGrayData = (id, params) => PUT(`/fullSiteGray/${id}`, params);
9 | }
10 |
11 | const globalApi = new GlobalApi();
12 |
13 | export default globalApi;
14 |
--------------------------------------------------------------------------------
/src/http/LiveTourApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class LiveTourApi {
6 | getData = () => GET('/liveTours', {});
7 |
8 | insertData = params => POST('/liveTours', params);
9 |
10 | modifyData = (id, params) => PUT(`/liveTours/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/liveTours/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchLiveTours', params);
15 | }
16 |
17 | const liveTourApi = new LiveTourApi();
18 |
19 | export default liveTourApi;
20 |
--------------------------------------------------------------------------------
/src/http/LoginApi.js:
--------------------------------------------------------------------------------
1 | import { POST } from '../util/axios';
2 |
3 | class LoginApi {
4 | login = params => POST('/login', params);
5 |
6 | modifyPassword = params => POST('/modifyPassword', params);
7 | }
8 |
9 | const loginApi = new LoginApi();
10 |
11 | export default loginApi;
12 |
--------------------------------------------------------------------------------
/src/http/MottoApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class MottoApi {
6 | getData = () => GET('/mottoes', {});
7 |
8 | insertData = params => POST('/mottoes', params);
9 |
10 | modifyData = (id, params) => PUT(`/mottoes/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/mottoes/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchMottoes', params);
15 | }
16 |
17 | const mottoApi = new MottoApi();
18 |
19 | export default mottoApi;
20 |
--------------------------------------------------------------------------------
/src/http/PlayerApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class PlayerApi {
6 | getData = () => GET('/players', {});
7 |
8 | insertData = params => POST('/players', params);
9 |
10 | modifyData = (id, params) => PUT(`/players/${id}`, params);
11 |
12 | showData = (id, params) => PUT(`/players/show/${id}`, params);
13 |
14 | deleteData = id => DELETE(`/players/${id}`, {});
15 |
16 | batchDeleteData = params => POST('/batchPlayers', params);
17 | }
18 |
19 | const playerApi = new PlayerApi();
20 |
21 | export default playerApi;
22 |
--------------------------------------------------------------------------------
/src/http/ProgramExperienceApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class ProgramExperienceApi {
6 | getData = () => GET('/programExperience', {});
7 |
8 | insertData = params => POST('/programExperience', params);
9 |
10 | modifyData = (id, params) => PUT(`/programExperience/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/programExperience/${id}`, {});
13 | }
14 |
15 | const programExperienceApi = new ProgramExperienceApi();
16 |
17 | export default programExperienceApi;
18 |
--------------------------------------------------------------------------------
/src/http/ProjectApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class ProjectApi {
6 | getData = () => GET('/projects', {});
7 |
8 | insertData = params => POST('/projects', params);
9 |
10 | modifyData = (id, params) => PUT(`/projects/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/projects/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchProjects', params);
15 | }
16 |
17 | const projectApi = new ProjectApi();
18 |
19 | export default projectApi;
20 |
--------------------------------------------------------------------------------
/src/http/ServerStatusApi.js:
--------------------------------------------------------------------------------
1 | import { GET } from '../util/axios';
2 |
3 | class ServerStatusApi {
4 | getServerData = () => GET('/serviceInfo', {});
5 |
6 | getRawUsageStatusData = () => GET('/usageStats', {});
7 | }
8 |
9 | const serverStatusApi = new ServerStatusApi();
10 |
11 | export default serverStatusApi;
12 |
--------------------------------------------------------------------------------
/src/http/UploadApi.js:
--------------------------------------------------------------------------------
1 | import baseUrl from '../util/baseUrl';
2 |
3 | const uploadApi = `${baseUrl.production}uploads`;
4 |
5 | export default uploadApi;
6 |
--------------------------------------------------------------------------------
/src/http/UserInfoApi.js:
--------------------------------------------------------------------------------
1 | import { GET, POST, PUT } from '../util/axios';
2 |
3 | class UserInfoApi {
4 | getData = () => GET('/userInfo', {});
5 |
6 | insertData = params => POST('/userInfo', params);
7 |
8 | modifyData = (id, params) => PUT(`/userInfo/${id}`, params);
9 | }
10 |
11 | const userInfoApi = new UserInfoApi();
12 |
13 | export default userInfoApi;
14 |
--------------------------------------------------------------------------------
/src/http/WorkExperienceApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class WorkExperienceApi {
6 | getData = () => GET('/workExperience', {});
7 |
8 | insertData = params => POST('/workExperience', params);
9 |
10 | modifyData = (id, params) => PUT(`/workExperience/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/workExperience/${id}`, {});
13 | }
14 |
15 | const workExperienceApi = new WorkExperienceApi();
16 |
17 | export default workExperienceApi;
18 |
--------------------------------------------------------------------------------
/src/http/YanceyMusicApi.js:
--------------------------------------------------------------------------------
1 | import {
2 | DELETE, GET, POST, PUT,
3 | } from '../util/axios';
4 |
5 | class YanceyMusicApi {
6 | getData = () => GET('/yanceyMusic', {});
7 |
8 | insertData = params => POST('/yanceyMusic', params);
9 |
10 | modifyData = (id, params) => PUT(`/yanceyMusic/${id}`, params);
11 |
12 | deleteData = id => DELETE(`/yanceyMusic/${id}`, {});
13 |
14 | batchDeleteData = params => POST('/batchYanceyMusic', params);
15 | }
16 |
17 | const yanceyMusicApi = new YanceyMusicApi();
18 |
19 | export default yanceyMusicApi;
20 |
--------------------------------------------------------------------------------
/src/http/index.js:
--------------------------------------------------------------------------------
1 | import announcementApi from './AnnouncementApi';
2 | import mottoApi from './MottoApi';
3 | import projectApi from './ProjectApi';
4 | import coverApi from './CoverApi';
5 | import liveTourApi from './LiveTourApi';
6 | import featuredRecordApi from './FeaturedRecordApi';
7 | import yanceyMusicApi from './YanceyMusicApi';
8 | import playerApi from './PlayerApi';
9 | import serverStatusApi from './ServerStatusApi';
10 | import workExperienceApi from './WorkExperienceApi';
11 | import programExperienceApi from './ProgramExperienceApi';
12 | import articleApi from './ArticleApi';
13 | import aboutApi from './AboutApi';
14 | import loginApi from './LoginApi';
15 | import uploadApi from './UploadApi';
16 | import userInfoApi from './UserInfoApi';
17 | import globalApi from './GlobalApi';
18 |
19 | export {
20 | mottoApi,
21 | announcementApi,
22 | projectApi,
23 | coverApi,
24 | liveTourApi,
25 | featuredRecordApi,
26 | yanceyMusicApi,
27 | playerApi,
28 | serverStatusApi,
29 | workExperienceApi,
30 | programExperienceApi,
31 | articleApi,
32 | aboutApi,
33 | loginApi,
34 | uploadApi,
35 | userInfoApi,
36 | globalApi,
37 | };
38 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | /*body {*/
2 | /*margin: 0;*/
3 | /*padding: 0;*/
4 | /*font-family: sans-serif;*/
5 | /*}*/
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter } from 'react-router-dom';
4 | import App from './App';
5 | import registerServiceWorker from './registerServiceWorker';
6 |
7 | ReactDOM.render((
8 |
9 |
10 | ),
11 | document.getElementById('root'));
12 | registerServiceWorker();
13 |
--------------------------------------------------------------------------------
/src/layouts/layouts.css:
--------------------------------------------------------------------------------
1 | .ant-layout-sider {
2 | box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); }
3 | .ant-layout-sider .logo {
4 | background: #002140;
5 | height: 64px;
6 | line-height: 64px;
7 | overflow: hidden;
8 | padding-left: 24px;
9 | position: relative;
10 | transition: all .3s; }
11 | .ant-layout-sider .logo img {
12 | width: 32px;
13 | height: 32px; }
14 | .ant-layout-sider .logo h1 {
15 | color: #fff;
16 | display: inline-block;
17 | font-family: Myriad Pro, Helvetica Neue, Arial, Helvetica, sans-serif;
18 | font-size: 18px;
19 | font-weight: 600;
20 | margin: 0 0 0 12px;
21 | vertical-align: middle; }
22 |
23 | .ant-layout-header {
24 | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); }
25 |
26 | .global_config {
27 | display: flex;
28 | align-items: center;
29 | position: absolute;
30 | right: 48px;
31 | top: 0;
32 | font-size: 16px;
33 | color: rgba(0, 0, 0, 0.65); }
34 | .global_config .config_item {
35 | display: inline-block;
36 | padding: 0 12px;
37 | cursor: pointer;
38 | transition: all .3s, padding 0s; }
39 | .global_config .config_item:hover {
40 | background: rgba(0, 0, 0, 0.025); }
41 |
42 | .trigger {
43 | cursor: pointer;
44 | font-size: 20px;
45 | height: 64px;
46 | padding: 22px 24px;
47 | transition: all .3s, padding 0s; }
48 | .trigger:hover {
49 | background: rgba(0, 0, 0, 0.025); }
50 |
51 | /*# sourceMappingURL=layouts.css.map */
52 |
--------------------------------------------------------------------------------
/src/layouts/layouts.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAAA,iBAAkB;EAChB,UAAU,EAAE,+BAA8B;EAC1C,uBAAM;IACJ,UAAU,EAAE,OAAO;IACnB,MAAM,EAAE,IAAI;IACZ,WAAW,EAAE,IAAI;IACjB,QAAQ,EAAE,MAAM;IAChB,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,OAAO;IACnB,2BAAI;MACF,KAAK,EAAE,IAAI;MACX,MAAM,EAAE,IAAI;IAEd,0BAAG;MACD,KAAK,EAAE,IAAI;MACX,OAAO,EAAE,YAAY;MACrB,WAAW,EAAE,wDAAwD;MACrE,SAAS,EAAE,IAAI;MACf,WAAW,EAAE,GAAG;MAChB,MAAM,EAAE,UAAU;MAClB,cAAc,EAAE,MAAM;;AAK5B,kBAAmB;EACjB,UAAU,EAAE,+BAA8B;;AAG5C,cAAe;EACb,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,MAAM;EACnB,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,GAAG,EAAE,CAAC;EACN,SAAS,EAAE,IAAI;EACf,KAAK,EAAE,mBAAkB;EACzB,2BAAa;IACX,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,OAAO;IACf,UAAU,EAAE,mBAAmB;IAC/B,iCAAQ;MACN,UAAU,EAAE,oBAAmB;;AAKrC,QAAS;EACP,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,SAAS;EAClB,UAAU,EAAE,mBAAmB;EAC/B,cAAQ;IACN,UAAU,EAAE,oBAAmB",
4 | "sources": ["layouts.scss"],
5 | "names": [],
6 | "file": "layouts.css"
7 | }
--------------------------------------------------------------------------------
/src/layouts/layouts.scss:
--------------------------------------------------------------------------------
1 | .ant-layout-sider {
2 | box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
3 | .logo {
4 | background: #002140;
5 | height: 64px;
6 | line-height: 64px;
7 | overflow: hidden;
8 | padding-left: 24px;
9 | position: relative;
10 | transition: all .3s;
11 | img {
12 | width: 32px;
13 | height: 32px;
14 | }
15 | h1 {
16 | color: #fff;
17 | display: inline-block;
18 | font-family: Myriad Pro, Helvetica Neue, Arial, Helvetica, sans-serif;
19 | font-size: 18px;
20 | font-weight: 600;
21 | margin: 0 0 0 12px;
22 | vertical-align: middle;
23 | }
24 | }
25 | }
26 |
27 | .ant-layout-header {
28 | box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
29 | }
30 |
31 | .global_config {
32 | display: flex;
33 | align-items: center;
34 | position: absolute;
35 | right: 48px;
36 | top: 0;
37 | font-size: 16px;
38 | color: rgba(0, 0, 0, .65);
39 | .config_item {
40 | display: inline-block;
41 | padding: 0 12px;
42 | cursor: pointer;
43 | transition: all .3s, padding 0s;
44 | &:hover {
45 | background: rgba(0, 0, 0, .025);
46 | }
47 | }
48 | }
49 |
50 | .trigger {
51 | cursor: pointer;
52 | font-size: 20px;
53 | height: 64px;
54 | padding: 22px 24px;
55 | transition: all .3s, padding 0s;
56 | &:hover {
57 | background: rgba(0, 0, 0, .025);
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit data://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/stores/AboutStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { aboutApi } from '../http/index';
6 | import { getCurrentDate } from '../util/tools';
7 |
8 | configure({
9 | strict: 'always',
10 | });
11 |
12 | class AboutStore {
13 | @observable dataSource;
14 |
15 | @observable selectedRowKeys;
16 |
17 | @observable showModal;
18 |
19 | @observable modalType;
20 |
21 | @observable curId;
22 |
23 | @observable title;
24 |
25 | @observable introduction;
26 |
27 | @observable cover;
28 |
29 | @observable releaseDate;
30 |
31 | @observable uploadStatus;
32 |
33 | constructor() {
34 | this.aboutApi = aboutApi;
35 | this.dataSource = [];
36 | this.selectedRowKeys = [];
37 | this.showModal = false;
38 | this.curId = '';
39 | this.modalType = '';
40 | this.title = '';
41 | this.introduction = '';
42 | this.cover = '';
43 | this.releaseDate = '';
44 | this.uploadStatus = false;
45 | }
46 |
47 | getData = async () => {
48 | try {
49 | const response = await this.aboutApi.getData();
50 | runInAction(() => {
51 | this.dataSource = response.data;
52 | });
53 | } catch (e) {
54 | message.error('unknown error!');
55 | }
56 | };
57 |
58 | insertData = async () => {
59 | const params = {
60 | title: this.title,
61 | introduction: this.introduction,
62 | cover: this.cover,
63 | release_date: this.releaseDate,
64 | };
65 | try {
66 | await this.aboutApi.insertData(params);
67 | this.showModal = false;
68 | message.success('insert success');
69 | this.dataSource.splice(0, this.dataSource.length);
70 | await this.getData();
71 | } catch (e) {
72 | message.error('unknown error!');
73 | }
74 | };
75 |
76 | modifyData = async () => {
77 | const params = {
78 | title: this.title,
79 | introduction: this.introduction,
80 | cover: this.cover,
81 | release_date: this.releaseDate,
82 | };
83 | try {
84 | await this.aboutApi.modifyData(this.curId, params);
85 | this.showModal = false;
86 | message.success('modify success');
87 | this.dataSource.splice(0, this.dataSource.length);
88 | await this.getData();
89 | } catch (e) {
90 | message.error('unknown error!');
91 | }
92 | };
93 |
94 | deleteData = async (id) => {
95 | try {
96 | await this.aboutApi.deleteData(id);
97 | message.success('delete success');
98 | this.dataSource.splice(0, this.dataSource.length);
99 | await this.getData();
100 | } catch (e) {
101 | message.error('unknown error!');
102 | }
103 | };
104 |
105 | batchDelete = async () => {
106 | const params = {
107 | selectedList: this.selectedRowKeys,
108 | };
109 | try {
110 | await this.aboutApi.batchDeleteData(params);
111 | message.success('delete success');
112 | this.dataSource.splice(0, this.dataSource.length);
113 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
114 | await this.getData();
115 | } catch (e) {
116 | message.error('unknown error!');
117 | }
118 | };
119 |
120 | @computed get isFilled() {
121 | return this.title !== '' && this.introduction !== '' && this.cover !== '' && this.releaseDate !== '';
122 | }
123 |
124 | @action onSelectChange = (selectedRowKeys) => {
125 | this.selectedRowKeys = selectedRowKeys;
126 | };
127 |
128 | @action openModal = (type, id = '', title = '', introduction = '', releaseDate = getCurrentDate(), cover = '') => {
129 | this.modalType = type;
130 | this.curId = id;
131 | this.title = title;
132 | this.introduction = introduction;
133 | this.releaseDate = releaseDate;
134 | this.cover = cover;
135 | this.showModal = true;
136 | };
137 |
138 | @action closeModal = () => {
139 | this.showModal = false;
140 | this.title = '';
141 | this.introduction = '';
142 | this.cover = '';
143 | this.releaseDate = '';
144 | };
145 |
146 | @action onTitleChange = (e) => {
147 | this.title = e.target.value;
148 | };
149 |
150 | @action onIntroductionChange = (e) => {
151 | this.introduction = e.target.value;
152 | };
153 |
154 |
155 | @action onReleaseDateChange = (date, dateString) => {
156 | this.releaseDate = dateString;
157 | };
158 |
159 | @action onUploadChange = (info) => {
160 | if (info.file.status === 'uploading') {
161 | this.uploadStatus = true;
162 | return;
163 | }
164 | if (info.file.status === 'done') {
165 | this.uploadStatus = false;
166 | this.cover = info.file.response.path;
167 | }
168 | }
169 | }
170 |
171 | const aboutStore = new AboutStore(aboutApi);
172 |
173 | export default aboutStore;
174 |
--------------------------------------------------------------------------------
/src/stores/AnnouncementStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { announcementApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class AnnouncementStore {
12 | @observable dataSource;
13 |
14 | @observable selectedRowKeys;
15 |
16 | @observable showModal;
17 |
18 | @observable modalType;
19 |
20 | @observable curId;
21 |
22 | @observable content;
23 |
24 | constructor() {
25 | this.announcementApi = announcementApi;
26 | this.dataSource = [];
27 | this.selectedRowKeys = [];
28 | this.showModal = false;
29 | this.curId = '';
30 | this.modalType = '';
31 | this.content = '';
32 | }
33 |
34 | getData = async () => {
35 | try {
36 | const response = await this.announcementApi.getData();
37 | runInAction(() => {
38 | this.dataSource = response.data;
39 | });
40 | } catch (e) {
41 | message.error('unknown error!');
42 | }
43 | };
44 |
45 | insertData = async () => {
46 | const params = {
47 | content: this.content,
48 | };
49 | try {
50 | await this.announcementApi.insertData(params);
51 | this.showModal = false;
52 | message.success('insert success');
53 | this.dataSource.splice(0, this.dataSource.length);
54 | await this.getData();
55 | } catch (e) {
56 | message.error('unknown error!');
57 | }
58 | };
59 |
60 | modifyData = async () => {
61 | const params = {
62 | content: this.content,
63 | };
64 | try {
65 | await this.announcementApi.modifyData(this.curId, params);
66 | this.showModal = false;
67 | message.success('modify success');
68 | this.dataSource.splice(0, this.dataSource.length);
69 | await this.getData();
70 | } catch (e) {
71 | message.error('unknown error!');
72 | }
73 | };
74 |
75 | deleteData = async (id) => {
76 | try {
77 | await this.announcementApi.deleteData(id);
78 | message.success('delete success');
79 | this.dataSource.splice(0, this.dataSource.length);
80 | await this.getData();
81 | } catch (e) {
82 | message.error('unknown error!');
83 | }
84 | };
85 |
86 | batchDelete = async () => {
87 | const params = {
88 | selectedList: this.selectedRowKeys,
89 | };
90 | try {
91 | await this.announcementApi.batchDeleteData(params);
92 | message.success('delete success');
93 | this.dataSource.splice(0, this.dataSource.length);
94 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
95 | await this.getData();
96 | } catch (e) {
97 | message.error('unknown error!');
98 | }
99 | };
100 |
101 | @computed get isFilled() {
102 | return this.content !== '';
103 | }
104 |
105 | @action onSelectChange = (selectedRowKeys) => {
106 | this.selectedRowKeys = selectedRowKeys;
107 | };
108 |
109 | @action openModal = (type, id = '', content = '') => {
110 | this.modalType = type;
111 | this.curId = id;
112 | this.content = content;
113 | this.showModal = true;
114 | };
115 |
116 | @action closeModal = () => {
117 | this.showModal = false;
118 | this.content = '';
119 | };
120 |
121 | @action onContentChange = (e) => {
122 | this.content = e.target.value;
123 | };
124 | }
125 |
126 | const announcementStore = new AnnouncementStore(announcementApi);
127 |
128 | export default announcementStore;
129 |
--------------------------------------------------------------------------------
/src/stores/ArticleDetailStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import Editor from 'tui-editor';
6 | import { articleApi } from '../http/index';
7 | import history from '../history';
8 |
9 | configure({
10 | strict: 'always',
11 | });
12 |
13 | class ArticleDetailStore {
14 | @observable headerCover;
15 |
16 | @observable title;
17 |
18 | @observable summary;
19 |
20 | @observable uploadStatus;
21 |
22 | @observable editorImage;
23 |
24 | @observable editorImageName;
25 |
26 | @observable editorInstance;
27 |
28 | @observable tags;
29 |
30 | @observable inputVisible;
31 |
32 | @observable inputValue;
33 |
34 | @observable activity;
35 |
36 | constructor() {
37 | this.articleApi = articleApi;
38 | this.headerCover = '';
39 | this.title = '';
40 | this.summary = '';
41 | this.tags = [];
42 | this.uploadStatus = false;
43 | this.editorImage = '';
44 | this.editorImageName = '';
45 | this.editorInstance = {};
46 | this.inputVisible = false;
47 | this.inputValue = '';
48 | this.activity = '';
49 | }
50 |
51 | initEditor = () => {
52 | const editor = new Editor({
53 | el: document.querySelector('#editSection'),
54 | initialEditType: 'markdown',
55 | previewStyle: 'vertical',
56 | height: '800px',
57 | hideModeSwitch: true,
58 | exts: ['scrollSync'],
59 | toolbarItems: [
60 | 'heading',
61 | 'bold',
62 | 'italic',
63 | 'strike',
64 | 'divider',
65 | 'hr',
66 | 'quote',
67 | 'divider',
68 | 'ul',
69 | 'ol',
70 | 'task',
71 | 'indent',
72 | 'outdent',
73 | 'divider',
74 | 'table',
75 | 'link',
76 | 'divider',
77 | 'code',
78 | 'codeblock',
79 | 'divider',
80 | ],
81 | });
82 | const toolbar = editor.getUI()
83 | .getToolbar();
84 | toolbar.addButton({
85 | name: 'upload',
86 | className: 'tui-image',
87 | event: 'upload',
88 | tooltip: 'Upload Images',
89 | }, -1);
90 | this.editorInstance = editor;
91 | };
92 |
93 | insertData = async (content, status) => {
94 | const params = {
95 | header_cover: this.headerCover,
96 | title: this.title,
97 | summary: this.summary,
98 | content,
99 | tags: this.tags,
100 | status,
101 | };
102 | try {
103 | const response = await this.articleApi.insertData(params);
104 | message.success('insert success');
105 | if (this.activity === 'toUpdate') {
106 | history.push(`/article/update/${response.data._id}`); /* eslint-disable-line */
107 | } else {
108 | history.push('/article/list');
109 | }
110 | } catch (e) {
111 | message.error('unknown error!');
112 | }
113 | };
114 |
115 | getDataById = async () => {
116 | try {
117 | const response = await this.articleApi.getDataById(this.curId);
118 | runInAction(() => {
119 | this.headerCover = response.data.curArticle.header_cover;
120 | this.title = response.data.curArticle.title;
121 | this.summary = response.data.curArticle.summary;
122 | this.tags = response.data.curArticle.tags;
123 | this.editorInstance.insertText(this.editorInstance.convertor.toMarkdown(response.data.curArticle.content));
124 | });
125 | } catch (e) {
126 | message.error('no this article!');
127 | history.push('/exception');
128 | }
129 | };
130 |
131 | modifyData = async (content, status) => {
132 | const params = {
133 | header_cover: this.headerCover,
134 | title: this.title,
135 | summary: this.summary,
136 | content,
137 | tags: this.tags,
138 | status,
139 | };
140 | try {
141 | await this.articleApi.modifyData(this.curId, params);
142 | message.success('modify success');
143 | if (this.activity === 'toList') {
144 | history.push('/article/list');
145 | }
146 | } catch (e) {
147 | message.error('unknown error!');
148 | }
149 | };
150 |
151 | clearData = () => {
152 | this.headerCover = '';
153 | this.title = '';
154 | this.summary = '';
155 | this.tags = [];
156 | };
157 |
158 | @computed get curId() {
159 | return document.location.pathname.split('/')
160 | .slice(-1)[0];
161 | }
162 |
163 | // input change listening
164 | @action onHeaderCoverChange = (e) => {
165 | this.headerCover = e.target.value;
166 | };
167 |
168 | @action onTitleChange = (e) => {
169 | this.title = e.target.value;
170 | };
171 |
172 | @action onSummaryChange = (e) => {
173 | this.summary = e.target.value;
174 | };
175 |
176 | @action onContentChange = (e) => {
177 | this.content = e.target.value;
178 | };
179 |
180 | @action onTagsChange = (e) => {
181 | this.tags = e.target.value;
182 | };
183 |
184 | @action onHeaderCoverUploadChange = (info) => {
185 | if (info.file.status === 'uploading') {
186 | this.uploadStatus = true;
187 | return;
188 | }
189 | if (info.file.status === 'done') {
190 | this.uploadStatus = false;
191 | this.headerCover = info.file.response.path;
192 | }
193 | };
194 |
195 | @action onContentImageUploadChange = (info) => {
196 | if (info.file.status === 'done') {
197 | message.success(`${info.file.name} file uploaded successfully.`);
198 | this.editorImageName = info.file.name;
199 | this.editorImage = info.file.response.path;
200 | } else if (info.file.status === 'error') {
201 | message.error(`${info.file.name} file upload failed.`);
202 | }
203 | };
204 |
205 | // tags
206 | @action handleClose = (removedTag) => {
207 | this.tags = this.tags.filter(tag => tag !== removedTag);
208 | };
209 |
210 | @action showInput = () => {
211 | this.inputVisible = true;
212 | };
213 |
214 | @action handleInputChange = (e) => {
215 | this.inputValue = e.target.value;
216 | };
217 |
218 | @action handleInputConfirm = () => {
219 | if (this.inputValue && this.tags.indexOf(this.inputValue) === -1) {
220 | this.tags = [...this.tags, this.inputValue];
221 | }
222 | this.inputValue = '';
223 | this.inputVisible = false;
224 | };
225 |
226 | saveInputRef = input => this.input = input; /* eslint-disable-line */
227 |
228 | @computed get isFilled() {
229 | return this.headerCover !== '' && this.title !== '' && this.summary !== '' && this.tags.length !== 0;
230 | }
231 |
232 | // save
233 | @action handleSave = async (activity, content, status) => {
234 | if (content) {
235 | if (this.isFilled) {
236 | this.activity = activity;
237 | if (window.location.pathname.indexOf('update') !== -1) {
238 | await this.modifyData(content, status);
239 | } else {
240 | await this.insertData(content, status);
241 | }
242 | } else {
243 | message.error('All items are required!');
244 | }
245 | } else {
246 | message.error('Write something?');
247 | }
248 | };
249 | }
250 |
251 | const articleDetailStore = new ArticleDetailStore(articleApi);
252 |
253 | export default articleDetailStore;
254 |
--------------------------------------------------------------------------------
/src/stores/ArticleStore.js:
--------------------------------------------------------------------------------
1 | import { action, observable, configure, runInAction } from 'mobx';
2 | import { message } from 'antd/lib/index';
3 | import { articleApi } from '../http/index';
4 |
5 | configure({
6 | strict: 'always'
7 | });
8 |
9 | class ArticleStore {
10 | @observable dataSource;
11 |
12 | @observable dayDataSource;
13 |
14 | @observable PVDataSource;
15 |
16 | @observable selectedRowKeys;
17 |
18 | @observable curId;
19 |
20 | @observable curPage;
21 |
22 | @observable totalAmount;
23 |
24 | @observable spinning;
25 |
26 | constructor() {
27 | this.articleApi = articleApi;
28 | this.dataSource = [];
29 | this.dayDataSource = [];
30 | this.PVDataSource = [];
31 | this.selectedRowKeys = [];
32 | this.curId = '';
33 | this.curPage = 1;
34 | this.totalAmount = 0;
35 | this.spinning = false;
36 | }
37 |
38 | getData = async () => {
39 | this.spinning = true;
40 | try {
41 | const response = await this.articleApi.getDataByPage(this.curPage);
42 | runInAction(() => {
43 | this.dataSource.splice(0, this.dataSource.length);
44 | this.dataSource = response.data;
45 | this.totalAmount = parseInt(response.headers.amount, 10);
46 | this.spinning = false;
47 | window.scrollTo(0, 0);
48 | });
49 | } catch (e) {
50 | message.error('unknown error');
51 | }
52 | };
53 |
54 | getDataByTitle = async title => {
55 | this.spinning = true;
56 | try {
57 | const response = await this.articleApi.getDataByTitle(title);
58 | runInAction(() => {
59 | this.dataSource.splice(0, this.dataSource.length);
60 | this.dataSource = response.data;
61 | this.totalAmount = parseInt(response.headers.amount, 10);
62 | this.spinning = false;
63 | });
64 | } catch (e) {
65 | message.error('unknown error');
66 | }
67 | };
68 |
69 | getDataByDay = async () => {
70 | try {
71 | const response = await this.articleApi.getDataByDay();
72 | runInAction(() => {
73 | const arr = [];
74 | for (let i = 0, l = response.data.length; i < l; i += 1) {
75 | const obj = {
76 | date: response.data[i]._id /* eslint-disable-line */,
77 | count: response.data[i].count
78 | };
79 | arr.push(obj);
80 | }
81 | this.dayDataSource = arr;
82 | });
83 | } catch (e) {
84 | // todo
85 | }
86 | };
87 |
88 | getDataByPV = async () => {
89 | try {
90 | const response = await this.articleApi.getDataByPV();
91 | runInAction(() => {
92 | const arr = [];
93 | for (let i = 0, l = response.data.length; i < l; i += 1) {
94 | const obj = {
95 | title: response.data[i].title /* eslint-disable-line */,
96 | pv_count: response.data[i].pv_count
97 | };
98 | arr.push(obj);
99 | }
100 | this.PVDataSource = arr;
101 | });
102 | } catch (e) {
103 | // todo
104 | }
105 | };
106 |
107 | getDataByDateRange = async (start, end) => {
108 | this.spinning = true;
109 | try {
110 | const response = await this.articleApi.getDataByDateRange(start, end);
111 | runInAction(() => {
112 | this.dataSource.splice(0, this.dataSource.length);
113 | this.dataSource = response.data;
114 | this.totalAmount = parseInt(response.headers.amount, 10);
115 | this.spinning = false;
116 | });
117 | } catch (e) {
118 | message.error('no articles!');
119 | }
120 | };
121 |
122 | switchStatus = async (id, checked) => {
123 | const params = {
124 | status: checked
125 | };
126 | try {
127 | await this.articleApi.switchStatus(id, params);
128 | if (checked) {
129 | message.success('this article has been published');
130 | } else {
131 | message.success('the article will be hidden');
132 | }
133 | this.dataSource.splice(0, this.dataSource.length);
134 | await this.getData();
135 | } catch (e) {
136 | message.error('unknown error!');
137 | }
138 | };
139 |
140 | deleteData = async id => {
141 | try {
142 | await this.articleApi.deleteData(id);
143 | message.success('delete success');
144 | this.dataSource.splice(0, this.dataSource.length);
145 | await this.getData();
146 | } catch (e) {
147 | message.error('unknown error!');
148 | }
149 | };
150 |
151 | batchDelete = async () => {
152 | const params = {
153 | selectedList: this.selectedRowKeys
154 | };
155 | try {
156 | await this.articleApi.batchDeleteData(params);
157 | message.success('delete success');
158 | this.dataSource.splice(0, this.dataSource.length);
159 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
160 | await this.getData();
161 | } catch (e) {
162 | message.error('unknown error!');
163 | }
164 | };
165 |
166 | @action onSelectChange = selectedRowKeys => {
167 | this.selectedRowKeys = selectedRowKeys;
168 | };
169 |
170 | @action onSwitchPage = pageNumber => {
171 | this.curPage = pageNumber;
172 | this.getData();
173 | // reset pageNumber, make sure the first request is the first page
174 | this.curPage = 1;
175 | };
176 |
177 | @action onTitleSearchChange = value => {
178 | this.getDataByTitle(value);
179 | };
180 |
181 | @action onDateRangeSearchChange = (date, daterange) => {
182 | this.getDataByDateRange(daterange[0], daterange[1]);
183 | };
184 |
185 | @action resetSearch = () => {
186 | this.getData();
187 | };
188 | }
189 |
190 | const articleStore = new ArticleStore(articleApi);
191 |
192 | export default articleStore;
193 |
--------------------------------------------------------------------------------
/src/stores/CoverStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { coverApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class CoverStore {
12 | @observable dataSource;
13 |
14 | @observable selectedRowKeys;
15 |
16 | @observable showModal;
17 |
18 | @observable modalType;
19 |
20 | @observable curId;
21 |
22 | @observable curShow;
23 |
24 | @observable name;
25 |
26 | @observable coverUrl;
27 |
28 | @observable uploadStatus;
29 |
30 | constructor() {
31 | this.coverApi = coverApi;
32 | this.dataSource = [];
33 | this.selectedRowKeys = [];
34 | this.showModal = false;
35 | this.curId = '';
36 | this.curShow = true;
37 | this.modalType = '';
38 | this.name = '';
39 | this.coverUrl = '';
40 | this.uploadStatus = false;
41 | }
42 |
43 | getData = async () => {
44 | try {
45 | const response = await this.coverApi.getData();
46 | runInAction(() => {
47 | this.dataSource = response.data;
48 | });
49 | } catch (e) {
50 | message.error('unknown error!');
51 | }
52 | };
53 |
54 | insertData = async () => {
55 | const params = {
56 | name: this.name,
57 | url: this.coverUrl,
58 | show: true,
59 | };
60 | try {
61 | await this.coverApi.insertData(params);
62 | this.showModal = false;
63 | message.success('insert success');
64 | this.dataSource.splice(0, this.dataSource.length);
65 | await this.getData();
66 | } catch (e) {
67 | message.error('unknown error!');
68 | }
69 | };
70 |
71 | modifyData = async () => {
72 | const params = {
73 | name: this.name,
74 | url: this.coverUrl,
75 | show: this.curShow,
76 | };
77 | try {
78 | await this.coverApi.modifyData(this.curId, params);
79 | this.showModal = false;
80 | message.success('modify success');
81 | this.dataSource.splice(0, this.dataSource.length);
82 | await this.getData();
83 | } catch (e) {
84 | message.error('unknown error!');
85 | }
86 | };
87 |
88 | onSwitchShow = async (id, name, url, checked) => {
89 | const params = {
90 | name,
91 | url,
92 | show: checked,
93 | };
94 | try {
95 | const response = await this.coverApi.modifyData(id, params);
96 | if (checked) {
97 | message.success(`"${response.data.name}" will be shown`);
98 | } else {
99 | message.success(`"${response.data.name}" will be hidden`);
100 | }
101 | this.dataSource.splice(0, this.dataSource.length);
102 | await this.getData();
103 | } catch (e) {
104 | message.error('unknown error!');
105 | }
106 | };
107 |
108 | deleteData = async (id) => {
109 | try {
110 | await this.coverApi.deleteData(id);
111 | message.success('delete success');
112 | this.dataSource.splice(0, this.dataSource.length);
113 | await this.getData();
114 | } catch (e) {
115 | message.error('unknown error!');
116 | }
117 | };
118 |
119 | batchDelete = async () => {
120 | const params = {
121 | selectedList: this.selectedRowKeys,
122 | };
123 | try {
124 | await this.coverApi.batchDeleteData(params);
125 | message.success('delete success');
126 | this.dataSource.splice(0, this.dataSource.length);
127 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
128 | await this.getData();
129 | } catch (e) {
130 | message.error('unknown error!');
131 | }
132 | };
133 |
134 | @computed get isFilled() {
135 | return this.name !== '' && this.coverUrl !== '';
136 | }
137 |
138 | @action onSelectChange = (selectedRowKeys) => {
139 | this.selectedRowKeys = selectedRowKeys;
140 | };
141 |
142 | @action openModal = (type, id = '', name = '', coverUrl = '', curShow) => {
143 | this.modalType = type;
144 | this.curId = id;
145 | this.curShow = curShow;
146 | this.name = name;
147 | this.coverUrl = coverUrl;
148 | this.showModal = true;
149 | };
150 |
151 | @action closeModal = () => {
152 | this.showModal = false;
153 | this.name = '';
154 | this.coverUrl = '';
155 | };
156 |
157 | @action onTitleChange = (e) => {
158 | this.name = e.target.value;
159 | };
160 |
161 | @action onUploadChange = (info) => {
162 | if (info.file.status === 'uploading') {
163 | this.uploadStatus = true;
164 | return;
165 | }
166 | if (info.file.status === 'done') {
167 | this.uploadStatus = false;
168 | this.coverUrl = info.file.response.path;
169 | }
170 | };
171 | }
172 |
173 | const coverStore = new CoverStore(coverApi);
174 |
175 | export default coverStore;
176 |
--------------------------------------------------------------------------------
/src/stores/FeaturedRecordStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { featuredRecordApi } from '../http/index';
6 | import { getCurrentDate } from '../util/tools';
7 |
8 | configure({
9 | strict: 'always',
10 | });
11 |
12 | class FeaturedRecordStore {
13 | @observable dataSource;
14 |
15 | @observable selectedRowKeys;
16 |
17 | @observable showModal;
18 |
19 | @observable modalType;
20 |
21 | @observable curId;
22 |
23 | @observable albumName;
24 |
25 | @observable artist;
26 |
27 | @observable cover;
28 |
29 | @observable buyUrl;
30 |
31 | @observable releaseDate;
32 |
33 | @observable uploadStatus;
34 |
35 | constructor() {
36 | this.featuredRecordApi = featuredRecordApi;
37 | this.dataSource = [];
38 | this.selectedRowKeys = [];
39 | this.showModal = false;
40 | this.curId = '';
41 | this.modalType = '';
42 | this.albumName = '';
43 | this.artist = '';
44 | this.cover = '';
45 | this.buyUrl = '';
46 | this.releaseDate = '';
47 | this.uploadStatus = false;
48 | }
49 |
50 | getData = async () => {
51 | try {
52 | const response = await this.featuredRecordApi.getData();
53 | runInAction(() => {
54 | this.dataSource = response.data;
55 | });
56 | } catch (e) {
57 | message.error('unknown error!');
58 | }
59 | };
60 |
61 | insertData = async () => {
62 | const params = {
63 | album_name: this.albumName,
64 | artist: this.artist,
65 | cover: this.cover,
66 | buy_url: this.buyUrl,
67 | release_date: this.releaseDate,
68 | };
69 | try {
70 | await this.featuredRecordApi.insertData(params);
71 | this.showModal = false;
72 | message.success('insert success');
73 | this.dataSource.splice(0, this.dataSource.length);
74 | await this.getData();
75 | } catch (e) {
76 | message.error('unknown error!');
77 | }
78 | };
79 |
80 | modifyData = async () => {
81 | const params = {
82 | album_name: this.albumName,
83 | artist: this.artist,
84 | cover: this.cover,
85 | buy_url: this.buyUrl,
86 | release_date: this.releaseDate,
87 | };
88 | try {
89 | await this.featuredRecordApi.modifyData(this.curId, params);
90 | this.showModal = false;
91 | message.success('modify success');
92 | this.dataSource.splice(0, this.dataSource.length);
93 | await this.getData();
94 | } catch (e) {
95 | message.error('unknown error!');
96 | }
97 | };
98 |
99 | deleteData = async (id) => {
100 | try {
101 | await this.featuredRecordApi.deleteData(id);
102 | message.success('delete success');
103 | this.dataSource.splice(0, this.dataSource.length);
104 | await this.getData();
105 | } catch (e) {
106 | message.error('unknown error!');
107 | }
108 | };
109 |
110 | batchDelete = async () => {
111 | const params = {
112 | selectedList: this.selectedRowKeys,
113 | };
114 | try {
115 | await this.featuredRecordApi.batchDeleteData(params);
116 | message.success('delete success');
117 | this.dataSource.splice(0, this.dataSource.length);
118 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
119 | await this.getData();
120 | } catch (e) {
121 | message.error('unknown error!');
122 | }
123 | };
124 |
125 | @computed get isFilled() {
126 | return this.albumName !== '' && this.artist !== '' && this.cover !== '' && this.buyUrl !== '' && this.releaseDate !== '';
127 | }
128 |
129 | @action onSelectChange = (selectedRowKeys) => {
130 | this.selectedRowKeys = selectedRowKeys;
131 | };
132 |
133 | @action openModal = (type, id = '', albumName = '', artist = '', buyUrl = '', releaseDate = getCurrentDate(), cover = '') => {
134 | this.modalType = type;
135 | this.curId = id;
136 | this.albumName = albumName;
137 | this.artist = artist;
138 | this.buyUrl = buyUrl;
139 | this.releaseDate = releaseDate;
140 | this.cover = cover;
141 | this.showModal = true;
142 | };
143 |
144 | @action closeModal = () => {
145 | this.showModal = false;
146 | this.albumName = '';
147 | this.artist = '';
148 | this.cover = '';
149 | this.buyUrl = '';
150 | this.releaseDate = '';
151 | };
152 |
153 | @action onAlbumNameChange = (e) => {
154 | this.albumName = e.target.value;
155 | };
156 |
157 | @action onArtistChange = (e) => {
158 | this.artist = e.target.value;
159 | };
160 |
161 | @action onBuyUrlChange = (e) => {
162 | this.buyUrl = e.target.value;
163 | };
164 |
165 | @action onReleaseDateChange = (date, dateString) => {
166 | this.releaseDate = dateString;
167 | };
168 |
169 | @action onUploadChange = (info) => {
170 | if (info.file.status === 'uploading') {
171 | this.uploadStatus = true;
172 | return;
173 | }
174 | if (info.file.status === 'done') {
175 | this.uploadStatus = false;
176 | this.cover = info.file.response.path;
177 | }
178 | }
179 | }
180 |
181 | const featuredRecordStore = new FeaturedRecordStore(featuredRecordApi);
182 |
183 | export default featuredRecordStore;
184 |
--------------------------------------------------------------------------------
/src/stores/GlobalStore.js:
--------------------------------------------------------------------------------
1 | import { action, observable, configure } from 'mobx';
2 | import { message } from 'antd/lib/index';
3 | import { globalApi } from '../http/index';
4 |
5 | configure({
6 | strict: 'always',
7 | });
8 |
9 | class GlobalStore {
10 | @observable userName;
11 |
12 | @observable fullSiteGrayStatus;
13 |
14 | @observable curId;
15 |
16 | constructor() {
17 | this.globalApi = globalApi;
18 | this.fullSiteGrayStatus = false;
19 | this.curId = '';
20 | }
21 |
22 | getData = async () => {
23 | try {
24 | const response = await this.globalApi.getData();
25 | this.curId = response.data._id; /* eslint-disable-line */
26 | this.fullSiteGrayStatus = response.data.full_site_gray;
27 | } catch (e) {
28 | message.error('unknown error!');
29 | }
30 | };
31 |
32 | insertFullSiteGrayData = async () => {
33 | const params = {
34 | full_site_gray: this.fullSiteGrayStatus,
35 | };
36 | try {
37 | await this.globalApi.insertFullSiteGrayData(params);
38 | message.success('insert success');
39 | await this.getData();
40 | } catch (e) {
41 | message.error('unknown error!');
42 | }
43 | };
44 |
45 | modifyFullSiteGrayData = async () => {
46 | const params = {
47 | full_site_gray: this.fullSiteGrayStatus,
48 | };
49 | try {
50 | const response = await this.globalApi.modifyFullSiteGrayData(this.curId, params);
51 | message.success(`turn ${response.data.full_site_gray ? 'on' : 'off'} gray`);
52 | await this.getData();
53 | } catch (e) {
54 | message.error('unknown error!');
55 | }
56 | };
57 |
58 | @action onFullSiteGray = (checked) => {
59 | this.fullSiteGrayStatus = checked;
60 | if (!this.curId) {
61 | this.insertFullSiteGrayData();
62 | } else {
63 | this.modifyFullSiteGrayData();
64 | }
65 | };
66 | }
67 |
68 | const globalStore = new GlobalStore(globalApi);
69 |
70 | export default globalStore;
71 |
--------------------------------------------------------------------------------
/src/stores/LiveTourStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { liveTourApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class LiveToursStore {
12 | @observable dataSource;
13 |
14 | @observable selectedRowKeys;
15 |
16 | @observable showModal;
17 |
18 | @observable modalType;
19 |
20 | @observable curId;
21 |
22 | @observable title;
23 |
24 | @observable poster;
25 |
26 | @observable uploadStatus;
27 |
28 | constructor() {
29 | this.liveTourApi = liveTourApi;
30 | this.dataSource = [];
31 | this.selectedRowKeys = [];
32 | this.showModal = false;
33 | this.curId = '';
34 | this.modalType = '';
35 | this.title = '';
36 | this.poster = '';
37 | this.uploadStatus = false;
38 | }
39 |
40 | getData = async () => {
41 | try {
42 | const response = await this.liveTourApi.getData();
43 | runInAction(() => {
44 | this.dataSource = response.data;
45 | });
46 | } catch (e) {
47 | message.error('unknown error!');
48 | }
49 | };
50 |
51 | insertData = async () => {
52 | const params = {
53 | title: this.title,
54 | poster: this.poster,
55 | };
56 | try {
57 | await this.liveTourApi.insertData(params);
58 | this.showModal = false;
59 | message.success('insert success');
60 | this.dataSource.splice(0, this.dataSource.length);
61 | await this.getData();
62 | } catch (e) {
63 | message.error('unknown error!');
64 | }
65 | };
66 |
67 | modifyData = async () => {
68 | const params = {
69 | title: this.title,
70 | poster: this.poster,
71 | };
72 | try {
73 | await this.liveTourApi.modifyData(this.curId, params);
74 | this.showModal = false;
75 | message.success('modify success');
76 | this.dataSource.splice(0, this.dataSource.length);
77 | await this.getData();
78 | } catch (e) {
79 | message.error('unknown error!');
80 | }
81 | };
82 |
83 | deleteData = async (id) => {
84 | try {
85 | await this.liveTourApi.deleteData(id);
86 | message.success('delete success');
87 | this.dataSource.splice(0, this.dataSource.length);
88 | await this.getData();
89 | } catch (e) {
90 | message.error('unknown error!');
91 | }
92 | };
93 |
94 | batchDelete = async () => {
95 | const params = {
96 | selectedList: this.selectedRowKeys,
97 | };
98 | try {
99 | await this.liveTourApi.batchDeleteData(params);
100 | message.success('delete success');
101 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
102 | this.dataSource.splice(0, this.dataSource.length);
103 | await this.getData();
104 | } catch (e) {
105 | message.error('unknown error!');
106 | }
107 | };
108 |
109 | @computed get isFilled() {
110 | return this.title !== '' && this.poster !== '';
111 | }
112 |
113 | @action onSelectChange = (selectedRowKeys) => {
114 | this.selectedRowKeys = selectedRowKeys;
115 | };
116 |
117 | @action openModal = (type, id = '', title = '', poster = '') => {
118 | this.modalType = type;
119 | this.curId = id;
120 | this.title = title;
121 | this.poster = poster;
122 | this.showModal = true;
123 | };
124 |
125 | @action closeModal = () => {
126 | this.showModal = false;
127 | this.title = '';
128 | this.poster = '';
129 | };
130 |
131 | @action onTitleChange = (e) => {
132 | this.title = e.target.value;
133 | };
134 |
135 | @action onIntroductionChange = (e) => {
136 | this.introduction = e.target.value;
137 | };
138 |
139 | @action onUrlChange = (e) => {
140 | this.url = e.target.value;
141 | };
142 |
143 | @action onUploadChange = (info) => {
144 | if (info.file.status === 'uploading') {
145 | this.uploadStatus = true;
146 | return;
147 | }
148 | if (info.file.status === 'done') {
149 | this.uploadStatus = false;
150 | this.poster = info.file.response.path;
151 | }
152 | }
153 | }
154 |
155 | const liveTourStore = new LiveToursStore(liveTourApi);
156 |
157 | export default liveTourStore;
158 |
--------------------------------------------------------------------------------
/src/stores/LoginStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { loginApi } from '../http/index';
6 | import history from '../history';
7 |
8 | configure({
9 | strict: 'always',
10 | });
11 |
12 | class LoginStore {
13 | @observable email;
14 |
15 | @observable password;
16 |
17 | @observable captcha;
18 |
19 | @observable loginStatus;
20 |
21 | constructor() {
22 | this.loginApi = loginApi;
23 | this.email = '';
24 | this.password = '';
25 | this.captcha = '';
26 | this.loginStatus = false;
27 | }
28 |
29 | login = async () => {
30 | const params = {
31 | email: this.email,
32 | password: this.password,
33 | response: this.captcha,
34 | };
35 | this.loginStatus = true;
36 | try {
37 | const response = await this.loginApi.login(params);
38 | window.localStorage.token = response.data.token;
39 | window.localStorage.expires_date = response.data.expires_date;
40 | message.success('Login Success!');
41 | history.push('/');
42 | this.email = '';
43 | this.password = '';
44 | this.captcha = '';
45 | this.loginStatus = false;
46 | } catch (e) {
47 | message.error(e.response.data.message);
48 | this.loginStatus = false;
49 | }
50 | };
51 |
52 | @computed get isFilled() {
53 | return this.email !== '' && this.password !== '' && this.captcha !== '';
54 | }
55 |
56 | @action onEmailChange = (e) => {
57 | this.email = e.target.value;
58 | };
59 |
60 | @action onPasswordChange = (e) => {
61 | this.password = e.target.value;
62 | };
63 |
64 | @action onCaptchaChange = (value) => {
65 | this.captcha = value;
66 | };
67 | }
68 |
69 | const loginStore = new LoginStore(loginApi);
70 |
71 | export default loginStore;
72 |
--------------------------------------------------------------------------------
/src/stores/ModifyPasswordStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { loginApi } from '../http/index';
6 | import history from '../history';
7 |
8 | configure({
9 | strict: 'always',
10 | });
11 |
12 | class ModifyPasswordStore {
13 | @observable email;
14 |
15 | @observable oldPassword;
16 |
17 | @observable newPassword;
18 |
19 | @observable confirmPassword;
20 |
21 | constructor() {
22 | this.loginApi = loginApi;
23 | this.email = '';
24 | this.oldPassword = '';
25 | this.newPassword = '';
26 | this.confirmPassword = '';
27 | }
28 |
29 | modifyPassword = async () => {
30 | const params = {
31 | email: this.email,
32 | old_password: this.oldPassword,
33 | new_password: this.newPassword,
34 | };
35 | try {
36 | await this.loginApi.modifyPassword(params);
37 | this.email = '';
38 | this.oldPassword = '';
39 | this.newPassword = '';
40 | this.confirmPassword = '';
41 | message.success('Password has been modified!');
42 | message.success('You must ReLogin after 2 seconds...');
43 | window.localStorage.clear();
44 | setTimeout(() => {
45 | history.push('/login');
46 | }, 2000);
47 | } catch (e) {
48 | message.error(e.response.data.message);
49 | }
50 | };
51 |
52 | @computed get isFilled() {
53 | return this.email !== '' && this.oldPassword !== '' && this.newPassword !== '' && this.confirmPassword !== '';
54 | }
55 |
56 | @computed get checkPasswordEqual() {
57 | return this.newPassword === this.confirmPassword;
58 | }
59 |
60 | @action onEmailChange = (e) => {
61 | this.email = e.target.value;
62 | };
63 |
64 | @action onOldPasswordChange = (e) => {
65 | this.oldPassword = e.target.value;
66 | };
67 |
68 | @action onNewPasswordChange = (e) => {
69 | this.newPassword = e.target.value;
70 | };
71 |
72 | @action onConfirmPasswordChange = (e) => {
73 | this.confirmPassword = e.target.value;
74 | };
75 |
76 |
77 | @action handleModifyPassword = () => {
78 | if (!this.checkPasswordEqual) {
79 | message.error('Sorry, the new password and confirming password disagree!');
80 | } else {
81 | this.modifyPassword();
82 | }
83 | }
84 | }
85 |
86 | const modifyPasswordStore = new ModifyPasswordStore(loginApi);
87 |
88 | export default modifyPasswordStore;
89 |
--------------------------------------------------------------------------------
/src/stores/MottoStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { mottoApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class MottoStore {
12 | @observable dataSource;
13 |
14 | @observable selectedRowKeys;
15 |
16 | @observable showModal;
17 |
18 | @observable modalType;
19 |
20 | @observable curId;
21 |
22 | @observable content;
23 |
24 | constructor() {
25 | this.mottoApi = mottoApi;
26 | this.dataSource = [];
27 | this.selectedRowKeys = [];
28 | this.showModal = false;
29 | this.curId = '';
30 | this.modalType = '';
31 | this.content = '';
32 | }
33 |
34 | getData = async () => {
35 | try {
36 | const response = await this.mottoApi.getData();
37 | runInAction(() => {
38 | this.dataSource = response.data;
39 | });
40 | } catch (e) {
41 | message.error('unknown error!');
42 | }
43 | };
44 |
45 | insertData = async () => {
46 | const params = {
47 | content: this.content,
48 | };
49 | try {
50 | await this.mottoApi.insertData(params);
51 | this.showModal = false;
52 | message.success('insert success');
53 | this.dataSource.splice(0, this.dataSource.length);
54 | await this.getData();
55 | } catch (e) {
56 | message.error('unknown error!');
57 | }
58 | };
59 |
60 | modifyData = async () => {
61 | const params = {
62 | content: this.content,
63 | };
64 | try {
65 | await this.mottoApi.modifyData(this.curId, params);
66 | this.showModal = false;
67 | message.success('modify success');
68 | this.dataSource.splice(0, this.dataSource.length);
69 | await this.getData();
70 | } catch (e) {
71 | message.error('unknown error!');
72 | }
73 | };
74 |
75 | deleteData = async (id) => {
76 | try {
77 | await this.mottoApi.deleteData(id);
78 | message.success('delete success');
79 | this.dataSource.splice(0, this.dataSource.length);
80 | await this.getData();
81 | } catch (e) {
82 | message.error('unknown error!');
83 | }
84 | };
85 |
86 | batchDelete = async () => {
87 | const params = {
88 | selectedList: this.selectedRowKeys,
89 | };
90 | try {
91 | await this.mottoApi.batchDeleteData(params);
92 | message.success('delete success');
93 | this.dataSource.splice(0, this.dataSource.length);
94 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
95 | await this.getData();
96 | } catch (e) {
97 | message.error('unknown error!');
98 | }
99 | };
100 |
101 | @computed get isFilled() {
102 | return this.content !== '';
103 | }
104 |
105 | @action onSelectChange = (selectedRowKeys) => {
106 | this.selectedRowKeys = selectedRowKeys;
107 | };
108 |
109 | @action openModal = (type, id = '', content = '') => {
110 | this.modalType = type;
111 | this.curId = id;
112 | this.content = content;
113 | this.showModal = true;
114 | };
115 |
116 | @action closeModal = () => {
117 | this.showModal = false;
118 | this.content = '';
119 | };
120 |
121 | @action onContentChange = (e) => {
122 | this.content = e.target.value;
123 | };
124 | }
125 |
126 | const mottoStore = new MottoStore(mottoApi);
127 |
128 | export default mottoStore;
129 |
--------------------------------------------------------------------------------
/src/stores/PlayerStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { playerApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class PlayerStore {
12 | @observable dataSource;
13 |
14 | @observable artistData;
15 |
16 | @observable selectedRowKeys;
17 |
18 | @observable showModal;
19 |
20 | @observable modalType;
21 |
22 | @observable curId;
23 |
24 | @observable curShow;
25 |
26 | @observable title;
27 |
28 | @observable artist;
29 |
30 | @observable coverUrl;
31 |
32 | @observable musicFileUrl;
33 |
34 | @observable lrc;
35 |
36 | @observable imgUploadStatus;
37 |
38 | @observable musicUploadStatus;
39 |
40 | constructor() {
41 | this.playerApi = playerApi;
42 | this.dataSource = [];
43 | this.artistData = [];
44 | this.selectedRowKeys = [];
45 | this.showModal = false;
46 | this.curId = '';
47 | this.curShow = true;
48 | this.modalType = '';
49 | this.title = '';
50 | this.artist = '';
51 | this.coverUrl = '';
52 | this.musicFileUrl = '';
53 | this.lrc = '';
54 | this.imgUploadStatus = false;
55 | this.musicUploadStatus = false;
56 | }
57 |
58 | getData = async () => {
59 | try {
60 | const response = await this.playerApi.getData();
61 | runInAction(() => {
62 | this.dataSource = response.data;
63 | this.artistData.splice(0, this.artistData.length);
64 | // filter by artist
65 | const arr = [];
66 | const obj = {};
67 | for (let i = 0; i < response.data.length; i += 1) {
68 | arr.push(response.data[i].artist);
69 | }
70 | const noRepeatArr = Array.from(new Set(arr));
71 | for (let i = 0; i < noRepeatArr.length; i += 1) {
72 | obj.text = noRepeatArr[i];
73 | obj.value = noRepeatArr[i];
74 | this.artistData.push(obj);
75 | }
76 | });
77 | } catch (e) {
78 | message.error('unknown error!');
79 | }
80 | };
81 |
82 | insertData = async () => {
83 | const params = {
84 | title: this.title,
85 | artist: this.artist,
86 | cover: this.coverUrl,
87 | music_file_url: this.musicFileUrl,
88 | lrc: this.lrc,
89 | show: true,
90 | };
91 | try {
92 | await this.playerApi.insertData(params);
93 | this.showModal = false;
94 | message.success('insert success');
95 | this.dataSource.splice(0, this.dataSource.length);
96 | await this.getData();
97 | } catch (e) {
98 | message.error('unknown error!');
99 | }
100 | };
101 |
102 | modifyData = async () => {
103 | const params = {
104 | title: this.title,
105 | artist: this.artist,
106 | cover: this.coverUrl,
107 | music_file_url: this.musicFileUrl,
108 | lrc: this.lrc,
109 | show: this.curShow,
110 | };
111 | try {
112 | await this.playerApi.modifyData(this.curId, params);
113 | this.showModal = false;
114 | message.success('modify success');
115 | this.dataSource.splice(0, this.dataSource.length);
116 | await this.getData();
117 | } catch (e) {
118 | message.error('unknown error!');
119 | }
120 | };
121 |
122 | onSwitchShow = async (id, title, artist, coverUrl, musicFileUrl, lrc, checked) => {
123 | const params = {
124 | title,
125 | artist,
126 | cover: coverUrl,
127 | music_file_url: musicFileUrl,
128 | lrc,
129 | show: checked,
130 | };
131 | try {
132 | await this.playerApi.modifyData(id, params);
133 | if (checked) {
134 | message.success('the cover will be shown');
135 | } else {
136 | message.success('the cover will be hidden');
137 | }
138 | this.dataSource.splice(0, this.dataSource.length);
139 | await this.getData();
140 | } catch (e) {
141 | message.error('unknown error!');
142 | }
143 | };
144 |
145 | deleteData = async (id) => {
146 | try {
147 | await this.playerApi.deleteData(id);
148 | message.success('delete success');
149 | this.dataSource.splice(0, this.dataSource.length);
150 | await this.getData();
151 | } catch (e) {
152 | message.error('unknown error!');
153 | }
154 | };
155 |
156 | batchDelete = async () => {
157 | const params = {
158 | selectedList: this.selectedRowKeys,
159 | };
160 | try {
161 | await this.playerApi.batchDeleteData(params);
162 | message.success('delete success');
163 | this.dataSource.splice(0, this.dataSource.length);
164 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
165 | await this.getData();
166 | } catch (e) {
167 | message.error('unknown error!');
168 | }
169 | };
170 |
171 | @computed get isFilled() {
172 | return this.title !== '' && this.artist !== '' && this.coverUrl !== '' && this.lrc !== '' && this.musicFileUrl !== '';
173 | }
174 |
175 | @action onSelectChange = (selectedRowKeys) => {
176 | this.selectedRowKeys = selectedRowKeys;
177 | };
178 |
179 | @action openModal = (type, id = '', title = '', artist = '', coverUrl = '', musicFileUrl = '', lrc = '', curShow) => {
180 | this.modalType = type;
181 | this.curId = id;
182 | this.curShow = curShow;
183 | this.title = title;
184 | this.artist = artist;
185 | this.coverUrl = coverUrl;
186 | this.musicFileUrl = musicFileUrl;
187 | this.lrc = lrc;
188 | this.showModal = true;
189 | };
190 |
191 | @action closeModal = () => {
192 | this.showModal = false;
193 | this.title = '';
194 | this.artist = '';
195 | this.coverUrl = '';
196 | this.musicFileUrl = '';
197 | this.lrc = '';
198 | };
199 |
200 | @action onTitleChange = (e) => {
201 | this.title = e.target.value;
202 | };
203 |
204 | @action onArtistChange = (e) => {
205 | this.artist = e.target.value;
206 | };
207 |
208 | @action onLrcChange = (e) => {
209 | this.lrc = e.target.value;
210 | };
211 |
212 | @action onImgUploadChange = (info) => {
213 | if (info.file.status === 'uploading') {
214 | this.imgUploadStatus = true;
215 | return;
216 | }
217 | if (info.file.status === 'done') {
218 | this.imgUploadStatus = false;
219 | this.coverUrl = info.file.response.path;
220 | }
221 | };
222 |
223 | @action onMusicFileUploadChange = (info) => {
224 | if (info.file.status === 'uploading') {
225 | this.musicUploadStatus = true;
226 | }
227 | if (info.file.status === 'removed') {
228 | this.musicFileUrl = '';
229 | this.musicUploadStatus = false;
230 | }
231 | if (info.file.status === 'done') {
232 | message.success(`${info.file.name} file uploaded successfully`);
233 | this.musicFileUrl = info.file.response.path;
234 | this.musicUploadStatus = false;
235 | } else if (info.file.status === 'error') {
236 | message.error(`${info.file.name} file upload failed.`);
237 | this.musicUploadStatus = false;
238 | }
239 | };
240 | }
241 |
242 | const playerStore = new PlayerStore(playerApi);
243 |
244 | export default playerStore;
245 |
--------------------------------------------------------------------------------
/src/stores/ProgramExperienceStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { programExperienceApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class ProgramExperienceStore {
12 | @observable dataSource;
13 |
14 | @observable showModal;
15 |
16 | @observable modalType;
17 |
18 | @observable programName;
19 |
20 | @observable programUrl;
21 |
22 | @observable programContent;
23 |
24 | @observable curId;
25 |
26 | @observable tags;
27 |
28 | @observable inputVisible;
29 |
30 | @observable inputValue;
31 |
32 | constructor() {
33 | this.programExperienceApi = programExperienceApi;
34 | this.dataSource = [];
35 | this.showModal = false;
36 | this.modalType = '';
37 | this.programName = '';
38 | this.programUrl = '';
39 | this.programContent = '';
40 | this.curId = '';
41 | // tags
42 | this.tags = [];
43 | this.inputVisible = false;
44 | this.inputValue = '';
45 | }
46 |
47 | getData = async () => {
48 | try {
49 | const response = await this.programExperienceApi.getData();
50 | this.dataSource = response.data;
51 | } catch (e) {
52 | message.error('unknown error!');
53 | }
54 | };
55 |
56 | insertData = async () => {
57 | const params = {
58 | program_name: this.programName,
59 | program_url: this.programUrl,
60 | program_content: this.programContent,
61 | program_technology_stack: this.tags,
62 | };
63 | try {
64 | await this.programExperienceApi.insertData(params);
65 | this.showModal = false;
66 | message.success('insert success');
67 | this.dataSource.splice(0, this.dataSource.length);
68 | await this.getData();
69 | } catch (e) {
70 | message.error('unknown error!');
71 | }
72 | };
73 |
74 | modifyData = async () => {
75 | const params = {
76 | program_name: this.programName,
77 | program_url: this.programUrl,
78 | program_content: this.programContent,
79 | program_technology_stack: this.tags,
80 | };
81 | try {
82 | await this.programExperienceApi.modifyData(this.curId, params);
83 | this.showModal = false;
84 | message.success('modify success');
85 | this.dataSource.splice(0, this.dataSource.length);
86 | await this.getData();
87 | } catch (e) {
88 | message.error('unknown error!');
89 | }
90 | };
91 |
92 | deleteData = async (id) => {
93 | try {
94 | await this.programExperienceApi.deleteData(id);
95 | message.success('delete success');
96 | this.dataSource.splice(0, this.dataSource.length);
97 | await this.getData();
98 | } catch (e) {
99 | message.error('unknown error!');
100 | }
101 | };
102 |
103 | @computed get isFilled() {
104 | return this.programName !== '' && this.programUrl !== '' && this.programContent !== '';
105 | }
106 |
107 | @action openModal = (type, programName = '', programUrl = '', programContent = '', tags = [], id) => {
108 | this.showModal = true;
109 | this.modalType = type;
110 | this.programName = programName;
111 | this.programUrl = programUrl;
112 | this.programContent = programContent;
113 | this.tags = tags;
114 | this.curId = id;
115 | };
116 |
117 | @action closeModal = () => {
118 | this.showModal = false;
119 | };
120 |
121 | @action onProgramNameChange = (e) => {
122 | this.programName = e.target.value;
123 | };
124 |
125 | @action onProgramUrlChange = (e) => {
126 | this.programUrl = e.target.value;
127 | };
128 |
129 | @action onProgramContentChange = (e) => {
130 | this.programContent = e.target.value;
131 | };
132 |
133 | // tags
134 | @action handleClose = (removedTag) => {
135 | this.tags = this.tags.filter(tag => tag !== removedTag);
136 | };
137 |
138 | @action showInput = () => {
139 | this.inputVisible = true;
140 | };
141 |
142 | @action handleInputChange = (e) => {
143 | this.inputValue = e.target.value;
144 | };
145 |
146 | @action handleInputConfirm = () => {
147 | if (this.inputValue && this.tags.indexOf(this.inputValue) === -1) {
148 | this.tags = [...this.tags, this.inputValue];
149 | }
150 | this.inputValue = '';
151 | this.inputVisible = false;
152 | };
153 |
154 | saveInputRef = input => this.input = input; /* eslint-disable-line */
155 | }
156 |
157 | const programExperienceStore = new ProgramExperienceStore(programExperienceApi);
158 |
159 | export default programExperienceStore;
160 |
--------------------------------------------------------------------------------
/src/stores/ProjectStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { projectApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class ProjectStore {
12 | @observable dataSource;
13 |
14 | @observable selectedRowKeys;
15 |
16 | @observable showModal;
17 |
18 | @observable modalType;
19 |
20 | @observable curId;
21 |
22 | @observable title;
23 |
24 | @observable introduction;
25 |
26 | @observable poster;
27 |
28 | @observable url;
29 |
30 | @observable uploadStatus;
31 |
32 | constructor() {
33 | this.projectApi = projectApi;
34 | this.dataSource = [];
35 | this.selectedRowKeys = [];
36 | this.showModal = false;
37 | this.curId = '';
38 | this.modalType = '';
39 | this.title = '';
40 | this.introduction = '';
41 | this.poster = '';
42 | this.url = '';
43 | this.uploadStatus = false;
44 | }
45 |
46 | getData = async () => {
47 | try {
48 | const response = await this.projectApi.getData();
49 | runInAction(() => {
50 | this.dataSource = response.data;
51 | });
52 | } catch (e) {
53 | message.error(e.message);
54 | }
55 | };
56 |
57 | insertData = async () => {
58 | const params = {
59 | title: this.title,
60 | introduction: this.introduction,
61 | poster: this.poster,
62 | url: this.url,
63 | };
64 | try {
65 | await this.projectApi.insertData(params);
66 | this.showModal = false;
67 | message.success('insert success');
68 | this.dataSource.splice(0, this.dataSource.length);
69 | await this.getData();
70 | } catch (e) {
71 | message.error('unknown error!');
72 | }
73 | };
74 |
75 | modifyData = async () => {
76 | const params = {
77 | title: this.title,
78 | introduction: this.introduction,
79 | poster: this.poster,
80 | url: this.url,
81 | };
82 | try {
83 | await this.projectApi.modifyData(this.curId, params);
84 | this.showModal = false;
85 | message.success('modify success');
86 | this.dataSource.splice(0, this.dataSource.length);
87 | await this.getData();
88 | } catch (e) {
89 | message.error('unknown error!');
90 | }
91 | };
92 |
93 | deleteData = async (id) => {
94 | try {
95 | await this.projectApi.deleteData(id);
96 | message.success('delete success');
97 | this.dataSource.splice(0, this.dataSource.length);
98 | await this.getData();
99 | } catch (e) {
100 | message.error('unknown error!');
101 | }
102 | };
103 |
104 | batchDelete = async () => {
105 | const params = {
106 | selectedList: this.selectedRowKeys,
107 | };
108 | try {
109 | await this.projectApi.batchDeleteData(params);
110 | message.success('delete success');
111 | this.dataSource.splice(0, this.dataSource.length);
112 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
113 | await this.getData();
114 | } catch (e) {
115 | message.error('unknown error!');
116 | }
117 | };
118 |
119 | @computed get isFilled() {
120 | return this.title !== '' && this.introduction !== '' && this.poster !== '' && this.url !== '';
121 | }
122 |
123 | @action onSelectChange = (selectedRowKeys) => {
124 | this.selectedRowKeys = selectedRowKeys;
125 | };
126 |
127 | @action openModal = (type, id = '', title = '', introduction = '', poster = '', url = '') => {
128 | this.modalType = type;
129 | this.curId = id;
130 | this.title = title;
131 | this.introduction = introduction;
132 | this.poster = poster;
133 | this.url = url;
134 | this.showModal = true;
135 | };
136 |
137 | @action closeModal = () => {
138 | this.showModal = false;
139 | this.title = '';
140 | this.introduction = '';
141 | this.poster = '';
142 | this.url = '';
143 | };
144 |
145 | @action onTitleChange = (e) => {
146 | this.title = e.target.value;
147 | };
148 |
149 | @action onIntroductionChange = (e) => {
150 | this.introduction = e.target.value;
151 | };
152 |
153 | @action onUrlChange = (e) => {
154 | this.url = e.target.value;
155 | };
156 |
157 | @action onUploadChange = (info) => {
158 | if (info.file.status === 'uploading') {
159 | this.uploadStatus = true;
160 | return;
161 | }
162 | if (info.file.status === 'done') {
163 | this.uploadStatus = false;
164 | this.poster = info.file.response.path;
165 | }
166 | }
167 | }
168 |
169 | const projectStore = new ProjectStore(projectApi);
170 |
171 | export default projectStore;
172 |
--------------------------------------------------------------------------------
/src/stores/ServerStatusStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { serverStatusApi } from '../http/index';
5 | import { formatJSONDate } from '../util/tools';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class ServerStatusStore {
12 | @observable bandwidthDosage;
13 |
14 | @observable totalBandwidth;
15 |
16 | @observable diskDosage;
17 |
18 | @observable totalDisk;
19 |
20 | @observable SWAPDosage;
21 |
22 | @observable totalSWAP;
23 |
24 | @observable RAMDosage;
25 |
26 | @observable totalRAM;
27 |
28 | @observable timestampData;
29 |
30 | @observable networkInBytesData;
31 |
32 | @observable networkOutBytesData;
33 |
34 | @observable diskReadBytesData;
35 |
36 | @observable diskWriteBytesData;
37 |
38 | @observable cpuUsageData;
39 |
40 | @observable dataLength;
41 |
42 | @observable curTab;
43 |
44 | @observable serverStatusLoading;
45 |
46 | @observable serverUsageLoading;
47 |
48 |
49 | constructor() {
50 | this.serverStatusApi = serverStatusApi;
51 | this.bandwidthDosage = 0;
52 | this.totalBandwidth = 0;
53 | this.diskDosage = 0;
54 | this.totalDisk = 0;
55 | this.SWAPDosage = 0;
56 | this.totalSWAP = 0;
57 | this.RAMDosage = 0;
58 | this.totalRAM = 0;
59 | this.timestampData = [];
60 | this.networkInBytesData = [];
61 | this.networkOutBytesData = [];
62 | this.diskReadBytesData = [];
63 | this.diskWriteBytesData = [];
64 | this.cpuUsageData = [];
65 | this.dataLength = 12;
66 | this.curTab = 'oneHour';
67 | this.serverStatusLoading = false;
68 | this.serverUsageLoading = false;
69 | }
70 |
71 | @computed get bandwidthUsage() {
72 | return this.totalBandwidth === 0 ? 0 : Math.round(this.bandwidthDosage / this.totalBandwidth * 100);
73 | }
74 |
75 | @computed get diskUsage() {
76 | return this.totalDisk === 0 ? 0 : Math.round(this.diskDosage / this.totalDisk * 100);
77 | }
78 |
79 | @computed get RAMUsage() {
80 | return this.totalRAM === 0 ? 0 : Math.round(this.RAMDosage / this.totalRAM * 100);
81 | }
82 |
83 | @computed get SWAPUsage() {
84 | return this.totalSWAP === 0 ? 0 : Math.round(this.SWAPDosage / this.totalSWAP * 100);
85 | }
86 |
87 | getServerData = async () => {
88 | this.serverStatusLoading = true;
89 | try {
90 | const response = await this.serverStatusApi.getServerData();
91 | runInAction(() => {
92 | this.bandwidthDosage = (response.data.data_counter / 1024 / 1024 / 1024).toFixed(2);
93 | this.totalBandwidth = (response.data.plan_monthly_data / 1024 / 1024 / 1024).toFixed(2);
94 | this.diskDosage = (response.data.ve_used_disk_space_b / 1024 / 1024 / 1024).toFixed(2);
95 | this.totalDisk = (response.data.plan_disk / 1024 / 1024 / 1024).toFixed(2);
96 | this.RAMDosage = (response.data.plan_ram / 1024 / 1024 - response.data.mem_available_kb / 1024).toFixed(2);
97 | this.totalRAM = (response.data.plan_ram / 1024 / 1024).toFixed(2);
98 | this.SWAPDosage = (response.data.swap_total_kb / 1024 - response.data.swap_available_kb / 1024).toFixed(2);
99 | this.totalSWAP = (response.data.swap_total_kb / 1024).toFixed(2);
100 | this.serverStatusLoading = false;
101 | });
102 | } catch (e) {
103 | this.serverStatusLoading = false;
104 | }
105 | };
106 |
107 | getRawUsageStatusData = async () => {
108 | this.serverUsageLoading = true;
109 | try {
110 | const response = await this.serverStatusApi.getRawUsageStatusData();
111 | runInAction(() => {
112 | for (let i = 0, l = response.data.data.length; i < l; i += 1) {
113 | this.timestampData.push(formatJSONDate(parseInt(response.data.data[i].timestamp, 10) * 1000));
114 | this.networkInBytesData.push(parseInt(response.data.data[i].network_in_bytes, 10));
115 | this.networkOutBytesData.push(parseInt(response.data.data[i].network_out_bytes, 10));
116 | this.diskReadBytesData.push(parseInt(response.data.data[i].disk_read_bytes, 10));
117 | this.diskWriteBytesData.push(parseInt(response.data.data[i].disk_write_bytes, 10));
118 | this.cpuUsageData.push(parseInt(response.data.data[i].cpu_usage, 10));
119 | this.serverUsageLoading = false;
120 | }
121 | });
122 | } catch (e) {
123 | this.serverUsageLoading = false;
124 | }
125 | };
126 |
127 | @action onSelectRange = (e) => {
128 | const value = e.target.value;
129 | this.curTab = value;
130 | if (value === 'sevenDays') {
131 | this.dataLength = 2016;
132 | } else if (value === 'oneDay') {
133 | this.dataLength = 288;
134 | } else if (value === 'halfDay') {
135 | this.dataLength = 144;
136 | } else {
137 | this.dataLength = 12;
138 | }
139 | };
140 | }
141 |
142 | const serverStatusStore = new ServerStatusStore(serverStatusApi);
143 |
144 | export default serverStatusStore;
145 |
--------------------------------------------------------------------------------
/src/stores/UserInfoStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { userInfoApi } from '../http/index';
6 |
7 | configure({
8 | strict: 'always',
9 | });
10 |
11 | class UserInfoStore {
12 | @observable userName;
13 |
14 | @observable position;
15 |
16 | @observable selfIntroduction;
17 |
18 | @observable city;
19 |
20 | @observable avatar;
21 |
22 | @observable curId;
23 |
24 | constructor() {
25 | this.userInfoApi = userInfoApi;
26 | this.userName = '';
27 | this.position = '';
28 | this.selfIntroduction = '';
29 | this.city = '';
30 | this.avatar = '';
31 | this.curId = '';
32 | }
33 |
34 | getData = async () => {
35 | try {
36 | const response = await this.userInfoApi.getData();
37 | this.userName = response.data.user_name;
38 | this.position = response.data.position;
39 | this.selfIntroduction = response.data.self_introduction;
40 | this.city = response.data.city;
41 | this.avatar = response.data.avatar;
42 | this.curId = response.data._id; /* eslint-disable-line */
43 | } catch (e) {
44 | message.error('unknown error!');
45 | }
46 | };
47 |
48 | insertData = async () => {
49 | const params = {
50 | user_name: this.userName,
51 | position: this.position,
52 | self_introduction: this.selfIntroduction,
53 | city: this.city,
54 | avatar: this.avatar,
55 | };
56 | try {
57 | await this.userInfoApi.insertData(params);
58 | message.success('insert success');
59 | await this.getData();
60 | } catch (e) {
61 | message.error('unknown error!');
62 | }
63 | };
64 |
65 | modifyData = async () => {
66 | const params = {
67 | user_name: this.userName,
68 | position: this.position,
69 | self_introduction: this.selfIntroduction,
70 | city: this.city,
71 | avatar: this.avatar,
72 | };
73 | try {
74 | await this.userInfoApi.modifyData(this.curId, params);
75 | message.success('modify success');
76 | await this.getData();
77 | } catch (e) {
78 | message.error('unknown error!');
79 | }
80 | };
81 |
82 | @computed get isFilled() {
83 | return this.userName && this.position && this.selfIntroduction && this.city && this.avatar;
84 | }
85 |
86 | @action onUserNameChange = (e) => {
87 | this.userName = e.target.value;
88 | };
89 |
90 | @action onPositionChange = (e) => {
91 | this.position = e.target.value;
92 | };
93 |
94 | @action onSelfIntroductionChange = (e) => {
95 | this.selfIntroduction = e.target.value;
96 | };
97 |
98 | @action onCityChange = (e) => {
99 | this.city = e.target.value;
100 | };
101 |
102 | @action onUploadChange = (info) => {
103 | if (info.file.status === 'uploading') {
104 | return;
105 | }
106 | if (info.file.status === 'done') {
107 | this.avatar = info.file.response.path;
108 | }
109 | };
110 |
111 | onSubmitChange = () => {
112 | if (!this.curId) {
113 | this.insertData();
114 | } else {
115 | this.modifyData();
116 | }
117 | };
118 | }
119 |
120 | const userInfoStore = new UserInfoStore(userInfoApi);
121 |
122 | export default userInfoStore;
123 |
--------------------------------------------------------------------------------
/src/stores/WorkExperienceStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { workExperienceApi } from '../http/index';
6 | import { getCurrentDate } from '../util/tools';
7 |
8 | configure({
9 | strict: 'always',
10 | });
11 |
12 | class WorkExperienceStore {
13 | @observable dataSource;
14 |
15 | @observable showModal;
16 |
17 | @observable modalType;
18 |
19 | @observable enterpriseName;
20 |
21 | @observable position;
22 |
23 | @observable inService;
24 |
25 | @observable workContent;
26 |
27 | @observable curId;
28 |
29 | @observable tags;
30 |
31 | @observable inputVisible;
32 |
33 | @observable inputValue;
34 |
35 | constructor() {
36 | this.workExperienceApi = workExperienceApi;
37 | this.dataSource = [];
38 | this.showModal = false;
39 | this.modalType = '';
40 | this.enterpriseName = '';
41 | this.position = '';
42 | this.inService = [];
43 | this.workContent = '';
44 | this.curId = '';
45 | // tags
46 | this.tags = [];
47 | this.inputVisible = false;
48 | this.inputValue = '';
49 | }
50 |
51 | getData = async () => {
52 | try {
53 | const response = await this.workExperienceApi.getData();
54 | this.dataSource = response.data;
55 | } catch (e) {
56 | message.error('unknown error!');
57 | }
58 | };
59 |
60 | insertData = async () => {
61 | const params = {
62 | enterprise_name: this.enterpriseName,
63 | position: this.position,
64 | in_service: this.inService,
65 | work_content: this.workContent,
66 | work_technology_stack: this.tags,
67 | };
68 | try {
69 | await this.workExperienceApi.insertData(params);
70 | this.showModal = false;
71 | message.success('insert success');
72 | this.dataSource.splice(0, this.dataSource.length);
73 | await this.getData();
74 | } catch (e) {
75 | message.error('unknown error!');
76 | }
77 | };
78 |
79 | modifyData = async () => {
80 | const params = {
81 | enterprise_name: this.enterpriseName,
82 | position: this.position,
83 | in_service: this.inService,
84 | work_content: this.workContent,
85 | work_technology_stack: this.tags,
86 | };
87 | try {
88 | await this.workExperienceApi.modifyData(this.curId, params);
89 | this.showModal = false;
90 | message.success('modify success');
91 | this.dataSource.splice(0, this.dataSource.length);
92 | await this.getData();
93 | } catch (e) {
94 | message.error('unknown error!');
95 | }
96 | };
97 |
98 | deleteData = async (id) => {
99 | try {
100 | await this.workExperienceApi.deleteData(id);
101 | message.success('delete success');
102 | this.dataSource.splice(0, this.dataSource.length);
103 | await this.getData();
104 | } catch (e) {
105 | message.error('unknown error!');
106 | }
107 | };
108 |
109 | @computed get isFilled() {
110 | return this.enterpriseName !== '' && this.position !== '' && new Set([...this.inService]).size !== 1 && this.workContent !== '';
111 | }
112 |
113 | @action openModal = (type, enterpriseName = '', position = '', inService = [getCurrentDate(), getCurrentDate()], workContent = '', tags = [], id) => {
114 | this.showModal = true;
115 | this.modalType = type;
116 | this.enterpriseName = enterpriseName;
117 | this.position = position;
118 | this.inService = inService;
119 | this.workContent = workContent;
120 | this.tags = tags;
121 | this.curId = id;
122 | };
123 |
124 | @action closeModal = () => {
125 | this.showModal = false;
126 | };
127 |
128 | @action onEnterpriseNameChange = (e) => {
129 | this.enterpriseName = e.target.value;
130 | };
131 |
132 | @action onPositionChange = (e) => {
133 | this.position = e.target.value;
134 | };
135 |
136 | @action onInServiceChange = (date, dateString) => {
137 | this.inService = dateString;
138 | };
139 |
140 | @action onWorkContentChange = (e) => {
141 | this.workContent = e.target.value;
142 | };
143 |
144 | // tags
145 | @action handleClose = (removedTag) => {
146 | this.tags = this.tags.filter(tag => tag !== removedTag);
147 | };
148 |
149 | @action showInput = () => {
150 | this.inputVisible = true;
151 | };
152 |
153 | @action handleInputChange = (e) => {
154 | this.inputValue = e.target.value;
155 | };
156 |
157 | @action handleInputConfirm = () => {
158 | if (this.inputValue && this.tags.indexOf(this.inputValue) === -1) {
159 | this.tags = [...this.tags, this.inputValue];
160 | }
161 | this.inputValue = '';
162 | this.inputVisible = false;
163 | };
164 |
165 | saveInputRef = input => this.input = input; /* eslint-disable-line */
166 | }
167 |
168 | const workExperienceStore = new WorkExperienceStore(workExperienceApi);
169 |
170 | export default workExperienceStore;
171 |
--------------------------------------------------------------------------------
/src/stores/YanceyMusicStore.js:
--------------------------------------------------------------------------------
1 | import {
2 | action, observable, configure, runInAction, computed,
3 | } from 'mobx';
4 | import { message } from 'antd/lib/index';
5 | import { yanceyMusicApi } from '../http/index';
6 | import { getCurrentDate } from '../util/tools';
7 |
8 | configure({
9 | strict: 'always',
10 | });
11 |
12 | class YanceyMusicStore {
13 | @observable dataSource;
14 |
15 | @observable selectedRowKeys;
16 |
17 | @observable showModal;
18 |
19 | @observable modalType;
20 |
21 | @observable curId;
22 |
23 | @observable title;
24 |
25 | @observable cover;
26 |
27 | @observable soundCloudUrl;
28 |
29 | @observable releaseDate;
30 |
31 | @observable uploadStatus;
32 |
33 | constructor() {
34 | this.yanceyMusicApi = yanceyMusicApi;
35 | this.dataSource = [];
36 | this.selectedRowKeys = [];
37 | this.showModal = false;
38 | this.curId = '';
39 | this.modalType = '';
40 | this.title = '';
41 | this.cover = '';
42 | this.soundCloudUrl = '';
43 | this.releaseDate = '';
44 | this.uploadStatus = false;
45 | }
46 |
47 | getData = async () => {
48 | try {
49 | const response = await this.yanceyMusicApi.getData();
50 | runInAction(() => {
51 | this.dataSource = response.data;
52 | });
53 | } catch (e) {
54 | message.error('unknown error!');
55 | }
56 | };
57 |
58 | insertData = async () => {
59 | const params = {
60 | title: this.title,
61 | cover: this.cover,
62 | soundCloud_url: this.soundCloudUrl,
63 | release_date: this.releaseDate,
64 | };
65 | try {
66 | await this.yanceyMusicApi.insertData(params);
67 | this.showModal = false;
68 | message.success('insert success');
69 | this.dataSource.splice(0, this.dataSource.length);
70 | await this.getData();
71 | } catch (e) {
72 | message.error('unknown error!');
73 | }
74 | };
75 |
76 | modifyData = async () => {
77 | const params = {
78 | title: this.title,
79 | cover: this.cover,
80 | soundCloud_url: this.soundCloudUrl,
81 | release_date: this.releaseDate,
82 | };
83 | try {
84 | await this.yanceyMusicApi.modifyData(this.curId, params);
85 | this.showModal = false;
86 | message.success('modify success');
87 | this.dataSource.splice(0, this.dataSource.length);
88 | await this.getData();
89 | } catch (e) {
90 | message.error('unknown error!');
91 | }
92 | };
93 |
94 | deleteData = async (id) => {
95 | try {
96 | await this.yanceyMusicApi.deleteData(id);
97 | message.success('delete success');
98 | this.dataSource.splice(0, this.dataSource.length);
99 | await this.getData();
100 | } catch (e) {
101 | message.error('unknown error!');
102 | }
103 | };
104 |
105 | batchDelete = async () => {
106 | const params = {
107 | selectedList: this.selectedRowKeys,
108 | };
109 | try {
110 | await this.yanceyMusicApi.batchDeleteData(params);
111 | message.success('delete success');
112 | this.dataSource.splice(0, this.dataSource.length);
113 | this.selectedRowKeys.splice(0, this.selectedRowKeys.length);
114 | await this.getData();
115 | } catch (e) {
116 | message.error('unknown error!');
117 | }
118 | };
119 |
120 | @computed get isFilled() {
121 | return this.title !== '' && this.cover !== '' && this.soundCloudUrl !== '' && this.releaseDate !== '';
122 | }
123 |
124 | @action onSelectChange = (selectedRowKeys) => {
125 | this.selectedRowKeys = selectedRowKeys;
126 | };
127 |
128 | @action openModal = (type, id = '', title = '', soundCloudUrl = '', releaseDate = getCurrentDate(), cover = '') => {
129 | this.modalType = type;
130 | this.curId = id;
131 | this.title = title;
132 | this.soundCloudUrl = soundCloudUrl;
133 | this.releaseDate = releaseDate;
134 | this.cover = cover;
135 | this.showModal = true;
136 | };
137 |
138 | @action closeModal = () => {
139 | this.showModal = false;
140 | this.title = '';
141 | this.cover = '';
142 | this.soundCloudUrl = '';
143 | this.releaseDate = '';
144 | };
145 |
146 | @action onTitleChange = (e) => {
147 | this.title = e.target.value;
148 | };
149 |
150 | @action onSoundCloudUrlChange = (e) => {
151 | this.soundCloudUrl = e.target.value;
152 | };
153 |
154 | @action onReleaseDateChange = (date, dateString) => {
155 | this.releaseDate = dateString;
156 | };
157 |
158 | @action onUploadChange = (info) => {
159 | if (info.file.status === 'uploading') {
160 | this.uploadStatus = true;
161 | return;
162 | }
163 | if (info.file.status === 'done') {
164 | this.uploadStatus = false;
165 | this.cover = info.file.response.path;
166 | }
167 | }
168 | }
169 |
170 | const yanceyMusicStore = new YanceyMusicStore(yanceyMusicApi);
171 |
172 | export default yanceyMusicStore;
173 |
--------------------------------------------------------------------------------
/src/stores/index.js:
--------------------------------------------------------------------------------
1 | import announcementStore from './AnnouncementStore';
2 | import mottoStore from './MottoStore';
3 | import projectStore from './ProjectStore';
4 | import coverStore from './CoverStore';
5 | import liveTourStore from './LiveTourStore';
6 | import featuredRecordStore from './FeaturedRecordStore';
7 | import yanceyMusicStore from './YanceyMusicStore';
8 | import playerStore from './PlayerStore';
9 | import serverStatusStore from './ServerStatusStore';
10 | import workExperienceStore from './WorkExperienceStore';
11 | import programExperienceStore from './ProgramExperienceStore';
12 | import articleStore from './ArticleStore';
13 | import articleDetailStore from './ArticleDetailStore';
14 | import aboutStore from './AboutStore';
15 | import loginStore from './LoginStore';
16 | import userInfoStore from './UserInfoStore';
17 | import globalStore from './GlobalStore';
18 | import modifyPasswordStore from './ModifyPasswordStore';
19 |
20 | export default {
21 | mottoStore,
22 | announcementStore,
23 | projectStore,
24 | coverStore,
25 | liveTourStore,
26 | featuredRecordStore,
27 | yanceyMusicStore,
28 | playerStore,
29 | serverStatusStore,
30 | workExperienceStore,
31 | programExperienceStore,
32 | articleStore,
33 | articleDetailStore,
34 | aboutStore,
35 | loginStore,
36 | userInfoStore,
37 | globalStore,
38 | modifyPasswordStore,
39 | };
40 |
--------------------------------------------------------------------------------
/src/util/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { message } from 'antd/lib/index';
3 | import baseUrl from './baseUrl';
4 | import history from '../history';
5 |
6 | // config timeout
7 | axios.defaults.timeout = 5 * 10000;
8 |
9 | // config cookie
10 | // axios.defaults.withCredentials = true
11 |
12 | // config request header
13 | axios.defaults.headers.post['Content-Type'] = 'application/json';
14 | axios.defaults.headers.put['Content-Type'] = 'application/json';
15 |
16 | // config base url
17 | axios.defaults.baseURL = baseUrl.production;
18 |
19 | // config request interceptors
20 | let cancelFlag = true;
21 | axios.interceptors.request.use(
22 | (req) => {
23 | if (req.url !== '/login') {
24 | const now = new Date().getTime();
25 | const token = window.localStorage.getItem('token');
26 | const expires = window.localStorage.getItem('expires_date');
27 | if (expires && token) {
28 | if (expires - now < 0) {
29 | message.error('token expires!');
30 | window.localStorage.clear();
31 | setTimeout(() => {
32 | history.push('/login');
33 | }, 2000);
34 | return false;
35 | }
36 | req.headers.Authorization = `Bearer ${token}`;
37 | } else if (cancelFlag) {
38 | history.push('/login');
39 | cancelFlag = false;
40 | return false;
41 | } else {
42 | history.push('/login');
43 | return false;
44 | }
45 | }
46 | return req;
47 | },
48 | err => Promise.reject(err),
49 | );
50 |
51 | // config response interceptors
52 | axios.interceptors.response.use(
53 | res => res,
54 | err => Promise.reject(err)
55 | ,
56 | );
57 |
58 | // GET
59 | export function GET(url, params) {
60 | return new Promise((resolve, reject) => {
61 | axios
62 | .get(url, { params })
63 | .then((res) => {
64 | resolve(res);
65 | })
66 | .catch((err) => {
67 | reject(err);
68 | });
69 | });
70 | }
71 |
72 | // POST
73 | export function POST(url, params, config) {
74 | return new Promise((resolve, reject) => {
75 | axios
76 | .post(url, params, config)
77 | .then(
78 | (res) => {
79 | resolve(res);
80 | },
81 | (err) => {
82 | reject(err);
83 | },
84 | )
85 | .catch((err) => {
86 | reject(err);
87 | });
88 | });
89 | }
90 |
91 | // PUT
92 | export function PUT(url, params) {
93 | return new Promise((resolve, reject) => {
94 | axios
95 | .put(url, params)
96 | .then((res) => {
97 | resolve(res);
98 | })
99 | .catch((err) => {
100 | reject(err);
101 | });
102 | });
103 | }
104 |
105 | // DELETE
106 | export function DELETE(url, params) {
107 | return new Promise((resolve, reject) => {
108 | axios
109 | .delete(url, { data: params })
110 | .then((res) => {
111 | resolve(res);
112 | })
113 | .catch((err) => {
114 | reject(err);
115 | });
116 | });
117 | }
118 |
--------------------------------------------------------------------------------
/src/util/baseUrl.js:
--------------------------------------------------------------------------------
1 | const baseUri = {
2 | development: 'http://127.0.0.1:3001/api/',
3 | production: 'https://api.yanceyleo.com/api/',
4 | };
5 |
6 | export default baseUri;
7 |
--------------------------------------------------------------------------------
/src/util/tools.js:
--------------------------------------------------------------------------------
1 | import { message } from 'antd';
2 | import { uploadApi } from '../http/index';
3 |
4 | export const beforeUpload = (file) => {
5 | const isImageFormat = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif';
6 | if (!isImageFormat) {
7 | message.error('You can only upload JPG or PNG or GIF image!');
8 | }
9 | const isLt2M = file.size / 1024 / 1024 < 2;
10 | if (!isLt2M) {
11 | message.error('Image must smaller than 2MB!');
12 | }
13 | return isImageFormat && isLt2M;
14 | };
15 |
16 | export const musicBeforeUpload = (file) => {
17 | const isMusicFormat = file.type === 'audio/mp3' || file.type === 'audio/x-m4a';
18 | if (!isMusicFormat) {
19 | message.error('You can only upload MP3 or M4A music!');
20 | }
21 | const isLt15M = file.size / 1024 / 1024 < 15;
22 | if (!isLt15M) {
23 | message.error('Music File must smaller than 15MB!');
24 | }
25 | return isMusicFormat && isLt15M;
26 | };
27 |
28 | export const formatJSONDate = jsonDate => new Date(+new Date(new Date(jsonDate).toJSON()) + 8 * 3600 * 1000).toISOString()
29 | .replace(/T/g, ' ')
30 | .replace(/\.[\d]{3}Z/, '');
31 |
32 | export const getType = param => Object.prototype.toString.call(param)
33 | .slice(8, -1)
34 | .toLowerCase();
35 |
36 | export const capitalized = str => str.toLowerCase()
37 | .replace(/( |^)[a-z]/g, L => L.toUpperCase());
38 |
39 |
40 | export const getCurrentDate = () => {
41 | const date = new Date();
42 | const year = date.getFullYear();
43 | const month = date.getMonth() + 1;
44 | const day = date.getDate();
45 | return `${year}-${month}-${day}`;
46 | };
47 |
48 | export const formatTimestampDate = (date) => {
49 | const timestampDate = new Date(date);
50 | const Y = `${timestampDate.getFullYear()}-`;
51 | const M = `${timestampDate.getMonth() + 1 < 10 ? `0${timestampDate.getMonth() + 1}` : timestampDate.getMonth() + 1}-`;
52 | const D = `${timestampDate.getDate() < 10 ? `0${timestampDate.getDate()}` : timestampDate.getDate()} `;
53 | const h = `${timestampDate.getHours() < 10 ? `0${timestampDate.getHours()}` : timestampDate.getHours()}:`;
54 | const m = `${timestampDate.getMinutes() < 10 ? `0${timestampDate.getMinutes()}` : timestampDate.getMinutes()}:`;
55 | const s = (timestampDate.getSeconds() < 10 ? `0${timestampDate.getSeconds()}` : timestampDate.getSeconds());
56 | return Y + M + D + h + m + s;
57 | };
58 |
59 | export function checkWebp() {
60 | return (document.createElement('canvas')
61 | .toDataURL('image/webp')
62 | .indexOf('data:image/webp') === 0);
63 | }
64 |
65 | export const webp = '?x-oss-process=image/format,webp';
66 |
67 | export const upload = () => {
68 | const token = window.localStorage.getItem('token');
69 | return {
70 | headers: {
71 | Authorization: `Bearer ${token}`,
72 | },
73 | action: uploadApi,
74 | };
75 | };
76 |
--------------------------------------------------------------------------------