├── public
├── robots.txt
├── favicon.ico
├── config.local.js
├── img
│ └── icons
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── mstile-150x150.png
│ │ ├── apple-touch-icon.png
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon-60x60.png
│ │ ├── apple-touch-icon-76x76.png
│ │ ├── apple-touch-icon-120x120.png
│ │ ├── apple-touch-icon-152x152.png
│ │ ├── apple-touch-icon-180x180.png
│ │ └── msapplication-icon-144x144.png
├── vendor
│ ├── element-icons.535877f.woff
│ ├── element-icons.732389d.ttf
│ ├── vendor-manifest.json
│ └── vendor.dll.css
├── manifest.json
└── index.html
├── .browserslistrc
├── .env.production
├── src
├── assets
│ ├── img
│ │ ├── logo.png
│ │ ├── 401_images
│ │ │ └── 401.gif
│ │ └── 404_images
│ │ │ ├── 404.png
│ │ │ └── 404_cloud.png
│ ├── custom-theme
│ │ └── fonts
│ │ │ ├── element-icons.ttf
│ │ │ └── element-icons.woff
│ ├── less
│ │ ├── app.less
│ │ ├── svg-icon.less
│ │ ├── transition.less
│ │ ├── element-ui.less
│ │ ├── variable.less
│ │ └── btn.less
│ └── js
│ │ ├── variable.ts
│ │ └── export2Zip.js
├── icons
│ ├── svg
│ │ ├── chart.svg
│ │ ├── size.svg
│ │ ├── link.svg
│ │ ├── guide.svg
│ │ ├── component.svg
│ │ ├── money.svg
│ │ ├── email.svg
│ │ ├── drag.svg
│ │ ├── guide2.svg
│ │ ├── documentation.svg
│ │ ├── fullscreen.svg
│ │ ├── user.svg
│ │ ├── lock.svg
│ │ ├── excel.svg
│ │ ├── example.svg
│ │ ├── star.svg
│ │ ├── table.svg
│ │ ├── search.svg
│ │ ├── password.svg
│ │ ├── tab.svg
│ │ ├── message.svg
│ │ ├── theme.svg
│ │ ├── peoples.svg
│ │ ├── edit.svg
│ │ ├── nested.svg
│ │ ├── tree-table.svg
│ │ ├── eye.svg
│ │ ├── clipboard.svg
│ │ ├── list.svg
│ │ ├── icon.svg
│ │ ├── international.svg
│ │ ├── wechat.svg
│ │ ├── people.svg
│ │ ├── language.svg
│ │ ├── eye-open.svg
│ │ ├── 404.svg
│ │ ├── zip.svg
│ │ ├── bug.svg
│ │ ├── dog.svg
│ │ ├── pdf.svg
│ │ ├── exit-fullscreen.svg
│ │ └── tree.svg
│ └── components
│ │ ├── chart.ts
│ │ ├── size.ts
│ │ ├── link.ts
│ │ ├── guide.ts
│ │ ├── component.ts
│ │ ├── money.ts
│ │ ├── drag.ts
│ │ ├── email.ts
│ │ ├── guide2.ts
│ │ ├── documentation.ts
│ │ ├── fullscreen.ts
│ │ ├── user.ts
│ │ ├── lock.ts
│ │ ├── excel.ts
│ │ ├── example.ts
│ │ ├── star.ts
│ │ ├── search.ts
│ │ ├── table.ts
│ │ ├── password.ts
│ │ ├── tab.ts
│ │ ├── message.ts
│ │ ├── theme.ts
│ │ ├── peoples.ts
│ │ ├── edit.ts
│ │ ├── nested.ts
│ │ ├── index.ts
│ │ ├── tree-table.ts
│ │ ├── eye.ts
│ │ ├── clipboard.ts
│ │ ├── list.ts
│ │ ├── icon.ts
│ │ ├── international.ts
│ │ ├── wechat.ts
│ │ ├── people.ts
│ │ ├── eye-open.ts
│ │ ├── language.ts
│ │ ├── 404.ts
│ │ ├── zip.ts
│ │ ├── bug.ts
│ │ ├── dog.ts
│ │ └── pdf.ts
├── components
│ ├── ImageCropper
│ │ └── utils
│ │ │ ├── mimes.ts
│ │ │ └── effectRipple.ts
│ ├── Tinymce
│ │ ├── toolbar.ts
│ │ └── plugins.ts
│ ├── MarkdownEditor
│ │ └── defaultOptions.ts
│ ├── Charts
│ │ └── mixins
│ │ │ └── resize.ts
│ ├── ScreenFull
│ │ └── index.vue
│ ├── LangSelect
│ │ └── index.vue
│ ├── Hamburger
│ │ └── index.vue
│ ├── TreeTable
│ │ └── eval.ts
│ ├── SizeSelect
│ │ └── index.vue
│ └── DragSelect
│ │ └── index.vue
├── shims-vue.d.ts
├── views
│ ├── example
│ │ ├── components
│ │ │ ├── Dropdown
│ │ │ │ ├── index.ts
│ │ │ │ ├── Comment.vue
│ │ │ │ ├── SourceUrl.vue
│ │ │ │ └── Platform.vue
│ │ │ └── Warning.vue
│ │ ├── edit.vue
│ │ └── create.vue
│ ├── svgIcons
│ │ └── requireIcons.ts
│ ├── nested
│ │ ├── menu1
│ │ │ ├── index.vue
│ │ │ ├── menu1-3
│ │ │ │ └── index.vue
│ │ │ ├── menu1-2
│ │ │ │ ├── menu1-2-2
│ │ │ │ │ └── index.vue
│ │ │ │ ├── menu1-2-1
│ │ │ │ │ └── index.vue
│ │ │ │ └── index.vue
│ │ │ └── menu1-1
│ │ │ │ └── index.vue
│ │ └── menu2
│ │ │ └── index.vue
│ ├── login
│ │ ├── authredirect.vue
│ │ └── socialSignIn.vue
│ ├── redirect
│ │ └── index.vue
│ ├── errorLog
│ │ ├── errorTestA.vue
│ │ ├── errorTestB.vue
│ │ └── index.vue
│ ├── permission
│ │ ├── page.vue
│ │ └── components
│ │ │ └── SwitchRoles.vue
│ ├── pdf
│ │ └── index.vue
│ ├── charts
│ │ ├── mixChart.vue
│ │ ├── line.vue
│ │ └── keyboard.vue
│ ├── table
│ │ └── dynamicTable
│ │ │ ├── index.vue
│ │ │ └── unfixedThead.vue
│ ├── excel
│ │ ├── components
│ │ │ ├── AutoWidthOption.vue
│ │ │ ├── FilenameOption.vue
│ │ │ └── BookTypeOption.vue
│ │ └── uploadExcel.vue
│ ├── dashboard
│ │ ├── index.vue
│ │ └── admin
│ │ │ └── components
│ │ │ └── TransactionTable.vue
│ ├── treeTable
│ │ ├── custom
│ │ │ └── data.ts
│ │ └── data.ts
│ ├── guide
│ │ ├── index.vue
│ │ └── defineSteps.ts
│ ├── componentsDemo
│ │ ├── dropZone.vue
│ │ ├── dragSelect.vue
│ │ ├── dndList.vue
│ │ ├── tinymce.vue
│ │ ├── jsonEditor.vue
│ │ ├── avatarUpload.vue
│ │ ├── dragKanban.vue
│ │ └── splitPane.vue
│ ├── clipboard
│ │ └── index.vue
│ ├── tab
│ │ └── index.vue
│ └── i18n-demo
│ │ └── local.ts
├── interface
│ └── index.ts
├── layout
│ ├── components
│ │ ├── index.ts
│ │ ├── Sidebar
│ │ │ ├── Link.vue
│ │ │ ├── FixiOSBug.ts
│ │ │ └── index.vue
│ │ └── AppMain.vue
│ └── mixin
│ │ └── ResizeHandler.ts
├── utils
│ ├── getPageTitle.ts
│ ├── permission.ts
│ ├── clipboard.ts
│ ├── validate.ts
│ ├── auth.ts
│ └── scrollTo.js
├── shims-tsx.d.ts
├── services
│ ├── autoMatchBaseUrl.ts
│ ├── RESTFULLURL.ts
│ └── index.ts
├── constant.ts
├── directives
│ ├── index.ts
│ ├── permission.ts
│ ├── waves
│ │ ├── waves.css
│ │ └── index.ts
│ ├── el-table.ts
│ └── clipboard.ts
├── App.vue
├── pwa
│ ├── service-worker.js
│ └── register-service-worker.ts
├── store
│ ├── modules
│ │ ├── errorLog.ts
│ │ └── settings.ts
│ ├── index.ts
│ └── getters.ts
├── settings.ts
├── router
│ └── modules
│ │ ├── charts.ts
│ │ └── table.ts
├── registerServiceWorker.ts
├── errorLog.ts
├── main.ts
├── lang
│ └── index.ts
└── filters
│ └── index.ts
├── .travis.yml
├── .env.staging
├── babel.config.js
├── postcss.config.js
├── jsconfig.json
├── types
├── vue-global.d.ts
└── index.d.ts
├── .gitignore
├── .env.development
├── .editorconfig
├── tslint.json
├── README.md
├── LICENSE
├── tsconfig.json
└── mock
├── remoteSearch.ts
└── user.ts
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/config.local.js:
--------------------------------------------------------------------------------
1 | window.LOCAL_CONFIG = {
2 | API_HOME: 'http://localhost:5577/dev-api'
3 | };
4 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'production'
3 |
4 | # base api
5 | VUE_APP_BASE_API = '/prod-api'
6 |
--------------------------------------------------------------------------------
/src/assets/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/src/assets/img/logo.png
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: stable
3 | script: npm run test
4 | notifications:
5 | email: false
6 |
--------------------------------------------------------------------------------
/src/assets/img/401_images/401.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/src/assets/img/401_images/401.gif
--------------------------------------------------------------------------------
/src/assets/img/404_images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/src/assets/img/404_images/404.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/.env.staging:
--------------------------------------------------------------------------------
1 | NODE_ENV = production
2 |
3 | # just a flag
4 | ENV = 'staging'
5 |
6 | # base api
7 | VUE_APP_BASE_API = '/stage-api'
8 |
9 |
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset',
4 | '@babel/preset-typescript'
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/public/vendor/element-icons.535877f.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/vendor/element-icons.535877f.woff
--------------------------------------------------------------------------------
/public/vendor/element-icons.732389d.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/vendor/element-icons.732389d.ttf
--------------------------------------------------------------------------------
/src/assets/img/404_images/404_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/src/assets/img/404_images/404_cloud.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/src/assets/custom-theme/fonts/element-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/src/assets/custom-theme/fonts/element-icons.ttf
--------------------------------------------------------------------------------
/src/assets/custom-theme/fonts/element-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cklwblove/vue-element-admin-ts/HEAD/src/assets/custom-theme/fonts/element-icons.woff
--------------------------------------------------------------------------------
/src/icons/svg/chart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/ImageCropper/utils/mimes.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | 'jpg': 'image/jpeg',
3 | 'png': 'image/png',
4 | 'gif': 'image/gif',
5 | 'svg': 'image/svg+xml',
6 | 'psd': 'image/photoshop'
7 | };
8 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue';
3 | export default Vue;
4 | }
5 |
6 | declare module '*.svg' {
7 | import Vue from 'vue';
8 | export default Vue;
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/src/icons/svg/size.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/less/app.less:
--------------------------------------------------------------------------------
1 | @import "./variable";
2 | @import "~mixins";
3 | @import "./transition";
4 | @import "./svg-icon";
5 | @import "./element-ui";
6 | @import "./sidebar";
7 | @import "./btn";
8 |
9 | @import "main";
10 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | plugins: {
5 | // to edit target browsers: use "browserslist" field in package.json
6 | autoprefixer: {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": [
6 | "src/*"
7 | ]
8 | }
9 | },
10 | "exclude": [
11 | "node_modules",
12 | "dist"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/src/views/example/components/Dropdown/index.ts:
--------------------------------------------------------------------------------
1 | export { default as CommentDropdown } from './Comment.vue';
2 | export { default as PlatformDropdown } from './Platform.vue';
3 | export { default as SourceUrlDropdown } from './SourceUrl.vue';
4 |
--------------------------------------------------------------------------------
/types/vue-global.d.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | declare module 'vue/types/vue' {
4 | // 可以使用 `VueConstructor` 接口
5 | // 来声明全局属性
6 | interface Vue {
7 | readonly $services: any;
8 | readonly $ELEMENT: any;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/interface/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 定义接口类
3 | * 最佳实践 -> 接口名字一般建议 I 开头,便于别人阅读
4 | */
5 |
6 | export interface IDataValues {
7 | year: string;
8 | value: number;
9 | }
10 |
11 | export interface IListQuery {
12 | page: number;
13 | limit: number;
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/js/variable.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | menuText: '#bfcbd9',
3 | menuActiveText: '#409EFF',
4 | subMenuActiveText: '#f4f4f5',
5 | menuBg: '#304156',
6 | menuHover: '#263445',
7 | subMenuBg: '#1f2d3d',
8 | subMenuHover: '#001528',
9 | sideBarWidth: '180px'
10 | };
11 |
--------------------------------------------------------------------------------
/src/icons/svg/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare interface Window {
2 | LOCAL_CONFIG?: any;
3 | tinymce?: any;
4 | webkitURL?: any;
5 | }
6 |
7 | declare module '*.png';
8 |
9 | declare module '*.gif';
10 |
11 | declare module 'vue-count-to';
12 |
13 | declare module 'vuedraggable';
14 |
15 | declare module 'vue-splitpane';
16 |
--------------------------------------------------------------------------------
/src/layout/components/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Navbar } from './Navbar.vue';
2 | export { default as Sidebar } from './Sidebar/index.vue';
3 | export { default as TagsView } from './TagsView/index.vue';
4 | export { default as AppMain } from './AppMain.vue';
5 | export { default as Settings } from './Settings/index.vue';
6 |
--------------------------------------------------------------------------------
/src/views/svgIcons/requireIcons.ts:
--------------------------------------------------------------------------------
1 | const req = require.context('../../icons/svg', false, /\.svg$/);
2 | const requireAll = (requireContext) => requireContext.keys();
3 |
4 | const re = /\.\/(.*)\.svg/;
5 |
6 | const icons = requireAll(req).map((i) => {
7 | return i.match(re)[1];
8 | });
9 |
10 | export default icons;
11 |
--------------------------------------------------------------------------------
/src/icons/svg/guide.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/src/icons/svg/component.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/money.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/nested/menu2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/src/icons/svg/email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/drag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils/getPageTitle.ts:
--------------------------------------------------------------------------------
1 | import i18n from '@/lang';
2 | import settings from '@/settings';
3 |
4 | export default function getPageTitle(key: string) {
5 | const hasKey = i18n.te(`route.${key}`);
6 | if (hasKey) {
7 | const pageName = i18n.t(`route.${key}`);
8 | return `${pageName} - ${settings.title}`;
9 | }
10 | return `${settings.title}`;
11 | }
12 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-3/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue';
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/icons/components/chart.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'chart': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/guide2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/src/views/login/authredirect.vue:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/src/views/redirect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/src/icons/components/size.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'size': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
--------------------------------------------------------------------------------
/src/views/errorLog/errorTestA.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ a.a }}
5 |
6 |
7 |
8 |
9 |
16 |
17 |
20 |
--------------------------------------------------------------------------------
/src/views/errorLog/errorTestB.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
20 |
--------------------------------------------------------------------------------
/src/icons/svg/documentation.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/fullscreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/services/autoMatchBaseUrl.ts:
--------------------------------------------------------------------------------
1 | import {UPLOAD_PREFIX} from '../constant';
2 |
3 | // 根据前缀,自动匹配基础的url
4 | export default function autoMatchBaseUrl(prefix: string) {
5 | let baseUrl = '';
6 | switch (prefix) {
7 | case UPLOAD_PREFIX:
8 | prefix = '';
9 | baseUrl = window.LOCAL_CONFIG.API_UPLOAD;
10 | break;
11 | default:
12 | baseUrl = window.LOCAL_CONFIG.API_HOME;
13 | }
14 |
15 | return `${baseUrl}`;
16 | }
17 |
--------------------------------------------------------------------------------
/src/constant.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @authors liwb (lwbhtml@gmail.com)
4 | * @date 2018/6/5 上午10:43
5 | * @description 定义项目所需常量
6 | */
7 |
8 | const TIMEOUT: number = 25000;
9 | const PAGE_NUM: number = 15;
10 | const UPLOAD_PREFIX: string = 'upload/';
11 | const HOME_PREFIX: string = 'home/';
12 | const SUCCESS_STATUS = 20000;
13 |
14 | export {
15 | TIMEOUT,
16 | PAGE_NUM,
17 | UPLOAD_PREFIX,
18 | HOME_PREFIX,
19 | SUCCESS_STATUS
20 | };
21 |
--------------------------------------------------------------------------------
/src/services/RESTFULLURL.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | loginByUsername: '/user/login',
3 | logout: '/user/logout',
4 | getUserInfo: '/user/info/',
5 | getList: '/transaction/list',
6 | search: '/search/user',
7 | articleList: '/article/list',
8 | articleDetail: '/article/detail',
9 | articlePv: '/article/pv',
10 | articleCreate: '/article/create',
11 | articleUpdate: '/article/update',
12 | getRoutes: '/routes',
13 | roles: '/roles',
14 | };
15 |
--------------------------------------------------------------------------------
/src/icons/svg/excel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/services/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import request from './request';
3 | import urls from './RESTFULLURL';
4 |
5 | const FUNS: any = {};
6 |
7 | Object.keys(urls).forEach((key) => {
8 | FUNS[key] = (options = {}) => {
9 | return request(urls[key], options);
10 | };
11 | });
12 |
13 | // 将services挂载到vue的原型上
14 | // views引用的方法:this.$services.接口名(小驼峰)
15 | Object.defineProperty(Vue.prototype, '$services', {value: FUNS});
16 |
17 | export default FUNS;
18 |
--------------------------------------------------------------------------------
/src/directives/index.ts:
--------------------------------------------------------------------------------
1 | import Vue, { DirectiveOptions } from 'vue';
2 |
3 | import permission from './permission';
4 | import waves from './waves';
5 | import elDragDialog from './el-dragDialog';
6 | import clipboard from './clipboard';
7 |
8 | const directives = {
9 | permission,
10 | waves,
11 | elDragDialog,
12 | clipboard
13 | };
14 |
15 | Object.keys(directives).forEach((key) => {
16 | Vue.directive(key, (directives as { [key: string]: DirectiveOptions })[key]);
17 | });
18 |
--------------------------------------------------------------------------------
/src/views/example/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
21 |
--------------------------------------------------------------------------------
/src/views/example/create.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
21 |
--------------------------------------------------------------------------------
/src/icons/components/link.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'link': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/example.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Tinymce/toolbar.ts:
--------------------------------------------------------------------------------
1 | // Here is a list of the toolbar
2 | // Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
3 |
4 | const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'];
5 |
6 | export default toolbar;
7 |
--------------------------------------------------------------------------------
/src/icons/components/guide.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'guide': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/component.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'component': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/money.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'money': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/drag.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'drag': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/email.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'email': {
7 | width: 128,
8 | height: 96,
9 | viewBox: '0 0 128 96',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/permission/page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
22 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-cli3-typescript-template",
3 | "short_name": "vue-cli3-typescript-template",
4 | "icons": [
5 | {
6 | "src": "./img/icons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./img/icons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "start_url": "./index.html",
17 | "display": "standalone",
18 | "background_color": "#000000",
19 | "theme_color": "#4DBA87"
20 | }
21 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/src/views/pdf/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $t('pdf.tips') }}
4 |
5 | Click to download PDF
6 |
7 |
8 |
9 |
10 |
17 |
18 |
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
23 | # Optional npm cache directory
24 | .npm
25 |
26 | # Optional eslint cache
27 | .eslintcache
28 |
29 | # Optional REPL history
30 | .node_repl_history
31 |
32 | # Output of 'npm pack'
33 | *.tgz
34 |
35 | .project
36 | .happypack
37 | .history
38 | yarn.lock
39 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= webpackConfig.name %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/icons/components/guide2.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'guide2': {
7 | width: 1000,
8 | height: 1000,
9 | viewBox: '0 0 1000 1000',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'development'
3 |
4 | # base api
5 | VUE_APP_BASE_API = '/dev-api'
6 |
7 | # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
8 | # to control whether the babel-plugin-dynamic-import-node plugin is enabled.
9 | # It only does one thing by converting all import() to require().
10 | # This configuration can significantly increase the speed of hot updates,
11 | # when you have a large number of pages.
12 | # Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
13 |
14 | VUE_CLI_BABEL_TRANSPILE_MODULES = true
15 |
--------------------------------------------------------------------------------
/src/assets/less/svg-icon.less:
--------------------------------------------------------------------------------
1 | /* recommended css code for vue-svgicon */
2 | .svg-icon {
3 | display: inline-block;
4 | width: 16px;
5 | height: 16px;
6 | color: inherit;
7 | vertical-align: middle;
8 | fill: none;
9 | stroke: currentColor;
10 | }
11 |
12 | .svg-fill {
13 | fill: currentColor;
14 | stroke: none;
15 | }
16 |
17 | .svg-up {
18 | /* default */
19 | transform: rotate(0deg);
20 | }
21 |
22 | .svg-right {
23 | transform: rotate(90deg);
24 | }
25 |
26 | .svg-down {
27 | transform: rotate(180deg);
28 | }
29 |
30 | .svg-left {
31 | transform: rotate(-90deg);
32 | }
33 |
--------------------------------------------------------------------------------
/src/icons/svg/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Tinymce/plugins.ts:
--------------------------------------------------------------------------------
1 | // Any plugins you want to use has to be imported
2 | // Detail plugins list see https://www.tinymce.com/docs/plugins/
3 | // Custom builds see https://www.tinymce.com/download/custom-builds/
4 |
5 | const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount'];
6 |
7 | export default plugins;
8 |
--------------------------------------------------------------------------------
/src/views/charts/mixChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
21 |
28 |
--------------------------------------------------------------------------------
/src/views/example/components/Warning.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 创建和编辑页面是不能被keep-alive 缓存的,因为keep-alive 的include 目前不支持根据路由来缓存,所以目前都是基于component name 来缓存的,如果你想要实现缓存的效果,可以使用localstorage 等浏览器缓存方案。或者不要使用keep-alive
4 | 的include,直接缓存所有页面。详情见
5 | 文档
8 |
9 |
10 |
11 |
18 |
--------------------------------------------------------------------------------
/src/icons/svg/password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/charts/line.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
21 |
22 |
29 |
--------------------------------------------------------------------------------
/src/icons/components/documentation.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'documentation': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/fullscreen.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'fullscreen': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/pwa/service-worker.js:
--------------------------------------------------------------------------------
1 | // This is the code piece that GenerateSW mode can't provide for us.
2 | // This code listens for the user's confirmation to update the app.
3 | self.addEventListener('message', (e) => {
4 | if (e.data) {
5 | if (e.data === 'skipWaiting') {
6 | self.skipWaiting();
7 | }
8 | }
9 | });
10 |
11 | workbox.clientsClaim();
12 |
13 | // The precaching code provided by Workbox. You don't need to change this part.
14 | self.__precacheManifest = [].concat(self.__precacheManifest || []);
15 | workbox.precaching.suppressWarnings();
16 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
17 |
--------------------------------------------------------------------------------
/src/icons/components/user.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'user': {
7 | width: 130,
8 | height: 130,
9 | viewBox: '0 0 130 130',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/lock.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'lock': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/tab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/charts/keyboard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
21 |
28 |
--------------------------------------------------------------------------------
/src/icons/components/excel.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'excel': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/modules/errorLog.ts:
--------------------------------------------------------------------------------
1 | import { getModule, Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
2 | import store from '@/store';
3 |
4 | export interface IErrorLogState {
5 | logs: any[];
6 | }
7 |
8 | @Module({dynamic: true, store, name: 'errorLog'})
9 | class ErrorLog extends VuexModule implements IErrorLogState {
10 | logs: any[] = [];
11 |
12 | @Action({commit: 'ADD_ERROR_LOG'})
13 | AddErrorLog(log) {
14 | return log;
15 | }
16 |
17 | @Mutation
18 | ADD_ERROR_LOG(log) {
19 | console.log('ADD_ERROR_LOG', this.logs);
20 | this.logs.push(log);
21 | }
22 | }
23 |
24 | export const ErrorLogModule = getModule(ErrorLog);
25 |
--------------------------------------------------------------------------------
/src/icons/svg/theme.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/components/example.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'example': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/table/dynamicTable/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ $t('table.dynamicTips1') }}
4 |
5 |
6 |
{{ $t('table.dynamicTips2') }}
7 |
8 |
9 |
10 |
11 |
24 |
--------------------------------------------------------------------------------
/src/assets/js/export2Zip.js:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | import { saveAs } from 'file-saver';
3 | import JSZip from 'jszip';
4 |
5 | export function export_txt_to_zip(th, jsonData, txtName, zipName) {
6 | const zip = new JSZip();
7 | const txt_name = txtName || 'file';
8 | const zip_name = zipName || 'file';
9 | const data = jsonData;
10 | let txtData = `${th}\r\n`;
11 | data.forEach((row) => {
12 | let tempStr = '';
13 | tempStr = row.toString();
14 | txtData += `${tempStr}\r\n`;
15 | });
16 | zip.file(`${txt_name}.txt`, txtData);
17 | zip.generateAsync({
18 | type: 'blob'
19 | }).then((blob) => {
20 | saveAs(blob, `${zip_name}.zip`);
21 | }, (err) => {
22 | alert('导出失败');
23 | });
24 | }
25 |
--------------------------------------------------------------------------------
/src/icons/svg/peoples.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/MarkdownEditor/defaultOptions.ts:
--------------------------------------------------------------------------------
1 | // doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor
2 | export default {
3 | minHeight: '200px',
4 | previewStyle: 'vertical',
5 | useCommandShortcut: true,
6 | useDefaultHTMLSanitizer: true,
7 | usageStatistics: false,
8 | hideModeSwitch: false,
9 | toolbarItems: [
10 | 'heading',
11 | 'bold',
12 | 'italic',
13 | 'strike',
14 | 'divider',
15 | 'hr',
16 | 'quote',
17 | 'divider',
18 | 'ul',
19 | 'ol',
20 | 'task',
21 | 'indent',
22 | 'outdent',
23 | 'divider',
24 | 'table',
25 | 'image',
26 | 'link',
27 | 'divider',
28 | 'code',
29 | 'codeblock'
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------
/src/directives/permission.ts:
--------------------------------------------------------------------------------
1 | import store from '@/store';
2 |
3 | export default {
4 | inserted(el, binding, vnode) {
5 | const {value} = binding;
6 | const roles = store.getters && store.getters.roles;
7 | console.log('permission directive roles', roles);
8 | if (value && value instanceof Array && value.length > 0) {
9 | const permissionRoles = value;
10 |
11 | const hasPermission = roles.some((role) => {
12 | return permissionRoles.includes(role);
13 | });
14 |
15 | if (!hasPermission) {
16 | el.parentNode && el.parentNode.removeChild(el);
17 | }
18 | } else {
19 | throw new Error(`need roles! Like v-permission="['admin','editor']"`);
20 | }
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/src/icons/components/star.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'star': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/excel/components/AutoWidthOption.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | True
6 | False
7 |
8 |
9 |
10 |
11 |
27 |
--------------------------------------------------------------------------------
/src/views/excel/components/FilenameOption.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | True
6 | False
7 |
8 |
9 |
10 |
11 |
27 |
--------------------------------------------------------------------------------
/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
33 |
--------------------------------------------------------------------------------
/src/icons/components/search.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'search': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
34 |
--------------------------------------------------------------------------------
/src/utils/permission.ts:
--------------------------------------------------------------------------------
1 | import store from '@/store';
2 |
3 | /**
4 | * @param {Array} value
5 | * @returns {Boolean}
6 | * @example see @/views/permission/directive.vue
7 | */
8 | export default function checkPermission(value) {
9 | // console.log('checkPermission value', value);
10 | if (value && value instanceof Array && value.length > 0) {
11 | const roles = store.getters && store.getters.roles;
12 | const permissionRoles = value;
13 | // console.log('checkPermission permissionRoles', value);
14 | // console.log('checkPermission roles', value);
15 | return roles.some((role) => {
16 | return permissionRoles.includes(role);
17 | });
18 | } else {
19 | console.error(`need roles! Like v-permission="['admin','editor']"`);
20 | return false;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/icons/components/table.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'table': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/nested.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/components/password.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'password': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/tab.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'tab': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import { IAppState } from './modules/app';
4 | import { IErrorLogState } from './modules/errorLog';
5 | import { ITagsViewState } from './modules/tagsView';
6 | import { IUserState } from './modules/user';
7 | import { IPermissionState } from './modules/permission';
8 | import { ISettingsState } from './modules/settings';
9 | import getters from './getters';
10 |
11 | Vue.use(Vuex);
12 |
13 | export interface IRootState {
14 | app: IAppState;
15 | user: IUserState;
16 | permission: IPermissionState;
17 | tagsView: ITagsViewState;
18 | errorLog: IErrorLogState;
19 | settings: ISettingsState;
20 | }
21 |
22 | // Declare empty store first, dynamically register all modules later.
23 | const store = new Vuex.Store({getters});
24 |
25 | export default store;
26 |
--------------------------------------------------------------------------------
/src/views/excel/components/BookTypeOption.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
32 |
--------------------------------------------------------------------------------
/src/icons/components/message.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'message': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | charset = utf-8
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | # Indentation override for js(x), ts(x) and vue files
14 | [*.{js,jsx,ts,tsx,vue}]
15 | indent_size = 2
16 | indent_style = space
17 |
18 | # Indentation override for css related files
19 | [*.{css,styl,scss,less,sass}]
20 | indent_size = 2
21 | indent_style = space
22 |
23 | # Indentation override for html files
24 | [*.html]
25 | indent_size = 2
26 | indent_style = space
27 |
28 | # Trailing space override for markdown file
29 | [*.md]
30 | trim_trailing_whitespace = false
31 |
32 | # Indentation override for config files
33 | [*.{json,yml}]
34 | indent_size = 2
35 | indent_style = space
36 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/FixiOSBug.ts:
--------------------------------------------------------------------------------
1 | import { Component, Vue } from 'vue-property-decorator';
2 |
3 | @Component
4 | export default class FixiOSBugMixin extends Vue {
5 | get device() {
6 | return this.$store.getters.device;
7 | }
8 |
9 | mounted() {
10 | // In order to fix the click on menu on the ios device will trigger the mouseeleave bug
11 | // https://github.com/PanJiaChen/vue-element-admin/issues/1135
12 | this.fixBugIniOS();
13 | }
14 |
15 | fixBugIniOS() {
16 | const $submenu = this.$refs.submenu;
17 | if ($submenu) {
18 | // @ts-ignore
19 | const handleMouseleave = $submenu.handleMouseleave;
20 | // @ts-ignore
21 | $submenu.handleMouseleave = (e) => {
22 | if (this.device === 'mobile') {
23 | return;
24 | }
25 | handleMouseleave(e);
26 | };
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/icons/components/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'theme': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/tree-table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/directives/waves/waves.css:
--------------------------------------------------------------------------------
1 | .waves-ripple {
2 | position: absolute;
3 | border-radius: 100%;
4 | background-color: rgba(0, 0, 0, 0.15);
5 | background-clip: padding-box;
6 | pointer-events: none;
7 | -webkit-user-select: none;
8 | -moz-user-select: none;
9 | -ms-user-select: none;
10 | user-select: none;
11 | -webkit-transform: scale(0);
12 | -ms-transform: scale(0);
13 | transform: scale(0);
14 | opacity: 1;
15 | }
16 |
17 | .waves-ripple.z-active {
18 | opacity: 0;
19 | -webkit-transform: scale(2);
20 | -ms-transform: scale(2);
21 | transform: scale(2);
22 | -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
23 | transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
24 | transition: opacity 1.2s ease-out, transform 0.6s ease-out;
25 | transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
26 | }
27 |
--------------------------------------------------------------------------------
/src/icons/components/peoples.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'peoples': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils/clipboard.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Clipboard from 'clipboard';
3 |
4 | function clipboardSuccess() {
5 | Vue.prototype.$message({
6 | message: 'Copy successfully',
7 | type: 'success',
8 | duration: 1500
9 | });
10 | }
11 |
12 | function clipboardError() {
13 | Vue.prototype.$message({
14 | message: 'Copy failed',
15 | type: 'error'
16 | });
17 | }
18 |
19 | export default function handleClipboard(text, event) {
20 | const clipboard: any = new Clipboard(event.target, {
21 | text: () => text
22 | });
23 | clipboard.on('success', () => {
24 | clipboardSuccess();
25 | clipboard.off('error');
26 | clipboard.off('success');
27 | clipboard.destroy();
28 | });
29 | clipboard.on('error', () => {
30 | clipboardError();
31 | clipboard.off('error');
32 | clipboard.off('success');
33 | clipboard.destroy();
34 | });
35 | clipboard.onClick(event);
36 | }
37 |
--------------------------------------------------------------------------------
/src/assets/less/transition.less:
--------------------------------------------------------------------------------
1 | //globl transition css
2 |
3 | /*fade*/
4 | .fade-enter-active,
5 | .fade-leave-active {
6 | transition: opacity 0.28s;
7 | }
8 |
9 | .fade-enter,
10 | .fade-leave-active {
11 | opacity: 0;
12 | }
13 |
14 | /*fade-transform*/
15 | .fade-transform-leave-active,
16 | .fade-transform-enter-active {
17 | transition: all .5s;
18 | }
19 |
20 | .fade-transform-enter {
21 | opacity: 0;
22 | transform: translateX(-30px);
23 | }
24 |
25 | .fade-transform-leave-to {
26 | opacity: 0;
27 | transform: translateX(30px);
28 | }
29 |
30 | /*breadcrumb transition*/
31 | .breadcrumb-enter-active,
32 | .breadcrumb-leave-active {
33 | transition: all .5s;
34 | }
35 |
36 | .breadcrumb-enter,
37 | .breadcrumb-leave-active {
38 | opacity: 0;
39 | transform: translateX(20px);
40 | }
41 |
42 | .breadcrumb-move {
43 | transition: all .5s;
44 | }
45 |
46 | .breadcrumb-leave-active {
47 | position: absolute;
48 | }
49 |
--------------------------------------------------------------------------------
/src/views/treeTable/custom/data.ts:
--------------------------------------------------------------------------------
1 | const data = [
2 | {
3 | name: '1',
4 | timeLine: 100,
5 | children: [
6 | {
7 | name: '1-1',
8 | timeLine: 20
9 | },
10 | {
11 | name: '1-2',
12 | timeLine: 60,
13 | children: [
14 | {
15 | name: '1-2-1',
16 | timeLine: 35
17 | },
18 | {
19 | name: '1-2-2',
20 | timeLine: 25
21 | }
22 | ]
23 | }
24 | ]
25 | },
26 | {
27 | name: '2',
28 | timeLine: 80,
29 | children: [
30 | {
31 | name: '2-1',
32 | timeLine: 30
33 | },
34 | {
35 | name: '2-2',
36 | timeLine: 50
37 | },
38 | {
39 | name: '2-3',
40 | timeLine: 60
41 | }
42 | ]
43 | },
44 | {
45 | name: '3',
46 | timeLine: 40
47 | }
48 | ];
49 |
50 | export default data;
51 |
52 |
--------------------------------------------------------------------------------
/src/icons/svg/clipboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/vendor/vendor-manifest.json:
--------------------------------------------------------------------------------
1 | {"name":"vendor_54783f8a6561d148af4b","content":{"./node_modules/vue/dist/vue.runtime.esm.js":{"id":2,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"./node_modules/webpack/buildin/global.js":{"id":5,"buildMeta":{"providedExports":true}},"./node_modules/process/browser.js":{"id":18,"buildMeta":{"providedExports":true}},"./node_modules/timers-browserify/main.js":{"id":35,"buildMeta":{"providedExports":true}},"./node_modules/setimmediate/setImmediate.js":{"id":36,"buildMeta":{"providedExports":true}},"./node_modules/vue-router/dist/vue-router.esm.js":{"id":185,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"./node_modules/vuex/dist/vuex.esm.js":{"id":186,"buildMeta":{"exportsType":"namespace","providedExports":["default","Store","install","mapState","mapMutations","mapGetters","mapActions","createNamespacedHelpers"]}},"./node_modules/normalize.css/normalize.css":{"id":187,"buildMeta":{"providedExports":true}}}}
--------------------------------------------------------------------------------
/src/views/guide/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ $t('guide.description') }}
5 | driver.js.
6 |
7 |
8 |
{{ $t('guide.button') }}
9 |
10 |
11 |
12 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/src/views/permission/components/SwitchRoles.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ $t('permission.roles') }}: {{ roles }}
4 | {{ $t('permission.switchRoles') }}:
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
38 |
--------------------------------------------------------------------------------
/src/settings.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | title: 'Vue Element Admin Typescript',
3 |
4 | theme: '#1890ff',
5 |
6 | /**
7 | * @type {boolean} true | false
8 | * @description Whether show the settings right-panel
9 | */
10 | showSettings: true,
11 |
12 | /**
13 | * @type {boolean} true | false
14 | * @description Whether need tagsView
15 | */
16 | tagsView: true,
17 |
18 | /**
19 | * @type {boolean} true | false
20 | * @description Whether fix the header
21 | */
22 | fixedHeader: false,
23 |
24 | /**
25 | * @type {boolean} true | false
26 | * @description Whether show the logo in sidebar
27 | */
28 | sidebarLogo: false,
29 |
30 | /**
31 | * @type {string | array} 'production' | ['production', 'development']
32 | * @description Need show err logs component.
33 | * The default is only used in the production env
34 | * If you want to also use it in dev, you can pass ['production', 'development']
35 | */
36 | errorLog: 'production'
37 | };
38 |
--------------------------------------------------------------------------------
/src/icons/svg/list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/components/edit.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'edit': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/nested.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'nested': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/router/modules/charts.ts:
--------------------------------------------------------------------------------
1 | /** When your routing table is too long, you can split it into small modules**/
2 |
3 | import Layout from '@/layout/index.vue';
4 |
5 | const chartsRouter = {
6 | path: '/charts',
7 | component: Layout,
8 | redirect: 'noredirect',
9 | name: 'Charts',
10 | meta: {
11 | title: 'charts',
12 | icon: 'chart'
13 | },
14 | children: [
15 | {
16 | path: 'keyboard',
17 | component: () => import('@/views/charts/keyboard.vue'),
18 | name: 'KeyboardChart',
19 | meta: {title: 'keyboardChart', noCache: true}
20 | },
21 | {
22 | path: 'line',
23 | component: () => import('@/views/charts/line.vue'),
24 | name: 'LineChart',
25 | meta: {title: 'lineChart', noCache: true}
26 | },
27 | {
28 | path: 'mixchart',
29 | component: () => import('@/views/charts/mixChart.vue'),
30 | name: 'MixChart',
31 | meta: {title: 'mixChart', noCache: true}
32 | }
33 | ]
34 | };
35 |
36 | export default chartsRouter;
37 |
--------------------------------------------------------------------------------
/src/utils/validate.ts:
--------------------------------------------------------------------------------
1 | export function isValidUsername(str: string) {
2 | const validMap = ['admin', 'editor'];
3 | return validMap.indexOf(str.trim()) >= 0;
4 | }
5 |
6 | // 小写字母
7 | export function validateLowerCase(str: string) {
8 | const reg = /^[a-z]+$/;
9 | return reg.test(str);
10 | }
11 |
12 | // 大写字母
13 | export function validateUpperCase(str: string) {
14 | const reg = /^[A-Z]+$/;
15 | return reg.test(str);
16 | }
17 |
18 | // 大小写字母
19 | export function validateAlphabets(str: string) {
20 | const reg = /^[A-Za-z]+$/;
21 | return reg.test(str);
22 | }
23 |
24 | /**
25 | * @param {Array} arg
26 | * @returns {Boolean}
27 | */
28 | export function isArray(arg: any) {
29 | if (typeof Array.isArray === 'undefined') {
30 | return Object.prototype.toString.call(arg) === '[object Array]';
31 | }
32 | return Array.isArray(arg);
33 | }
34 |
35 | /**
36 | * @param {string} str
37 | * @returns {Boolean}
38 | */
39 | export function isString(str) {
40 | return typeof str === 'string' || str instanceof String;
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Charts/mixins/resize.ts:
--------------------------------------------------------------------------------
1 | import { Vue, Component } from 'vue-property-decorator';
2 | import { debounce } from '@/utils';
3 |
4 | @Component
5 | export default class ResizeMixins extends Vue {
6 | sidebarElm: any = null;
7 |
8 | resizeHandler = debounce(() => {
9 | // @ts-ignore
10 | if (this.chart) {
11 | // @ts-ignore
12 | this.chart.resize();
13 | }
14 | }, 100);
15 |
16 | mounted() {
17 | window.addEventListener('resize', this.resizeHandler);
18 |
19 | this.sidebarElm = document.getElementsByClassName('sidebar-container')[0];
20 | this.sidebarElm && this.sidebarElm.addEventListener('transitionend', this.sidebarResizeHandler);
21 | }
22 |
23 | beforeDestroy() {
24 | window.removeEventListener('resize', this.resizeHandler);
25 |
26 | this.sidebarElm && this.sidebarElm.removeEventListener('transitionend', this.sidebarResizeHandler);
27 | }
28 |
29 | sidebarResizeHandler(e) {
30 | if (e.propertyName === 'width') {
31 | this.resizeHandler();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/icons/svg/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-console */
2 |
3 | import { register } from 'register-service-worker';
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready() {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB',
11 | );
12 | },
13 | registered() {
14 | console.log('Service worker has been registered.');
15 | },
16 | cached() {
17 | console.log('Content has been cached for offline use.');
18 | },
19 | updatefound() {
20 | console.log('New content is downloading.');
21 | },
22 | updated() {
23 | console.log('New content is available; please refresh.');
24 | },
25 | offline() {
26 | console.log('No internet connection found. App is running in offline mode.');
27 | },
28 | error(error) {
29 | console.error('Error during service worker registration:', error);
30 | },
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "warning",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "linterOptions": {
7 | "exclude": [
8 | "node_modules/**",
9 | "build/**",
10 | "package.json"
11 | ]
12 | },
13 | "rules": {
14 | "quotemark": [true, "single"],
15 | "indent": [true, "spaces", 2],
16 | "trailing-comma": false,
17 | "interface-name": false,
18 | "ordered-imports": false,
19 | "no-var-requires": false,
20 | "object-literal-sort-keys": false,
21 | "object-literal-key-quotes": false,
22 | "no-consecutive-blank-lines": false,
23 | "no-console": false,
24 | "completed-docs": false,
25 | "curly": [
26 | true,
27 | "ignore-same-line"
28 | ],
29 | "jsdoc-format": false,
30 | "no-redundant-jsdoc": false,
31 | "max-line-length": [true, 500],
32 | "no-unused-expression": false,
33 | "no-shadowed-variable": false,
34 | "member-access": [true, "no-public"],
35 | "no-string-literal": false
36 | },
37 | "jsRules": {
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/ScreenFull/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
32 |
33 |
43 |
--------------------------------------------------------------------------------
/src/views/example/components/Dropdown/Comment.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ !commentDisabled?'评论已打开':'评论已关闭' }}
4 |
5 |
6 |
7 |
8 |
9 | 关闭评论
10 | 打开评论
11 |
12 |
13 |
14 |
15 |
16 |
17 |
34 |
35 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/dropZone.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Based on dropzone .
5 | {{ $t('components.dropzoneTips') }}
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
35 |
--------------------------------------------------------------------------------
/src/icons/components/index.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | import './404'
3 | import './bug'
4 | import './cat'
5 | import './chart'
6 | import './clipboard'
7 | import './component'
8 | import './dashboard'
9 | import './documentation'
10 | import './dog'
11 | import './drag'
12 | import './edit'
13 | import './email'
14 | import './example'
15 | import './excel'
16 | import './exit-fullscreen'
17 | import './eye-open'
18 | import './eye'
19 | import './form'
20 | import './fullscreen'
21 | import './guide'
22 | import './guide2'
23 | import './icon'
24 | import './international'
25 | import './language'
26 | import './link'
27 | import './list'
28 | import './lock'
29 | import './message'
30 | import './money'
31 | import './nested'
32 | import './password'
33 | import './pdf'
34 | import './people'
35 | import './peoples'
36 | import './qq'
37 | import './search'
38 | import './shopping'
39 | import './size'
40 | import './star'
41 | import './tab'
42 | import './table'
43 | import './theme'
44 | import './tree-table'
45 | import './tree'
46 | import './user'
47 | import './wechat'
48 | import './zip'
49 |
--------------------------------------------------------------------------------
/src/utils/auth.ts:
--------------------------------------------------------------------------------
1 | import pkg from '../../package.json';
2 | import store from 'store';
3 |
4 | const {name} = pkg;
5 |
6 | const TokenKey = `${name}/Admin-Token`;
7 | const LANGUAGE = `${name}/language`;
8 | const SIZE = `${name}/size`;
9 | const SIDEBAR_STATUS = `${name}/sidebarStatus`;
10 |
11 | export function getToken() {
12 | return store.get(TokenKey);
13 | }
14 |
15 | export function setToken(token: string) {
16 | return store.set(TokenKey, token);
17 | }
18 |
19 | export function removeToken() {
20 | return store.remove(TokenKey);
21 | }
22 |
23 | export function setLanguage(language: string) {
24 | return store.set(LANGUAGE, language);
25 | }
26 |
27 | // getLanguage -> @/lang/index
28 |
29 | export function getSize() {
30 | return store.get(SIZE);
31 | }
32 |
33 | export function setSize(size: string) {
34 | return store.set(SIZE, size);
35 | }
36 |
37 | export function getSidebarStatus() {
38 | return store.get(SIDEBAR_STATUS);
39 | }
40 |
41 | export function setSidebarStatus(sidebarStatus: string) {
42 | return store.set(SIDEBAR_STATUS, sidebarStatus);
43 | }
44 |
--------------------------------------------------------------------------------
/src/views/errorLog/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{ $t('errorLog.tips') }}
7 |
8 | {{ $t('errorLog.description') }}
9 |
10 | {{ $t('errorLog.documentation') }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
33 |
34 |
39 |
--------------------------------------------------------------------------------
/src/icons/components/tree-table.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'tree-table': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/store/modules/settings.ts:
--------------------------------------------------------------------------------
1 | import { getModule, Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
2 | import store from '@/store';
3 | import defaultSettings from '@/settings';
4 |
5 | const {showSettings, tagsView, fixedHeader, sidebarLogo, theme} = defaultSettings;
6 |
7 | export interface ISettingsState {
8 | theme: string;
9 | showSettings: boolean;
10 | tagsView: boolean;
11 | fixedHeader: boolean;
12 | sidebarLogo: boolean;
13 | }
14 |
15 | @Module({dynamic: true, store, name: 'settings'})
16 | class Settings extends VuexModule implements ISettingsState {
17 | theme = theme;
18 | showSettings = showSettings;
19 | tagsView = tagsView;
20 | fixedHeader = fixedHeader;
21 | sidebarLogo = sidebarLogo;
22 |
23 | @Action({commit: 'CHANGE_SETTING'})
24 | ChangeSetting(data: any) {
25 | console.log('data', data);
26 | return data;
27 | }
28 |
29 | @Mutation
30 | CHANGE_SETTING({key, value}) {
31 | if (this.hasOwnProperty(key)) {
32 | this[key] = value;
33 | }
34 | }
35 | }
36 |
37 | export const SettingsModule = getModule(Settings);
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-element-admin-ts
2 |
3 | > [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 的 *typescript* 版本 by [vue-cli3](https://cli.vuejs.org/zh/) and [vue-cli3-typescript-template](https://github.com/cklwblove/vue-cli3-typescript-template)
4 |
5 |
6 | ## 效果
7 |
8 | 
9 |
10 | ### 安装
11 |
12 | ```node
13 | yarn install
14 | ```
15 |
16 | ### 开发
17 |
18 | ```node
19 | yarn run serve
20 | ```
21 |
22 | ### 线上构建
23 |
24 | ```node
25 | yarn run build
26 | ```
27 |
28 | ### 代码检测
29 |
30 | ```node
31 | yarn run lint
32 | ```
33 |
34 | ## 相关链接
35 |
36 | - [TypeScript 学习资源合集](https://juejin.im/entry/5b9e4a135188255c3a2d3695)
37 | - [Awesome TypeScript](https://github.com/semlinker/awesome-typescript)
38 | - [如何用 TypeScript 编写 Vue 项目](https://gitbook.cn/books/5a0fdd6a0321202f017b8eb7/index.html)
39 | - [原有vue项目接入typescript](https://blog.fundebug.com/2018/11/30/how-to-use-typescript-in-vue/)
40 |
41 | ## License
42 |
43 | [MIT](https://github.com/cklwblove/vue-element-admin-ts/blob/master/LICENSE)
44 |
--------------------------------------------------------------------------------
/src/icons/svg/international.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/example/components/Dropdown/SourceUrl.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 外链
5 |
6 |
7 |
8 |
9 |
10 | 填写url
11 |
12 |
13 |
14 |
15 |
16 |
17 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/src/icons/components/eye.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'eye': {
7 | width: 128,
8 | height: 64,
9 | viewBox: '0 0 128 64',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 lwbgithub
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 |
--------------------------------------------------------------------------------
/src/icons/svg/wechat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/components/clipboard.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'clipboard': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/errorLog.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import { isArray, isString } from '@/utils/validate';
3 | import { ErrorLogModule } from '@/store/modules/errorLog';
4 | import settings from '@/settings';
5 |
6 | // you can set in settings.js
7 | // errorLog:'production' | ['production', 'development']
8 | const {errorLog: needErrorLog} = settings;
9 |
10 | const checkNeed = () => {
11 | const env = process.env.NODE_ENV as string;
12 | if (isString(needErrorLog)) {
13 | return env === needErrorLog;
14 | }
15 | if (isArray(needErrorLog)) {
16 | return needErrorLog.includes(env);
17 | }
18 | return false;
19 | };
20 |
21 | // you can set only in production env show the error-log
22 | if (checkNeed()) {
23 | Vue.config.errorHandler = (err, vm, info) => {
24 | // Don't ask me why I use Vue.nextTick, it just a hack.
25 | // detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
26 | Vue.nextTick(() => {
27 | ErrorLogModule.AddErrorLog({
28 | err,
29 | vm,
30 | info,
31 | url: window.location.href
32 | });
33 | console.error(err, info);
34 | });
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/src/icons/svg/people.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/components/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
27 |
28 |
52 |
--------------------------------------------------------------------------------
/src/icons/components/list.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'list': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/router/modules/table.ts:
--------------------------------------------------------------------------------
1 | /** When your routing table is too long, you can split it into small modules**/
2 |
3 | import Layout from '@/layout/index.vue';
4 |
5 | const tableRouter = {
6 | path: '/table',
7 | component: Layout,
8 | redirect: '/table/complex-table',
9 | name: 'Table',
10 | meta: {
11 | title: 'Table',
12 | icon: 'table'
13 | },
14 | children: [
15 | {
16 | path: 'dynamic-table',
17 | component: () => import('@/views/table/dynamicTable/index.vue'),
18 | name: 'DynamicTable',
19 | meta: {title: 'dynamicTable'}
20 | },
21 | {
22 | path: 'drag-table',
23 | component: () => import('@/views/table/dragTable.vue'),
24 | name: 'DragTable',
25 | meta: {title: 'dragTable'}
26 | },
27 | {
28 | path: 'inline-edit-table',
29 | component: () => import('@/views/table/inlineEditTable.vue'),
30 | name: 'InlineEditTable',
31 | meta: {title: 'inlineEditTable'}
32 | },
33 | {
34 | path: 'complex-table',
35 | component: () => import('@/views/table/complexTable.vue'),
36 | name: 'ComplexTable',
37 | meta: {title: 'complexTable'}
38 | }
39 | ]
40 | };
41 | export default tableRouter;
42 |
--------------------------------------------------------------------------------
/src/icons/svg/language.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/components/icon.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'icon': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/dragSelect.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{ item }}
10 |
11 |
12 |
13 |
14 |
15 |
46 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "strictNullChecks": true,
7 | "jsx": "preserve",
8 | "importHelpers": true,
9 | "moduleResolution": "node",
10 | "experimentalDecorators": true,
11 | // JSON parse
12 | "resolveJsonModule": true,
13 | "esModuleInterop": true,
14 | // error TS7017: Index signature of object type implicitly has an 'any' type.
15 | "noImplicitAny": false,
16 | // Don't emit; allow Babel to transform files.
17 | "noEmit": true,
18 | "sourceMap": true,
19 | "allowJs": true,
20 | "baseUrl": ".",
21 | "types": [
22 | "node",
23 | "webpack-env"
24 | ],
25 | "paths": {
26 | "@/*": [
27 | "src/*",
28 | "mock/*"
29 | ]
30 | },
31 | "lib": [
32 | "esnext",
33 | "dom",
34 | "dom.iterable",
35 | "scripthost"
36 | ]
37 | },
38 | "include": [
39 | "src/**/*.ts",
40 | "src/**/*.tsx",
41 | "src/**/*.vue",
42 | "mock/**/*.ts",
43 | "mock/*.ts",
44 | "tests/**/*.ts",
45 | "tests/**/*.tsx",
46 | "./types/*.d.ts"
47 | ],
48 | "exclude": [
49 | "node_modules",
50 | "build/*.ts"
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/src/icons/svg/eye-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/example/components/Dropdown/Platform.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 平台({{ platforms.length }})
5 |
6 |
7 |
8 |
9 |
10 | {{ item.name }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
39 |
--------------------------------------------------------------------------------
/src/views/excel/uploadExcel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
43 |
--------------------------------------------------------------------------------
/src/directives/el-table.ts:
--------------------------------------------------------------------------------
1 | import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event';
2 |
3 | /**
4 | * How to use
5 | * ...
6 | * el-table height is must be set
7 | * bottomOffset: 30(default) // The height of the table from the bottom of the page.
8 | */
9 |
10 | const doResize = (el, binding, vnode) => {
11 | const {componentInstance: $table} = vnode;
12 |
13 | const {value} = binding;
14 |
15 | if (!$table.height) {
16 | throw new Error(`el-$table must set the height. Such as height='100px'`);
17 | }
18 | const bottomOffset = (value && value.bottomOffset) || 30;
19 |
20 | if (!$table) return;
21 |
22 | const height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset;
23 | $table.layout.setHeight(height);
24 | $table.doLayout();
25 | };
26 |
27 | export default {
28 | bind(el, binding, vnode) {
29 | el.resizeListener = () => {
30 | doResize(el, binding, vnode);
31 | };
32 |
33 | addResizeListener(el, el.resizeListener);
34 | },
35 | inserted(el, binding, vnode) {
36 | doResize(el, binding, vnode);
37 | },
38 | unbind(el) {
39 | removeResizeListener(el, el.resizeListener);
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/src/store/getters.ts:
--------------------------------------------------------------------------------
1 | import { IRootState } from '@/store/index';
2 |
3 | const getters = {
4 | sidebar: (state: IRootState) => state.app.sidebar,
5 | language: (state: IRootState) => state.app.language,
6 | size: (state: IRootState) => state.app.size,
7 | device: (state: IRootState) => state.app.device,
8 | visitedViews: (state: IRootState) => state.tagsView.visitedViews,
9 | cachedViews: (state: IRootState) => state.tagsView.cachedViews,
10 | token: (state: IRootState) => state.user.token,
11 | avatar: (state: IRootState) => state.user.avatar,
12 | name: (state: IRootState) => state.user.name,
13 | introduction: (state: IRootState) => state.user.introduction,
14 | status: (state: IRootState) => state.user.status,
15 | roles: (state: IRootState) => state.user.roles,
16 | permission_routers: (state: IRootState) => state.permission.routes,
17 | errorLogs: (state: IRootState) => state.errorLog.logs,
18 | theme: (state: IRootState) => state.settings.theme,
19 | fixedHeader: (state: IRootState) => state.settings.fixedHeader,
20 | tagsView: (state: IRootState) => state.settings.tagsView,
21 | sidebarLogo: (state: IRootState) => state.settings.sidebarLogo,
22 | showSettings: (state: IRootState) => state.settings.showSettings
23 | };
24 |
25 | export default getters;
26 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/dndList.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
46 |
--------------------------------------------------------------------------------
/src/icons/components/international.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'international': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/mock/remoteSearch.ts:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs';
2 |
3 | const NameList: any[] = [];
4 | const count = 100;
5 |
6 | for (let i = 0; i < count; i++) {
7 | NameList.push(Mock.mock({
8 | name: '@first'
9 | }));
10 | }
11 | NameList.push({name: 'mockPan'});
12 |
13 | export default [
14 | // username search
15 | {
16 | url: '/search/user',
17 | type: 'get',
18 | response: (config) => {
19 | const {name} = config.query;
20 | const mockNameList = NameList.filter((item) => {
21 | const lowerCaseName = item.name.toLowerCase();
22 | return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0);
23 | });
24 | return {
25 | code: 20000,
26 | data: {items: mockNameList}
27 | };
28 | }
29 | },
30 |
31 | // transaction list
32 | {
33 | url: '/transaction/list',
34 | type: 'get',
35 | response: (_) => {
36 | return {
37 | code: 20000,
38 | data: {
39 | total: 20,
40 | 'items|20': [{
41 | order_no: '@guid()',
42 | timestamp: +Mock.Random.date('T'),
43 | username: '@name()',
44 | price: '@float(1000, 15000, 0, 2)',
45 | 'status|1': ['success', 'pending']
46 | }]
47 | }
48 | };
49 | }
50 | }
51 | ];
52 |
53 |
--------------------------------------------------------------------------------
/src/views/guide/defineSteps.ts:
--------------------------------------------------------------------------------
1 | const steps = [
2 | {
3 | element: '.hamburger-container',
4 | popover: {
5 | title: 'Hamburger',
6 | description: 'Open && Close sidebar',
7 | position: 'bottom'
8 | }
9 | },
10 | {
11 | element: '.breadcrumb-container',
12 | popover: {
13 | title: 'Breadcrumb',
14 | description: 'Indicate the current page location',
15 | position: 'bottom'
16 | }
17 | },
18 | {
19 | element: '.screenfull',
20 | popover: {
21 | title: 'Screenfull',
22 | description: 'Bring the page into fullscreen',
23 | position: 'left'
24 | }
25 | },
26 | {
27 | element: '.international-icon',
28 | popover: {
29 | title: 'Switch language',
30 | description: 'Switch the system language',
31 | position: 'left'
32 | }
33 | },
34 | {
35 | element: '.theme-switch',
36 | popover: {
37 | title: 'Theme Switch',
38 | description: 'Custom switch system theme',
39 | position: 'left'
40 | }
41 | },
42 | {
43 | element: '.tags-view-container',
44 | popover: {
45 | title: 'Tags view',
46 | description: 'The history of the page you visited',
47 | position: 'bottom'
48 | },
49 | padding: 0
50 | }
51 | ];
52 |
53 | export default steps;
54 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Component from 'vue-class-component';
3 | import Element from 'element-ui';
4 | import { getSize } from '@/utils/auth';
5 | import SvgIcon from 'vue-svgicon';
6 | import App from './App.vue';
7 | import router from './router';
8 | import store from './store';
9 | import i18n from './lang';
10 | import './errorLog';
11 | import './icons/components';
12 | import './router/router.interceptor';
13 | import './filters';
14 | import './directives';
15 | import './services';
16 | import './pwa/register-service-worker';
17 | // mock
18 | import { mockXHR } from '../mock';
19 |
20 | // 注册钩子函数
21 | Component.registerHooks([
22 | 'beforeRouteEnter',
23 | 'beforeRouteLeave',
24 | 'beforeRouteUpdate'
25 | ]);
26 |
27 | // mock api in github pages site build
28 | if (process.env.NODE_ENV === 'production') {
29 | mockXHR();
30 | }
31 |
32 | Vue.use(Element, {
33 | size: getSize() || 'medium', // set element-ui default size
34 | i18n: (key, value) => i18n.t(key, value)
35 | });
36 |
37 | Vue.use(SvgIcon, {
38 | tagName: 'svg-icon',
39 | defaultWidth: '1em',
40 | defaultHeight: '1em'
41 | });
42 |
43 | Vue.config.productionTip = process.env.NODE_ENV === 'production';
44 |
45 | new Vue({
46 | router,
47 | store,
48 | i18n,
49 | render: (h) => h(App)
50 | }).$mount('#app');
51 |
--------------------------------------------------------------------------------
/src/icons/components/wechat.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'wechat': {
7 | width: 128,
8 | height: 110,
9 | viewBox: '0 0 128 110',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/people.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'people': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/components/LangSelect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 中文
8 | English
9 | Español
10 |
11 |
12 |
13 |
14 |
36 |
37 |
44 |
45 |
--------------------------------------------------------------------------------
/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
26 |
27 |
40 |
--------------------------------------------------------------------------------
/src/icons/svg/404.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/components/eye-open.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'eye-open': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 1024 1024',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/svg/zip.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/table/dynamicTable/unfixedThead.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | apple
7 | banana
8 | orange
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{ scope.row[fruit] }}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
47 |
--------------------------------------------------------------------------------
/src/icons/components/language.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'language': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/clipboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | copy
7 |
8 |
9 |
10 |
11 | copy
12 |
13 |
14 |
15 |
16 |
17 |
18 |
40 |
--------------------------------------------------------------------------------
/src/lang/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import VueI18n from 'vue-i18n';
3 | import elementEnLocale from 'element-ui/lib/locale/lang/en'; // element-ui lang
4 | import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'; // element-ui lang
5 | import elementEsLocale from 'element-ui/lib/locale/lang/es'; // element-ui lang
6 | import enLocale from './en';
7 | import zhLocale from './zh';
8 | import esLocale from './es';
9 | import store from 'store';
10 |
11 | Vue.use(VueI18n);
12 |
13 | const messages = {
14 | en: {
15 | ...enLocale,
16 | ...elementEnLocale
17 | },
18 | zh: {
19 | ...zhLocale,
20 | ...elementZhLocale
21 | },
22 | es: {
23 | ...esLocale,
24 | ...elementEsLocale
25 | }
26 | };
27 |
28 | export function getLanguage() {
29 | const chooseLanguage = store.get('language');
30 | if (chooseLanguage) return chooseLanguage;
31 | const navigatorNew = window.navigator as any;
32 |
33 | // if has not choose language
34 | const language = (navigatorNew.language || navigatorNew.browserLanguage).toLowerCase();
35 | const locales = Object.keys(messages);
36 | for (const locale of locales) {
37 | if (language.indexOf(locale) > -1) {
38 | return locale;
39 | }
40 | }
41 | return 'en';
42 | }
43 |
44 | const i18n = new VueI18n({
45 | // set locale
46 | // options: en | zh | es
47 | locale: getLanguage(),
48 | // set locale messages
49 | messages
50 | });
51 |
52 | export default i18n;
53 |
--------------------------------------------------------------------------------
/src/views/tab/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | mounted times :{{ createdTimes }}
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
40 |
41 |
46 |
--------------------------------------------------------------------------------
/src/assets/less/element-ui.less:
--------------------------------------------------------------------------------
1 | //覆盖一些element-ui样式
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 | .cell {
19 | .el-tag {
20 | margin-right: 0px;
21 | }
22 | }
23 |
24 | .small-padding {
25 | .cell {
26 | padding-left: 5px;
27 | padding-right: 5px;
28 | }
29 | }
30 |
31 | .fixed-width {
32 | .el-button--mini {
33 | padding: 7px 10px;
34 | width: 60px;
35 | }
36 | }
37 |
38 | .status-col {
39 | .cell {
40 | padding: 0 10px;
41 | text-align: center;
42 |
43 | .el-tag {
44 | margin-right: 0px;
45 | }
46 | }
47 | }
48 |
49 | //暂时性解决dialog 问题 https://github.com/ElemeFE/element/issues/2461
50 | .el-dialog {
51 | transform: none;
52 | left: 0;
53 | position: relative;
54 | margin: 0 auto;
55 | }
56 |
57 | //文章页textarea修改样式
58 | .article-textarea {
59 | textarea {
60 | padding-right: 40px;
61 | resize: none;
62 | border: none;
63 | border-radius: 0px;
64 | border-bottom: 1px solid #bfcbd9;
65 | }
66 | }
67 |
68 | //element ui upload
69 | .upload-container {
70 | .el-upload {
71 | width: 100%;
72 |
73 | .el-upload-dragger {
74 | width: 100%;
75 | height: 200px;
76 | }
77 | }
78 | }
79 |
80 | //dropdown
81 | .el-dropdown-menu {
82 | a {
83 | display: block
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/layout/mixin/ResizeHandler.ts:
--------------------------------------------------------------------------------
1 | import { Component, Vue, Watch } from 'vue-property-decorator';
2 | import { AppModule, DeviceType } from '@/store/modules/app';
3 |
4 | const {body} = document;
5 | const WIDTH = 1024;
6 | const RATIO = 3;
7 |
8 | @Component({
9 | name: 'ResizeHandlerMixin'
10 | })
11 | export default class ResizeHandlerMixin extends Vue {
12 | get sidebar() {
13 | return this.$store.getters.sidebar;
14 | }
15 |
16 | get device() {
17 | return this.$store.getters.device;
18 | }
19 |
20 | @Watch('$route')
21 | onRouteChange() {
22 | if (this.device === DeviceType.Mobile && this.sidebar.opened) {
23 | AppModule.CloseSideBar(false);
24 | }
25 | }
26 |
27 | beforeMount() {
28 | window.addEventListener('resize', this.resizeHandler);
29 | }
30 |
31 | beforeDestroy() {
32 | window.removeEventListener('resize', this.resizeHandler);
33 | }
34 |
35 | mounted() {
36 | const isMobile = this.isMobile();
37 | if (isMobile) {
38 | AppModule.ToggleDevice(DeviceType.Mobile);
39 | AppModule.CloseSideBar(true);
40 | }
41 | }
42 |
43 | isMobile() {
44 | const rect = body.getBoundingClientRect();
45 | return rect.width - RATIO < WIDTH;
46 | }
47 |
48 | resizeHandler() {
49 | if (!document.hidden) {
50 | const isMobile = this.isMobile();
51 | AppModule.ToggleDevice(isMobile ? DeviceType.Mobile : DeviceType.Desktop);
52 |
53 | if (isMobile) {
54 | AppModule.CloseSideBar(true);
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/icons/svg/bug.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/less/variable.less:
--------------------------------------------------------------------------------
1 | //公共变量
2 | @lessPath: "../assets/less/";
3 | @pageImgPath: "../assets/img/";
4 | @fontPath: "../fonts/";
5 |
6 | // colora
7 | @colorBlueMain: #43a9f1;
8 | @colorBlueLight: #49b2f5;
9 | @colorBlueText: #0076ff;
10 |
11 | @colorGrayMain: #414141;
12 | @colorGrayLight: #f3f3f3;
13 | @colorGrayAssist: #e1e1e1;
14 | @colorBorder: #e9e9e9;
15 | @colorGray: #c8c8c8;
16 | @colorAfter: #eee;
17 | @tabBorder: #d9d9d9;
18 |
19 | @colorWhite: #fff;
20 | @colorBlack: #333;
21 |
22 | // font
23 | @fontColor: @colorGrayMain;
24 | @fontColorBlack: @colorBlack;
25 | @fontColorLight: @colorGrayLight;
26 | @fontColorAssist: @colorGrayAssist;
27 |
28 | // bg
29 | @bgColor: #f2f2f2;
30 | @bgColorLight: #f7f7f7;
31 |
32 | //line
33 | @colorLine: @colorGrayAssist;
34 |
35 | //colorAssist
36 | @colorRed: #ff5648;
37 | @colorGreen: #47b34f;
38 | @colorOrange: #ffaf32;
39 | @colorOrangeLight: #ffb42f;
40 |
41 | //fontSize
42 | @fontSizeH1: 20px;
43 | @fontSizeH2: 16px;
44 | @fontSizeH3: 14px;
45 | @fontSizeH4: 12px;
46 |
47 | // vue-element-admin
48 | // base color
49 | @blue: #324157;
50 | @light-blue: #3A71A8;
51 | @red: #C03639;
52 | @pink: #E65D6E;
53 | @green: #30B08F;
54 | @tiffany: #4AB7BD;
55 | @yellow: #FEC171;
56 | @panGreen: #30B08F;
57 |
58 | //sidebar
59 | @menuText: #bfcbd9;
60 | @menuActiveText: #409EFF;
61 | @subMenuActiveText: #f4f4f5; //https://github.com/ElemeFE/element/issues/12951
62 |
63 | @menuBg: #304156;
64 | @menuHover: #263445;
65 |
66 | @subMenuBg: #1f2d3d;
67 | @subMenuHover: #001528;
68 |
69 | @sideBarWidth: 210px;
70 |
--------------------------------------------------------------------------------
/src/components/ImageCropper/utils/effectRipple.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 点击波纹效果
3 | *
4 | * @param {[event]} e [description]
5 | * @param {[Object]} arg_opts [description]
6 | * @return {[bollean]} [description]
7 | */
8 | export default function(e, argOpts?: object) {
9 | const opts = Object.assign({
10 | ele: e.target, // 波纹作用元素
11 | type: 'hit', // hit点击位置扩散center中心点扩展
12 | bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
13 | }, argOpts);
14 | const target = opts.ele;
15 | if (target) {
16 | const rect = target.getBoundingClientRect();
17 | let ripple = target.querySelector('.e-ripple');
18 | if (!ripple) {
19 | ripple = document.createElement('span');
20 | ripple.className = 'e-ripple';
21 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
22 | target.appendChild(ripple);
23 | } else {
24 | ripple.className = 'e-ripple';
25 | }
26 | switch (opts.type) {
27 | case 'center':
28 | ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
29 | ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
30 | break;
31 | default:
32 | ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
33 | ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
34 | }
35 | ripple.style.backgroundColor = opts.bgc;
36 | ripple.className = 'e-ripple z-active';
37 | return false;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/icons/svg/dog.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/TreeTable/eval.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | // Flattened array
4 | export default function treeToArray(data, children = 'children') {
5 | let tmp: any[] = [];
6 | data.forEach((item, index) => {
7 | Vue.set(item, '_index', index);
8 | tmp.push(item);
9 | if (item[children] && item[children].length > 0) {
10 | const res = treeToArray(item[children], children);
11 | tmp = tmp.concat(res);
12 | }
13 | });
14 | return tmp;
15 | }
16 |
17 | export function addAttrs(data, {parent = null, preIndex = false, level = 0, expand = false, children = 'children', show = true, select = false}: any = {}) {
18 | data.forEach((item, index) => {
19 | const id = (preIndex ? `${preIndex}-${index}` : index) + '';
20 | Vue.set(item, '_id', id);
21 | Vue.set(item, '_level', level);
22 | Vue.set(item, '_expand', expand);
23 | Vue.set(item, '_parent', parent);
24 | Vue.set(item, '_show', show);
25 | Vue.set(item, '_select', select);
26 | if (item[children] && item[children].length > 0) {
27 | addAttrs(item[children], {
28 | parent: item,
29 | level: level + 1,
30 | expand,
31 | preIndex: id,
32 | children,
33 | status,
34 | select
35 | });
36 | }
37 | });
38 | }
39 |
40 | export function cleanParentAttr(data, children = 'children') {
41 | data.forEach((item) => {
42 | item._parent = null;
43 | if (item[children] && item[children].length > 0) {
44 | addAttrs(item[children], children);
45 | }
46 | });
47 | return data;
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/tinymce.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
32 |
33 |
38 |
--------------------------------------------------------------------------------
/src/views/login/socialSignIn.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 微信
5 |
6 |
7 | QQ
8 |
9 |
10 |
11 |
12 |
26 |
27 |
65 |
--------------------------------------------------------------------------------
/src/pwa/register-service-worker.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from 'register-service-worker';
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready() {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB'
11 | );
12 | },
13 | registered(registration) {
14 | console.log('Service worker has been registered.');
15 | // Routinely check for app updates by testing for a new service worker.
16 | setInterval(() => {
17 | registration.update();
18 | }, 1000 * 60 * 60); // hourly checks
19 | },
20 | cached() {
21 | console.log('Content has been cached for offline use.');
22 | },
23 | updatefound() {
24 | console.log('New content is downloading.');
25 | },
26 | updated(registration) {
27 | console.log('New content is available; please refresh.');
28 | // Add a custom event and dispatch it.
29 | // Used to display of a 'refresh' banner following a service worker update.
30 | // Set the event payload to the service worker registration object.
31 | document.dispatchEvent(
32 | new CustomEvent('swUpdated', {detail: registration})
33 | );
34 | },
35 | offline() {
36 | console.log('No internet connection found. App is running in offline mode.');
37 | },
38 | error(error) {
39 | console.error('Error during service worker registration:', error);
40 | }
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/src/icons/components/404.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | '404': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/zip.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'zip': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/jsonEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
JsonEditor is base on CodeMirrorr ,
4 | lint base on json-lint
5 |
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
34 |
--------------------------------------------------------------------------------
/src/icons/svg/pdf.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/SizeSelect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{
9 | item.label }}
10 |
11 |
12 |
13 |
14 |
15 |
58 |
--------------------------------------------------------------------------------
/src/components/DragSelect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
45 |
46 |
57 |
--------------------------------------------------------------------------------
/src/icons/components/bug.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'bug': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 128 128',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/icons/components/dog.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'dog': {
7 | width: 225,
8 | height: 200,
9 | viewBox: '0 0 1152 1024',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/views/dashboard/admin/components/TransactionTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ scope.row.order_no | orderNoFilter }}
6 |
7 |
8 |
9 |
10 | ¥{{ scope.row.price | toThousandFilter }}
11 |
12 |
13 |
14 |
15 | {{ scope.row.status }}
16 |
17 |
18 |
19 |
20 |
21 |
54 |
55 |
58 |
--------------------------------------------------------------------------------
/src/views/i18n-demo/local.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | zh: {
3 | i18nView: {
4 | title: '切换语言',
5 | note: '本项目国际化基于 vue-i18n',
6 | datePlaceholder: '请选择日期',
7 | selectPlaceholder: '请选择',
8 | tableDate: '日期',
9 | tableName: '姓名',
10 | tableAddress: '地址',
11 | default: '默认按钮',
12 | primary: '主要按钮',
13 | success: '成功按钮',
14 | info: '信息按钮',
15 | warning: '警告按钮',
16 | danger: '危险按钮',
17 | one: '一',
18 | two: '二',
19 | three: '三'
20 | }
21 | },
22 | en: {
23 | i18nView: {
24 | title: 'Switch Language',
25 | note: 'The internationalization of this project is based on vue-i18n',
26 | datePlaceholder: 'Pick a day',
27 | selectPlaceholder: 'Select',
28 | tableDate: 'tableDate',
29 | tableName: 'tableName',
30 | tableAddress: 'tableAddress',
31 | default: 'default:',
32 | primary: 'primary',
33 | success: 'success',
34 | info: 'info',
35 | warning: 'warning',
36 | danger: 'danger',
37 | one: 'One',
38 | two: 'Two',
39 | three: 'Three'
40 | }
41 | },
42 | es: {
43 | i18nView: {
44 | title: 'Switch Language',
45 | note: 'The internationalization of this project is based on vue-i18n',
46 | datePlaceholder: 'Pick a day',
47 | selectPlaceholder: 'Select',
48 | tableDate: 'tableDate',
49 | tableName: 'tableName',
50 | tableAddress: 'tableAddress',
51 | default: 'default:',
52 | primary: 'primary',
53 | success: 'success',
54 | info: 'info',
55 | warning: 'warning',
56 | danger: 'danger',
57 | one: 'One',
58 | two: 'Two',
59 | three: 'Three'
60 | }
61 | }
62 | };
63 |
--------------------------------------------------------------------------------
/src/icons/svg/exit-fullscreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/avatarUpload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is based on
4 | vue-image-crop-upload.
5 | {{ $t('components.imageUploadTips') }}
6 |
7 |
8 |
9 |
10 |
Change Avatar
12 |
13 |
14 |
23 |
24 |
25 |
26 |
55 |
56 |
63 |
--------------------------------------------------------------------------------
/src/views/treeTable/data.ts:
--------------------------------------------------------------------------------
1 | const data = [
2 | {
3 | id: 0,
4 | event: 'Event-0',
5 | timeLine: 50
6 | },
7 | {
8 | id: 1,
9 | event: 'Event-1',
10 | timeLine: 100,
11 | children: [
12 | {
13 | id: 2,
14 | event: 'Event-2',
15 | timeLine: 10
16 |
17 | },
18 | {
19 | id: 3,
20 | event: 'Event-3',
21 | timeLine: 90,
22 | children: [
23 | {
24 | id: 4,
25 | event: 'Event-4',
26 | timeLine: 5
27 |
28 | },
29 | {
30 | id: 5,
31 | event: 'Event-5',
32 | timeLine: 10
33 |
34 | },
35 | {
36 | id: 6,
37 | event: 'Event-6',
38 | timeLine: 75,
39 |
40 | children: [
41 | {
42 | id: 7,
43 | event: 'Event-7',
44 | timeLine: 50,
45 |
46 | children: [
47 | {
48 | id: 71,
49 | event: 'Event-7-1',
50 | timeLine: 25
51 |
52 | },
53 | {
54 | id: 72,
55 | event: 'Event-7-2',
56 | timeLine: 5
57 |
58 | },
59 | {
60 | id: 73,
61 | event: 'Event-7-3',
62 | timeLine: 20
63 | }
64 | ]
65 | },
66 | {
67 | id: 8,
68 | event: 'Event-8',
69 | timeLine: 25
70 | }
71 | ]
72 | }
73 | ]
74 | }
75 | ]
76 | }
77 | ];
78 |
79 | export default data;
80 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/directives/waves/index.ts:
--------------------------------------------------------------------------------
1 | import './waves.css';
2 |
3 | export default {
4 | bind(el, binding) {
5 | el.addEventListener('click', (e) => {
6 | const customOpts = Object.assign({}, binding.value);
7 | const opts = Object.assign({
8 | ele: el, // 波纹作用元素
9 | type: 'hit', // hit 点击位置扩散 center中心点扩展
10 | color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
11 | }, customOpts);
12 | const target = opts.ele;
13 | if (target) {
14 | target.style.position = 'relative';
15 | target.style.overflow = 'hidden';
16 | const rect = target.getBoundingClientRect();
17 | let ripple = target.querySelector('.waves-ripple');
18 | if (!ripple) {
19 | ripple = document.createElement('span');
20 | ripple.className = 'waves-ripple';
21 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
22 | target.appendChild(ripple);
23 | } else {
24 | ripple.className = 'waves-ripple';
25 | }
26 | switch (opts.type) {
27 | case 'center':
28 | ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
29 | ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
30 | break;
31 | default:
32 | ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop || document.body.scrollTop) + 'px';
33 | ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || document.body.scrollLeft) + 'px';
34 | }
35 | ripple.style.backgroundColor = opts.color;
36 | ripple.className = 'waves-ripple z-active';
37 | return false;
38 | }
39 | }, false);
40 | }
41 | };
42 |
43 |
--------------------------------------------------------------------------------
/src/icons/components/pdf.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | // @ts-ignore
4 | import icon from 'vue-svgicon'
5 | icon.register({
6 | 'pdf': {
7 | width: 128,
8 | height: 128,
9 | viewBox: '0 0 1024 1024',
10 | data: ''
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/filters/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @authors liwb (lwbhtml@gmail.com)
4 | * @date 2018/6/5 上午10:43
5 | * @description 定义过滤器模块
6 | */
7 |
8 | import Vue from 'vue';
9 |
10 | import { formatDate } from '@liwb/cloud-utils';
11 |
12 | import {
13 | parseTime,
14 | formatTime
15 | } from '@/utils';
16 |
17 | function pluralize(time, label) {
18 | if (time === 1) {
19 | return time + label;
20 | }
21 | return time + label + 's';
22 | }
23 |
24 | /* 数字 格式化*/
25 | export function numberFormatter(num, digits) {
26 | const si = [
27 | {value: 1E18, symbol: 'E'},
28 | {value: 1E15, symbol: 'P'},
29 | {value: 1E12, symbol: 'T'},
30 | {value: 1E9, symbol: 'G'},
31 | {value: 1E6, symbol: 'M'},
32 | {value: 1E3, symbol: 'k'}
33 | ];
34 | for (const s of si) {
35 | if (num >= s.value) {
36 | return (num / s.value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + s.symbol;
37 | }
38 | }
39 | return num.toString();
40 | }
41 |
42 | export function toThousandFilter(num) {
43 | return (+num || 0).toString().replace(/^-?\d+/g, (m) => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','));
44 | }
45 |
46 | // Filter for article status
47 | export const articleStatusFilter = (status: string) => {
48 | const statusMap: { [key: string]: string } = {
49 | published: 'success',
50 | success: 'success',
51 | draft: 'info',
52 | deleted: 'danger',
53 | pending: 'danger'
54 | };
55 | return statusMap[status];
56 | };
57 |
58 | // register global utility filters.
59 | const filters = {
60 | formatDate,
61 | parseTime,
62 | formatTime,
63 | numberFormatter,
64 | toThousandFilter,
65 | articleStatusFilter
66 | };
67 |
68 | Object.keys(filters).forEach((key) => {
69 | // tslint:disable-next-line:ban-types
70 | Vue.filter(key, (filters as { [key: string]: Function })[key]);
71 | });
72 |
--------------------------------------------------------------------------------
/src/assets/less/btn.less:
--------------------------------------------------------------------------------
1 | @import './variable';
2 |
3 | .colorBtn(@color) {
4 | background: @color;
5 |
6 | &:hover {
7 | color: @color;
8 |
9 | &:before,
10 | &:after {
11 | background: @color;
12 | }
13 | }
14 | }
15 |
16 | .blue-btn {
17 | .colorBtn(@blue);
18 | }
19 |
20 | .light-blue-btn {
21 | .colorBtn(@light-blue);
22 | }
23 |
24 | .red-btn {
25 | .colorBtn(@red);
26 | }
27 |
28 | .pink-btn {
29 | .colorBtn(@pink);
30 | }
31 |
32 | .green-btn {
33 | .colorBtn(@green);
34 | }
35 |
36 | .tiffany-btn {
37 | .colorBtn(@tiffany);
38 | }
39 |
40 | .yellow-btn {
41 | .colorBtn(@yellow);
42 | }
43 |
44 | .pan-btn {
45 | font-size: 14px;
46 | color: #fff;
47 | padding: 14px 36px;
48 | border-radius: 8px;
49 | border: none;
50 | outline: none;
51 | transition: 600ms ease all;
52 | position: relative;
53 | display: inline-block;
54 |
55 | &:hover {
56 | background: #fff;
57 |
58 | &:before,
59 | &:after {
60 | width: 100%;
61 | transition: 600ms ease all;
62 | }
63 | }
64 |
65 | &:before,
66 | &:after {
67 | content: '';
68 | position: absolute;
69 | top: 0;
70 | right: 0;
71 | height: 2px;
72 | width: 0;
73 | transition: 400ms ease all;
74 | }
75 |
76 | &::after {
77 | right: inherit;
78 | top: inherit;
79 | left: 0;
80 | bottom: 0;
81 | }
82 | }
83 |
84 | .custom-button {
85 | display: inline-block;
86 | line-height: 1;
87 | white-space: nowrap;
88 | cursor: pointer;
89 | background: #fff;
90 | color: #fff;
91 | -webkit-appearance: none;
92 | text-align: center;
93 | box-sizing: border-box;
94 | outline: 0;
95 | margin: 0;
96 | padding: 10px 15px;
97 | font-size: 14px;
98 | border-radius: 4px;
99 | }
100 |
--------------------------------------------------------------------------------
/mock/user.ts:
--------------------------------------------------------------------------------
1 | const tokens = {
2 | admin: {
3 | token: 'admin-token'
4 | },
5 | editor: {
6 | token: 'editor-token'
7 | }
8 | };
9 |
10 | const users = {
11 | 'admin-token': {
12 | roles: ['admin'],
13 | introduction: 'I am a super administrator',
14 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
15 | name: 'Super Admin'
16 | },
17 | 'editor-token': {
18 | roles: ['editor'],
19 | introduction: 'I am an editor',
20 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
21 | name: 'Normal Editor'
22 | }
23 | };
24 |
25 | export default [
26 | // user login
27 | {
28 | url: '/user/login',
29 | type: 'post',
30 | response: (config) => {
31 | const {username} = config.body;
32 | const token = tokens[username];
33 |
34 | // mock error
35 | if (!token) {
36 | return {
37 | code: 60204,
38 | message: 'Account and password are incorrect.'
39 | };
40 | }
41 |
42 | return {
43 | code: 20000,
44 | data: token
45 | };
46 | }
47 | },
48 |
49 | // get user info
50 | {
51 | url: '/user/info\.*',
52 | type: 'get',
53 | response: (config) => {
54 | const {token} = config.query;
55 | const info = users[token];
56 |
57 | // mock error
58 | if (!info) {
59 | return {
60 | code: 50008,
61 | message: 'Login failed, unable to get user details.'
62 | };
63 | }
64 |
65 | return {
66 | code: 20000,
67 | data: info
68 | };
69 | }
70 | },
71 |
72 | // user logout
73 | {
74 | url: '/user/logout',
75 | type: 'post',
76 | response: (_) => {
77 | return {
78 | code: 20000,
79 | data: 'success'
80 | };
81 | }
82 | }
83 | ];
84 |
--------------------------------------------------------------------------------
/src/utils/scrollTo.js:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | Math.easeInOutQuad = function (t, b, c, d) {
3 | t /= d / 2;
4 | if (t < 1) {
5 | return c / 2 * t * t + b;
6 | }
7 | t--;
8 | return -c / 2 * (t * (t - 2) - 1) + b;
9 | };
10 |
11 | // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
12 | var requestAnimFrame = (function () {
13 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
14 | window.setTimeout(callback, 1000 / 60);
15 | };
16 | })();
17 |
18 | // because it's so fucking difficult to detect the scrolling element, just move them all
19 | function move(amount) {
20 | document.documentElement.scrollTop = amount;
21 | document.body.parentNode.scrollTop = amount;
22 | document.body.scrollTop = amount;
23 | }
24 |
25 | function position() {
26 | return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop;
27 | }
28 |
29 | export function scrollTo(to, duration, callback) {
30 | const start = position();
31 | const change = to - start;
32 | const increment = 20;
33 | let currentTime = 0;
34 | duration = (typeof (duration) === 'undefined') ? 500 : duration;
35 | var animateScroll = function () {
36 | // increment the time
37 | currentTime += increment;
38 | // find the value with the quadratic in-out easing function
39 | var val = Math.easeInOutQuad(currentTime, start, change, duration);
40 | // move the document.body
41 | move(val);
42 | // do the animation unless its over
43 | if (currentTime < duration) {
44 | requestAnimFrame(animateScroll);
45 | } else {
46 | if (callback && typeof (callback) === 'function') {
47 | // the animation is done so lets callback
48 | callback();
49 | }
50 | }
51 | };
52 | animateScroll();
53 | }
54 |
--------------------------------------------------------------------------------
/src/directives/clipboard.ts:
--------------------------------------------------------------------------------
1 | // Inspired by https://github.com/Inndy/vue-clipboard2
2 | const Clipboard = require('clipboard');
3 | if (!Clipboard) {
4 | throw new Error('you should npm install `clipboard` --save at first ');
5 | }
6 |
7 | export default {
8 | bind(el, binding) {
9 | if (binding.arg === 'success') {
10 | el._v_clipboard_success = binding.value;
11 | } else if (binding.arg === 'error') {
12 | el._v_clipboard_error = binding.value;
13 | } else {
14 | const clipboard = new Clipboard(el, {
15 | text() {
16 | return binding.value;
17 | },
18 | action() {
19 | return binding.arg === 'cut' ? 'cut' : 'copy';
20 | }
21 | });
22 | clipboard.on('success', (e) => {
23 | const callback = el._v_clipboard_success;
24 | callback && callback(e); // eslint-disable-line
25 | });
26 | clipboard.on('error', (e) => {
27 | const callback = el._v_clipboard_error;
28 | callback && callback(e); // eslint-disable-line
29 | });
30 | el._v_clipboard = clipboard;
31 | }
32 | },
33 | update(el, binding) {
34 | if (binding.arg === 'success') {
35 | el._v_clipboard_success = binding.value;
36 | } else if (binding.arg === 'error') {
37 | el._v_clipboard_error = binding.value;
38 | } else {
39 | el._v_clipboard.text = () => {
40 | return binding.value;
41 | };
42 | el._v_clipboard.action = () => {
43 | return binding.arg === 'cut' ? 'cut' : 'copy';
44 | };
45 | }
46 | },
47 | unbind(el, binding) {
48 | if (binding.arg === 'success') {
49 | delete el._v_clipboard_success;
50 | } else if (binding.arg === 'error') {
51 | delete el._v_clipboard_error;
52 | } else {
53 | el._v_clipboard.destroy();
54 | delete el._v_clipboard;
55 | }
56 | }
57 | };
58 |
--------------------------------------------------------------------------------
/src/views/componentsDemo/dragKanban.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
40 |
41 |
71 |
--------------------------------------------------------------------------------
/public/vendor/vendor.dll.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}
--------------------------------------------------------------------------------
/src/views/componentsDemo/splitPane.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
SplitPane If you've used
4 | codepen,
5 | jsfiddle will not be unfamiliar.
6 | Github repository
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
41 |
42 |
70 |
71 |
--------------------------------------------------------------------------------