├── app
├── view
│ ├── .gitkeep
│ └── README.md
├── web
│ ├── page
│ │ ├── about
│ │ │ ├── about.css
│ │ │ └── about.vue
│ │ ├── index
│ │ │ ├── index.css
│ │ │ └── index.vue
│ │ ├── category
│ │ │ ├── category.css
│ │ │ └── category.vue
│ │ └── admin
│ │ │ ├── home
│ │ │ ├── store
│ │ │ │ └── app
│ │ │ │ │ ├── getters.ts
│ │ │ │ │ ├── mutation-type.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── mutations.ts
│ │ │ │ │ └── actions.ts
│ │ │ ├── view
│ │ │ │ ├── notfound.vue
│ │ │ │ ├── dashboard
│ │ │ │ │ └── index.vue
│ │ │ │ ├── detail.vue
│ │ │ │ ├── write
│ │ │ │ │ └── index.vue
│ │ │ │ └── list.vue
│ │ │ ├── home.vue
│ │ │ ├── home.ts
│ │ │ ├── router
│ │ │ │ └── index.ts
│ │ │ └── component
│ │ │ │ └── panel.vue
│ │ │ └── login
│ │ │ ├── login.ts
│ │ │ ├── login.less
│ │ │ └── login.vue
│ ├── theme
│ │ ├── form-item.css
│ │ ├── menu-item.css
│ │ ├── submenu.css
│ │ ├── tab-pane.css
│ │ ├── breadcrumb-item.css
│ │ ├── button-group.css
│ │ ├── checkbox-button.css
│ │ ├── checkbox-group.css
│ │ ├── collapse-item.css
│ │ ├── dropdown-item.css
│ │ ├── dropdown-menu.css
│ │ ├── menu-item-group.css
│ │ ├── aside.css
│ │ ├── footer.css
│ │ ├── header.css
│ │ ├── radio-group.css
│ │ ├── fonts
│ │ │ ├── element-icons.ttf
│ │ │ └── element-icons.woff
│ │ ├── main.css
│ │ ├── steps.css
│ │ ├── card.css
│ │ ├── container.css
│ │ ├── option-group.css
│ │ ├── rate.css
│ │ ├── badge.css
│ │ ├── option.css
│ │ ├── reset.css
│ │ ├── row.css
│ │ ├── spinner.css
│ │ ├── breadcrumb.css
│ │ ├── display.css
│ │ ├── scrollbar.css
│ │ ├── carousel-item.css
│ │ ├── collapse.css
│ │ ├── alert.css
│ │ ├── tree.css
│ │ ├── popper.css
│ │ ├── switch.css
│ │ ├── loading.css
│ │ ├── notification.css
│ │ ├── message.css
│ │ ├── progress.css
│ │ ├── popover.css
│ │ ├── tag.css
│ │ ├── carousel.css
│ │ ├── radio-button.css
│ │ ├── tooltip.css
│ │ ├── dialog.css
│ │ ├── form.css
│ │ ├── select-dropdown.css
│ │ ├── radio.css
│ │ ├── icon.css
│ │ ├── menu.css
│ │ ├── step.css
│ │ ├── input.css
│ │ ├── color-picker.css
│ │ ├── checkbox.css
│ │ ├── base.css
│ │ └── input-number.css
│ ├── typescript
│ │ ├── window.d.ts
│ │ ├── vue.d.ts
│ │ └── webpack.d.ts
│ ├── framework
│ │ └── vue
│ │ │ ├── component
│ │ │ └── index.ts
│ │ │ ├── directive
│ │ │ └── index.ts
│ │ │ ├── entry
│ │ │ ├── client-loader.ts
│ │ │ ├── server-loader.ts
│ │ │ ├── client.ts
│ │ │ └── server.ts
│ │ │ └── filter
│ │ │ └── index.ts
│ ├── component
│ │ ├── layout
│ │ │ ├── index
│ │ │ │ ├── footer
│ │ │ │ │ ├── footer.css
│ │ │ │ │ └── footer.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── content
│ │ │ │ │ ├── content.vue
│ │ │ │ │ └── content.css
│ │ │ │ ├── main.vue
│ │ │ │ └── header
│ │ │ │ │ ├── header.less
│ │ │ │ │ └── header.vue
│ │ │ ├── default.ts
│ │ │ ├── admin
│ │ │ │ ├── index.ts
│ │ │ │ ├── content
│ │ │ │ │ ├── content.vue
│ │ │ │ │ └── content.css
│ │ │ │ ├── index.css
│ │ │ │ ├── footer
│ │ │ │ │ ├── footer.vue
│ │ │ │ │ └── footer.css
│ │ │ │ ├── menu
│ │ │ │ │ └── index.ts
│ │ │ │ ├── main.vue
│ │ │ │ ├── header
│ │ │ │ │ ├── header.less
│ │ │ │ │ └── header.vue
│ │ │ │ └── aside
│ │ │ │ │ └── aside.vue
│ │ │ └── layout.ts
│ │ └── MarkdownEditor
│ │ │ └── index.vue
│ ├── asset
│ │ ├── images
│ │ │ ├── logo.png
│ │ │ ├── favicon.ico
│ │ │ ├── loading.gif
│ │ │ └── egg-vue-webpack-dev.png
│ │ ├── fonts
│ │ │ ├── FontAwesome.otf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ ├── fontawesome-webfont.woff2
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ └── glyphicons-halflings-regular.woff2
│ │ └── css
│ │ │ └── global.css
│ ├── tsconfig.json
│ └── view
│ │ ├── layout.html
│ │ └── layout.ejs
├── extend
│ ├── context.ts
│ └── application.ts
├── model
│ ├── artilcedetail.ts
│ ├── user.ts
│ └── article.ts
├── lib
│ ├── db
│ │ ├── mongo.ts
│ │ ├── msyql.ts
│ │ ├── factory.ts
│ │ ├── base.ts
│ │ ├── collection.ts
│ │ └── file.ts
│ └── condition.ts
├── controller
│ ├── about
│ │ └── about.ts
│ ├── category
│ │ └── category.ts
│ ├── admin
│ │ └── admin.ts
│ └── index
│ │ └── index.ts
├── router.ts
├── index.td.ts
├── middleware
│ └── access.ts
├── service
│ └── article.ts
└── mocks
│ └── article
│ └── list.ts
├── docs
├── TypeScript.md
├── images
│ ├── admin.png
│ ├── home.png
│ ├── webpack.png
│ ├── egg-webpack.png
│ ├── webpack-build.png
│ ├── vue-mutil-page.png
│ └── vue-single-page.png
├── perform.md
└── issue_template.md
├── config
├── plugin.ts
├── config.test.ts
├── plugin.local.ts
├── config.prod.ts
├── config.local.ts
├── config.default.ts
└── tsconfig.json
├── .gitattributes
├── postcss.config.js
├── typings
├── config
│ ├── plugin.d.ts
│ └── index.d.ts
└── app
│ ├── extend
│ ├── context.d.ts
│ └── application.d.ts
│ ├── service
│ └── index.d.ts
│ ├── middleware
│ └── index.d.ts
│ ├── model
│ └── index.d.ts
│ └── controller
│ └── index.d.ts
├── .babelrc
├── .gitignore
├── test
└── lowdb.test.js
├── tslint.json
├── .vscode
└── settings.json
├── tsconfig.json
├── webpack.config.js
├── LICENSE
├── README.md
└── package.json
/app/view/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/TypeScript.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/page/about/about.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/page/index/index.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/form-item.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/menu-item.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/submenu.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/tab-pane.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/breadcrumb-item.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/button-group.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/checkbox-button.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/checkbox-group.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/collapse-item.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/dropdown-item.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/dropdown-menu.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/theme/menu-item-group.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/typescript/window.d.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/page/category/category.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/framework/vue/component/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/framework/vue/directive/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/web/component/layout/index/footer/footer.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/view/README.md:
--------------------------------------------------------------------------------
1 | ## egg规范view目录, 保证view文件夹存在, 否则app.config.view.root为空, 编译服务器文件会存放到该目录.
--------------------------------------------------------------------------------
/app/web/page/admin/home/store/app/getters.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | export default {};
--------------------------------------------------------------------------------
/app/web/theme/aside.css:
--------------------------------------------------------------------------------
1 | .el-aside{overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}
--------------------------------------------------------------------------------
/app/web/theme/footer.css:
--------------------------------------------------------------------------------
1 | .el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}
--------------------------------------------------------------------------------
/app/web/theme/header.css:
--------------------------------------------------------------------------------
1 | .el-header{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}
--------------------------------------------------------------------------------
/config/plugin.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | vuessr: {
3 | package: 'egg-view-vue-ssr'
4 | }
5 | };
--------------------------------------------------------------------------------
/app/web/typescript/vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.vue" {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
--------------------------------------------------------------------------------
/docs/images/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/admin.png
--------------------------------------------------------------------------------
/docs/images/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/home.png
--------------------------------------------------------------------------------
/app/extend/context.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | export default {
3 | get db() {
4 | return this.app.db;
5 | }
6 | };
--------------------------------------------------------------------------------
/app/web/theme/radio-group.css:
--------------------------------------------------------------------------------
1 | .el-radio-group{display:inline-block;line-height:1;vertical-align:middle;font-size:0}
--------------------------------------------------------------------------------
/docs/images/webpack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/webpack.png
--------------------------------------------------------------------------------
/app/model/artilcedetail.ts:
--------------------------------------------------------------------------------
1 | export default class ArticleDetail {
2 | public id: number;
3 | public content: string;
4 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=javascript
2 | *.css linguist-language=javascript
3 | *.html linguist-language=javascript
--------------------------------------------------------------------------------
/app/web/asset/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/images/logo.png
--------------------------------------------------------------------------------
/docs/images/egg-webpack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/egg-webpack.png
--------------------------------------------------------------------------------
/docs/images/webpack-build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/webpack-build.png
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | plugins: [
5 | require('autoprefixer')
6 | ]
7 | };
8 |
--------------------------------------------------------------------------------
/docs/images/vue-mutil-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/vue-mutil-page.png
--------------------------------------------------------------------------------
/docs/images/vue-single-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/docs/images/vue-single-page.png
--------------------------------------------------------------------------------
/app/web/asset/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/images/favicon.ico
--------------------------------------------------------------------------------
/app/web/asset/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/images/loading.gif
--------------------------------------------------------------------------------
/app/web/asset/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/app/web/theme/fonts/element-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/theme/fonts/element-icons.ttf
--------------------------------------------------------------------------------
/app/web/theme/fonts/element-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/theme/fonts/element-icons.woff
--------------------------------------------------------------------------------
/app/web/theme/main.css:
--------------------------------------------------------------------------------
1 | .el-main{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box;padding:20px}
--------------------------------------------------------------------------------
/app/web/asset/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/app/web/asset/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/app/web/asset/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/app/web/asset/images/egg-vue-webpack-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/images/egg-vue-webpack-dev.png
--------------------------------------------------------------------------------
/app/model/user.ts:
--------------------------------------------------------------------------------
1 | export default class User {
2 | public id: number;
3 | public name: string;
4 | public password: string;
5 | public roleId: number;
6 | }
--------------------------------------------------------------------------------
/app/web/asset/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/app/web/asset/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/web/asset/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/app/web/asset/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/app/web/asset/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hubcarl/egg-typescript-element-kit/HEAD/app/web/asset/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/app/lib/db/mongo.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import BaseDB from './base';
3 | export default class MongoDB extends BaseDB {
4 | constructor(name: string) {
5 | super(name);
6 | }
7 | }
--------------------------------------------------------------------------------
/app/lib/db/msyql.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import BaseDB from './base';
3 | export default class MySQLDB extends BaseDB {
4 | constructor(name?: string) {
5 | super(name);
6 | }
7 | }
--------------------------------------------------------------------------------
/config/config.test.ts:
--------------------------------------------------------------------------------
1 |
2 | import { Application, EggAppConfig } from 'egg';
3 |
4 | export default (app: EggAppConfig) => {
5 | const exports: any = {};
6 |
7 | return exports;
8 | };
9 |
--------------------------------------------------------------------------------
/app/web/typescript/webpack.d.ts:
--------------------------------------------------------------------------------
1 | declare var EASY_ENV_IS_NODE: boolean;
2 | declare var EASY_ENV_IS_BROWSER: boolean;
3 | declare var process : {
4 | env: {
5 | NODE_ENV: string
6 | }
7 | }
--------------------------------------------------------------------------------
/docs/perform.md:
--------------------------------------------------------------------------------
1 | http://www.jianshu.com/p/1dffe3126686
2 |
3 | http://alexkuz.github.io/webpack-chart/
4 | http://webpack.github.io/analyse/
5 |
6 |
7 | http://kiwenlau.com/2017/04/01/nodejs-async-await/
--------------------------------------------------------------------------------
/config/plugin.local.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | cors: {
3 | package: 'egg-cors'
4 | },
5 | webpack: {
6 | package: 'egg-webpack'
7 | },
8 | webpackvue : {
9 | package: 'egg-webpack-vue'
10 | }
11 | };
--------------------------------------------------------------------------------
/typings/config/plugin.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg-cors';
5 | import 'egg-webpack';
6 | import 'egg-webpack-vue';
7 | import 'egg-view-vue-ssr';
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [["env",{ "modules": false }]],
3 | "plugins": [
4 | "transform-object-rest-spread",
5 | "syntax-dynamic-import",
6 | "transform-object-assign"
7 | ],
8 | "comments": false
9 | }
10 |
--------------------------------------------------------------------------------
/app/web/page/admin/home/store/app/mutation-type.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | export const SET_ARTICLE_LIST = 'SET_ARTICLE_LIST';
4 | export const SET_ARTICLE_DETAIL = 'SET_ARTICLE_DETAIL';
5 | export const SET_SAVE_ARTICLE = 'SET_SAVE_ARTICLE';
--------------------------------------------------------------------------------
/app/controller/about/about.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import { Controller } from 'egg';
3 | export default class AboutController extends Controller {
4 | public async index() {
5 | await this.ctx.render('about/about.js', { message: 'vue server side render!' });
6 | }
7 | }
--------------------------------------------------------------------------------
/app/web/page/admin/home/view/notfound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Not Find The Page!!!
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/config/config.prod.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 生产环境配置
3 | *
4 | * 最终生效的配置为 prod + default(前者覆盖后者)
5 | */
6 |
7 | import { Application, EggAppConfig } from 'egg';
8 |
9 | export default (app: EggAppConfig) => {
10 | const exports: any = {};
11 |
12 | return exports;
13 | };
14 |
--------------------------------------------------------------------------------
/app/web/component/layout/default.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import MainLayout from './main.vue';
3 | import '../../asset/css/global.css';
4 | import createLayout from './layout';
5 | const tpl = '
';
6 | export default createLayout('Layout', { }, tpl);
--------------------------------------------------------------------------------
/typings/app/extend/context.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import ExtendObject from '../../../app/extend/context';
5 | declare module 'egg' {
6 | interface Context {
7 | db: typeof ExtendObject.db;
8 | }
9 | }
--------------------------------------------------------------------------------
/app/controller/category/category.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import { Controller } from 'egg';
3 | export default class CategoryController extends Controller {
4 | public async index() {
5 | await this.ctx.render('category/category.js', { message: 'Egg + TypeScript: Category'});
6 | }
7 | }
--------------------------------------------------------------------------------
/typings/app/service/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import Article from '../../../app/service/article';
5 |
6 | declare module 'egg' {
7 | interface IService {
8 | article: Article;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/typings/app/extend/application.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import ExtendObject from '../../../app/extend/application';
5 | declare module 'egg' {
6 | interface Application {
7 | db: typeof ExtendObject.db;
8 | }
9 | }
--------------------------------------------------------------------------------
/typings/app/middleware/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import Access from '../../../app/middleware/access';
5 |
6 | declare module 'egg' {
7 | interface IMiddleware {
8 | access: typeof Access;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/docs/issue_template.md:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/app/web/theme/steps.css:
--------------------------------------------------------------------------------
1 | .el-steps{display:-webkit-box;display:-ms-flexbox;display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#f5f7fa}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}
--------------------------------------------------------------------------------
/app/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../config/tsconfig.json",
3 | "compilerOptions": {
4 | "target": "es5",
5 | "module": "esnext",
6 | "lib": [
7 | "es6",
8 | "dom"
9 | ]
10 | },
11 |
12 | "exclude": [
13 | "node_modules",
14 | "**/*.spec.ts"
15 | ]
16 | }
--------------------------------------------------------------------------------
/app/extend/application.ts:
--------------------------------------------------------------------------------
1 | import DB from '../lib/db/base';
2 | import DBFactory from '../lib/db/factory';
3 | const DBSymbol = Symbol('Application#db');
4 | export default {
5 | get db(): DB {
6 | if (!this[DBSymbol]) {
7 | this[DBSymbol] = DBFactory();
8 | }
9 | return this[DBSymbol];
10 | },
11 | };
--------------------------------------------------------------------------------
/app/web/page/admin/home/home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
18 |
--------------------------------------------------------------------------------
/app/web/theme/card.css:
--------------------------------------------------------------------------------
1 | .el-card{border-radius:4px;border:1px solid #e6ebf5;background-color:#fff;overflow:hidden;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);color:#2d2f33}.el-card__header{padding:18px 20px;border-bottom:1px solid #e6ebf5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}
--------------------------------------------------------------------------------
/app/lib/db/factory.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import FileDB from './file';
3 | import MongoDB from './mongo';
4 | import MySQLDB from './msyql';
5 | export default function(type?: string) {
6 | switch (type) {
7 | case 'mysql':
8 | return new MySQLDB();
9 | case 'mongo':
10 | return new MySQLDB();
11 | default:
12 | return new FileDB();
13 | }
14 | }
--------------------------------------------------------------------------------
/app/web/component/layout/admin/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import MainLayout from './main.vue';
3 | import '../../../asset/css/global.css';
4 | import './index.css';
5 | import createLayout from '../layout';
6 | const tpl = '';
7 | export default createLayout('Layout', { MainLayout }, tpl);
8 |
--------------------------------------------------------------------------------
/app/web/component/layout/index/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import MainLayout from './main.vue';
3 | import '../../../asset/css/bootstrap.css';
4 | import '../../../asset/css/blog.css';
5 | import createLayout from '../layout';
6 | const tpl = '';
7 | export default createLayout('Layout', { MainLayout }, tpl);
8 |
--------------------------------------------------------------------------------
/app/web/theme/container.css:
--------------------------------------------------------------------------------
1 | .el-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-sizing:border-box;box-sizing:border-box}.el-container.is-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .happypack/
3 | node_modules/
4 | npm-debug.log
5 | .idea/
6 | dist
7 | static
8 | public
9 | private
10 | run
11 | *.iml
12 | artifacts.json
13 | *tmp
14 | _site
15 | logs
16 | app/**/*.js
17 | config/**/*.js
18 | index.js
19 | config/manifest.json
20 | app/view/*
21 | !app/view/layout.html
22 | !app/view/README.md
23 | !app/view/.gitkeep
24 | package-lock.json
25 | yarn.lock
26 | *.log
27 | coverage
--------------------------------------------------------------------------------
/app/web/component/layout/index/content/content.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
23 |
--------------------------------------------------------------------------------
/app/web/framework/vue/entry/client-loader.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = function(source) {
3 | this.cacheable();
4 | return `
5 | import Vue from 'vue';
6 | import Layout from 'component/layout/index';
7 | import render from 'client';
8 | import Page from '${this.resourcePath.replace(/\\/g, '\\\\')}';
9 | Vue.component(Layout.name, Layout);
10 | export default render({ ...Page });
11 | `;
12 | };
--------------------------------------------------------------------------------
/app/web/framework/vue/entry/server-loader.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = function(source) {
3 | this.cacheable();
4 | return `
5 | import Vue from 'vue';
6 | import Layout from 'component/layout/index';
7 | import render from 'server';
8 | import Page from '${this.resourcePath.replace(/\\/g, '\\\\')}';
9 | Vue.component(Layout.name, Layout);
10 | export default render({ ...Page });
11 | `;
12 | };
--------------------------------------------------------------------------------
/app/web/page/admin/home/view/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | vue-server-render detail
4 |
5 |
6 |
7 |
10 |
18 |
--------------------------------------------------------------------------------
/app/web/page/admin/home/store/app/index.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import Vue from 'vue';
3 | import Vuex from 'vuex';
4 |
5 | import actions from './actions';
6 | import getters from './getters';
7 | import mutations from './mutations';
8 |
9 | Vue.use(Vuex);
10 |
11 | const state = {
12 | articleTotal: 0,
13 | articleList: [],
14 | article: {}
15 | };
16 |
17 | export default new Vuex.Store({
18 | state,
19 | actions,
20 | getters,
21 | mutations
22 | });
--------------------------------------------------------------------------------
/app/web/framework/vue/filter/index.ts:
--------------------------------------------------------------------------------
1 | // import Vue from 'vue';
2 |
3 | // /**
4 | // * 去掉HTML标签
5 | // */
6 | // Vue.filter('removeHtml', input => {
7 | // return input && input.replace(/<(?:.|\n)*?>/gm, '')
8 | // .replace(/(”)/g, '\"')
9 | // .replace(/“/g, '\"')
10 | // .replace(/—/g, '-')
11 | // .replace(/ /g, '')
12 | // .replace(/>/g, '>')
13 | // .replace(/</g, '<')
14 | // .replace(/<[\w\s"':=\/]*/, '');
15 | // });
--------------------------------------------------------------------------------
/test/lowdb.test.js:
--------------------------------------------------------------------------------
1 | const lowdb = require('lowdb');
2 | const FileSync = require('lowdb/adapters/FileSync');
3 | const file = new FileSync('blog.json');
4 | const db = lowdb(file);
5 | db._.mixin({
6 | like(array, predicate){
7 | Object.keys(predicate).forEach(item => {
8 |
9 | });
10 | }
11 | })
12 | const result = db.get('article')
13 | .filter(item => {
14 | return item.title && item.title.indexOf('webpack')>-1;
15 | })
16 | .value();
17 |
18 | console.log(result);
--------------------------------------------------------------------------------
/app/web/theme/option-group.css:
--------------------------------------------------------------------------------
1 | .el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#dfe4ed}.el-select-group__title{padding-left:20px;font-size:12px;color:#878d99;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}
--------------------------------------------------------------------------------
/app/web/component/layout/admin/content/content.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
25 |
--------------------------------------------------------------------------------
/typings/app/model/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import Article from '../../../app/model/article';
5 | import Artilcedetail from '../../../app/model/artilcedetail';
6 | import User from '../../../app/model/user';
7 |
8 | declare module 'sequelize' {
9 | interface Sequelize {
10 | Article: ReturnType;
11 | Artilcedetail: ReturnType;
12 | User: ReturnType;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/web/component/layout/admin/index.css:
--------------------------------------------------------------------------------
1 | .admin .search {
2 | margin-top: 8px;
3 | margin-bottom: 16px;
4 | }
5 | .admin label {
6 | padding-left: 8px;
7 | padding-right: 8px;
8 | color: #878d99
9 | }
10 |
11 | .admin .search-input{
12 | max-width: 200px;
13 | }
14 | .admin .search-button{
15 | margin-left: 16px;
16 | }
17 | .admin .add-button{
18 | float:right;
19 | margin-right: 16px;
20 | }
21 |
22 | .admin .long-input {
23 | max-width: 75%;
24 | }
25 |
26 | .admin .top16 {
27 | margin-top: 16px;
28 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "jsRules": {},
7 | "rules": {
8 | "ordered-imports": false,
9 | "trailing-comma": false,
10 | "quotemark": [true, "single", "jsx-double"],
11 | "eofline": false,
12 | "object-literal-sort-keys": false,
13 | "interface-name": false,
14 | "arrow-parens": false,
15 | "no-console": false,
16 | "max-line-length": false,
17 | "only-arrow-functions": false
18 | },
19 | "rulesDirectory": ["app"]
20 | }
--------------------------------------------------------------------------------
/app/web/component/layout/index/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
11 |
21 |
--------------------------------------------------------------------------------
/app/web/theme/rate.css:
--------------------------------------------------------------------------------
1 | .el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-rate{height:20px;line-height:1}.el-rate:active,.el-rate:focus{outline-width:0}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#b4bccc;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-rate__text{font-size:14px;vertical-align:middle}
--------------------------------------------------------------------------------
/app/web/page/admin/login/login.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import ElementUI from 'element-ui';
3 | import clientRender from 'client';
4 | import serverRender from 'server';
5 | import Layout from 'component/layout/default';
6 | import login from './login.vue';
7 | import '../../../theme/index.css';
8 | import '../../../asset/css/font-awesome.min.css';
9 |
10 | Vue.use(ElementUI);
11 | Vue.component(Layout.name, Layout);
12 | const options = {
13 | ...login,
14 | };
15 |
16 | export default EASY_ENV_IS_NODE ? serverRender(options) : clientRender(options);
17 |
--------------------------------------------------------------------------------
/app/web/theme/badge.css:
--------------------------------------------------------------------------------
1 | .el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#fa5555;border-radius:10px;color:#fff;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #fff}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}
--------------------------------------------------------------------------------
/app/web/asset/css/global.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | outline: none;
5 | box-sizing: border-box;
6 | }
7 | html, body{
8 | height: 100%;
9 | }
10 |
11 | a {
12 | color: #3c8dbc;
13 | text-decoration: none;
14 | }
15 |
16 | -webkit-scrollbar {
17 | width: 4px;
18 | background-color: #F5F5F5;
19 | }
20 |
21 | -webkit-scrollbar-track {
22 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
23 | background-color: #F5F5F5;
24 | }
25 |
26 | -webkit-scrollbar-thumb {
27 | box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
28 | background-color: #3e8dbb;
29 | }
--------------------------------------------------------------------------------
/app/web/theme/option.css:
--------------------------------------------------------------------------------
1 | .el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#5a5e66;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#b4bccc;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#fff}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#f5f7fa}.el-select-dropdown__item.selected{color:#3C8DBC;font-weight:700}.el-select-dropdown__item span{line-height:34px!important}
--------------------------------------------------------------------------------
/app/web/page/admin/home/store/app/mutations.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import {
4 | SET_ARTICLE_LIST,
5 | SET_ARTICLE_DETAIL,
6 | SET_SAVE_ARTICLE
7 | } from './mutation-type';
8 |
9 | const mutations = {
10 | [SET_ARTICLE_LIST](state, { list, total }) {
11 | state.articleTotal = total;
12 | state.articleList = list;
13 | },
14 | [SET_ARTICLE_DETAIL](state, data) {
15 | state.article = data;
16 | },
17 | [SET_SAVE_ARTICLE](state, data) {
18 | state.articleTotal += 1;
19 | state.articleList = [data].concat(state.articleList);
20 | }
21 | };
22 | export default mutations;
23 |
--------------------------------------------------------------------------------
/app/web/component/layout/admin/footer/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
19 |
--------------------------------------------------------------------------------
/app/web/framework/vue/entry/client.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import '../filter';
3 | import '../directive';
4 | import '../component';
5 |
6 | declare global {
7 | interface Window { __INITIAL_STATE__: any; }
8 | }
9 |
10 | export default function(options) {
11 | const state = window.__INITIAL_STATE__ || {};
12 | Vue.prototype.$http = require('axios');
13 | if (options.store) {
14 | options.store.replaceState(state);
15 | } else if (state) {
16 | options.data = Object.assign(state, options.data && options.data());
17 | }
18 | const app = new Vue(options);
19 | app.$mount('#app');
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.tabSize": 2,
3 | "editor.detectIndentation": false,
4 | "eslint.autoFixOnSave": true,
5 | "files.exclude": {
6 | "USE_GITIGNORE": true,
7 | "**/*.js": {
8 | "when": "$(basename).ts"
9 | }
10 | },
11 | "path-intellisense.mappings": {
12 | "lib": "${workspaceRoot}/app/web/lib",
13 | "asset": "${workspaceRoot}/app/web/asset",
14 | "component": "${workspaceRoot}/app/web/component",
15 | "page": "${workspaceRoot}/app/web/page",
16 | "store": "${workspaceRoot}/app/web/store",
17 | },
18 | "typescript.tsdk": "node_modules/typescript/lib"
19 | }
--------------------------------------------------------------------------------
/app/web/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Egg + Vue + Webpack
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/web/page/about/about.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Egg + TypeScript: About
5 |
6 |
7 |
8 |
11 |
33 |
34 |
--------------------------------------------------------------------------------
/app/web/page/admin/login/login.less:
--------------------------------------------------------------------------------
1 | .login{
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | position: absolute;
6 | height: 100%;
7 | width: 100%;
8 | background-color: #e4e5e6;
9 | .login-form{
10 | width: 375px;
11 | height: 400px;
12 | padding: 30px;
13 | background-color: white;
14 | text-align: left;
15 | border-radius: 4px;
16 | position: relative;
17 | margin-left: 0;
18 | margin-right: 0;
19 | zoom: 1;
20 | display: block;
21 | .login-header{
22 | text-align: center;
23 | font-size: 16px;
24 | font-weight: bold;
25 | margin-bottom: 20px;
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./config/tsconfig.json",
3 | "compileOnSave": true,
4 | "compilerOptions": {
5 | "target": "es2017",
6 | "module": "commonjs",
7 | /* Experimental Options */
8 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
9 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
10 | },
11 | "include": [
12 | "index.ts",
13 | "app/**/*.ts",
14 | "config/**/*.ts",
15 | "mock/**/*.ts",
16 | "test/**/*.ts"
17 | ],
18 | "exclude": [
19 | "public",
20 | "app/web",
21 | "app/public",
22 | "app/view"
23 | ]
24 | }
--------------------------------------------------------------------------------
/typings/app/controller/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import AboutAbout from '../../../app/controller/about/about';
5 | import AdminAdmin from '../../../app/controller/admin/admin';
6 | import CategoryCategory from '../../../app/controller/category/category';
7 | import IndexIndex from '../../../app/controller/index/index';
8 |
9 | declare module 'egg' {
10 | interface IController {
11 | about: {
12 | about: AboutAbout;
13 | };
14 | admin: {
15 | admin: AdminAdmin;
16 | };
17 | category: {
18 | category: CategoryCategory;
19 | };
20 | index: {
21 | index: IndexIndex;
22 | };
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/web/page/admin/home/home.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import ElementUI from 'element-ui';
3 | import { sync } from 'vuex-router-sync';
4 | import clientRender from 'client';
5 | import serverRender from 'server';
6 | import Layout from 'component/layout/admin';
7 | import store from './store/app';
8 | import router from './router';
9 | import home from './home.vue';
10 | import '../../../theme/index.css';
11 | import '../../../asset/css/font-awesome.min.css';
12 |
13 | Vue.use(ElementUI);
14 | Vue.component(Layout.name, Layout);
15 | sync(store, router);
16 |
17 | const options = {
18 | ...home,
19 | router,
20 | store
21 | };
22 |
23 | export default EASY_ENV_IS_NODE ? serverRender(options) : clientRender(options);
24 |
--------------------------------------------------------------------------------
/app/web/page/category/category.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ message }}
5 |
6 |
7 |
8 |
11 |
34 |
35 |
--------------------------------------------------------------------------------
/app/web/theme/reset.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";body{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;font-weight:400;font-size:14px;color:#000}a{color:#3C8DBC;text-decoration:none}a:focus,a:hover{color:rgb(99, 164, 201)}a:active{color:#3a8ee6}h1,h2,h3,h4,h5,h6{color:#5a5e66;font-weight:inherit}h1:first-child,h2:first-child,h3:first-child,h4:first-child,h5:first-child,h6:first-child,p:first-child{margin-top:0}h1:last-child,h2:last-child,h3:last-child,h4:last-child,h5:last-child,h6:last-child,p:last-child{margin-bottom:0}h1{font-size:20px}h2{font-size:18px}h3{font-size:16px}h4,h5,h6,p{font-size:inherit}p{line-height:1.8}sub,sup{font-size:13px}small{font-size:12px}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}
--------------------------------------------------------------------------------
/app/web/page/admin/home/view/detail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | vue-server-render detail
Add
4 |

5 |
6 |
7 |
10 |
26 |
--------------------------------------------------------------------------------
/app/router.ts:
--------------------------------------------------------------------------------
1 |
2 | import { Application } from 'egg';
3 |
4 | export default (application: Application) => {
5 | const { router, controller } = application;
6 | router.get('/', controller.index.index.index);
7 | router.get('/client', controller.index.index.client);
8 | router.get('/list', controller.index.index.list);
9 | router.get('/category', controller.category.category.index);
10 | router.get('/about', controller.about.about.index);
11 | router.get('/login', controller.admin.admin.login);
12 | router.post('/admin/api/article/list', controller.admin.admin.list);
13 | router.post('/admin/api/article/add', controller.admin.admin.add);
14 | router.get('/admin/api/article/:id', controller.admin.admin.detail);
15 | router.get('/admin(/.+)?', controller.admin.admin.home);
16 | };
--------------------------------------------------------------------------------
/app/lib/db/base.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import Condition from '../condition';
3 | import * as shortid from 'shortid';
4 | export default class DB {
5 | public instance;
6 | public name: string;
7 | constructor(name: string = 'blog.json') {
8 | this.name = name;
9 | }
10 |
11 | public getUniqueId() {
12 | return shortid.generate();
13 | }
14 |
15 | public get(collectionName: string) {
16 | return null;
17 | }
18 |
19 | public add(collectionName: string, json: object) {
20 | return null;
21 | }
22 |
23 | public update(collectionName: string, where: object, json: object) {
24 | return null;
25 | }
26 |
27 | public delete(collectionName: string, field: number | string) {
28 | return null;
29 | }
30 |
31 | public getPager(collectionName: string, condition: Condition) {
32 | return null;
33 | }
34 | }
--------------------------------------------------------------------------------
/app/web/page/admin/home/router/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | import VueRouter from 'vue-router';
4 | import Dashboard from '../view/dashboard/index.vue';
5 | import ArticleList from '../view/list.vue';
6 |
7 | Vue.use(VueRouter);
8 |
9 | export default new VueRouter({
10 | mode: 'history',
11 | base: '/admin/',
12 | routes: [
13 | {
14 | path: '/',
15 | component: Dashboard
16 | },
17 | {
18 | path: '/article/list',
19 | component: ArticleList
20 | },
21 | {
22 | path: '/article/add',
23 | component: () => import('../view/write/index.vue')
24 | },
25 | {
26 | path: '/article/detail/:id',
27 | component: () => import('../view/detail.vue')
28 | },
29 | {
30 | path: '*', component: () => import('../view/notfound.vue')
31 | }
32 | ]
33 | });
34 |
--------------------------------------------------------------------------------
/app/web/theme/row.css:
--------------------------------------------------------------------------------
1 | .el-row{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table;content:""}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}
--------------------------------------------------------------------------------
/app/web/theme/spinner.css:
--------------------------------------------------------------------------------
1 | .el-time-spinner{width:100%;white-space:nowrap}.el-spinner{display:inline-block;vertical-align:middle}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}
--------------------------------------------------------------------------------
/app/lib/condition.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import { JsonProperty } from '@hubcarl/json-typescript-mapper';
3 | export default class Condition {
4 | @JsonProperty('title')
5 | public title: string;
6 | @JsonProperty('categoryId')
7 | public categoryId: number;
8 | @JsonProperty('status')
9 | public status: number;
10 | @JsonProperty('tag')
11 | public tag: string;
12 | @JsonProperty('pageIndex')
13 | public pageIndex: number;
14 | @JsonProperty('pageSize')
15 | public pageSize: number;
16 | public where: any = {};
17 | public like: any = {};
18 | public orderByField: string = 'createTime';
19 | public orderBy: string = 'desc';
20 |
21 | constructor() {
22 | this.title = undefined;
23 | this.categoryId = undefined;
24 | this.status = undefined;
25 | this.tag = undefined;
26 | this.pageIndex = 1;
27 | this.pageSize = 10;
28 | this.where = {};
29 | this.like = {};
30 | }
31 | }
--------------------------------------------------------------------------------
/app/web/component/layout/admin/menu/index.ts:
--------------------------------------------------------------------------------
1 | const menu = {
2 | home: {
3 | name: '首页',
4 | path: '/',
5 | icon: 'fa fa-home',
6 | },
7 | content: {
8 | name: '内容管理',
9 | icon: 'fa fa-file',
10 | children: {
11 | list: {
12 | name: '文章管理',
13 | path: '/article/list'
14 | },
15 | add: {
16 | name: '添加文章',
17 | path: '/article/add'
18 | }
19 | }
20 | },
21 | learn: {
22 | name: '学习资料',
23 | icon: 'fa fa-file',
24 | children: {
25 | Egg: {
26 | name: 'Egg学习',
27 | path: '/'
28 | },
29 | Vue: {
30 | name: 'Vue学习',
31 | path: '/'
32 | },
33 | TypeScript: {
34 | name: 'TypeScript',
35 | path: '/'
36 | },
37 | EasyWebpack: {
38 | name: 'easywebpack',
39 | path: '/'
40 | }
41 | }
42 | }
43 | };
44 |
45 | export default menu;
--------------------------------------------------------------------------------
/app/index.td.ts:
--------------------------------------------------------------------------------
1 | import DB from './lib/db/base';
2 |
3 | import AboutController from './controller/about/about';
4 | import AdminController from './controller/admin/admin';
5 | import CategoryController from './controller/category/category';
6 | import IndexController from './controller/index/index';
7 |
8 | import ArticleService from './service/article';
9 |
10 | declare module 'egg' {
11 | interface Application {
12 | db: DB;
13 | }
14 |
15 | interface Context {
16 | db: DB;
17 | }
18 |
19 | interface IController {
20 | index: {
21 | index: IndexController,
22 | };
23 | category: {
24 | category: CategoryController,
25 | };
26 | about: {
27 | about: AboutController,
28 | };
29 | admin: {
30 | admin: AdminController,
31 | };
32 | }
33 |
34 | interface IService {
35 | article: ArticleService;
36 | }
37 |
38 | function startCluster(options: any);
39 | }
--------------------------------------------------------------------------------
/app/web/theme/breadcrumb.css:
--------------------------------------------------------------------------------
1 | .el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#b4bccc}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner,.el-breadcrumb__inner a{font-weight:700;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#2d2f33}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner:hover{color:#3C8DBC;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#5a5e66;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}
--------------------------------------------------------------------------------
/app/model/article.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { JsonProperty } from '@hubcarl/json-typescript-mapper';
4 |
5 | export default class Article {
6 | @JsonProperty('id')
7 | public id: string;
8 | @JsonProperty('title')
9 | public title: string;
10 | @JsonProperty('summary')
11 | public summary: string;
12 | @JsonProperty('categoryId')
13 | public categoryId: number;
14 | @JsonProperty('tag')
15 | public tag: string;
16 | @JsonProperty('categoryId')
17 | public authorId: number;
18 | @JsonProperty('createTime')
19 | public createTime: number;
20 | @JsonProperty('hits')
21 | public hits: number;
22 | @JsonProperty('url')
23 | public url: string;
24 | @JsonProperty('status')
25 | public status: number;
26 |
27 | constructor() {
28 | this.id = void 0;
29 | this.title = undefined;
30 | this.summary = undefined;
31 | this.tag = undefined;
32 | this.hits = 0;
33 | this.createTime = Date.now();
34 | }
35 | }
--------------------------------------------------------------------------------
/app/web/theme/display.css:
--------------------------------------------------------------------------------
1 | @media only screen and (max-width:767px){.hidden-xs-only{display:none!important}}@media only screen and (min-width:768px){.hidden-sm-and-up{display:none!important}}@media only screen and (min-width:768px) and (max-width:991px){.hidden-sm-only{display:none!important}}@media only screen and (max-width:991px){.hidden-sm-and-down{display:none!important}}@media only screen and (min-width:992px){.hidden-md-and-up{display:none!important}}@media only screen and (min-width:992px) and (max-width:1199px){.hidden-md-only{display:none!important}}@media only screen and (max-width:1199px){.hidden-md-and-down{display:none!important}}@media only screen and (min-width:1200px){.hidden-lg-and-up{display:none!important}}@media only screen and (min-width:1200px) and (max-width:1919px){.hidden-lg-only{display:none!important}}@media only screen and (max-width:1919px){.hidden-lg-and-down{display:none!important}}@media only screen and (min-width:1920px){.hidden-xl-only{display:none!important}}
--------------------------------------------------------------------------------
/typings/config/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file was auto created by egg-ts-helper
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import { EggAppConfig } from 'egg';
5 | import ExportConfigDefault from '../../config/config.default';
6 | import ExportConfigLocal from '../../config/config.local';
7 | import ExportConfigProd from '../../config/config.prod';
8 | import ExportConfigTest from '../../config/config.test';
9 | type ConfigDefault = ReturnType;
10 | type ConfigLocal = ReturnType;
11 | type ConfigProd = ReturnType;
12 | type ConfigTest = ReturnType;
13 | type NewEggAppConfig = EggAppConfig & ConfigDefault & ConfigLocal & ConfigProd & ConfigTest;
14 |
15 | declare module 'egg' {
16 | interface Application {
17 | config: NewEggAppConfig;
18 | }
19 |
20 | interface Controller {
21 | config: NewEggAppConfig;
22 | }
23 |
24 | interface Service {
25 | config: NewEggAppConfig;
26 | }
27 | }
--------------------------------------------------------------------------------
/app/web/view/layout.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= htmlWebpackPlugin.options.title %>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | <% htmlWebpackPlugin.options.css.forEach(function(href){ %>
13 |
14 | <% }) %>
15 |
16 |
17 |
18 |
19 | <% htmlWebpackPlugin.options.js.forEach(function(src){ %>
20 |
21 | <% }) %>
22 |
23 |
--------------------------------------------------------------------------------
/app/controller/admin/admin.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from 'egg';
2 | import { deserialize } from '@hubcarl/json-typescript-mapper';
3 | import Article from '../../model/article';
4 | import Condition from '../../lib/condition';
5 | export default class AdminController extends Controller {
6 |
7 | public async login(ctx) {
8 | await ctx.renderClient('admin/login/login.js', {});
9 | }
10 |
11 | public async home(ctx) {
12 | await ctx.render('admin/home/home.js', { url: this.ctx.url.replace(/\/admin/, '') });
13 | }
14 |
15 | public async list(ctx) {
16 | const condition = deserialize(Condition, ctx.request.body);
17 | console.log(condition);
18 | this.ctx.body = ctx.service.article.getArtilceList(condition);
19 | }
20 |
21 | public async add(ctx) {
22 | const article = deserialize(Article, ctx.request.body);
23 | ctx.body = this.service.article.saveArticle(article);
24 | }
25 |
26 | public async detail(ctx) {
27 | const id = ctx.query.id;
28 | ctx.body = {};
29 | }
30 | }
--------------------------------------------------------------------------------
/app/web/theme/scrollbar.css:
--------------------------------------------------------------------------------
1 | .el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(135,141,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(135,141,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}
--------------------------------------------------------------------------------
/app/web/theme/carousel-item.css:
--------------------------------------------------------------------------------
1 | .el-carousel__item,.el-carousel__mask{position:absolute;height:100%;top:0;left:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#fff;opacity:.24;-webkit-transition:.2s;transition:.2s}
--------------------------------------------------------------------------------
/app/lib/db/collection.ts:
--------------------------------------------------------------------------------
1 | import DB from './base';
2 | import Condition from '../condition';
3 | export default class Collection {
4 | private db: DB;
5 | private name: string;
6 | constructor(db: DB, name: string) {
7 | this.db = db;
8 | this.name = name;
9 | }
10 |
11 | public get() {
12 | return this.db.get(this.name);
13 | }
14 |
15 | public add(json: object) {
16 | return this.db.add(this.name, json);
17 | }
18 |
19 | public update(where: object, json: object) {
20 | return this.db.update(this.name, where, json);
21 | }
22 |
23 | public delete(field: number | string) {
24 | return this.db.delete(this.name, field);
25 | }
26 |
27 | public getPager(condition: Condition) {
28 | return this.db.getPager(this.name, condition);
29 | }
30 |
31 | public getOrderAscByField(field: string) {
32 | return this.get().orderBy(field, 'asc').value();
33 | }
34 |
35 | public getOrderDescByField(field: string) {
36 | return this.get().orderBy(field, 'desc').value();
37 | }
38 | }
--------------------------------------------------------------------------------
/config/config.local.ts:
--------------------------------------------------------------------------------
1 | import { Application, EggAppConfig } from 'egg';
2 | import * as ip from 'ip';
3 | import * as path from 'path';
4 |
5 | export default (app: EggAppConfig) => {
6 | const exports: any = {};
7 |
8 | exports.static = {
9 | maxAge: 0, // maxAge 缓存,默认 1 年
10 | };
11 |
12 | exports.development = {
13 | watchDirs: ['build'], // 指定监视的目录(包括子目录),当目录下的文件变化的时候自动重载应用,路径从项目根目录开始写
14 | ignoreDirs: ['app/web', 'public', 'config'], // 指定过滤的目录(包括子目录)
15 | };
16 |
17 | exports.webpack = {
18 | browser: 'http://localhost:7001',
19 | };
20 |
21 | exports.logview = {
22 | dir: path.join(app.baseDir, 'logs'),
23 | };
24 |
25 | const localIP = ip.address();
26 | const domainWhiteList = [];
27 | [7001, 9000, 9001].forEach((port) => {
28 | domainWhiteList.push(`http://localhost:${port}`);
29 | domainWhiteList.push(`http://127.0.0.1:${port}`);
30 | domainWhiteList.push(`http://${localIP}:${port}`);
31 | });
32 |
33 | exports.security = { domainWhiteList };
34 |
35 | return exports;
36 | };
37 |
--------------------------------------------------------------------------------
/app/web/component/layout/admin/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
33 |
43 |
--------------------------------------------------------------------------------
/app/web/component/layout/index/footer/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
27 |
32 |
--------------------------------------------------------------------------------
/app/controller/index/index.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import { Controller } from 'egg';
3 | import Condition from '../../lib/condition';
4 | export default class IndexController extends Controller {
5 |
6 | public async index() {
7 | const condition: Condition = new Condition();
8 | condition.pageIndex = 1;
9 | const result = this.service.article.getArtilceList(condition);
10 | await this.ctx.render('index/index.js', result);
11 | }
12 |
13 | public async client() { // 前端渲染
14 | const condition: Condition = new Condition();
15 | condition.pageIndex = 1;
16 | const result = this.service.article.getArtilceList(condition);
17 | await this.ctx.renderClient('index/index.js', result);
18 | }
19 |
20 | public async list() {
21 | const { pageIndex, pageSize } = this.ctx.query;
22 | const condition: Condition = new Condition();
23 | condition.pageIndex = pageIndex;
24 | condition.pageSize = pageSize;
25 | this.ctx.body = this.service.article.getArtilceList(condition);
26 | }
27 |
28 | public async detail() {
29 | const id = this.ctx.query.id;
30 | }
31 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | egg: true,
4 | framework: 'vue',
5 | entry: {
6 | include: ['app/web/page',
7 | {
8 | 'admin/login/login': 'app/web/page/admin/login/login.ts?loader=false',
9 | 'admin/home/home': 'app/web/page/admin/home/home.ts?loader=false'
10 | }
11 | ],
12 | exclude: [/app\/web\/page\/admin\/home\/(component|view|router|store)/],
13 | loader: {
14 | client: 'app/web/framework/vue/entry/client-loader.ts',
15 | server: 'app/web/framework/vue/entry/server-loader.ts',
16 | }
17 | },
18 | alias: {
19 | server: 'app/web/framework/vue/entry/server.ts',
20 | client: 'app/web/framework/vue/entry/client.ts',
21 | asset: 'app/web/asset',
22 | component: 'app/web/component',
23 | framework: 'app/web/framework',
24 | store: 'app/web/store',
25 | vue: 'vue/dist/vue.esm.js'
26 | },
27 | dll: ['vue', 'axios', 'vuex', 'vuex-router-sync'],
28 | loaders: {
29 | less: {
30 | framework: true
31 | },
32 | typescript: true
33 | },
34 | plugins: {
35 |
36 | },
37 | done() {
38 |
39 | }
40 | };
--------------------------------------------------------------------------------
/config/config.default.ts:
--------------------------------------------------------------------------------
1 | import { Application, EggAppConfig } from 'egg';
2 | import * as fs from 'fs';
3 | import * as path from 'path';
4 |
5 | export default (app: EggAppConfig) => {
6 | const exports: any = {};
7 |
8 | exports.siteFile = {
9 | '/favicon.ico': fs.readFileSync(path.join(app.baseDir, 'app/web/asset/images/favicon.ico')),
10 | '/logo.png': fs.readFileSync(path.join(app.baseDir, 'app/web/asset/images/logo.png')),
11 | };
12 |
13 | exports.view = {
14 | cache: false,
15 | };
16 |
17 | exports.vuessr = {
18 | layout: path.join(app.baseDir, 'app/web/view/layout.html'),
19 | renderOptions: {
20 | // 告诉 vue-server-renderer 去 app/view 查找异步 chunk 文件
21 | basedir: path.join(app.baseDir, 'app/view'),
22 | },
23 | };
24 |
25 | exports.logger = {
26 | consoleLevel: 'DEBUG',
27 | dir: path.join(app.baseDir, 'logs'),
28 | };
29 |
30 | exports.static = {
31 | prefix: '/public/',
32 | dir: path.join(app.baseDir, 'public'),
33 | };
34 |
35 | exports.keys = '123456';
36 |
37 | exports.middleware = [
38 | 'access',
39 | ];
40 |
41 | return exports;
42 | };
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 sky.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/web/framework/vue/entry/server.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import '../filter';
3 | import '../directive';
4 | import '../component';
5 |
6 | export default function render(options) {
7 | if (options.store && options.router) {
8 | return (context) => {
9 | options.store.replaceState({ ...options.store.state, ...context.state });
10 | options.router.push({ path: context.state.url });
11 | const matchedComponents = options.router.getMatchedComponents();
12 | if (!matchedComponents) {
13 | return Promise.reject({ code: '404' });
14 | }
15 | return Promise.all(
16 | matchedComponents.map((component) => {
17 | if (component.preFetch) {
18 | return component.preFetch(options.store);
19 | }
20 | return null;
21 | })
22 | ).then(() => {
23 | context.state = { ...options.store.state, ...context.state };
24 | return new Vue(options);
25 | });
26 | };
27 | }
28 | return (context) => {
29 | const VueApp = Vue.extend(options);
30 | const app = new VueApp({ data: context.state });
31 | return Promise.resolve(app);
32 | };
33 | }
--------------------------------------------------------------------------------
/app/web/page/admin/home/store/app/actions.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as Type from './mutation-type';
4 | import Vue from 'vue';
5 | import Vuex from 'vuex';
6 | import axios from 'axios';
7 |
8 | Vue.use(Vuex);
9 |
10 | const actions = {
11 |
12 | FETCH_ARTICLE_LIST: ({ commit, dispatch, state }, condition) => {
13 | return axios.post(`/admin/api/article/list`, condition, {
14 | headers: {
15 | 'x-csrf-token': state.csrf,
16 | 'Cookie': `csrfToken=${state.csrf}`
17 | }
18 | }).then(response => {
19 | commit(Type.SET_ARTICLE_LIST, response.data);
20 | });
21 | },
22 |
23 | FETCH_ARTICLE_DETAIL: ({ commit, dispatch, state }, { id }) => {
24 | return axios.get(`/admin/api/article/${id}`)
25 | .then(response => {
26 | commit(Type.SET_ARTICLE_DETAIL, response.data);
27 | });
28 | },
29 |
30 | SAVE_ARTICLE: ({ commit, dispatch, state }, data) => {
31 | return axios.post(`/admin/api/article/add`, data, {
32 | headers: {
33 | 'x-csrf-token': state.csrf,
34 | }
35 | }).then(response => {
36 | commit(Type.SET_ARTICLE_LIST, data);
37 | });
38 | },
39 |
40 | };
41 |
42 | export default actions;
--------------------------------------------------------------------------------
/app/web/theme/collapse.css:
--------------------------------------------------------------------------------
1 | .el-collapse-item__header,.el-collapse-item__wrap{background-color:#fff;border-bottom:1px solid #e6ebf5}.el-collapse,.el-collapse-item__header,.el-collapse-item__wrap{border-bottom:1px solid #e6ebf5}.el-collapse{border-top:1px solid #e6ebf5}.el-collapse-item__header{height:48px;line-height:48px;color:#2d2f33;cursor:pointer;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin-right:8px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:right;line-height:48px;font-weight:300}.el-collapse-item__header.focusing:focus:not(:hover){color:#3C8DBC}.el-collapse-item__wrap{will-change:height;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#2d2f33;line-height:1.769230769230769}.el-collapse-item.is-active .el-collapse-item__header{border-bottom-color:transparent}.el-collapse-item.is-active .el-collapse-item__header .el-collapse-item__arrow{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item:last-child{margin-bottom:-1px}
--------------------------------------------------------------------------------
/app/web/component/layout/admin/header/header.less:
--------------------------------------------------------------------------------
1 | .header {
2 | width: 100%;
3 | position: fixed;
4 | display: flex;
5 | height: 50px;
6 | background-color: #3c8dbc;
7 | z-index: 10;
8 | .logo {
9 | .min {
10 | display: none;
11 | }
12 | width: 230px;
13 | height: 50px;
14 | text-align: center;
15 | line-height: 50px;
16 | color: #fff;
17 | background-color: #367fa9;
18 | -webkit-transition: width 0.35s;
19 | transition: width 0.35s;
20 | }
21 | .right {
22 | position: absolute;
23 | right: 0;
24 | }
25 | .header-btn {
26 | .el-badge__content {
27 | top: 14px;
28 | right: 7px;
29 | text-align: center;
30 | font-size: 9px;
31 | padding: 0 3px;
32 | background-color: #00a65a;
33 | color: #fff;
34 | border: none;
35 | white-space: nowrap;
36 | vertical-align: baseline;
37 | border-radius: .25em;
38 | }
39 | overflow: hidden;
40 | height: 50px;
41 | display: inline-block;
42 | text-align: center;
43 | line-height: 50px;
44 | cursor: pointer;
45 | padding: 0 14px;
46 | color: #fff;
47 | &:hover {
48 | background-color: #367fa9
49 | }
50 | }
51 | }
52 |
53 | .menu {
54 | border-right: none;
55 | }
--------------------------------------------------------------------------------
/app/web/component/layout/index/header/header.less:
--------------------------------------------------------------------------------
1 | .header {
2 | width: 100%;
3 | position: fixed;
4 | display: flex;
5 | height: 50px;
6 | background-color: #3c8dbc;
7 | z-index: 10;
8 | .logo {
9 | .min {
10 | display: none;
11 | }
12 | width: 230px;
13 | height: 50px;
14 | text-align: center;
15 | line-height: 50px;
16 | color: #fff;
17 | background-color: #367fa9;
18 | -webkit-transition: width 0.35s;
19 | transition: width 0.35s;
20 | }
21 | .right {
22 | position: absolute;
23 | right: 0;
24 | }
25 | .header-btn {
26 | .el-badge__content {
27 | top: 14px;
28 | right: 7px;
29 | text-align: center;
30 | font-size: 9px;
31 | padding: 0 3px;
32 | background-color: #00a65a;
33 | color: #fff;
34 | border: none;
35 | white-space: nowrap;
36 | vertical-align: baseline;
37 | border-radius: .25em;
38 | }
39 | overflow: hidden;
40 | height: 50px;
41 | display: inline-block;
42 | text-align: center;
43 | line-height: 50px;
44 | cursor: pointer;
45 | padding: 0 14px;
46 | color: #fff;
47 | &:hover {
48 | background-color: #367fa9
49 | }
50 | }
51 | }
52 |
53 | .menu {
54 | border-right: none;
55 | }
--------------------------------------------------------------------------------
/app/middleware/access.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import * as util from 'util';
3 | export default () => {
4 | const skipExt = [ '.png', '.jpeg', '.jpg', '.ico', '.gif' ];
5 | return function *(next) {
6 | const start = new Date().getTime();
7 |
8 | yield * next;
9 |
10 | const rs = Math.ceil(new Date().getTime() - start);
11 |
12 | this.set('X-Response-Time', rs);
13 |
14 | const ext = path.extname(this.url).toLocaleLowerCase();
15 | const isSkip = skipExt.indexOf(ext) !== -1 && this.status < 400;
16 |
17 | if (!isSkip) {
18 | const ip = this.get('X-Real-IP') || this.ip;
19 | const port = this.get('X-Real-Port');
20 | const protocol = this.protocol.toUpperCase();
21 | const method = this.method;
22 | const url = this.url;
23 | const status = this.status;
24 | const length = this.length || '-';
25 | const referrer = this.get('referrer') || '-';
26 | const ua = this.get('user-agent') || '-';
27 | const serverTime = this.response.get('X-Server-Response-Time') || '-';
28 | const message = util.format('[access] %s:%s - %s %s %s/%s %s %s %s %s %s',
29 | ip, port, method, url, protocol, status, length, referrer, rs, serverTime, ua);
30 | this.logger.info(message);
31 | }
32 | };
33 | };
34 |
--------------------------------------------------------------------------------
/app/service/article.ts:
--------------------------------------------------------------------------------
1 | import { Context, Service } from 'egg';
2 | import { deserialize } from '@hubcarl/json-typescript-mapper';
3 | import Colllection from '../lib/db/collection';
4 | import Article from '../model/article';
5 | import Condition from '../lib/condition';
6 | const ARTICLE_COLLECTION = Symbol.for('ArticeService#Collection');
7 |
8 | export default class ArticeService extends Service {
9 | private colllection: Colllection;
10 | constructor(ctx: Context) {
11 | super(ctx);
12 | this.ctx = ctx;
13 | this.colllection = new Colllection(ctx.db, 'article');
14 | }
15 |
16 | public getArtilceList(condition: Condition) {
17 | if (condition.categoryId) {
18 | condition.where.categoryId = condition.categoryId;
19 | }
20 | if (condition.status) {
21 | condition.where.status = condition.status;
22 | }
23 | if (condition.title) {
24 | condition.like.title = condition.title;
25 | }
26 | return this.colllection.getPager(condition);
27 | }
28 |
29 | public saveArticle(data: object) {
30 | const article: Article = deserialize(Article, data);
31 | if (article.id) {
32 | return this.colllection.update({ id: article.id }, article);
33 | }
34 | article.id = this.ctx.db.getUniqueId();
35 | return this.colllection.add(article);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/web/theme/alert.css:
--------------------------------------------------------------------------------
1 | .el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#fff;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success{background-color:#f0f9eb;color:#67c23a}.el-alert--success .el-alert__description{color:#67c23a}.el-alert--info{background-color:#f3f4f5;color:#878d99}.el-alert--info .el-alert__description{color:#878d99}.el-alert--warning{background-color:#fdf5e6;color:#eb9e05}.el-alert--warning .el-alert__description{color:#eb9e05}.el-alert--error{background-color:#fee;color:#fa5555}.el-alert--error .el-alert__description{color:#fa5555}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;color:#b4bccc;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-alert-fade-enter,.el-alert-fade-leave-active{opacity:0}
--------------------------------------------------------------------------------
/app/web/theme/tree.css:
--------------------------------------------------------------------------------
1 | .el-tree{cursor:default;background:#fff;color:#5a5e66}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#6f7180}.el-tree-node{white-space:nowrap}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#f5f7fa}.el-tree-node__expand-icon{cursor:pointer;color:#b4bccc;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#b4bccc}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}
--------------------------------------------------------------------------------
/app/web/theme/popper.css:
--------------------------------------------------------------------------------
1 | .el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#e6ebf5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#e6ebf5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#e6ebf5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#e6ebf5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}
--------------------------------------------------------------------------------
/app/web/theme/switch.css:
--------------------------------------------------------------------------------
1 | .el-switch{display:inline-block;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer;vertical-align:middle}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;color:#2d2f33}.el-switch__label.is-active{color:#3C8DBC}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__input:focus~.el-switch__core{outline:#3C8DBC solid 1px}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #d8dce5;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#d8dce5;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s}.el-switch__core .el-switch__button{position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;width:16px;height:16px;background-color:#fff}.el-switch.is-checked .el-switch__core{border-color:#3C8DBC;background-color:#3C8DBC}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}
--------------------------------------------------------------------------------
/app/web/theme/loading.css:
--------------------------------------------------------------------------------
1 | .el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:10000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-loading-spinner .el-loading-text{color:#3C8DBC;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#3C8DBC;stroke-linecap:round}.el-loading-spinner i{color:#3C8DBC}.el-loading-fade-enter,.el-loading-fade-leave-active{opacity:0}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}
--------------------------------------------------------------------------------
/app/web/theme/notification.css:
--------------------------------------------------------------------------------
1 | .el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #e6ebf5;position:fixed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px}.el-notification__title{font-weight:700;font-size:16px;color:#2d2f33;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#5a5e66;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px;-webkit-transform:translateY(4px);transform:translateY(4px)}.el-notification__closeBtn{position:absolute;top:15px;right:15px;cursor:pointer;color:#878d99;font-size:16px}.el-notification__closeBtn:hover{color:#5a5e66}.el-notification .el-icon-success{color:#67c23a}.el-notification .el-icon-error{color:#fa5555}.el-notification .el-icon-info{color:#878d99}.el-notification .el-icon-warning{color:#eb9e05}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-notification-fade-leave-active{opacity:0}
--------------------------------------------------------------------------------
/app/web/page/admin/login/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
38 |
39 |
40 |
41 |
64 |
65 |
--------------------------------------------------------------------------------
/app/web/theme/message.css:
--------------------------------------------------------------------------------
1 | .el-message__closeBtn:focus,.el-message__content:focus{outline-width:0}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;border-width:1px;border-style:solid;border-color:#e6ebf5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,transform .4s;transition:opacity .3s,transform .4s,-webkit-transform .4s;overflow:hidden;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message p{margin:0}.el-message--info .el-message__content{color:#878d99}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67c23a}.el-message--warning{background-color:#fdf5e6;border-color:#fbeccd}.el-message--warning .el-message__content{color:#eb9e05}.el-message--error{background-color:#fee;border-color:#fedddd}.el-message--error .el-message__content{color:#fa5555}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#b4bccc;font-size:16px}.el-message__closeBtn:hover{color:#878d99}.el-message .el-icon-success{color:#67c23a}.el-message .el-icon-error{color:#fa5555}.el-message .el-icon-info{color:#878d99}.el-message .el-icon-warning{color:#eb9e05}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}
--------------------------------------------------------------------------------
/app/web/theme/progress.css:
--------------------------------------------------------------------------------
1 | .el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#5a5e66;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle{display:inline-block}.el-progress--circle .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner::after,.el-progress-bar__innerText{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67c23a}.el-progress.is-success .el-progress__text{color:#67c23a}.el-progress.is-exception .el-progress-bar__inner{background-color:#fa5555}.el-progress.is-exception .el-progress__text{color:#fa5555}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#e6ebf5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#3C8DBC;text-align:right;border-radius:100px;line-height:1;white-space:nowrap}.el-progress-bar__inner::after{content:"";height:100%}.el-progress-bar__innerText{color:#fff;font-size:12px;margin:0 5px}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}
--------------------------------------------------------------------------------
/app/web/page/admin/home/view/write/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 提交
7 | 草稿
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/app/web/theme/popover.css:
--------------------------------------------------------------------------------
1 | .el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#e6ebf5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#e6ebf5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#e6ebf5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#e6ebf5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-popover{position:absolute;background:#fff;min-width:150px;border-radius:4px;border:1px solid #e6ebf5;padding:12px;z-index:2000;color:#5a5e66;line-height:1.4;text-align:justify;word-break:break-all;font-size:14px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#2d2f33;font-size:16px;line-height:1;margin-bottom:12px}
--------------------------------------------------------------------------------
/app/lib/db/file.ts:
--------------------------------------------------------------------------------
1 | import * as lowdb from 'lowdb';
2 | import * as lodashid from 'lodash-id';
3 | import * as FileSync from 'lowdb/adapters/FileSync';
4 | import BaseDB from './base';
5 | import Condition from '../condition';
6 | export default class FileDB extends BaseDB {
7 | public instance;
8 | constructor(name?: string) {
9 | super(name);
10 | const file = new FileSync(this.name);
11 | this.instance = lowdb(file);
12 | this.instance._.mixin(lodashid);
13 | this.create();
14 | }
15 |
16 | public create() {
17 | this.instance.defaults({ article: [], user: {} }).write();
18 | }
19 |
20 | public get(collectionName: string) {
21 | return this.instance.get(collectionName);
22 | }
23 |
24 | public add(collectionName: string, json: object) {
25 | return this.get(collectionName)
26 | .push(json)
27 | .write();
28 | }
29 |
30 | public update(collectionName: string, where: object, json: object) {
31 | return this.get(collectionName).find(where).assign(json).write();
32 | }
33 |
34 | public delete(collectionName: string, field: number | string) {
35 | return this.get(collectionName).write();
36 | }
37 |
38 | public getPager(collectionName: string, condition: Condition) {
39 | const {
40 | where,
41 | like,
42 | pageIndex,
43 | pageSize,
44 | orderByField,
45 | orderBy
46 | } = condition;
47 | const start = (pageIndex - 1) * pageSize;
48 | const end = pageIndex * pageSize;
49 | const result = this.get(collectionName)
50 | .filter(where)
51 | .filter(item => {
52 | return Object.keys(like).reduce((isLike, key) => {
53 | return isLike && item[key] && item[key].indexOf(like[key]) > -1;
54 | }, true);
55 | })
56 | .orderBy(orderByField, orderBy);
57 | const total = result.size().value();
58 | const list = result.slice(start, end).value();
59 | return { total, list };
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/web/component/layout/admin/aside/aside.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
26 |
27 |
28 |
47 |
48 |
--------------------------------------------------------------------------------
/app/web/theme/tag.css:
--------------------------------------------------------------------------------
1 | .el-tag{background-color:rgba(64,158,255,.1);display:inline-block;padding:0 10px;height:32px;line-height:30px;font-size:12px;color:#3C8DBC;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid rgba(64,158,255,.2);white-space:nowrap}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:18px;width:18px;line-height:18px;vertical-align:middle;top:-1px;right:-5px;color:#3C8DBC}.el-tag .el-icon-close::before{display:block}.el-tag .el-icon-close:hover{background-color:#3C8DBC;color:#fff}.el-tag--info,.el-tag--info .el-tag__close{color:#878d99}.el-tag--info{background-color:rgba(135,141,153,.1);border-color:rgba(135,141,153,.2)}.el-tag--info.is-hit{border-color:#878d99}.el-tag--info .el-tag__close:hover{background-color:#878d99;color:#fff}.el-tag--success{background-color:rgba(103,194,58,.1);border-color:rgba(103,194,58,.2);color:#67c23a}.el-tag--success.is-hit{border-color:#67c23a}.el-tag--success .el-tag__close{color:#67c23a}.el-tag--success .el-tag__close:hover{background-color:#67c23a;color:#fff}.el-tag--warning{background-color:rgba(235,158,5,.1);border-color:rgba(235,158,5,.2);color:#eb9e05}.el-tag--warning.is-hit{border-color:#eb9e05}.el-tag--warning .el-tag__close{color:#eb9e05}.el-tag--warning .el-tag__close:hover{background-color:#eb9e05;color:#fff}.el-tag--danger{background-color:rgba(250,85,85,.1);border-color:rgba(250,85,85,.2);color:#fa5555}.el-tag--danger.is-hit{border-color:#fa5555}.el-tag--danger .el-tag__close{color:#fa5555}.el-tag--danger .el-tag__close:hover{background-color:#fa5555;color:#fff}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}
--------------------------------------------------------------------------------
/app/web/theme/carousel.css:
--------------------------------------------------------------------------------
1 | .el-carousel{overflow-x:hidden;position:relative}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#fff;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);margin:0;padding:0;z-index:2}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#b4bccc;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{display:inline-block;background-color:transparent;padding:12px 4px;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#fff;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}
--------------------------------------------------------------------------------
/app/web/theme/radio-button.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";.el-radio-button,.el-radio-button__inner{display:inline-block;position:relative;outline:0}.el-radio-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;background:#fff;border:1px solid #d8dce5;font-weight:500;border-left:0;color:#5a5e66;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#3C8DBC}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1;left:-999px}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#fff;background-color:#3C8DBC;border-color:#3C8DBC;-webkit-box-shadow:-1px 0 0 0 #3C8DBC;box-shadow:-1px 0 0 0 #3C8DBC}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#b4bccc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#e6ebf5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#edf2fc}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #d8dce5;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active){-webkit-box-shadow:0 0 2px 2px #3C8DBC;box-shadow:0 0 2px 2px #3C8DBC}
--------------------------------------------------------------------------------
/app/web/page/index/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |

21 |
22 |
23 |
24 |
27 |
75 |
76 |
--------------------------------------------------------------------------------
/app/web/theme/tooltip.css:
--------------------------------------------------------------------------------
1 | .el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#2d2f33;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#2d2f33;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#2d2f33}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#2d2f33}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#2d2f33;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#2d2f33;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#2d2f33}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#2d2f33}.el-tooltip__popper.is-dark{background:#2d2f33;color:#fff}.el-tooltip__popper.is-light{background:#fff;border:1px solid #2d2f33}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#2d2f33}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#fff}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#2d2f33}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#fff}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#2d2f33}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#fff}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#2d2f33}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#fff}
--------------------------------------------------------------------------------
/app/web/component/layout/layout.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import { PluginObject } from 'vue/types/plugin';
3 | export default function createLayout(name: string, components: object, tpl: string): PluginObject {
4 | return {
5 | name,
6 | props: ['title', 'description', 'keywords'],
7 | components,
8 | computed: {
9 | vTitle() {
10 | return this.$root.title || this.title || 'Egg + TypeScript + Element + Webpack';
11 | },
12 | vKeywords() {
13 | return this.$root.keywords || this.keywords || 'egg, typescript, vue, webpack, server side render';
14 | },
15 | vDescription() {
16 | return this.$root.description || this.description || 'Egg + TypeScript + Element + Webpack server side render';
17 | },
18 | baseClass() {
19 | return this.$root.baseClass;
20 | }
21 | },
22 | template: EASY_ENV_IS_BROWSER ? tpl : `
23 |
24 |
25 | {{vTitle}}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | ${tpl}
44 |
45 | `,
46 | install(vue, options) {
47 | //
48 | }
49 | };
50 | }
51 |
--------------------------------------------------------------------------------
/app/web/theme/dialog.css:
--------------------------------------------------------------------------------
1 | .v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@-webkit-keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-dialog{position:relative;margin:0 auto 50px;background:#fff;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:15px 15px 10px}.el-dialog__headerbtn{position:absolute;top:15px;right:15px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#878d99}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#3C8DBC}.el-dialog__title{line-height:24px;font-size:18px;color:#2d2f33}.el-dialog__body{padding:30px 20px;color:#5a5e66;line-height:24px;font-size:14px}.el-dialog__footer{padding:10px 15px 15px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__header{padding-top:30px}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 27px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit;padding-bottom:30px}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # egg-typescript-element-kit
2 |
3 | 基于 Egg + TypeScript + Element + Webpack3 多页面和单页面服务端客户端渲染同构完整工程项目.
4 |
5 | - 前台系统:http://localhost:7001
6 |
7 | 
8 |
9 | - 后台系统:http://localhost:7001/admin
10 |
11 | 
12 |
13 |
14 | ## 1. 项目介绍
15 |
16 | ### 插件版本
17 |
18 | - Egg: ^2.x.x
19 | - Node: Node ^8.x.x+,
20 | - Webpack ^4.x.x
21 | - Vue: ^2.5.0
22 | - TypeScript: ^2.6.2
23 | - Element UI: ^2.0.0
24 | - [easywebpack-vue](https://github.com/hubcarl/easywebpack)
25 | - [egg-view-vue-ssr](https://github.com/hubcarl/egg-view-vue-ssr)
26 | - [egg-webpack](https://github.com/hubcarl/egg-webpack)
27 | - [egg-webpack-vue](https://github.com/hubcarl/egg-webpack-vue)
28 |
29 | ### 项目特性
30 |
31 | - 支持 Egg Node 端代码 和 前端代码 TypeScript 编写和构建
32 |
33 | - 支持 service worker 自动化构建
34 |
35 | - 支持 async 和 await 特性, Controller 采用 class 方式编写
36 |
37 | - 支持 server 和 client 端代码修改, Webpack 时时编译和热更新, `npm run dev` 一键启动应用
38 |
39 | - 基于 vue + vuex + vue-router + axios 单页面服务器客户端同构实现
40 |
41 | - 支持开发环境, 测试环境,正式环境 Webpack 编译
42 |
43 | - 支持 js/css/image 资源依赖, 内置支持CDN特性
44 |
45 | - 支持 Webpack DLL 自动化构建
46 |
47 | - 支持 Vue 组件服务端渲染异步加载
48 |
49 | ## 2. 系统功能
50 |
51 | ### 前台博客系统
52 |
53 | **采用 Egg + Vue 服务端渲染**
54 |
55 | - 博客首页
56 | - 博客文章列表展示
57 | - 博客文章详情页面
58 | - 博客分类浏览
59 |
60 | ### 后台管理系统
61 |
62 | **采用 Egg + Vue + Vue-Router + Element 单页面服务端同构渲染**
63 |
64 | - 用户登陆
65 | - 用户注册
66 | - Dashboard
67 | - 文章管理
68 | - Markdown添加文章
69 | - 权限管理
70 |
71 | ## 3. 使用
72 |
73 | #### 3.1 安装依赖
74 |
75 | ```bash
76 | npm install
77 | npm start
78 | ```
79 |
80 | #### 3.2 启动应用
81 |
82 | ```bash
83 | npm run dev
84 | ```
85 |
86 | 应用访问: http://127.0.0.1:7001
87 |
88 | 
89 |
90 |
91 | #### 3.3 构建
92 |
93 | - TypeScript Egg 构建
94 |
95 | ```bash
96 | npm run tsc
97 | ```
98 |
99 | - TypeScript 前端工程构建
100 |
101 | ```bash
102 | npm run tsc
103 | ```
104 |
105 | #### 3.4 打包部署
106 |
107 | 1. 先运行 `npm run build` 构建 TypeScript Egg 代码和 TypeScript 前端代码
108 | 2. 项目代码和构建代码一起打包代码
109 | 3. 应用部署后,通过 `npm start` 启动应用
110 |
111 | ## 4. 文档
112 |
113 | - http://hubcarl.github.io/easywebpack/vue/rule
114 | - https://zhuanlan.zhihu.com/easywebpack
115 |
116 | ## 5. 参考资料
117 |
118 | - [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
119 |
120 | ## License
121 |
122 | [MIT](LICENSE)
123 |
--------------------------------------------------------------------------------
/app/web/component/layout/index/header/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
32 |
48 |
49 |
50 |
53 |
71 |
--------------------------------------------------------------------------------
/app/web/theme/form.css:
--------------------------------------------------------------------------------
1 | .el-form--inline .el-form-item,.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form-item::after,.el-form-item__content::after{clear:both}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{margin-right:10px}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#5a5e66;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__error{color:#fa5555;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required .el-form-item__label:before{content:'*';color:#fa5555;margin-right:4px}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus{border-color:#fa5555}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#fa5555}.el-form-item.is-success .el-input__inner,.el-form-item.is-success .el-input__inner:focus,.el-form-item.is-success .el-textarea__inner,.el-form-item.is-success .el-textarea__inner:focus{border-color:#67c23a}.el-form-item.is-success .el-input-group__append .el-input__inner,.el-form-item.is-success .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-success .el-input__validateIcon{color:#67c23a}.el-form-item--feedback .el-input__validateIcon{display:inline-block}
--------------------------------------------------------------------------------
/app/web/theme/select-dropdown.css:
--------------------------------------------------------------------------------
1 | .el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#e6ebf5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#e6ebf5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#e6ebf5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#e6ebf5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #dfe4ed;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#3C8DBC;background-color:#fff}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#f5f7fa}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\E611";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown .popper__arrow{-webkit-transform:translateX(-400%);transform:translateX(-400%)}.el-select-dropdown.is-arrow-fixed .popper__arrow{-webkit-transform:translateX(-200%);transform:translateX(-200%)}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}
--------------------------------------------------------------------------------
/app/web/component/layout/admin/header/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
29 |
30 |
31 |
32 |
51 |
94 |
--------------------------------------------------------------------------------
/app/web/component/layout/admin/footer/footer.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | height: 120px;
3 | background-color: #324057;
4 | color: #a4aebd;
5 | width: 100%;
6 | }
7 |
8 | .footer * {
9 | word-spacing: 0
10 | }
11 |
12 | .footer .container {
13 | height: 100%;
14 | box-sizing: border-box
15 | }
16 |
17 | .footer .footer-main {
18 | font-size: 0;
19 | padding-top: 40px;
20 | display: inline-block
21 | }
22 |
23 | .footer .footer-main .footer-main-title {
24 | line-height: 1;
25 | font-size: 22px;
26 | margin: 0
27 | }
28 |
29 | .footer .footer-main .footer-main-link {
30 | display: inline-block;
31 | margin: 12px 18px 0 0;
32 | line-height: 1;
33 | font-size: 12px;
34 | color: #768193
35 | }
36 |
37 | .footer .footer-main .footer-main-link a {
38 | color: #768193;
39 | text-decoration: none
40 | }
41 |
42 | .footer .footer-social {
43 | float: right;
44 | line-height: 120px
45 | }
46 |
47 | .footer .footer-social .elementdoc {
48 | transition: .3s;
49 | display: inline-block;
50 | line-height: 32px;
51 | text-align: center;
52 | color: #8d99ab;
53 | background-color: transparent;
54 | width: 32px;
55 | height: 32px;
56 | font-size: 32px;
57 | vertical-align: middle
58 | }
59 |
60 | .footer .footer-social .elementdoc:hover {
61 | transform: scale(1.2)
62 | }
63 |
64 | .footer .footer-social .doc-icon-weixin {
65 | margin-right: 36px
66 | }
67 |
68 | .footer .footer-social .doc-icon-weixin:hover {
69 | color: #fff
70 | }
71 |
72 | .footer .footer-social .doc-icon-github {
73 | margin-right: 0
74 | }
75 |
76 | .footer .footer-social .doc-icon-github:hover {
77 | color: #fff
78 | }
79 |
80 | .footer-popover {
81 | padding: 0;
82 | min-width: 120px;
83 | line-height: normal;
84 | box-shadow: 0 0 11px 0 rgba(174, 187, 211, .24)
85 | }
86 |
87 | .footer-popover .footer-popover-title {
88 | border-bottom: 1px solid #eaeefb;
89 | height: 30px;
90 | line-height: 30px;
91 | text-align: center;
92 | color: #99a9bf;
93 | background-color: #f8f9fe
94 | }
95 |
96 | .footer-popover img {
97 | width: 100px;
98 | height: 100px;
99 | margin: 10px
100 | }
101 |
102 | @media (max-width: 768px) {
103 | .footer .footer-social {
104 | display: none
105 | }
106 | }
107 |
108 | .footer-nav {
109 | padding: 24px 0;
110 | color: #99a9bf;
111 | font-size: 14px
112 | }
113 |
114 | .footer-nav:after {
115 | content: "";
116 | display: block;
117 | clear: both
118 | }
119 |
120 | .footer-nav i {
121 | transition: .3s;
122 | color: #d9def1;
123 | vertical-align: baseline
124 | }
125 |
126 | .footer-nav-link {
127 | cursor: pointer;
128 | transition: .3s
129 | }
130 |
131 | .footer-nav-link:hover, .footer-nav-link:hover i {
132 | color: #20a0ff
133 | }
134 |
135 | .footer-nav-left {
136 | float: left;
137 | margin-left: -4px
138 | }
139 |
140 | .footer-nav-right {
141 | float: right;
142 | margin-right: -4px
143 | }
--------------------------------------------------------------------------------
/app/web/component/MarkdownEditor/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
81 |
82 |
117 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egg-typescript-element-kit",
3 | "version": "2.0.0",
4 | "description": "基于 egg + typescript + element + webpack 服务端渲染同构工程骨架项目",
5 | "scripts": {
6 | "tsc": "tsc -p tsconfig.json",
7 | "build": "npm run tsc && easy build prod",
8 | "dev": "egg-bin dev -r 'egg-ts-helper/register'",
9 | "start": "egg-scripts start",
10 | "lint": "tslint --project .",
11 | "fix": "tslint --project . --fix",
12 | "debug": "egg-bin debug",
13 | "autod": "egg-bin autod",
14 | "cov": "egg-bin cov",
15 | "test": "npm run lint && egg-bin test",
16 | "ii": "npm install --registry https://registry.npm.taobao.org"
17 | },
18 | "dependencies": {
19 | "@hubcarl/json-typescript-mapper": "^1.1.4",
20 | "axios": "^0.17.1",
21 | "cross-env": "^5.0.0",
22 | "egg": "^2.1.0",
23 | "egg-bin": "^4.3.7",
24 | "egg-cors": "^2.0.0",
25 | "egg-logger": "^1.5.0",
26 | "egg-scripts": "^2.5.1",
27 | "egg-validate": "^1.0.0",
28 | "egg-view-vue-ssr": "^3.0.5",
29 | "element-ui": "^2.0.8",
30 | "extend": "~3.0.0",
31 | "font-awesome": "^4.7.0",
32 | "lodash": "^4.17.4",
33 | "lodash-id": "^0.14.0",
34 | "lowdb": "^1.0.0",
35 | "mockjs": "^1.0.1-beta3",
36 | "moment": "^2.17.1",
37 | "shortid": "^2.2.8",
38 | "showdown": "^1.8.6",
39 | "simplemde": "^1.11.2",
40 | "vue": "^2.5.0",
41 | "vue-hot-reload-api": "^2.1.0",
42 | "vue-material-input": "^1.2.0",
43 | "vue-router": "^3.0.1",
44 | "vuex": "^3.0.1",
45 | "vuex-router-sync": "^5.0.0"
46 | },
47 | "devDependencies": {
48 | "autod-egg": "^1.0.0",
49 | "autoprefixer": "^7.1.4",
50 | "babel-plugin-add-module-exports": "^0.2.1",
51 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
52 | "babel-plugin-transform-object-assign": "^6.22.0",
53 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
54 | "babel-plugin-transform-runtime": "^6.15.0",
55 | "babel-preset-env": "^1.6.0",
56 | "cz-conventional-changelog": "^2.1.0",
57 | "easywebpack-cli": "^3.9.0",
58 | "easywebpack-vue": "^4.0.0",
59 | "egg-logview": "^1.0.0",
60 | "egg-ts-helper": "^1.9.2",
61 | "egg-webpack": "^4.0.0",
62 | "egg-webpack-vue": "^2.0.0",
63 | "imagemin-webpack-plugin": "^2.1.0",
64 | "ip": "^1.1.5",
65 | "less": "^2.7.3",
66 | "less-loader": "^4.0.5",
67 | "ts-loader": "^4.0.0",
68 | "ts-node": "^5.0.1",
69 | "tslint": "^5.9.1",
70 | "tslint-loader": "^3.5.3",
71 | "typescript": "^2.6.2"
72 | },
73 | "egg": {
74 | "typescript": true
75 | },
76 | "engines": {
77 | "node": ">=8.0.0"
78 | },
79 | "ci": {
80 | "version": "8, 9"
81 | },
82 | "repository": {
83 | "type": "git",
84 | "url": "git+https://github.com/hubcarl/egg-typescript-element-kit.git"
85 | },
86 | "author": "hubcarl@126.com",
87 | "license": "MIT",
88 | "homepage": "https://github.com/hubcarl/egg-typescript-element-kit",
89 | "config": {
90 | "commitizen": {
91 | "path": "./node_modules/cz-conventional-changelog"
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/web/theme/radio.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.el-radio,.el-radio__input{white-space:nowrap;line-height:1;outline:0}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-radio{color:#5a5e66;font-weight:500;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.el-radio.is-bordered{padding:10px 20px 10px 10px;border-radius:4px;border:1px solid #d8dce5}.el-radio.is-bordered.is-checked{border-color:#3C8DBC}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#e6ebf5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#f5f7fa;border-color:#dfe4ed}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:8px 20px 8px 10px;border-radius:4px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--mini.is-bordered .el-radio__inner,.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--small.is-bordered{padding:6px 15px 6px 10px;border-radius:3px}.el-radio--mini.is-bordered{padding:4px 15px 4px 10px;border-radius:3px}.el-radio+.el-radio{margin-left:30px}.el-radio__input{cursor:pointer;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#f5f7fa}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#b4bccc}.el-radio__input.is-disabled+span.el-radio__label{color:#b4bccc;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#3C8DBC;background:#3C8DBC}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#3C8DBC}.el-radio__input.is-focus .el-radio__inner{border-color:#3C8DBC}.el-radio__inner{border:1px solid #d8dce5;border-radius:100%;width:14px;height:14px;background-color:#fff;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#3C8DBC}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#fff;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s cubic-bezier(.71,-.46,.88,.6);transition:-webkit-transform .15s cubic-bezier(.71,-.46,.88,.6);transition:transform .15s cubic-bezier(.71,-.46,.88,.6);transition:transform .15s cubic-bezier(.71,-.46,.88,.6),-webkit-transform .15s cubic-bezier(.71,-.46,.88,.6)}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #3C8DBC;box-shadow:0 0 2px 2px #3C8DBC}.el-radio__label{font-size:14px;padding-left:10px}
--------------------------------------------------------------------------------
/app/web/theme/icon.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:element-icons;src:url(fonts/element-icons.woff?t=1508751886602) format("woff"),url(fonts/element-icons.ttf?t=1508751886602) format("truetype");font-weight:400;font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-upload:before{content:"\e60d"}.el-icon-error:before{content:"\e62c"}.el-icon-success:before{content:"\e62d"}.el-icon-warning:before{content:"\e62e"}.el-icon-sort-down:before{content:"\e630"}.el-icon-sort-up:before{content:"\e631"}.el-icon-arrow-left:before{content:"\e600"}.el-icon-circle-plus:before{content:"\e601"}.el-icon-circle-plus-outline:before{content:"\e602"}.el-icon-arrow-down:before{content:"\e603"}.el-icon-arrow-right:before{content:"\e604"}.el-icon-arrow-up:before{content:"\e605"}.el-icon-back:before{content:"\e606"}.el-icon-circle-close:before{content:"\e607"}.el-icon-date:before{content:"\e608"}.el-icon-circle-close-outline:before{content:"\e609"}.el-icon-caret-left:before{content:"\e60a"}.el-icon-caret-bottom:before{content:"\e60b"}.el-icon-caret-top:before{content:"\e60c"}.el-icon-caret-right:before{content:"\e60e"}.el-icon-close:before{content:"\e60f"}.el-icon-d-arrow-left:before{content:"\e610"}.el-icon-check:before{content:"\e611"}.el-icon-delete:before{content:"\e612"}.el-icon-d-arrow-right:before{content:"\e613"}.el-icon-document:before{content:"\e614"}.el-icon-d-caret:before{content:"\e615"}.el-icon-edit-outline:before{content:"\e616"}.el-icon-download:before{content:"\e617"}.el-icon-goods:before{content:"\e618"}.el-icon-search:before{content:"\e619"}.el-icon-info:before{content:"\e61a"}.el-icon-message:before{content:"\e61b"}.el-icon-edit:before{content:"\e61c"}.el-icon-location:before{content:"\e61d"}.el-icon-loading:before{content:"\e61e"}.el-icon-location-outline:before{content:"\e61f"}.el-icon-menu:before{content:"\e620"}.el-icon-minus:before{content:"\e621"}.el-icon-bell:before{content:"\e622"}.el-icon-mobile-phone:before{content:"\e624"}.el-icon-news:before{content:"\e625"}.el-icon-more:before{content:"\e646"}.el-icon-more-outline:before{content:"\e626"}.el-icon-phone:before{content:"\e627"}.el-icon-phone-outline:before{content:"\e628"}.el-icon-picture:before{content:"\e629"}.el-icon-picture-outline:before{content:"\e62a"}.el-icon-plus:before{content:"\e62b"}.el-icon-printer:before{content:"\e62f"}.el-icon-rank:before{content:"\e632"}.el-icon-refresh:before{content:"\e633"}.el-icon-question:before{content:"\e634"}.el-icon-remove:before{content:"\e635"}.el-icon-share:before{content:"\e636"}.el-icon-star-on:before{content:"\e637"}.el-icon-setting:before{content:"\e638"}.el-icon-circle-check:before{content:"\e639"}.el-icon-service:before{content:"\e63a"}.el-icon-sold-out:before{content:"\e63b"}.el-icon-remove-outline:before{content:"\e63c"}.el-icon-star-off:before{content:"\e63d"}.el-icon-circle-check-outline:before{content:"\e63e"}.el-icon-tickets:before{content:"\e63f"}.el-icon-sort:before{content:"\e640"}.el-icon-zoom-in:before{content:"\e641"}.el-icon-time:before{content:"\e642"}.el-icon-view:before{content:"\e643"}.el-icon-upload2:before{content:"\e644"}.el-icon-zoom-out:before{content:"\e645"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}
--------------------------------------------------------------------------------
/app/web/component/layout/admin/content/content.css:
--------------------------------------------------------------------------------
1 | .main{
2 | margin-top: -80px;
3 | padding: 80px 0 120px;
4 | box-sizing: border-box;
5 | }
6 | .page-container{
7 | width: 1140px;
8 | padding: 0 30px;
9 | margin: 36 auto;
10 | }
11 | .page-component {
12 | padding-bottom: 95px;
13 | box-sizing: border-box
14 | }
15 |
16 | .page-component .content {
17 | margin-left: -1px
18 | }
19 |
20 | .page-component .content > h3 {
21 | margin: 45px 0 15px
22 | }
23 |
24 | .page-component .content > table {
25 | border-collapse: collapse;
26 | width: 100%;
27 | background-color: #fff;
28 | color: #5e6d82;
29 | font-size: 14px;
30 | margin-bottom: 45px
31 | }
32 |
33 | .page-component .content > table strong {
34 | font-weight: 400
35 | }
36 |
37 | .page-component .content > table th {
38 | text-align: left;
39 | border-top: 1px solid #eaeefb;
40 | background-color: #eff2f7;
41 | white-space: nowrap
42 | }
43 |
44 | .page-component .content > table td, .page-component .content > table th {
45 | border-bottom: 1px solid #eaeefb;
46 | padding: 10px;
47 | max-width: 250px
48 | }
49 |
50 | .page-component .content > table td:first-child, .page-component .content > table th:first-child {
51 | padding-left: 10px
52 | }
53 |
54 | .page-component .page-component-up {
55 | background-color: #58b7ff;
56 | position: fixed;
57 | right: 100px;
58 | bottom: 150px;
59 | width: 50px;
60 | height: 50px;
61 | border-radius: 25px;
62 | cursor: pointer;
63 | opacity: .4;
64 | transition: .3s
65 | }
66 |
67 | .page-component .page-component-up i {
68 | color: #fff;
69 | display: block;
70 | line-height: 50px;
71 | text-align: center;
72 | font-size: 22px
73 | }
74 |
75 | .page-component .page-component-up.hover {
76 | opacity: 1
77 | }
78 |
79 | .page-component .back-top-fade-enter, .page-component .back-top-fade-leave-active {
80 | transform: translateY(-30px);
81 | opacity: 0
82 | }
83 |
84 | .page-component {
85 | padding-bottom: 95px;
86 | box-sizing: border-box
87 | }
88 |
89 | .page-component .content {
90 | margin-left: -1px
91 | }
92 |
93 | .page-component .content > h3 {
94 | margin: 45px 0 15px
95 | }
96 |
97 | .page-component .content > table {
98 | border-collapse: collapse;
99 | width: 100%;
100 | background-color: #fff;
101 | color: #5e6d82;
102 | font-size: 14px;
103 | margin-bottom: 45px
104 | }
105 |
106 | .page-component .content > table strong {
107 | font-weight: 400
108 | }
109 |
110 | .page-component .content > table th {
111 | text-align: left;
112 | border-top: 1px solid #eaeefb;
113 | background-color: #eff2f7;
114 | white-space: nowrap
115 | }
116 |
117 | .page-component .content > table td, .page-component .content > table th {
118 | border-bottom: 1px solid #eaeefb;
119 | padding: 10px;
120 | max-width: 250px
121 | }
122 |
123 | .page-component .content > table td:first-child, .page-component .content > table th:first-child {
124 | padding-left: 10px
125 | }
126 |
127 | .page-component .page-component-up {
128 | background-color: #58b7ff;
129 | position: fixed;
130 | right: 100px;
131 | bottom: 150px;
132 | width: 50px;
133 | height: 50px;
134 | border-radius: 25px;
135 | cursor: pointer;
136 | opacity: .4;
137 | transition: .3s
138 | }
139 |
140 | .page-component .page-component-up i {
141 | color: #fff;
142 | display: block;
143 | line-height: 50px;
144 | text-align: center;
145 | font-size: 22px
146 | }
147 |
148 | .page-component .page-component-up.hover {
149 | opacity: 1
150 | }
151 |
152 | .page-component .back-top-fade-enter, .page-component .back-top-fade-leave-active {
153 | transform: translateY(-30px);
154 | opacity: 0
155 | }
--------------------------------------------------------------------------------
/app/web/component/layout/index/content/content.css:
--------------------------------------------------------------------------------
1 | .main{
2 | margin-top: -80px;
3 | padding: 80px 0 120px;
4 | box-sizing: border-box;
5 | }
6 | .page-container{
7 | width: 1140px;
8 | padding: 0 30px;
9 | margin: 36 auto;
10 | }
11 | .page-component {
12 | padding-bottom: 95px;
13 | box-sizing: border-box
14 | }
15 |
16 | .page-component .content {
17 | margin-left: -1px
18 | }
19 |
20 | .page-component .content > h3 {
21 | margin: 45px 0 15px
22 | }
23 |
24 | .page-component .content > table {
25 | border-collapse: collapse;
26 | width: 100%;
27 | background-color: #fff;
28 | color: #5e6d82;
29 | font-size: 14px;
30 | margin-bottom: 45px
31 | }
32 |
33 | .page-component .content > table strong {
34 | font-weight: 400
35 | }
36 |
37 | .page-component .content > table th {
38 | text-align: left;
39 | border-top: 1px solid #eaeefb;
40 | background-color: #eff2f7;
41 | white-space: nowrap
42 | }
43 |
44 | .page-component .content > table td, .page-component .content > table th {
45 | border-bottom: 1px solid #eaeefb;
46 | padding: 10px;
47 | max-width: 250px
48 | }
49 |
50 | .page-component .content > table td:first-child, .page-component .content > table th:first-child {
51 | padding-left: 10px
52 | }
53 |
54 | .page-component .page-component-up {
55 | background-color: #58b7ff;
56 | position: fixed;
57 | right: 100px;
58 | bottom: 150px;
59 | width: 50px;
60 | height: 50px;
61 | border-radius: 25px;
62 | cursor: pointer;
63 | opacity: .4;
64 | transition: .3s
65 | }
66 |
67 | .page-component .page-component-up i {
68 | color: #fff;
69 | display: block;
70 | line-height: 50px;
71 | text-align: center;
72 | font-size: 22px
73 | }
74 |
75 | .page-component .page-component-up.hover {
76 | opacity: 1
77 | }
78 |
79 | .page-component .back-top-fade-enter, .page-component .back-top-fade-leave-active {
80 | transform: translateY(-30px);
81 | opacity: 0
82 | }
83 |
84 | .page-component {
85 | padding-bottom: 95px;
86 | box-sizing: border-box
87 | }
88 |
89 | .page-component .content {
90 | margin-left: -1px
91 | }
92 |
93 | .page-component .content > h3 {
94 | margin: 45px 0 15px
95 | }
96 |
97 | .page-component .content > table {
98 | border-collapse: collapse;
99 | width: 100%;
100 | background-color: #fff;
101 | color: #5e6d82;
102 | font-size: 14px;
103 | margin-bottom: 45px
104 | }
105 |
106 | .page-component .content > table strong {
107 | font-weight: 400
108 | }
109 |
110 | .page-component .content > table th {
111 | text-align: left;
112 | border-top: 1px solid #eaeefb;
113 | background-color: #eff2f7;
114 | white-space: nowrap
115 | }
116 |
117 | .page-component .content > table td, .page-component .content > table th {
118 | border-bottom: 1px solid #eaeefb;
119 | padding: 10px;
120 | max-width: 250px
121 | }
122 |
123 | .page-component .content > table td:first-child, .page-component .content > table th:first-child {
124 | padding-left: 10px
125 | }
126 |
127 | .page-component .page-component-up {
128 | background-color: #58b7ff;
129 | position: fixed;
130 | right: 100px;
131 | bottom: 150px;
132 | width: 50px;
133 | height: 50px;
134 | border-radius: 25px;
135 | cursor: pointer;
136 | opacity: .4;
137 | transition: .3s
138 | }
139 |
140 | .page-component .page-component-up i {
141 | color: #fff;
142 | display: block;
143 | line-height: 50px;
144 | text-align: center;
145 | font-size: 22px
146 | }
147 |
148 | .page-component .page-component-up.hover {
149 | opacity: 1
150 | }
151 |
152 | .page-component .back-top-fade-enter, .page-component .back-top-fade-leave-active {
153 | transform: translateY(-30px);
154 | opacity: 0
155 | }
--------------------------------------------------------------------------------
/app/mocks/article/list.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const data = {
3 | list: [ {
4 | id: 1,
5 | title: 'vue-渐进式JavaScript 框架',
6 | summary: '简单小巧的核心,渐进式技术栈,足以应付任何规模的应用',
7 | hits: 200,
8 | url: 'https://cn.vuejs.org',
9 | status: 1,
10 | }, {
11 | id: 2,
12 | title: 'webpack配置官方文档',
13 | summary: 'webpack is a module bundler for modern JavaScript applications.',
14 | hits: 550,
15 | url: 'https://webpack.js.org/configuration/',
16 | status: 1,
17 | }, {
18 | id: 3,
19 | title: 'egg-为企业级框架和应用而生',
20 | summary: 'Born to buildbetter enterprise frameworks and apps with Node.js & Koa',
21 | hits: 278,
22 | url: 'https://eggjs.org/',
23 | }, {
24 | id: 4,
25 | title: 'axios-基于 Promise 的 HTTP 请求客户端',
26 | summary: '基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 node.js 中使用',
27 | hits: 998,
28 | url: 'https://www.awesomes.cn/repo/mzabriskie/axios',
29 | }, {
30 | id: 4,
31 | title: 'Centralized State Management for Vue.js',
32 | summary: 'Vuex 是一个专为Vue.js 应用程序开发的状态管理模式',
33 | hits: 232,
34 | url: 'https://github.com/vuejs/vuex',
35 | }, {
36 | id: 4,
37 | title: 'vue服务器渲染',
38 | summary: '服务器渲染可以加快首屏速度,利于SEO',
39 | hits: 565,
40 | url: 'http://csbun.github.io/blog/2016/08/vue-2-0-server-side-rendering/',
41 | }, {
42 | id: 4,
43 | title: 'webpack服务器构建',
44 | summary: 'Webpack is an amazing tool.',
45 | hits: 988,
46 | url: 'http://jlongster.com/Backend-Apps-with-Webpack--Part-I',
47 | }, {
48 | id: 4,
49 | title: 'vue component loader for Webpack',
50 | summary: 'Webpack loader for Vue.js components',
51 | hits: 322,
52 | url: 'https://github.com/vuejs/vue-loader',
53 | }, {
54 | id: 4,
55 | title: 'vue-router--The official router for Vue.js',
56 | summary: 'It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze',
57 | hits: 566,
58 | url: 'https://github.com/vuejs/vue-router',
59 | }, {
60 | id: 4,
61 | title: 'vue生命周期',
62 | summary: 'Vue.js 生命周期和route的生命周期讲解',
63 | hits: 434,
64 | url: 'http://www.jianshu.com/p/e9f884b6ba6c',
65 | }, {
66 | id: 4,
67 | title: 'babel到底将代码转换成什么鸟样',
68 | summary: '将babel捧作前端一个划时代的工具一定也不为过,它的出现让许多程序员幸福地用上了es6新语法',
69 | hits: 432,
70 | url: 'https://github.com/lcxfs1991/blog/issues/9',
71 | }, {
72 | id: 4,
73 | title: 'HTTP2 的真正性能到底如何',
74 | summary: 'HTTP2 的真正性能到底如何',
75 | hits: 565,
76 | url: 'https://segmentfault.com/a/1190000007219256?utm_source=weekly&utm_medium=email&utm_campaign=email_weekly',
77 | }, {
78 | id: 4,
79 | title: 'HTTP,HTTP2.0,SPDY,HTTPS讲解',
80 | summary: '使用SPDY加快你的网站速度',
81 | hits: 787,
82 | url: 'http://www.alloyteam.com/2016/07/httphttp2-0spdyhttps-reading-this-is-enough/',
83 | }, {
84 | id: 4,
85 | title: 'git - 简明指南',
86 | summary: '助你入门 git 的简明指南',
87 | hits: 121,
88 | url: 'http://rogerdudler.github.io/git-guide/index.zh.html',
89 | }, {
90 | id: 4,
91 | title: 'vue从1升级到2',
92 | summary: 'Migrating from v1 to v2',
93 | hits: 555,
94 | url: 'https://webpack.js.org/guides/migrating/',
95 | }],
96 | };
97 |
98 | let id: number = 1;
99 |
100 | const deepCopy = (json) => {
101 | return JSON.parse(JSON.stringify(json));
102 | };
103 |
104 | data.list = data.list.concat(deepCopy(data.list));
105 | data.list = data.list.concat(deepCopy(data.list));
106 |
107 | data.list.forEach((item) => {
108 | item.id = id++;
109 | });
110 |
111 | const total = data.list.length;
112 | export function getPage(pageIndex: number = 1, pageSize: number = 10) {
113 | const start = (pageIndex - 1) * pageSize;
114 | const end = start + Number(pageSize);
115 | const list = data.list.slice(start, end);
116 | return { list, total };
117 | }
118 |
119 | export function getDetail(uniqueId: number) {
120 | return data.list.filter((item) => {
121 | return item.id === uniqueId;
122 | }).slice(0, 1);
123 | }
--------------------------------------------------------------------------------
/app/web/page/admin/home/component/panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
New Visits
10 |
2600
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Messages
21 |
3000
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
Purchases
32 |
3200
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
Shoppings
43 |
3200
44 |
45 |
46 |
47 |
48 |
49 |
50 |
60 |
61 |
149 |
--------------------------------------------------------------------------------
/config/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5 | // "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
6 | // "lib": [], /* Specify library files to be included in the compilation: */
7 | "allowJs": true, /* Allow javascript files to be compiled. */
8 | // "checkJs": true, /* Report errors in .js files. */
9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
10 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
11 | // "sourceMap": true, /* Generates corresponding '.map' file. */
12 | // "outFile": "./", /* Concatenate and emit output to single file. */
13 | // "outDir": "./", /* Redirect output structure to the directory. */
14 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
15 | // "removeComments": true, /* Do not emit comments to output. */
16 | // "noEmit": true, /* Do not emit outputs. */
17 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
18 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
19 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
20 |
21 | /* Strict Type-Checking Options */
22 | "strict": false, /* Enable all strict type-checking options. */
23 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
24 | // "strictNullChecks": true, /* Enable strict null checks. */
25 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
26 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
27 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
28 |
29 | /* Additional Checks */
30 | // "noUnusedLocals": true, /* Report errors on unused locals. */
31 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
32 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
33 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
34 |
35 | /* Module Resolution Options */
36 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
37 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
38 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
39 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
40 | // "typeRoots": [], /* List of folders to include type definitions from. */
41 | // "types": [], /* Type declaration files to be included in compilation. */
42 | "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
43 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
44 |
45 | /* Source Map Options */
46 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
47 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
48 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
49 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
50 | }
51 | }
--------------------------------------------------------------------------------
/app/web/theme/menu.css:
--------------------------------------------------------------------------------
1 | .el-menu,.el-menu li{list-style:none}.el-menu,.el-menu--horizontal .el-menu-item:focus,.el-menu--horizontal .el-menu-item:hover,.el-menu--horizontal .el-submenu .el-submenu__title:hover,.el-menu--horizontal .el-submenu>.el-menu{background-color:#fff}.el-menu{border-right:solid 1px #e6e6e6;position:relative;margin:0;padding-left:0}.el-menu::after,.el-menu::before{display:table;content:""}.el-menu::after{clear:both}.el-menu--horizontal{border-right:none;border-bottom:solid 1px #e6e6e6}.el-menu--horizontal .el-menu-item{float:left;height:60px;line-height:60px;margin:0;cursor:pointer;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:2px solid transparent;color:#878d99}.el-menu--horizontal .el-menu-item a,.el-menu--horizontal .el-menu-item a:hover{color:inherit}.el-menu--horizontal .el-submenu{float:left;position:relative}.el-menu--horizontal .el-submenu:focus{outline:0}.el-menu--horizontal .el-submenu:focus>.el-submenu__title{color:#2d2f33}.el-menu--horizontal .el-submenu>.el-menu{position:absolute;top:65px;left:0;border:none;padding:5px 0;z-index:100;min-width:100%;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px}.el-menu--horizontal .el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#878d99}.el-menu--horizontal .el-submenu .el-menu-item{background-color:#fff;float:none;height:36px;line-height:36px;padding:0 10px}.el-menu--horizontal .el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu-item:focus,.el-menu--horizontal .el-menu-item:hover,.el-menu--horizontal .el-submenu__title:hover{outline:0;color:#2d2f33}.el-menu--horizontal>.el-menu-item.is-active,.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #3C8DBC;color:#2d2f33}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-menu .el-submenu{min-width:200px}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;z-index:10;border:1px solid #dfe4ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;padding:0 20px;cursor:pointer;position:relative;white-space:nowrap}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu-item{font-size:14px;color:#2d2f33;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item *{vertical-align:middle}.el-menu-item:first-child{margin-left:0}.el-menu-item:last-child{margin-right:0}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:rgb(236, 244, 248)}.el-menu-item i{color:#878d99}.el-menu-item.is-active{color:#3C8DBC}.el-menu-item.is-active i{color:inherit}.el-submenu__title{font-size:14px;color:#2d2f33;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#878d99}.el-submenu__title:hover{background-color:rgb(236, 244, 248)}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#3C8DBC}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#878d99}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}
--------------------------------------------------------------------------------
/app/web/theme/step.css:
--------------------------------------------------------------------------------
1 | .el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#2d2f33;border-color:#2d2f33}.el-step__head.is-wait{color:#b4bccc;border-color:#b4bccc}.el-step__head.is-success{color:#67c23a;border-color:#67c23a}.el-step__head.is-error{color:#fa5555;border-color:#fa5555}.el-step__head.is-finish{color:#3C8DBC;border-color:#3C8DBC}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#b4bccc}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#2d2f33}.el-step__title.is-wait{color:#b4bccc}.el-step__title.is-success{color:#67c23a}.el-step__title.is-error{color:#fa5555}.el-step__title.is-finish{color:#3C8DBC}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#2d2f33}.el-step__description.is-wait{color:#b4bccc}.el-step__description.is-success{color:#67c23a}.el-step__description.is-error{color:#fa5555}.el-step__description.is-finish{color:#3C8DBC}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:-webkit-box;display:-ms-flexbox;display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#b4bccc}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}
--------------------------------------------------------------------------------
/app/web/theme/input.css:
--------------------------------------------------------------------------------
1 | .el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #d8dce5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#5a5e66;display:inline-block;font-size:inherit;height:40px;line-height:1;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;text-align:center;height:100%;color:#b4bccc}.el-input__inner::-webkit-input-placeholder{color:#b4bccc}.el-input__inner:-ms-input-placeholder{color:#b4bccc}.el-input__inner::placeholder{color:#b4bccc}.el-input__inner:hover{border-color:#b4bccc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#3C8DBC;outline:0}.el-input__suffix{right:5px;transition:all .3s;pointer-events:none}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#dfe4ed;color:#b4bccc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#b4bccc}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#b4bccc}.el-input.is-disabled .el-input__inner::placeholder{color:#b4bccc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#878d99;vertical-align:middle;display:table-cell;position:relative;border:1px solid #d8dce5;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-textarea{display:inline-block;width:100%;vertical-align:bottom}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:14px;color:#5a5e66;background-color:#fff;background-image:none;border:1px solid #d8dce5;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#b4bccc}.el-textarea__inner:-ms-input-placeholder{color:#b4bccc}.el-textarea__inner::placeholder{color:#b4bccc}.el-textarea__inner:hover{border-color:#b4bccc}.el-textarea__inner:focus{outline:0;border-color:#3C8DBC}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#dfe4ed;color:#b4bccc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#b4bccc}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#b4bccc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#b4bccc}
--------------------------------------------------------------------------------
/app/web/theme/color-picker.css:
--------------------------------------------------------------------------------
1 | .el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(transparent));background:linear-gradient(to top,#000,transparent)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#3C8DBC;border-color:#3C8DBC}.el-color-dropdown__link-btn{cursor:pointer;color:#3C8DBC;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(primary,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#fff;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;background-color:#fff;border:1px solid #e6ebf5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}
--------------------------------------------------------------------------------
/app/web/page/admin/home/view/list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
18 |
19 |
20 | 查询
21 | 写文章
22 |
23 |
24 |
31 |
34 |
35 |
39 |
40 |
43 |
44 | {{props.row.title}}
45 |
46 |
47 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
63 |
64 |
65 | 修改
66 |
67 | 删除
68 |
69 |
70 |
71 |
72 |
73 |
80 | 批量删除
81 |
82 |
83 |
84 |
92 |
93 |
94 |
95 |
96 |
97 |
100 |
196 |
--------------------------------------------------------------------------------
/app/web/theme/checkbox.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";.el-checkbox,.el-checkbox__input{display:inline-block;position:relative}.el-checkbox-button__inner,.el-checkbox__input{white-space:nowrap;vertical-align:middle;outline:0}.el-checkbox{color:#5a5e66;font-weight:500;font-size:14px;cursor:pointer;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #d8dce5}.el-checkbox.is-bordered.is-checked{border-color:#3C8DBC}.el-checkbox.is-bordered.is-disabled{border-color:#e6ebf5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:3px 15px 7px 10px;border-radius:3px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:1px 15px 5px 10px;border-radius:3px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;line-height:1}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#d8dce5;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#b4bccc}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#edf2fc;border-color:#d8dce5}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#b4bccc}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#edf2fc;border-color:#d8dce5}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#b4bccc;border-color:#b4bccc}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#3C8DBC;border-color:#3C8DBC}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#b4bccc;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#3C8DBC}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#3C8DBC}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#fff;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #d8dce5;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#fff;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#3C8DBC}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #fff;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s cubic-bezier(.71,-.46,.88,.6) 50ms;transition:-webkit-transform .15s cubic-bezier(.71,-.46,.88,.6) 50ms;transition:transform .15s cubic-bezier(.71,-.46,.88,.6) 50ms;transition:transform .15s cubic-bezier(.71,-.46,.88,.6) 50ms,-webkit-transform .15s cubic-bezier(.71,-.46,.88,.6) 50ms;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;left:-999px}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox+.el-checkbox{margin-left:30px}.el-checkbox-button__inner{line-height:1;font-weight:500;cursor:pointer;background:#fff;border:1px solid #d8dce5;border-left:0;color:#5a5e66;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#3C8DBC}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;left:-999px}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#fff;background-color:#3C8DBC;border-color:#3C8DBC;-webkit-box-shadow:-1px 0 0 0 rgb(138, 187, 215);box-shadow:-1px 0 0 0 rgb(138, 187, 215)}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#b4bccc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#e6ebf5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #d8dce5;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#3C8DBC}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}
--------------------------------------------------------------------------------
/app/web/theme/base.css:
--------------------------------------------------------------------------------
1 | .el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;transition:opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;transition:transform .3s cubic-bezier(.23,1,.32,1) .1s,opacity .3s cubic-bezier(.23,1,.32,1) .1s;transition:transform .3s cubic-bezier(.23,1,.32,1) .1s,opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;transition:opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;transition:transform .3s cubic-bezier(.23,1,.32,1) .1s,opacity .3s cubic-bezier(.23,1,.32,1) .1s;transition:transform .3s cubic-bezier(.23,1,.32,1) .1s,opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;transition:opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;transition:transform .3s cubic-bezier(.23,1,.32,1) .1s,opacity .3s cubic-bezier(.23,1,.32,1) .1s;transition:transform .3s cubic-bezier(.23,1,.32,1) .1s,opacity .3s cubic-bezier(.23,1,.32,1) .1s,-webkit-transform .3s cubic-bezier(.23,1,.32,1) .1s;-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}@font-face{font-family:element-icons;src:url(fonts/element-icons.woff?t=1508751886602) format("woff"),url(fonts/element-icons.ttf?t=1508751886602) format("truetype");font-weight:400;font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-upload:before{content:"\e60d"}.el-icon-error:before{content:"\e62c"}.el-icon-success:before{content:"\e62d"}.el-icon-warning:before{content:"\e62e"}.el-icon-sort-down:before{content:"\e630"}.el-icon-sort-up:before{content:"\e631"}.el-icon-arrow-left:before{content:"\e600"}.el-icon-circle-plus:before{content:"\e601"}.el-icon-circle-plus-outline:before{content:"\e602"}.el-icon-arrow-down:before{content:"\e603"}.el-icon-arrow-right:before{content:"\e604"}.el-icon-arrow-up:before{content:"\e605"}.el-icon-back:before{content:"\e606"}.el-icon-circle-close:before{content:"\e607"}.el-icon-date:before{content:"\e608"}.el-icon-circle-close-outline:before{content:"\e609"}.el-icon-caret-left:before{content:"\e60a"}.el-icon-caret-bottom:before{content:"\e60b"}.el-icon-caret-top:before{content:"\e60c"}.el-icon-caret-right:before{content:"\e60e"}.el-icon-close:before{content:"\e60f"}.el-icon-d-arrow-left:before{content:"\e610"}.el-icon-check:before{content:"\e611"}.el-icon-delete:before{content:"\e612"}.el-icon-d-arrow-right:before{content:"\e613"}.el-icon-document:before{content:"\e614"}.el-icon-d-caret:before{content:"\e615"}.el-icon-edit-outline:before{content:"\e616"}.el-icon-download:before{content:"\e617"}.el-icon-goods:before{content:"\e618"}.el-icon-search:before{content:"\e619"}.el-icon-info:before{content:"\e61a"}.el-icon-message:before{content:"\e61b"}.el-icon-edit:before{content:"\e61c"}.el-icon-location:before{content:"\e61d"}.el-icon-loading:before{content:"\e61e"}.el-icon-location-outline:before{content:"\e61f"}.el-icon-menu:before{content:"\e620"}.el-icon-minus:before{content:"\e621"}.el-icon-bell:before{content:"\e622"}.el-icon-mobile-phone:before{content:"\e624"}.el-icon-news:before{content:"\e625"}.el-icon-more:before{content:"\e646"}.el-icon-more-outline:before{content:"\e626"}.el-icon-phone:before{content:"\e627"}.el-icon-phone-outline:before{content:"\e628"}.el-icon-picture:before{content:"\e629"}.el-icon-picture-outline:before{content:"\e62a"}.el-icon-plus:before{content:"\e62b"}.el-icon-printer:before{content:"\e62f"}.el-icon-rank:before{content:"\e632"}.el-icon-refresh:before{content:"\e633"}.el-icon-question:before{content:"\e634"}.el-icon-remove:before{content:"\e635"}.el-icon-share:before{content:"\e636"}.el-icon-star-on:before{content:"\e637"}.el-icon-setting:before{content:"\e638"}.el-icon-circle-check:before{content:"\e639"}.el-icon-service:before{content:"\e63a"}.el-icon-sold-out:before{content:"\e63b"}.el-icon-remove-outline:before{content:"\e63c"}.el-icon-star-off:before{content:"\e63d"}.el-icon-circle-check-outline:before{content:"\e63e"}.el-icon-tickets:before{content:"\e63f"}.el-icon-sort:before{content:"\e640"}.el-icon-zoom-in:before{content:"\e641"}.el-icon-time:before{content:"\e642"}.el-icon-view:before{content:"\e643"}.el-icon-upload2:before{content:"\e644"}.el-icon-zoom-out:before{content:"\e645"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}
--------------------------------------------------------------------------------
/app/web/theme/input-number.css:
--------------------------------------------------------------------------------
1 | .el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #d8dce5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#5a5e66;display:inline-block;font-size:inherit;height:40px;line-height:1;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#b4bccc;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#b4bccc}.el-input__inner:-ms-input-placeholder{color:#b4bccc}.el-input__inner::placeholder{color:#b4bccc}.el-input__inner:hover{border-color:#b4bccc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#3C8DBC;outline:0}.el-input__suffix{right:5px;transition:all .3s;pointer-events:none}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#dfe4ed;color:#b4bccc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#b4bccc}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#b4bccc}.el-input.is-disabled .el-input__inner::placeholder{color:#b4bccc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#878d99;vertical-align:middle;display:table-cell;position:relative;border:1px solid #d8dce5;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-textarea{display:inline-block;width:100%;vertical-align:bottom}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:14px;color:#5a5e66;background-color:#fff;background-image:none;border:1px solid #d8dce5;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#b4bccc}.el-textarea__inner:-ms-input-placeholder{color:#b4bccc}.el-textarea__inner::placeholder{color:#b4bccc}.el-textarea__inner:hover{border-color:#b4bccc}.el-textarea__inner:focus{outline:0;border-color:#3C8DBC}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#dfe4ed;color:#b4bccc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#b4bccc}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#b4bccc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#b4bccc}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#f5f7fa;color:#5a5e66;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#3C8DBC}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#3C8DBC}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#b4bccc;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #d8dce5}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #d8dce5}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#dfe4ed;color:#dfe4ed}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#dfe4ed;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #d8dce5}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #d8dce5;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}
--------------------------------------------------------------------------------