├── .eslintignore
├── .babelrc
├── cypress.json
├── src
├── components
│ ├── tree-select
│ │ ├── index.js
│ │ ├── tree-select.vue
│ │ └── tree-select-tree.vue
│ ├── main
│ │ ├── index.js
│ │ ├── components
│ │ │ ├── user
│ │ │ │ ├── index.js
│ │ │ │ ├── user.less
│ │ │ │ └── user.vue
│ │ │ ├── a-back-top
│ │ │ │ ├── index.js
│ │ │ │ └── index.vue
│ │ │ ├── language
│ │ │ │ ├── index.js
│ │ │ │ └── language.vue
│ │ │ ├── tags-nav
│ │ │ │ ├── index.js
│ │ │ │ └── tags-nav.less
│ │ │ ├── header-bar
│ │ │ │ ├── index.js
│ │ │ │ ├── sider-trigger
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── sider-trigger.less
│ │ │ │ │ └── sider-trigger.vue
│ │ │ │ ├── custom-bread-crumb
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── custom-bread-crumb.less
│ │ │ │ │ └── custom-bread-crumb.vue
│ │ │ │ ├── header-bar.less
│ │ │ │ └── header-bar.vue
│ │ │ ├── side-menu
│ │ │ │ ├── index.js
│ │ │ │ ├── item-mixin.js
│ │ │ │ ├── mixin.js
│ │ │ │ ├── side-menu.less
│ │ │ │ ├── side-menu-item.vue
│ │ │ │ ├── collapsed-menu.vue
│ │ │ │ └── side-menu.vue
│ │ │ ├── error-store
│ │ │ │ ├── index.js
│ │ │ │ └── error-store.vue
│ │ │ └── fullscreen
│ │ │ │ ├── index.js
│ │ │ │ └── fullscreen.vue
│ │ └── main.less
│ ├── icons
│ │ ├── index.js
│ │ └── icons.vue
│ ├── cropper
│ │ ├── index.js
│ │ ├── index.less
│ │ └── index.vue
│ ├── editor
│ │ ├── index.js
│ │ └── editor.vue
│ ├── split-pane
│ │ ├── index.js
│ │ ├── trigger.vue
│ │ └── index.less
│ ├── tables
│ │ ├── index.js
│ │ ├── index.less
│ │ ├── handle-btns.js
│ │ └── edit.vue
│ ├── count-to
│ │ ├── index.js
│ │ ├── index.less
│ │ └── count-to.vue
│ ├── drag-list
│ │ ├── index.js
│ │ └── drag-list.vue
│ ├── info-card
│ │ ├── index.js
│ │ └── infor-card.vue
│ ├── login-form
│ │ ├── index.js
│ │ └── login-form.vue
│ ├── common-icon
│ │ ├── index.js
│ │ └── common-icon.vue
│ ├── drag-drawer
│ │ ├── index.js
│ │ ├── mixin.js
│ │ ├── drag-drawer-trigger.vue
│ │ ├── index.less
│ │ └── drag-drawer.vue
│ ├── parent-view
│ │ ├── index.js
│ │ └── parent-view.vue
│ ├── markdown
│ │ ├── index.js
│ │ └── markdown.vue
│ ├── paste-editor
│ │ ├── index.js
│ │ ├── paste-editor.less
│ │ ├── plugins
│ │ │ └── placeholder.js
│ │ └── paste-editor.vue
│ ├── charts
│ │ ├── index.js
│ │ ├── bar.vue
│ │ └── pie.vue
│ └── common
│ │ ├── util.js
│ │ └── common.less
├── view
│ ├── single-page
│ │ ├── home
│ │ │ ├── index.js
│ │ │ ├── home.vue
│ │ │ └── example.vue
│ │ └── error-logger.vue
│ ├── multilevel
│ │ ├── level-2-1.vue
│ │ ├── level-2-3.vue
│ │ └── level-2-2
│ │ │ ├── level-2-2-1.vue
│ │ │ └── level-2-2-2.vue
│ ├── components
│ │ ├── markdown
│ │ │ └── markdown.vue
│ │ ├── editor
│ │ │ └── editor.vue
│ │ ├── cropper
│ │ │ └── cropper.vue
│ │ ├── icons
│ │ │ └── icons.vue
│ │ ├── org-tree
│ │ │ ├── index.less
│ │ │ ├── components
│ │ │ │ ├── zoom-controller.vue
│ │ │ │ └── org-view.vue
│ │ │ └── index.vue
│ │ ├── tables
│ │ │ └── tables.vue
│ │ ├── split-pane
│ │ │ └── split-pane.vue
│ │ ├── tree-select
│ │ │ └── index.vue
│ │ ├── drag-drawer
│ │ │ └── index.vue
│ │ └── drag-list
│ │ │ └── drag-list.vue
│ ├── error-page
│ │ ├── 404.vue
│ │ ├── 401.vue
│ │ ├── 500.vue
│ │ ├── error-content.vue
│ │ ├── back-btn-group.vue
│ │ └── error.less
│ ├── argu-page
│ │ ├── query.vue
│ │ └── params.vue
│ ├── login
│ │ ├── login.less
│ │ └── login.vue
│ ├── excel
│ │ ├── common.less
│ │ ├── export-excel.vue
│ │ └── upload-excel.vue
│ ├── error-store
│ │ └── error-store.vue
│ ├── i18n
│ │ └── i18n-page.vue
│ ├── update
│ │ ├── update-table.vue
│ │ └── update-paste.vue
│ ├── tools-methods
│ │ └── tools-methods.vue
│ ├── join-page.vue
│ └── directive
│ │ └── directive.vue
├── assets
│ ├── images
│ │ ├── logo.jpg
│ │ ├── login-bg.jpg
│ │ ├── logo-min.jpg
│ │ ├── talkingdata.png
│ │ ├── icon-qr-qq-wechat.png
│ │ ├── icon-social-juejin.svg
│ │ ├── icon-social-zhihu.svg
│ │ └── icon-social-twitter.svg
│ └── icons
│ │ ├── iconfont.eot
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.css
├── index.less
├── libs
│ ├── render-dom.js
│ ├── api.request.js
│ ├── axios.js
│ └── excel.js
├── directive
│ ├── directives.js
│ ├── index.js
│ └── module
│ │ ├── clipboard.js
│ │ └── draggable.js
├── api
│ ├── routers.js
│ ├── data.js
│ └── user.js
├── plugin
│ ├── index.js
│ └── error-store
│ │ └── index.js
├── router
│ ├── before-close.js
│ └── index.js
├── store
│ ├── index.js
│ └── module
│ │ └── app.js
├── App.vue
├── mock
│ ├── login.js
│ ├── data
│ │ ├── org-data.js
│ │ └── tree-select.js
│ ├── data.js
│ ├── index.js
│ └── user.js
├── config
│ └── index.js
├── locale
│ ├── index.js
│ └── lang
│ │ ├── zh-CN.js
│ │ ├── zh-TW.js
│ │ └── en-US.js
└── main.js
├── .postcssrc.js
├── public
├── favicon.ico
└── index.html
├── .travis.yml
├── tests
├── unit
│ ├── .eslintrc.js
│ └── HelloWorld.spec.js
└── e2e
│ ├── .eslintrc
│ ├── specs
│ └── test.js
│ ├── plugins
│ └── index.js
│ └── support
│ ├── index.js
│ └── commands.js
├── .editorconfig
├── .gitignore
├── .eslintrc.js
├── LICENSE
├── vue.config.js
├── package.json
└── README.md
/.eslintignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@vue/app"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "pluginsFile": "tests/e2e/plugins/index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/tree-select/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './tree-select.vue'
2 |
--------------------------------------------------------------------------------
/src/components/main/index.js:
--------------------------------------------------------------------------------
1 | import Main from './main.vue'
2 | export default Main
3 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/icons/index.js:
--------------------------------------------------------------------------------
1 | import Icons from './icons.vue'
2 | export default Icons
3 |
--------------------------------------------------------------------------------
/src/view/single-page/home/index.js:
--------------------------------------------------------------------------------
1 | import home from './home.vue'
2 | export default home
3 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/components/cropper/index.js:
--------------------------------------------------------------------------------
1 | import Cropper from './index.vue'
2 | export default Cropper
3 |
--------------------------------------------------------------------------------
/src/components/editor/index.js:
--------------------------------------------------------------------------------
1 | import Editor from './editor.vue'
2 | export default Editor
3 |
--------------------------------------------------------------------------------
/src/components/split-pane/index.js:
--------------------------------------------------------------------------------
1 | import Split from './split.vue'
2 | export default Split
3 |
--------------------------------------------------------------------------------
/src/components/tables/index.js:
--------------------------------------------------------------------------------
1 | import Tables from './tables.vue'
2 | export default Tables
3 |
--------------------------------------------------------------------------------
/src/components/count-to/index.js:
--------------------------------------------------------------------------------
1 | import countTo from './count-to.vue'
2 | export default countTo
3 |
--------------------------------------------------------------------------------
/src/components/main/components/user/index.js:
--------------------------------------------------------------------------------
1 | import User from './user.vue'
2 | export default User
3 |
--------------------------------------------------------------------------------
/src/components/drag-list/index.js:
--------------------------------------------------------------------------------
1 | import DragList from './drag-list.vue'
2 | export default DragList
3 |
--------------------------------------------------------------------------------
/src/components/info-card/index.js:
--------------------------------------------------------------------------------
1 | import InforCard from './infor-card.vue'
2 | export default InforCard
3 |
--------------------------------------------------------------------------------
/src/components/login-form/index.js:
--------------------------------------------------------------------------------
1 | import LoginForm from './login-form.vue'
2 | export default LoginForm
3 |
--------------------------------------------------------------------------------
/src/assets/images/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/images/logo.jpg
--------------------------------------------------------------------------------
/src/components/common-icon/index.js:
--------------------------------------------------------------------------------
1 | import CommonIcon from './common-icon.vue'
2 | export default CommonIcon
3 |
--------------------------------------------------------------------------------
/src/components/drag-drawer/index.js:
--------------------------------------------------------------------------------
1 | import DragDrawer from './drag-drawer.vue'
2 | export default DragDrawer
3 |
--------------------------------------------------------------------------------
/src/components/parent-view/index.js:
--------------------------------------------------------------------------------
1 | import ParentView from './parent-view.vue'
2 | export default ParentView
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: stable
3 | script: npm run lint
4 | notifications:
5 | email: false
6 |
--------------------------------------------------------------------------------
/src/assets/icons/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/icons/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/icons/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/icons/iconfont.ttf
--------------------------------------------------------------------------------
/src/components/main/components/a-back-top/index.js:
--------------------------------------------------------------------------------
1 | import ABackTop from './index.vue'
2 | export default ABackTop
3 |
--------------------------------------------------------------------------------
/src/components/main/components/language/index.js:
--------------------------------------------------------------------------------
1 | import Language from './language.vue'
2 | export default Language
3 |
--------------------------------------------------------------------------------
/src/components/main/components/tags-nav/index.js:
--------------------------------------------------------------------------------
1 | import TagsNav from './tags-nav.vue'
2 | export default TagsNav
3 |
--------------------------------------------------------------------------------
/src/components/markdown/index.js:
--------------------------------------------------------------------------------
1 | import MarkdownEditor from './markdown.vue'
2 | export default MarkdownEditor
3 |
--------------------------------------------------------------------------------
/src/components/paste-editor/index.js:
--------------------------------------------------------------------------------
1 | import PasteEditor from './paste-editor.vue'
2 | export default PasteEditor
3 |
--------------------------------------------------------------------------------
/src/assets/icons/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/icons/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/images/login-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/images/login-bg.jpg
--------------------------------------------------------------------------------
/src/assets/images/logo-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/images/logo-min.jpg
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/index.js:
--------------------------------------------------------------------------------
1 | import HeaderBar from './header-bar'
2 | export default HeaderBar
3 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/index.js:
--------------------------------------------------------------------------------
1 | import SideMenu from './side-menu.vue'
2 | export default SideMenu
3 |
--------------------------------------------------------------------------------
/src/assets/images/talkingdata.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/images/talkingdata.png
--------------------------------------------------------------------------------
/src/components/main/components/error-store/index.js:
--------------------------------------------------------------------------------
1 | import ErrorStore from './error-store.vue'
2 | export default ErrorStore
3 |
--------------------------------------------------------------------------------
/src/components/main/components/fullscreen/index.js:
--------------------------------------------------------------------------------
1 | import Fullscreen from './fullscreen.vue'
2 | export default Fullscreen
3 |
--------------------------------------------------------------------------------
/src/assets/images/icon-qr-qq-wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/view-design/iview-admin/HEAD/src/assets/images/icon-qr-qq-wechat.png
--------------------------------------------------------------------------------
/src/components/charts/index.js:
--------------------------------------------------------------------------------
1 | import ChartPie from './pie.vue'
2 | import ChartBar from './bar.vue'
3 | export { ChartPie, ChartBar }
4 |
--------------------------------------------------------------------------------
/src/components/drag-drawer/mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data () {
3 | return {
4 | prefix: 'drag-drawer'
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/sider-trigger/index.js:
--------------------------------------------------------------------------------
1 | import siderTrigger from './sider-trigger.vue'
2 | export default siderTrigger
3 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/custom-bread-crumb/index.js:
--------------------------------------------------------------------------------
1 | import customBreadCrumb from './custom-bread-crumb.vue'
2 | export default customBreadCrumb
3 |
--------------------------------------------------------------------------------
/src/index.less:
--------------------------------------------------------------------------------
1 | @import '~iview/src/styles/index.less';
2 |
3 | @menu-dark-title: #001529;
4 | @menu-dark-active-bg: #000c17;
5 | @layout-sider-background: #001529;
6 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | mocha: true
4 | },
5 | rules: {
6 | 'import/no-extraneous-dependencies': 'off'
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less:
--------------------------------------------------------------------------------
1 | .custom-bread-crumb{
2 | display: inline-block;
3 | vertical-align: top;
4 | }
5 |
--------------------------------------------------------------------------------
/src/view/multilevel/level-2-1.vue:
--------------------------------------------------------------------------------
1 |
2 | 多级菜单 -> 二级-1
3 |
4 |
9 |
--------------------------------------------------------------------------------
/src/view/multilevel/level-2-3.vue:
--------------------------------------------------------------------------------
1 |
2 | 多级菜单 -> 二级-3
3 |
4 |
9 |
--------------------------------------------------------------------------------
/src/components/common/util.js:
--------------------------------------------------------------------------------
1 | export const showTitle = (item, vm) => {
2 | return vm.$config.useI18n ? vm.$t(item.name) : ((item.meta && item.meta.title) || item.name)
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/tests/e2e/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "cypress"
4 | ],
5 | "env": {
6 | "mocha": true,
7 | "cypress/globals": true
8 | },
9 | "rules": {
10 | "strict": "off"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/libs/render-dom.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'RenderDom',
3 | functional: true,
4 | props: {
5 | render: Function
6 | },
7 | render: (h, ctx) => {
8 | return ctx.props.render(h)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/count-to/index.less:
--------------------------------------------------------------------------------
1 | @prefix: ~"count-to";
2 |
3 | .@{prefix}-wrapper{
4 | .content-outer{
5 | display: inline-block;
6 | .@{prefix}-unit-text{
7 | font-style: normal;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/directive/directives.js:
--------------------------------------------------------------------------------
1 | import draggable from './module/draggable'
2 | import clipboard from './module/clipboard'
3 |
4 | const directives = {
5 | draggable,
6 | clipboard
7 | }
8 |
9 | export default directives
10 |
--------------------------------------------------------------------------------
/src/components/common/common.less:
--------------------------------------------------------------------------------
1 | .no-select{
2 | -webkit-touch-callout: none;
3 | -webkit-user-select: none;
4 | -khtml-user-select: none;
5 | -moz-user-select: none;
6 | -ms-user-select: none;
7 | user-select: none;
8 | }
9 |
--------------------------------------------------------------------------------
/src/api/routers.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api.request'
2 |
3 | export const getRouterReq = (access) => {
4 | return axios.request({
5 | url: 'get_router',
6 | params: {
7 | access
8 | },
9 | method: 'get'
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/tests/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | // https://docs.cypress.io/api/introduction/api.html
2 |
3 | describe('My First Test', () => {
4 | it('Visits the app root url', () => {
5 | cy.visit('/')
6 | cy.contains('h1', 'Welcome to Your Vue.js App')
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/src/libs/api.request.js:
--------------------------------------------------------------------------------
1 | import HttpRequest from '@/libs/axios'
2 | import config from '@/config'
3 | const baseUrl = process.env.NODE_ENV === 'development' ? config.baseUrl.dev : config.baseUrl.pro
4 |
5 | const axios = new HttpRequest(baseUrl)
6 | export default axios
7 |
--------------------------------------------------------------------------------
/src/plugin/index.js:
--------------------------------------------------------------------------------
1 | import config from '@/config'
2 | const { plugin } = config
3 |
4 | export default (Vue) => {
5 | for (let name in plugin) {
6 | const value = plugin[name]
7 | Vue.use(require(`./${name}`).default, typeof value === 'object' ? value : undefined)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/main/components/user/user.less:
--------------------------------------------------------------------------------
1 | .user{
2 | &-avatar-dropdown{
3 | cursor: pointer;
4 | display: inline-block;
5 | // height: 64px;
6 | vertical-align: middle;
7 | // line-height: 64px;
8 | .ivu-badge-dot{
9 | top: 16px;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/header-bar.less:
--------------------------------------------------------------------------------
1 | .header-bar{
2 | width: 100%;
3 | height: 100%;
4 | position: relative;
5 | .custom-content-con{
6 | float: right;
7 | height: auto;
8 | padding-right: 20px;
9 | line-height: 64px;
10 | & > *{
11 | float: right;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/tables/index.less:
--------------------------------------------------------------------------------
1 | .search-con{
2 | padding: 10px 0;
3 | .search{
4 | &-col{
5 | display: inline-block;
6 | width: 200px;
7 | }
8 | &-input{
9 | display: inline-block;
10 | width: 200px;
11 | margin-left: 2px;
12 | }
13 | &-btn{
14 | margin-left: 2px;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/view/multilevel/level-2-2/level-2-2-1.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
多级菜单 -> 二级-2 -> 3级1
4 |
5 |
6 |
7 |
17 |
--------------------------------------------------------------------------------
/src/view/multilevel/level-2-2/level-2-2-2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
多级菜单 -> 二级-2 -> 3级2
4 |
5 |
6 |
7 |
17 |
--------------------------------------------------------------------------------
/src/router/before-close.js:
--------------------------------------------------------------------------------
1 | import { Modal } from 'iview'
2 |
3 | const beforeClose = {
4 | before_close_normal: (resolve) => {
5 | Modal.confirm({
6 | title: '确定要关闭这一页吗',
7 | onOk: () => {
8 | resolve(true)
9 | },
10 | onCancel: () => {
11 | resolve(false)
12 | }
13 | })
14 | }
15 | }
16 |
17 | export default beforeClose
18 |
--------------------------------------------------------------------------------
/tests/e2e/plugins/index.js:
--------------------------------------------------------------------------------
1 | // https://docs.cypress.io/guides/guides/plugins-guide.html
2 |
3 | module.exports = (on, config) => Object.assign({}, config, {
4 | fixturesFolder: 'tests/e2e/fixtures',
5 | integrationFolder: 'tests/e2e/specs',
6 | screenshotsFolder: 'tests/e2e/screenshots',
7 | videosFolder: 'tests/e2e/videos',
8 | supportFile: 'tests/e2e/support/index.js'
9 | })
10 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import user from './module/user'
5 | import app from './module/app'
6 |
7 | Vue.use(Vuex)
8 |
9 | export default new Vuex.Store({
10 | state: {
11 | //
12 | },
13 | mutations: {
14 | //
15 | },
16 | actions: {
17 | //
18 | },
19 | modules: {
20 | user,
21 | app
22 | }
23 | })
24 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | package-lock.json
6 |
7 | /tests/e2e/videos/
8 | /tests/e2e/screenshots/
9 |
10 | # local env files
11 | .env.local
12 | .env.*.local
13 |
14 | # Log files
15 | npm-debug.log*
16 | yarn-debug.log*
17 | yarn-error.log*
18 |
19 | # Editor directories and files
20 | .idea
21 | .vscode
22 | *.suo
23 | *.ntvs*
24 | *.njsproj
25 | *.sln
26 | *.sw*
27 |
28 | build/env.js
29 |
--------------------------------------------------------------------------------
/src/components/drag-drawer/drag-drawer-trigger.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
16 |
17 |
19 |
--------------------------------------------------------------------------------
/tests/unit/HelloWorld.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai'
2 | import { shallow } from '@vue/test-utils'
3 | import HelloWorld from '@/components/HelloWorld.vue'
4 |
5 | describe('HelloWorld.vue', () => {
6 | it('renders props.msg when passed', () => {
7 | const msg = 'new message'
8 | const wrapper = shallow(HelloWorld, {
9 | propsData: { msg }
10 | })
11 | expect(wrapper.text()).to.include(msg)
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/src/view/components/markdown/markdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
21 |
22 |
25 |
--------------------------------------------------------------------------------
/src/view/error-page/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
--------------------------------------------------------------------------------
/src/view/error-page/401.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
--------------------------------------------------------------------------------
/src/view/error-page/500.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/sider-trigger/sider-trigger.less:
--------------------------------------------------------------------------------
1 | .trans{
2 | transition: transform .2s ease;
3 | }
4 | @size: 40px;
5 | .sider-trigger-a{
6 | padding: 6px;
7 | width: @size;
8 | height: @size;
9 | display: inline-block;
10 | text-align: center;
11 | color: #5c6b77;
12 | margin-top: 12px;
13 | i{
14 | .trans;
15 | vertical-align: top;
16 | }
17 | &.collapsed i{
18 | transform: rotateZ(90deg);
19 | .trans;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/item-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | parentItem: {
4 | type: Object,
5 | default: () => {}
6 | },
7 | theme: String,
8 | iconSize: Number
9 | },
10 | computed: {
11 | parentName () {
12 | return this.parentItem.name
13 | },
14 | children () {
15 | return this.parentItem.children
16 | },
17 | textColor () {
18 | return this.theme === 'dark' ? '#fff' : '#495060'
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/plugin/error-store/index.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 | export default {
3 | install (Vue, options) {
4 | if (options.developmentOff && process.env.NODE_ENV === 'development') return
5 | Vue.config.errorHandler = (error, vm, mes) => {
6 | let info = {
7 | type: 'script',
8 | code: 0,
9 | mes: error.message,
10 | url: window.location.href
11 | }
12 | Vue.nextTick(() => {
13 | store.dispatch('addErrorLog', info)
14 | })
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | 'extends': [
4 | 'plugin:vue/essential',
5 | '@vue/standard'
6 | ],
7 | rules: {
8 | // allow async-await
9 | 'generator-star-spacing': 'off',
10 | // allow debugger during development
11 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'vue/no-parsing-error': [2, {
13 | 'x-invalid-end-tag': false
14 | }],
15 | 'no-undef': 'off',
16 | 'camelcase': 'off'
17 | },
18 | parserOptions: {
19 | parser: 'babel-eslint'
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/paste-editor/paste-editor.less:
--------------------------------------------------------------------------------
1 | .paste-editor-wrapper{
2 | width: 100%;
3 | height: 100%;
4 | border: 1px dashed gainsboro;
5 | textarea.textarea-el{
6 | width: 100%;
7 | height: 100%;
8 | }
9 | .CodeMirror{
10 | height: 100%;
11 | padding: 0;
12 | .CodeMirror-code div .CodeMirror-line > span > span.cm-tab{
13 | &::after{
14 | content: '→';
15 | color: #BFBFBF;
16 | }
17 | }
18 | }
19 | .first-row{
20 | font-weight: 700;
21 | font-size: 14px;
22 | }
23 | .incorrect-row{
24 | background: #F5CBD1;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/mixin.js:
--------------------------------------------------------------------------------
1 | import CommonIcon from '_c/common-icon'
2 | import { showTitle } from '@/libs/util'
3 | export default {
4 | components: {
5 | CommonIcon
6 | },
7 | methods: {
8 | showTitle (item) {
9 | return showTitle(item, this)
10 | },
11 | showChildren (item) {
12 | return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways))
13 | },
14 | getNameOrHref (item, children0) {
15 | return item.href ? `isTurnByHref_${item.href}` : (children0 ? item.children[0].name : item.name)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | We're sorry but iview-admin doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/icons/icons.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/src/directive/index.js:
--------------------------------------------------------------------------------
1 | import directive from './directives'
2 |
3 | const importDirective = Vue => {
4 | /**
5 | * 拖拽指令 v-draggable="options"
6 | * options = {
7 | * trigger: /这里传入作为拖拽触发器的CSS选择器/,
8 | * body: /这里传入需要移动容器的CSS选择器/,
9 | * recover: /拖动结束之后是否恢复到原来的位置/
10 | * }
11 | */
12 | Vue.directive('draggable', directive.draggable)
13 | /**
14 | * clipboard指令 v-draggable="options"
15 | * options = {
16 | * value: /在输入框中使用v-model绑定的值/,
17 | * success: /复制成功后的回调/,
18 | * error: /复制失败后的回调/
19 | * }
20 | */
21 | Vue.directive('clipboard', directive.clipboard)
22 | }
23 |
24 | export default importDirective
25 |
--------------------------------------------------------------------------------
/src/view/error-page/error-content.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{ code }}
7 | {{ desc }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
29 |
--------------------------------------------------------------------------------
/src/components/parent-view/parent-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
22 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
25 |
28 |
--------------------------------------------------------------------------------
/src/view/components/editor/editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 修改编辑器内容
5 |
6 |
7 |
8 |
30 |
31 |
34 |
--------------------------------------------------------------------------------
/tests/e2e/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/src/view/argu-page/query.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ID: {{ $route.query.id }}
5 | 调用closeTag方法关闭本页
6 |
7 |
8 |
9 |
10 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/src/view/argu-page/params.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ID: {{ $route.params.id }}
5 | 调用closeTag方法关闭本页
6 |
7 |
8 |
9 |
10 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/src/view/login/login.less:
--------------------------------------------------------------------------------
1 | .login{
2 | width: 100%;
3 | height: 100%;
4 | background-image: url('../../assets/images/login-bg.jpg');
5 | background-size: cover;
6 | background-position: center;
7 | position: relative;
8 | &-con{
9 | position: absolute;
10 | right: 160px;
11 | top: 50%;
12 | transform: translateY(-60%);
13 | width: 300px;
14 | &-header{
15 | font-size: 16px;
16 | font-weight: 300;
17 | text-align: center;
18 | padding: 30px 0;
19 | }
20 | .form-con{
21 | padding: 10px 0 0;
22 | }
23 | .login-tip{
24 | font-size: 10px;
25 | text-align: center;
26 | color: #c3c3c3;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/tables/handle-btns.js:
--------------------------------------------------------------------------------
1 | const btns = {
2 | delete: (h, params, vm) => {
3 | return h('Poptip', {
4 | props: {
5 | confirm: true,
6 | title: '你确定要删除吗?'
7 | },
8 | on: {
9 | 'on-ok': () => {
10 | vm.$emit('on-delete', params)
11 | vm.$emit('input', params.tableData.filter((item, index) => index !== params.row.initRowIndex))
12 | }
13 | }
14 | }, [
15 | h('Button', {
16 | props: {
17 | type: 'text',
18 | ghost: true
19 | }
20 | }, [
21 | h('Icon', {
22 | props: {
23 | type: 'md-trash',
24 | size: 18,
25 | color: '#000000'
26 | }
27 | })
28 | ])
29 | ])
30 | }
31 | }
32 |
33 | export default btns
34 |
--------------------------------------------------------------------------------
/src/mock/login.js:
--------------------------------------------------------------------------------
1 | import { getParams } from '@/libs/util'
2 | const USER_MAP = {
3 | super_admin: {
4 | name: 'super_admin',
5 | user_id: '1',
6 | access: ['super_admin', 'admin'],
7 | token: 'super_admin',
8 | avatar: 'https://file.iviewui.com/dist/a0e88e83800f138b94d2414621bd9704.png'
9 | },
10 | admin: {
11 | name: 'admin',
12 | user_id: '2',
13 | access: ['admin'],
14 | token: 'admin',
15 | avatar: 'https://avatars0.githubusercontent.com/u/20942571?s=460&v=4'
16 | }
17 | }
18 |
19 | export const login = req => {
20 | req = JSON.parse(req.body)
21 | return { token: USER_MAP[req.userName].token }
22 | }
23 |
24 | export const getUserInfo = req => {
25 | const params = getParams(req.url)
26 | return USER_MAP[params.token]
27 | }
28 |
29 | export const logout = req => {
30 | return null
31 | }
32 |
--------------------------------------------------------------------------------
/src/mock/data/org-data.js:
--------------------------------------------------------------------------------
1 | export default {
2 | id: 0,
3 | label: 'XXX科技有限公司',
4 | children: [
5 | {
6 | id: 2,
7 | label: '产品研发部',
8 | children: [
9 | {
10 | id: 5,
11 | label: '研发-前端'
12 | }, {
13 | id: 6,
14 | label: '研发-后端'
15 | }, {
16 | id: 9,
17 | label: 'UI设计'
18 | }, {
19 | id: 10,
20 | label: '产品经理'
21 | }
22 | ]
23 | },
24 | {
25 | id: 3,
26 | label: '销售部',
27 | children: [
28 | {
29 | id: 7,
30 | label: '销售一部'
31 | }, {
32 | id: 8,
33 | label: '销售二部'
34 | }
35 | ]
36 | },
37 | {
38 | id: 4,
39 | label: '财务部'
40 | }, {
41 | id: 11,
42 | label: 'HR人事'
43 | }
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/side-menu.less:
--------------------------------------------------------------------------------
1 | .side-menu-wrapper{
2 | user-select: none;
3 | .menu-collapsed{
4 | padding-top: 10px;
5 |
6 | .ivu-dropdown{
7 | width: 100%;
8 | .ivu-dropdown-rel a{
9 | width: 100%;
10 | }
11 | }
12 | .ivu-tooltip{
13 | width: 100%;
14 | .ivu-tooltip-rel{
15 | width: 100%;
16 | }
17 | .ivu-tooltip-popper .ivu-tooltip-content{
18 | .ivu-tooltip-arrow{
19 | border-right-color: #fff;
20 | }
21 | .ivu-tooltip-inner{
22 | background: #fff;
23 | color: #495060;
24 | }
25 | }
26 | }
27 |
28 |
29 | }
30 | a.drop-menu-a{
31 | display: inline-block;
32 | padding: 6px 15px;
33 | width: 100%;
34 | text-align: center;
35 | color: #495060;
36 | }
37 | }
38 | .menu-title{
39 | padding-left: 6px;
40 | }
41 |
--------------------------------------------------------------------------------
/src/view/error-page/back-btn-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 返回首页
4 | 返回上一页({{ second }}s)
5 |
6 |
7 |
8 |
39 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | /**
3 | * @description 配置显示在浏览器标签的title
4 | */
5 | title: 'iView-admin',
6 | /**
7 | * @description token在Cookie中存储的天数,默认1天
8 | */
9 | cookieExpires: 1,
10 | /**
11 | * @description 是否使用国际化,默认为false
12 | * 如果不使用,则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'}
13 | * 用来在菜单中显示文字
14 | */
15 | useI18n: true,
16 | /**
17 | * @description api请求基础路径
18 | */
19 | baseUrl: {
20 | dev: 'https://www.easy-mock.com/mock/5add9213ce4d0e69998a6f51/iview-admin/',
21 | pro: 'https://produce.com'
22 | },
23 | /**
24 | * @description 默认打开的首页的路由name值,默认为home
25 | */
26 | homeName: 'home',
27 | /**
28 | * @description 需要加载的插件
29 | */
30 | plugin: {
31 | 'error-store': {
32 | showInHeader: true, // 设为false后不会在顶部显示错误日志徽标
33 | developmentOff: true // 设为true后在开发环境不会收集错误信息,方便开发中排查错误
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/assets/images/icon-social-juejin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/e2e/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This is will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/src/mock/data.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { doCustomTimes } from '@/libs/util'
3 | import orgData from './data/org-data'
4 | import { treeData } from './data/tree-select'
5 | const Random = Mock.Random
6 |
7 | export const getTableData = req => {
8 | let tableData = []
9 | doCustomTimes(5, () => {
10 | tableData.push(Mock.mock({
11 | name: '@name',
12 | email: '@email',
13 | createTime: '@date'
14 | }))
15 | })
16 | return tableData
17 | }
18 |
19 | export const getDragList = req => {
20 | let dragList = []
21 | doCustomTimes(5, () => {
22 | dragList.push(Mock.mock({
23 | name: Random.csentence(10, 13),
24 | id: Random.increment(10)
25 | }))
26 | })
27 | return dragList
28 | }
29 |
30 | export const uploadImage = req => {
31 | return Promise.resolve()
32 | }
33 |
34 | export const getOrgData = req => {
35 | return orgData
36 | }
37 |
38 | export const getTreeSelectData = req => {
39 | return treeData
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/split-pane/trigger.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
40 |
41 |
44 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/header-bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
35 |
--------------------------------------------------------------------------------
/src/components/common-icon/common-icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
39 |
40 |
43 |
--------------------------------------------------------------------------------
/src/components/cropper/index.less:
--------------------------------------------------------------------------------
1 | .bg{
2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")
3 | }
4 | .cropper-wrapper{
5 | width: 600px;
6 | height: 340px;
7 | .img-box{
8 | height: 340px;
9 | width: 430px;
10 | border: 1px solid #ebebeb;
11 | display: inline-block;
12 | .bg;
13 | img{
14 | max-width: 100%;
15 | display: block;
16 | }
17 | }
18 | .right-con{
19 | display: inline-block;
20 | width: 170px;
21 | vertical-align: top;
22 | box-sizing: border-box;
23 | padding: 0 10px;
24 | .preview-box{
25 | height: 150px !important;
26 | width: 100% !important;
27 | overflow: hidden;
28 | border: 1px solid #ebebeb;
29 | .bg;
30 | }
31 | .button-box{
32 | padding: 10px 0 0;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/directive/module/clipboard.js:
--------------------------------------------------------------------------------
1 | import Clipboard from 'clipboard'
2 | export default {
3 | bind: (el, binding) => {
4 | const clipboard = new Clipboard(el, {
5 | text: () => binding.value.value
6 | })
7 | el.__success_callback__ = binding.value.success
8 | el.__error_callback__ = binding.value.error
9 | clipboard.on('success', e => {
10 | const callback = el.__success_callback__
11 | callback && callback(e)
12 | })
13 | clipboard.on('error', e => {
14 | const callback = el.__error_callback__
15 | callback && callback(e)
16 | })
17 | el.__clipboard__ = clipboard
18 | },
19 | update: (el, binding) => {
20 | el.__clipboard__.text = () => binding.value.value
21 | el.__success_callback__ = binding.value.success
22 | el.__error_callback__ = binding.value.error
23 | },
24 | unbind: (el, binding) => {
25 | delete el.__success_callback__
26 | delete el.__error_callback__
27 | el.__clipboard__.destroy()
28 | delete el.__clipboard__
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/view/error-page/error.less:
--------------------------------------------------------------------------------
1 | .error-page{
2 | width: 100%;
3 | height: 100%;
4 | position: relative;
5 | background: #f8f8f9;
6 | .content-con{
7 | width: 700px;
8 | height: 600px;
9 | position: absolute;
10 | left: 50%;
11 | top: 50%;
12 | transform: translate(-50%, -60%);
13 | img{
14 | display: block;
15 | width: 100%;
16 | height: 100%;
17 | }
18 | .text-con{
19 | position: absolute;
20 | left: 0px;
21 | top: 0px;
22 | h4{
23 | position: absolute;
24 | left: 0px;
25 | top: 0px;
26 | font-size: 80px;
27 | font-weight: 700;
28 | color: #348EED;
29 | }
30 | h5{
31 | position: absolute;
32 | width: 700px;
33 | left: 0px;
34 | top: 100px;
35 | font-size: 20px;
36 | font-weight: 700;
37 | color: #67647D;
38 | }
39 | }
40 | .back-btn-group{
41 | position: absolute;
42 | right: 0px;
43 | bottom: 20px;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/main/components/error-store/error-store.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
38 |
39 |
50 |
--------------------------------------------------------------------------------
/src/api/data.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api.request'
2 |
3 | export const getTableData = () => {
4 | return axios.request({
5 | url: 'get_table_data',
6 | method: 'get'
7 | })
8 | }
9 |
10 | export const getDragList = () => {
11 | return axios.request({
12 | url: 'get_drag_list',
13 | method: 'get'
14 | })
15 | }
16 |
17 | export const errorReq = () => {
18 | return axios.request({
19 | url: 'error_url',
20 | method: 'post'
21 | })
22 | }
23 |
24 | export const saveErrorLogger = info => {
25 | return axios.request({
26 | url: 'save_error_logger',
27 | data: info,
28 | method: 'post'
29 | })
30 | }
31 |
32 | export const uploadImg = formData => {
33 | return axios.request({
34 | url: 'image/upload',
35 | data: formData
36 | })
37 | }
38 |
39 | export const getOrgData = () => {
40 | return axios.request({
41 | url: 'get_org_data',
42 | method: 'get'
43 | })
44 | }
45 |
46 | export const getTreeSelectData = () => {
47 | return axios.request({
48 | url: 'get_tree_select_data',
49 | method: 'get'
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/src/view/login/login.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
16 |
17 |
18 |
42 |
43 |
46 |
--------------------------------------------------------------------------------
/src/view/components/cropper/cropper.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
43 |
44 |
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 TalkingData
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/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { login, logout, getUserInfo } from './login'
3 | import { getTableData, getDragList, uploadImage, getOrgData, getTreeSelectData } from './data'
4 | import { getMessageInit, getContentByMsgId, hasRead, removeReaded, restoreTrash, messageCount } from './user'
5 |
6 | // 配置Ajax请求延时,可用来测试网络延迟大时项目中一些效果
7 | Mock.setup({
8 | timeout: 1000
9 | })
10 |
11 | // 登录相关和获取用户信息
12 | Mock.mock(/\/login/, login)
13 | Mock.mock(/\/get_info/, getUserInfo)
14 | Mock.mock(/\/logout/, logout)
15 | Mock.mock(/\/get_table_data/, getTableData)
16 | Mock.mock(/\/get_drag_list/, getDragList)
17 | Mock.mock(/\/save_error_logger/, 'success')
18 | Mock.mock(/\/image\/upload/, uploadImage)
19 | Mock.mock(/\/message\/init/, getMessageInit)
20 | Mock.mock(/\/message\/content/, getContentByMsgId)
21 | Mock.mock(/\/message\/has_read/, hasRead)
22 | Mock.mock(/\/message\/remove_readed/, removeReaded)
23 | Mock.mock(/\/message\/restore/, restoreTrash)
24 | Mock.mock(/\/message\/count/, messageCount)
25 | Mock.mock(/\/get_org_data/, getOrgData)
26 | Mock.mock(/\/get_tree_select_data/, getTreeSelectData)
27 |
28 | export default Mock
29 |
--------------------------------------------------------------------------------
/src/view/excel/common.less:
--------------------------------------------------------------------------------
1 | .margin-top-8{
2 | margin-top: 8px;
3 | }
4 | .margin-top-10{
5 | margin-top: 10px;
6 | }
7 | .margin-top-20{
8 | margin-top: 20px;
9 | }
10 | .margin-left-10{
11 | margin-left: 10px;
12 | }
13 | .margin-bottom-10{
14 | margin-bottom: 10px;
15 | }
16 | .margin-bottom-100{
17 | margin-bottom: 100px;
18 | }
19 | .margin-right-10{
20 | margin-right: 10px;
21 | }
22 | .padding-left-6{
23 | padding-left: 6px;
24 | }
25 | .padding-left-8{
26 | padding-left: 5px;
27 | }
28 | .padding-left-10{
29 | padding-left: 10px;
30 | }
31 | .padding-left-20{
32 | padding-left: 20px;
33 | }
34 | .height-100{
35 | height: 100%;
36 | }
37 | .height-120px{
38 | height: 100px;
39 | }
40 | .height-200px{
41 | height: 200px;
42 | }
43 | .height-492px{
44 | height: 492px;
45 | }
46 | .height-460px{
47 | height: 460px;
48 | }
49 | .line-gray{
50 | height: 0;
51 | border-bottom: 2px solid #dcdcdc;
52 | }
53 | .notwrap{
54 | word-break:keep-all;
55 | white-space:nowrap;
56 | overflow: hidden;
57 | text-overflow: ellipsis;
58 | }
59 | .padding-left-5{
60 | padding-left: 10px;
61 | }
62 | [v-cloak]{
63 | display: none;
64 | }
--------------------------------------------------------------------------------
/src/components/main/components/language/language.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
52 |
--------------------------------------------------------------------------------
/src/view/error-store/error-store.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iview-admin会自动将你程序中的错误收集起来,你可以将错误日志发给后端保存起来。如果你不需要这个功能,将'./src/config/index.js'里的plugin的'error-store'属性删掉即可。
5 | 另外在开发环境下,你程序中的错误都会被收集起来,这样可能不利于你排查错误,你可以将'./src/config/index.js'的'error-store'的'developmentOff'设为true。
6 | 如果你只是想收集错误日志,不希望登录用户看到错误日志,你可以不提供查看日志的入口,只需将'./src/config/index.js'的'error-store'的'showInHeader'设为false。
7 |
8 |
9 |
10 |
11 | 点击测试触发程序错误
12 | 点击测试触发ajax接口请求错误
13 |
14 |
15 | ajax接口请求是请求easy-mock的一个不存在接口,所以服务端会报404错误,错误收集机制会收集这个错误,测试的时候有一定网络延迟,所以点击按钮之后稍等一会才会收集到错误。
16 |
17 |
18 |
19 |
20 |
21 |
22 |
36 |
37 |
40 |
--------------------------------------------------------------------------------
/src/locale/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueI18n from 'vue-i18n'
3 | import { localRead } from '@/libs/util'
4 | import customZhCn from './lang/zh-CN'
5 | import customZhTw from './lang/zh-TW'
6 | import customEnUs from './lang/en-US'
7 | import zhCnLocale from 'iview/src/locale/lang/zh-CN'
8 | import enUsLocale from 'iview/src/locale/lang/en-US'
9 | import zhTwLocale from 'iview/src/locale/lang/zh-TW'
10 |
11 | Vue.use(VueI18n)
12 |
13 | // 自动根据浏览器系统语言设置语言
14 | const navLang = navigator.language
15 | const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false
16 | let lang = localLang || localRead('local') || 'zh-CN'
17 |
18 | Vue.config.lang = lang
19 |
20 | // vue-i18n 6.x+写法
21 | Vue.locale = () => {}
22 | const messages = {
23 | 'zh-CN': Object.assign(zhCnLocale, customZhCn),
24 | 'zh-TW': Object.assign(zhTwLocale, customZhTw),
25 | 'en-US': Object.assign(enUsLocale, customEnUs)
26 | }
27 | const i18n = new VueI18n({
28 | locale: lang,
29 | messages
30 | })
31 |
32 | export default i18n
33 |
34 | // vue-i18n 5.x写法
35 | // Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn))
36 | // Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw))
37 | // Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs))
38 |
--------------------------------------------------------------------------------
/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ showTitle(item) }}
7 |
8 |
9 |
10 |
11 |
47 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/side-menu-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ showTitle(parentItem) }}
6 |
7 |
8 |
9 |
10 | {{ showTitle(item.children[0]) }}
11 |
12 |
13 |
14 | {{ showTitle(item) }}
15 |
16 |
17 |
18 |
19 |
27 |
--------------------------------------------------------------------------------
/src/locale/lang/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | home: '首页',
3 | login: '登录',
4 | components: '组件',
5 | count_to_page: '数字渐变',
6 | tables_page: '多功能表格',
7 | split_pane_page: '分割窗口',
8 | markdown_page: 'Markdown编辑器',
9 | editor_page: '富文本编辑器',
10 | icons_page: '自定义图标',
11 | img_cropper_page: '图片编辑器',
12 | update: '上传数据',
13 | join_page: 'QQ群',
14 | doc: '文档',
15 | update_table_page: '上传CSV文件',
16 | update_paste_page: '粘贴表格数据',
17 | multilevel: '多级菜单',
18 | directive_page: '指令',
19 | level_1: 'Level-1',
20 | level_2: 'Level-2',
21 | level_2_1: 'Level-2-1',
22 | level_2_3: 'Level-2-3',
23 | level_2_2: 'Level-2-2',
24 | level_2_2_1: 'Level-2-2-1',
25 | level_2_2_2: 'Level-2-2-2',
26 | excel: 'Excel',
27 | 'upload-excel': '上传excel',
28 | 'export-excel': '导出excel',
29 | tools_methods_page: '工具函数',
30 | drag_list_page: '拖拽列表',
31 | i18n_page: '多语言',
32 | modalTitle: '模态框题目',
33 | content: '这是模态框内容',
34 | buttonText: '显示模态框',
35 | 'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容',
36 | error_store_page: '错误收集',
37 | error_logger_page: '错误日志',
38 | query: '带参路由',
39 | params: '动态路由',
40 | cropper_page: '图片裁剪',
41 | message_page: '消息中心',
42 | tree_table_page: '树状表格',
43 | org_tree_page: '组织结构树',
44 | drag_drawer_page: '可拖动抽屉',
45 | tree_select_page: '树状下拉选择器'
46 | }
47 |
--------------------------------------------------------------------------------
/src/locale/lang/zh-TW.js:
--------------------------------------------------------------------------------
1 | export default {
2 | home: '首頁',
3 | login: '登錄',
4 | components: '组件',
5 | count_to_page: '数字渐变',
6 | tables_page: '多功能表格',
7 | split_pane_page: '分割窗口',
8 | markdown_page: 'Markdown編輯器',
9 | editor_page: '富文本編輯器',
10 | icons_page: '自定義圖標',
11 | img_cropper_page: '圖片編輯器',
12 | update: '上傳數據',
13 | join_page: 'QQ群',
14 | doc: '文檔',
15 | update_table_page: '上傳CSV文件',
16 | update_paste_page: '粘貼表格數據',
17 | multilevel: '多级菜单',
18 | directive_page: '指令',
19 | level_1: 'Level-1',
20 | level_2: 'Level-2',
21 | level_2_1: 'Level-2-1',
22 | level_2_3: 'Level-2-3',
23 | level_2_2: 'Level-2-2',
24 | level_2_2_1: 'Level-2-2-1',
25 | level_2_2_2: 'Level-2-2-2',
26 | excel: 'Excel',
27 | 'upload-excel': '上傳excel',
28 | 'export-excel': '導出excel',
29 | tools_methods_page: '工具函數',
30 | drag_list_page: '拖拽列表',
31 | i18n_page: '多語言',
32 | modalTitle: '模態框題目',
33 | content: '這是模態框內容',
34 | buttonText: '顯示模態框',
35 | 'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容',
36 | error_store_page: '錯誤收集',
37 | error_logger_page: '錯誤日誌',
38 | query: '帶參路由',
39 | params: '動態路由',
40 | cropper_page: '圖片裁剪',
41 | message_page: '消息中心',
42 | tree_table_page: '樹狀表格',
43 | org_tree_page: '組織結構樹',
44 | drag_drawer_page: '可拖動抽屜',
45 | tree_select_page: '樹狀下拉選擇器'
46 | }
47 |
--------------------------------------------------------------------------------
/src/view/i18n/i18n-page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
{{ $t('buttonText') }}
10 |
13 | {{ content }}
14 | {{ content }}
15 | {{ content }}
16 |
17 |
{{ $t('i18n-tip') }}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
40 |
41 |
51 |
--------------------------------------------------------------------------------
/src/components/charts/bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
59 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 | import store from './store'
7 | import iView from 'iview'
8 | import i18n from '@/locale'
9 | import config from '@/config'
10 | import importDirective from '@/directive'
11 | import { directive as clickOutside } from 'v-click-outside-x'
12 | import installPlugin from '@/plugin'
13 | import './index.less'
14 | import '@/assets/icons/iconfont.css'
15 | import TreeTable from 'tree-table-vue'
16 | import VOrgTree from 'v-org-tree'
17 | import 'v-org-tree/dist/v-org-tree.css'
18 | // 实际打包时应该不引入mock
19 | /* eslint-disable */
20 | if (process.env.NODE_ENV !== 'production') require('@/mock')
21 |
22 | Vue.use(iView, {
23 | i18n: (key, value) => i18n.t(key, value)
24 | })
25 | Vue.use(TreeTable)
26 | Vue.use(VOrgTree)
27 | /**
28 | * @description 注册admin内置插件
29 | */
30 | installPlugin(Vue)
31 | /**
32 | * @description 生产环境关掉提示
33 | */
34 | Vue.config.productionTip = false
35 | /**
36 | * @description 全局注册应用配置
37 | */
38 | Vue.prototype.$config = config
39 | /**
40 | * 注册指令
41 | */
42 | importDirective(Vue)
43 | Vue.directive('clickOutside', clickOutside)
44 |
45 | /* eslint-disable no-new */
46 | new Vue({
47 | el: '#app',
48 | router,
49 | i18n,
50 | store,
51 | render: h => h(App)
52 | })
53 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | const resolve = dir => {
4 | return path.join(__dirname, dir)
5 | }
6 |
7 | // 项目部署基础
8 | // 默认情况下,我们假设你的应用将被部署在域的根目录下,
9 | // 例如:https://www.my-app.com/
10 | // 默认:'/'
11 | // 如果您的应用程序部署在子路径中,则需要在这指定子路径
12 | // 例如:https://www.foobar.com/my-app/
13 | // 需要将它改为'/my-app/'
14 | // iview-admin线上演示打包路径: https://file.iviewui.com/admin-dist/
15 | const BASE_URL = process.env.NODE_ENV === 'production'
16 | ? '/'
17 | : '/'
18 |
19 | module.exports = {
20 | // Project deployment base
21 | // By default we assume your app will be deployed at the root of a domain,
22 | // e.g. https://www.my-app.com/
23 | // If your app is deployed at a sub-path, you will need to specify that
24 | // sub-path here. For example, if your app is deployed at
25 | // https://www.foobar.com/my-app/
26 | // then change this to '/my-app/'
27 | baseUrl: BASE_URL,
28 | // tweak internal webpack configuration.
29 | // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
30 | // 如果你不需要使用eslint,把lintOnSave设为false即可
31 | lintOnSave: true,
32 | chainWebpack: config => {
33 | config.resolve.alias
34 | .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
35 | .set('_c', resolve('src/components'))
36 | },
37 | // 设为false打包时不生成.map文件
38 | productionSourceMap: false
39 | // 这里写你调用接口的基础路径,来解决跨域,如果设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串
40 | // devServer: {
41 | // proxy: 'localhost:3000'
42 | // }
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/main/components/user/user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 消息中心
11 |
12 | 退出登录
13 |
14 |
15 |
16 |
17 |
18 |
60 |
--------------------------------------------------------------------------------
/src/directive/module/draggable.js:
--------------------------------------------------------------------------------
1 | import { on } from '@/libs/tools'
2 | export default {
3 | inserted: (el, binding, vnode) => {
4 | let triggerDom = document.querySelector(binding.value.trigger)
5 | triggerDom.style.cursor = 'move'
6 | let bodyDom = document.querySelector(binding.value.body)
7 | let pageX = 0
8 | let pageY = 0
9 | let transformX = 0
10 | let transformY = 0
11 | let canMove = false
12 | const handleMousedown = e => {
13 | let transform = /\(.*\)/.exec(bodyDom.style.transform)
14 | if (transform) {
15 | transform = transform[0].slice(1, transform[0].length - 1)
16 | let splitxy = transform.split('px, ')
17 | transformX = parseFloat(splitxy[0])
18 | transformY = parseFloat(splitxy[1].split('px')[0])
19 | }
20 | pageX = e.pageX
21 | pageY = e.pageY
22 | canMove = true
23 | }
24 | const handleMousemove = e => {
25 | let xOffset = e.pageX - pageX + transformX
26 | let yOffset = e.pageY - pageY + transformY
27 | if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`
28 | }
29 | const handleMouseup = e => {
30 | canMove = false
31 | }
32 | on(triggerDom, 'mousedown', handleMousedown)
33 | on(document, 'mousemove', handleMousemove)
34 | on(document, 'mouseup', handleMouseup)
35 | },
36 | update: (el, binding, vnode) => {
37 | if (!binding.value.recover) return
38 | let bodyDom = document.querySelector(binding.value.body)
39 | bodyDom.style.transform = ''
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/locale/lang/en-US.js:
--------------------------------------------------------------------------------
1 | export default {
2 | home: 'Home',
3 | login: 'Login',
4 | components: 'Components',
5 | count_to_page: 'Count-to',
6 | tables_page: 'Table',
7 | split_pane_page: 'Split-pane',
8 | markdown_page: 'Markdown-editor',
9 | editor_page: 'Rich-Text-Editor',
10 | icons_page: 'Custom-icon',
11 | img_cropper_page: 'Image-editor',
12 | update: 'Update',
13 | doc: 'Document',
14 | join_page: 'QQ Group',
15 | update_table_page: 'Update .CSV',
16 | update_paste_page: 'Paste Table Data',
17 | multilevel: 'multilevel',
18 | directive_page: 'Directive',
19 | level_1: 'Level-1',
20 | level_2: 'Level-2',
21 | level_2_1: 'Level-2-1',
22 | level_2_3: 'Level-2-3',
23 | level_2_2: 'Level-2-2',
24 | level_2_2_1: 'Level-2-2-1',
25 | level_2_2_2: 'Level-2-2-2',
26 | excel: 'Excel',
27 | 'upload-excel': 'Upload Excel',
28 | 'export-excel': 'Export Excel',
29 | tools_methods_page: 'Tools Methods',
30 | drag_list_page: 'Drag-list',
31 | i18n_page: 'Internationalization',
32 | modalTitle: 'Modal Title',
33 | content: 'This is the modal box content.',
34 | buttonText: 'Show Modal',
35 | 'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.',
36 | error_store_page: 'Error Collection',
37 | error_logger_page: 'Error Logger',
38 | query: 'Query',
39 | params: 'Params',
40 | cropper_page: 'Cropper',
41 | message_page: 'Message Center',
42 | tree_table_page: 'Tree Table',
43 | org_tree_page: 'Org Tree',
44 | drag_drawer_page: 'Draggable Drawer',
45 | tree_select_page: 'Tree Selector'
46 | }
47 |
--------------------------------------------------------------------------------
/src/assets/images/icon-social-zhihu.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/tree-select/tree-select.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
16 |
17 |
18 |
19 |
65 |
66 |
73 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api.request'
2 |
3 | export const login = ({ userName, password }) => {
4 | const data = {
5 | userName,
6 | password
7 | }
8 | return axios.request({
9 | url: 'login',
10 | data,
11 | method: 'post'
12 | })
13 | }
14 |
15 | export const getUserInfo = (token) => {
16 | return axios.request({
17 | url: 'get_info',
18 | params: {
19 | token
20 | },
21 | method: 'get'
22 | })
23 | }
24 |
25 | export const logout = (token) => {
26 | return axios.request({
27 | url: 'logout',
28 | method: 'post'
29 | })
30 | }
31 |
32 | export const getUnreadCount = () => {
33 | return axios.request({
34 | url: 'message/count',
35 | method: 'get'
36 | })
37 | }
38 |
39 | export const getMessage = () => {
40 | return axios.request({
41 | url: 'message/init',
42 | method: 'get'
43 | })
44 | }
45 |
46 | export const getContentByMsgId = msg_id => {
47 | return axios.request({
48 | url: 'message/content',
49 | method: 'get',
50 | params: {
51 | msg_id
52 | }
53 | })
54 | }
55 |
56 | export const hasRead = msg_id => {
57 | return axios.request({
58 | url: 'message/has_read',
59 | method: 'post',
60 | data: {
61 | msg_id
62 | }
63 | })
64 | }
65 |
66 | export const removeReaded = msg_id => {
67 | return axios.request({
68 | url: 'message/remove_readed',
69 | method: 'post',
70 | data: {
71 | msg_id
72 | }
73 | })
74 | }
75 |
76 | export const restoreTrash = msg_id => {
77 | return axios.request({
78 | url: 'message/restore',
79 | method: 'post',
80 | data: {
81 | msg_id
82 | }
83 | })
84 | }
85 |
--------------------------------------------------------------------------------
/src/mock/data/tree-select.js:
--------------------------------------------------------------------------------
1 | export const treeData = [
2 | {
3 | id: 1,
4 | title: '1',
5 | children: [
6 | {
7 | id: 11,
8 | title: '1-1',
9 | loading: false,
10 | children: [
11 | // {
12 | // id: 111,
13 | // title: '1-1-1'
14 | // },
15 | // {
16 | // id: 112,
17 | // title: '1-1-2'
18 | // },
19 | // {
20 | // id: 113,
21 | // title: '1-1-3'
22 | // },
23 | // {
24 | // id: 114,
25 | // title: '1-1-4'
26 | // }
27 | ]
28 | },
29 | {
30 | id: 12,
31 | title: '1-2',
32 | children: [
33 | {
34 | id: 121,
35 | title: '1-2-1'
36 | }
37 | ]
38 | }
39 | ]
40 | }
41 | ]
42 |
43 | export const newTreeData = [
44 | {
45 | id: 'a',
46 | title: 'a',
47 | children: [
48 | {
49 | id: 'a1',
50 | title: 'a-1',
51 | children: [
52 | {
53 | id: 112,
54 | title: '1-1-2'
55 | },
56 | {
57 | id: 'a12',
58 | title: 'a-1-2'
59 | },
60 | {
61 | id: 'a13',
62 | title: 'a-1-3'
63 | },
64 | {
65 | id: 'a14',
66 | title: 'a-1-4'
67 | }
68 | ]
69 | },
70 | {
71 | id: 'a2',
72 | title: 'a-2',
73 | children: [
74 | {
75 | id: 'a21',
76 | title: 'b-2-1'
77 | }
78 | ]
79 | }
80 | ]
81 | }
82 | ]
83 |
--------------------------------------------------------------------------------
/src/components/main/main.less:
--------------------------------------------------------------------------------
1 | .main{
2 | .logo-con{
3 | height: 64px;
4 | padding: 10px;
5 | img{
6 | height: 44px;
7 | width: auto;
8 | display: block;
9 | margin: 0 auto;
10 | }
11 | }
12 | .header-con{
13 | background: #fff;
14 | padding: 0 20px;
15 | width: 100%;
16 | }
17 | .main-layout-con{
18 | height: 100%;
19 | overflow: hidden;
20 | }
21 | .main-content-con{
22 | height: ~"calc(100% - 60px)";
23 | overflow: hidden;
24 | }
25 | .tag-nav-wrapper{
26 | padding: 0;
27 | height:40px;
28 | background:#F0F0F0;
29 | }
30 | .content-wrapper{
31 | padding: 18px;
32 | height: ~"calc(100% - 80px)";
33 | overflow: auto;
34 | }
35 | .left-sider{
36 | .ivu-layout-sider-children{
37 | overflow-y: scroll;
38 | margin-right: -18px;
39 | }
40 | }
41 | }
42 | .ivu-menu-item > i{
43 | margin-right: 12px !important;
44 | }
45 | .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
46 | margin-right: 8px !important;
47 | }
48 | .collased-menu-dropdown{
49 | width: 100%;
50 | margin: 0;
51 | line-height: normal;
52 | padding: 7px 0 6px 16px;
53 | clear: both;
54 | font-size: 12px !important;
55 | white-space: nowrap;
56 | list-style: none;
57 | cursor: pointer;
58 | transition: background 0.2s ease-in-out;
59 | &:hover{
60 | background: rgba(100, 100, 100, 0.1);
61 | }
62 | & * {
63 | color: #515a6e;
64 | }
65 | .ivu-menu-item > i{
66 | margin-right: 12px !important;
67 | }
68 | .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
69 | margin-right: 8px !important;
70 | }
71 | }
72 |
73 | .ivu-select-dropdown.ivu-dropdown-transfer{
74 | max-height: 400px;
75 | }
76 |
--------------------------------------------------------------------------------
/src/view/update/update-table.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 上传Csv文件
7 | 点击上传Csv文件
8 |
9 | util.js提供两个方法用来实现这个功能:
10 | getArrayFromFile :将Csv文件解析为二维数组
11 | getTableDataFromArray :将二维数组转为表格数据,具体请看文档
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
47 |
48 |
56 |
--------------------------------------------------------------------------------
/src/components/charts/pie.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
71 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import routes from './routers'
4 | import store from '@/store'
5 | import iView from 'iview'
6 | import { setToken, getToken, canTurnTo, setTitle } from '@/libs/util'
7 | import config from '@/config'
8 | const { homeName } = config
9 |
10 | Vue.use(Router)
11 | const router = new Router({
12 | routes,
13 | mode: 'history'
14 | })
15 | const LOGIN_PAGE_NAME = 'login'
16 |
17 | const turnTo = (to, access, next) => {
18 | if (canTurnTo(to.name, access, routes)) next() // 有权限,可访问
19 | else next({ replace: true, name: 'error_401' }) // 无权限,重定向到401页面
20 | }
21 |
22 | router.beforeEach((to, from, next) => {
23 | iView.LoadingBar.start()
24 | const token = getToken()
25 | if (!token && to.name !== LOGIN_PAGE_NAME) {
26 | // 未登录且要跳转的页面不是登录页
27 | next({
28 | name: LOGIN_PAGE_NAME // 跳转到登录页
29 | })
30 | } else if (!token && to.name === LOGIN_PAGE_NAME) {
31 | // 未登陆且要跳转的页面是登录页
32 | next() // 跳转
33 | } else if (token && to.name === LOGIN_PAGE_NAME) {
34 | // 已登录且要跳转的页面是登录页
35 | next({
36 | name: homeName // 跳转到homeName页
37 | })
38 | } else {
39 | if (store.state.user.hasGetInfo) {
40 | turnTo(to, store.state.user.access, next)
41 | } else {
42 | store.dispatch('getUserInfo').then(user => {
43 | // 拉取用户信息,通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组,如:['super_admin'] ['super_admin', 'admin']
44 | turnTo(to, user.access, next)
45 | }).catch(() => {
46 | setToken('')
47 | next({
48 | name: 'login'
49 | })
50 | })
51 | }
52 | }
53 | })
54 |
55 | router.afterEach(to => {
56 | setTitle(to, router.app)
57 | iView.LoadingBar.finish()
58 | window.scrollTo(0, 0)
59 | })
60 |
61 | export default router
62 |
--------------------------------------------------------------------------------
/src/components/drag-drawer/index.less:
--------------------------------------------------------------------------------
1 | @prefix: ~"drag-drawer";
2 | @drag-drawer-trigger-height: 100px;
3 | @drag-drawer-trigger-width: 8px;
4 |
5 | .@{prefix}-wrapper{
6 | &.no-select{
7 | user-select: none;
8 | }
9 | &.pointer-events-none{
10 | pointer-events: none;
11 | & .@{prefix}-trigger-wrapper{
12 | pointer-events: all;
13 | }
14 | }
15 | .ivu-drawer{
16 | &-header{
17 | overflow: hidden !important;
18 | box-sizing: border-box;
19 | }
20 | &-body{
21 | padding: 0;
22 | overflow: visible;
23 | position: static;
24 | display: flex;
25 | flex-direction: column;
26 | }
27 | }
28 | .@{prefix}-body-wrapper{
29 | width: 100%;
30 | height: 100%;
31 | padding: 16px;
32 | overflow: auto;
33 | }
34 | .@{prefix}-trigger-wrapper{
35 | top: 0;
36 | height: 100%;
37 | width: 0;
38 | .@{prefix}-move-trigger{
39 | position: absolute;
40 | top: 50%;
41 | height: @drag-drawer-trigger-height;
42 | width: @drag-drawer-trigger-width;
43 | background: rgb(243, 243, 243);
44 | transform: translate(-50%, -50%);
45 | border-radius: ~"4px / 6px";
46 | box-shadow: 0 0 1px 1px rgba(0, 0, 0, .2);
47 | line-height: @drag-drawer-trigger-height;
48 | cursor: col-resize;
49 | &-point{
50 | display: inline-block;
51 | width: 50%;
52 | transform: translateX(50%);
53 | i{
54 | display: block;
55 | border-bottom: 1px solid rgb(192, 192, 192);
56 | padding-bottom: 2px;
57 | }
58 | }
59 | }
60 | }
61 | .@{prefix}-footer{
62 | flex-grow: 1;
63 | width: 100%;
64 | bottom: 0;
65 | left: 0;
66 | border-top: 1px solid #e8e8e8;
67 | padding: 10px 16px;
68 | background: #fff;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/mock/user.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { doCustomTimes } from '@/libs/util'
3 | const Random = Mock.Random
4 |
5 | export const getMessageInit = () => {
6 | let unreadList = []
7 | doCustomTimes(3, () => {
8 | unreadList.push(Mock.mock({
9 | title: Random.cword(10, 15),
10 | create_time: '@date',
11 | msg_id: Random.increment(100)
12 | }))
13 | })
14 | let readedList = []
15 | doCustomTimes(4, () => {
16 | readedList.push(Mock.mock({
17 | title: Random.cword(10, 15),
18 | create_time: '@date',
19 | msg_id: Random.increment(100)
20 | }))
21 | })
22 | let trashList = []
23 | doCustomTimes(2, () => {
24 | trashList.push(Mock.mock({
25 | title: Random.cword(10, 15),
26 | create_time: '@date',
27 | msg_id: Random.increment(100)
28 | }))
29 | })
30 | return {
31 | unread: unreadList,
32 | readed: readedList,
33 | trash: trashList
34 | }
35 | }
36 |
37 | export const getContentByMsgId = () => {
38 | return ` 这是消息内容,这个内容是使用富文本编辑器 编辑的,所以你可以看到一些格式
你可以查看Mock返回的数据格式,和api请求的接口,来确定你的后端接口的开发 使用你的真实接口后,前端页面基本不需要修改即可满足基本需求 快来试试吧 ${Random.csentence(100, 200)}
`
39 | }
40 |
41 | export const hasRead = () => {
42 | return true
43 | }
44 |
45 | export const removeReaded = () => {
46 | return true
47 | }
48 |
49 | export const restoreTrash = () => {
50 | return true
51 | }
52 |
53 | export const messageCount = () => {
54 | return 3
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/editor/editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
70 |
71 |
76 |
--------------------------------------------------------------------------------
/src/components/login-form/login-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
73 |
--------------------------------------------------------------------------------
/src/view/components/icons/icons.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <Icons :size="30" type="{{ item }}">
9 | <CommonIcon :size="30" type="_{{ item }}">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | iView内置图标
18 | <CommonIcon :size="30" type="ionic">
19 |
20 |
21 |
22 |
23 |
24 |
25 | Icons组件支持自定义图标的显示,具体自定义图标字体文件的制作请参考文档。
26 | CommonIcon组件同时支持iView内置图标类型和自定义图标类型,为了区别这两种类型,需要在自定义图标名称前加下划线"_"
27 |
28 |
29 |
30 |
31 |
32 |
55 |
56 |
64 |
--------------------------------------------------------------------------------
/src/components/markdown/markdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
63 |
64 |
77 |
--------------------------------------------------------------------------------
/src/view/excel/export-excel.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | 导出文件
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
82 |
--------------------------------------------------------------------------------
/src/view/tools-methods/tools-methods.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 添加一个标签
7 |
8 |
9 | 动态路由,添加params
10 |
11 |
12 |
13 |
14 |
15 |
16 | 添加一个标签
17 |
18 |
19 | 动态路由,添加query
20 |
21 |
22 |
23 |
24 |
25 |
26 | 关闭工具方法页
27 |
28 |
29 | 手动关闭页面
30 |
31 |
32 |
33 |
34 |
35 |
36 |
78 |
79 |
82 |
--------------------------------------------------------------------------------
/src/components/info-card/infor-card.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 |
16 |
55 |
56 |
95 |
--------------------------------------------------------------------------------
/src/view/components/org-tree/index.less:
--------------------------------------------------------------------------------
1 | @wrapper: ~'department';
2 | .percent-100 {
3 | width: 100%;
4 | height: 100%;
5 | }
6 | .@{wrapper}-outer {
7 | .percent-100;
8 | overflow: hidden;
9 | .tip-box{
10 | position: absolute;
11 | left: 20px;
12 | top: 20px;
13 | z-index: 12;
14 | }
15 | .zoom-box {
16 | position: absolute;
17 | right: 30px;
18 | bottom: 30px;
19 | z-index: 2;
20 | }
21 | .view-box {
22 | position: absolute;
23 | top: 0;
24 | bottom: 0;
25 | left: 0;
26 | right: 0;
27 | z-index: 1;
28 | cursor: move;
29 | .org-tree-drag-wrapper {
30 | width: 100%;
31 | height: 100%;
32 | }
33 | .org-tree-wrapper {
34 | display: inline-block;
35 | position: absolute;
36 | left: 50%;
37 | top: 50%;
38 | transition: transform 0.2s ease-out;
39 | .org-tree-node-label {
40 | box-shadow: 0px 2px 12px 0px rgba(143, 154, 165, 0.4);
41 | border-radius: 4px;
42 | .org-tree-node-label-inner {
43 | padding: 0;
44 | .custom-org-node {
45 | padding: 14px 41px;
46 | background: #738699;
47 | user-select: none;
48 | word-wrap: none;
49 | white-space: nowrap;
50 | border-radius: 4px;
51 | color: #ffffff;
52 | font-size: 14px;
53 | font-weight: 500;
54 | line-height: 20px;
55 | transition: background 0.1s ease-in;
56 | cursor: default;
57 | &:hover {
58 | background: #5d6c7b;
59 | transition: background 0.1s ease-in;
60 | }
61 | &.has-children-label {
62 | cursor: pointer;
63 | }
64 | .context-menu{
65 | position: absolute;
66 | right: -10px;
67 | bottom: 20px;
68 | z-index: 10;
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/view/components/tables/tables.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 导出为Csv文件
6 |
7 |
8 |
9 |
10 |
68 |
69 |
72 |
--------------------------------------------------------------------------------
/src/view/update/update-paste.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 | 使用Tab键换列,使用回车键换行
10 | 显示表格数据
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
62 |
63 |
78 |
--------------------------------------------------------------------------------
/src/view/components/org-tree/components/zoom-controller.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ value }}%
7 |
8 |
9 |
10 |
11 |
12 |
13 |
48 |
49 |
82 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "iview-admin",
3 | "version": "2.0.0",
4 | "author": "Lison",
5 | "private": false,
6 | "scripts": {
7 | "dev": "vue-cli-service serve --open",
8 | "build": "vue-cli-service build",
9 | "lint": "vue-cli-service lint",
10 | "test:unit": "vue-cli-service test:unit",
11 | "test:e2e": "vue-cli-service test:e2e"
12 | },
13 | "dependencies": {
14 | "axios": "^0.18.0",
15 | "clipboard": "^2.0.0",
16 | "codemirror": "^5.38.0",
17 | "countup": "^1.8.2",
18 | "cropperjs": "^1.2.2",
19 | "dayjs": "^1.7.7",
20 | "echarts": "^4.0.4",
21 | "html2canvas": "^1.0.0-alpha.12",
22 | "iview": "^3.2.2",
23 | "iview-area": "^1.5.17",
24 | "js-cookie": "^2.2.0",
25 | "simplemde": "^1.11.2",
26 | "sortablejs": "^1.7.0",
27 | "tree-table-vue": "^1.1.0",
28 | "v-org-tree": "^1.0.6",
29 | "vue": "^2.5.10",
30 | "vue-i18n": "^7.8.0",
31 | "vue-router": "^3.0.1",
32 | "vuedraggable": "^2.16.0",
33 | "vuex": "^3.0.1",
34 | "wangeditor": "^3.1.1",
35 | "xlsx": "^0.13.3"
36 | },
37 | "devDependencies": {
38 | "@vue/cli-plugin-babel": "^3.0.1",
39 | "@vue/cli-plugin-eslint": "^3.0.1",
40 | "@vue/cli-plugin-unit-mocha": "^3.0.1",
41 | "@vue/cli-service": "^3.0.1",
42 | "@vue/eslint-config-standard": "^3.0.0-beta.10",
43 | "@vue/test-utils": "^1.0.0-beta.10",
44 | "chai": "^4.1.2",
45 | "eslint-plugin-cypress": "^2.0.1",
46 | "less": "^2.7.3",
47 | "less-loader": "^4.0.5",
48 | "lint-staged": "^6.0.0",
49 | "mockjs": "^1.0.1-beta3",
50 | "vue-template-compiler": "^2.5.13"
51 | },
52 | "browserslist": [
53 | "> 1%",
54 | "last 2 versions",
55 | "not ie <= 8"
56 | ],
57 | "gitHooks": {
58 | "pre-commit": "lint-staged"
59 | },
60 | "lint-staged": {
61 | "*.js": [
62 | "vue-cli-service lint",
63 | "git add"
64 | ],
65 | "*.vue": [
66 | "vue-cli-service lint",
67 | "git add"
68 | ]
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/view/components/split-pane/split-pane.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
40 |
41 |
80 |
--------------------------------------------------------------------------------
/src/view/components/org-tree/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
74 |
75 |
77 |
--------------------------------------------------------------------------------
/src/components/main/components/tags-nav/tags-nav.less:
--------------------------------------------------------------------------------
1 | .no-select{
2 | -webkit-touch-callout: none;
3 | -webkit-user-select: none;
4 | -khtml-user-select: none;
5 | -moz-user-select: none;
6 | -ms-user-select: none;
7 | user-select: none;
8 | }
9 | .size{
10 | width: 100%;
11 | height: 100%;
12 | }
13 | .tags-nav{
14 | position: relative;
15 | border-top: 1px solid #F0F0F0;
16 | border-bottom: 1px solid #F0F0F0;
17 | .no-select;
18 | .size;
19 | .close-con{
20 | position: absolute;
21 | right: 0;
22 | top: 0;
23 | height: 100%;
24 | width: 32px;
25 | background: #fff;
26 | text-align: center;
27 | z-index: 10;
28 | }
29 | .btn-con{
30 | position: absolute;
31 | top: 0px;
32 | height: 100%;
33 | background: #fff;
34 | padding-top: 3px;
35 | z-index: 10;
36 | button{
37 | padding: 6px 4px;
38 | line-height: 14px;
39 | text-align: center;
40 | }
41 | &.left-btn{
42 | left: 0px;
43 | }
44 | &.right-btn{
45 | right: 32px;
46 | border-right: 1px solid #F0F0F0;
47 | }
48 | }
49 | .scroll-outer{
50 | position: absolute;
51 | left: 28px;
52 | right: 61px;
53 | top: 0;
54 | bottom: 0;
55 | box-shadow: 0px 0 3px 2px rgba(100,100,100,.1) inset;
56 | .scroll-body{
57 | height: ~"calc(100% - 1px)";
58 | display: inline-block;
59 | padding: 1px 4px 0;
60 | position: absolute;
61 | overflow: visible;
62 | white-space: nowrap;
63 | transition: left .3s ease;
64 | .ivu-tag-dot-inner{
65 | transition: background .2s ease;
66 | }
67 | }
68 | }
69 | .contextmenu {
70 | position: absolute;
71 | margin: 0;
72 | padding: 5px 0;
73 | background: #fff;
74 | z-index: 1000;
75 | list-style-type: none;
76 | border-radius: 4px;
77 | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .1);
78 | li {
79 | margin: 0;
80 | padding: 5px 15px;
81 | cursor: pointer;
82 | &:hover {
83 | background: #eee;
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/components/tables/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ value }}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
45 |
46 |
74 |
--------------------------------------------------------------------------------
/src/view/join-page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | QQ 群号:621780943
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | iView 知乎专栏
19 |
20 |
21 |
22 | 掘金
23 |
24 |
25 |
26 | 活动直播间
27 |
28 |
29 |
30 | Twitter
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
48 |
67 |
--------------------------------------------------------------------------------
/src/libs/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import store from '@/store'
3 | // import { Spin } from 'iview'
4 | const addErrorLog = errorInfo => {
5 | const { statusText, status, request: { responseURL } } = errorInfo
6 | let info = {
7 | type: 'ajax',
8 | code: status,
9 | mes: statusText,
10 | url: responseURL
11 | }
12 | if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
13 | }
14 |
15 | class HttpRequest {
16 | constructor (baseUrl = baseURL) {
17 | this.baseUrl = baseUrl
18 | this.queue = {}
19 | }
20 | getInsideConfig () {
21 | const config = {
22 | baseURL: this.baseUrl,
23 | headers: {
24 | //
25 | }
26 | }
27 | return config
28 | }
29 | destroy (url) {
30 | delete this.queue[url]
31 | if (!Object.keys(this.queue).length) {
32 | // Spin.hide()
33 | }
34 | }
35 | interceptors (instance, url) {
36 | // 请求拦截
37 | instance.interceptors.request.use(config => {
38 | // 添加全局的loading...
39 | if (!Object.keys(this.queue).length) {
40 | // Spin.show() // 不建议开启,因为界面不友好
41 | }
42 | this.queue[url] = true
43 | return config
44 | }, error => {
45 | return Promise.reject(error)
46 | })
47 | // 响应拦截
48 | instance.interceptors.response.use(res => {
49 | this.destroy(url)
50 | const { data, status } = res
51 | return { data, status }
52 | }, error => {
53 | this.destroy(url)
54 | let errorInfo = error.response
55 | if (!errorInfo) {
56 | const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))
57 | errorInfo = {
58 | statusText,
59 | status,
60 | request: { responseURL: config.url }
61 | }
62 | }
63 | addErrorLog(errorInfo)
64 | return Promise.reject(error)
65 | })
66 | }
67 | request (options) {
68 | const instance = axios.create()
69 | options = Object.assign(this.getInsideConfig(), options)
70 | this.interceptors(instance, options.url)
71 | return instance(options)
72 | }
73 | }
74 | export default HttpRequest
75 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/collapsed-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
52 |
--------------------------------------------------------------------------------
/src/components/paste-editor/plugins/placeholder.js:
--------------------------------------------------------------------------------
1 | export default (codemirror) => {
2 | (function (mod) {
3 | mod(codemirror)
4 | })(function (CodeMirror) {
5 | CodeMirror.defineOption('placeholder', '', function (cm, val, old) {
6 | var prev = old && old !== CodeMirror.Init
7 | if (val && !prev) {
8 | cm.on('blur', onBlur)
9 | cm.on('change', onChange)
10 | cm.on('swapDoc', onChange)
11 | onChange(cm)
12 | } else if (!val && prev) {
13 | cm.off('blur', onBlur)
14 | cm.off('change', onChange)
15 | cm.off('swapDoc', onChange)
16 | clearPlaceholder(cm)
17 | var wrapper = cm.getWrapperElement()
18 | wrapper.className = wrapper.className.replace(' CodeMirror-empty', '')
19 | }
20 |
21 | if (val && !cm.hasFocus()) onBlur(cm)
22 | })
23 |
24 | function clearPlaceholder (cm) {
25 | if (cm.state.placeholder) {
26 | cm.state.placeholder.parentNode.removeChild(cm.state.placeholder)
27 | cm.state.placeholder = null
28 | }
29 | }
30 | function setPlaceholder (cm) {
31 | clearPlaceholder(cm)
32 | var elt = cm.state.placeholder = document.createElement('pre')
33 | elt.style.cssText = 'height: 0; overflow: visible; color: #80848f;'
34 | elt.style.direction = cm.getOption('direction')
35 | elt.className = 'CodeMirror-placeholder'
36 | var placeHolder = cm.getOption('placeholder')
37 | if (typeof placeHolder === 'string') placeHolder = document.createTextNode(placeHolder)
38 | elt.appendChild(placeHolder)
39 | cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild)
40 | }
41 |
42 | function onBlur (cm) {
43 | if (isEmpty(cm)) setPlaceholder(cm)
44 | }
45 | function onChange (cm) {
46 | let wrapper = cm.getWrapperElement()
47 | let empty = isEmpty(cm)
48 | wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') + (empty ? ' CodeMirror-empty' : '')
49 |
50 | if (empty) setPlaceholder(cm)
51 | else clearPlaceholder(cm)
52 | }
53 |
54 | function isEmpty (cm) {
55 | return (cm.lineCount() === 1) && (cm.getLine(0) === '')
56 | }
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/src/view/single-page/error-logger.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
导出日志记录
4 |
注:这里只会显示成功保存到服务端的错误日志,而且页面错误日志不会在浏览器持久化存储,刷新页面即会丢失
5 |
6 |
7 |
8 |
9 |
88 |
89 |
92 |
--------------------------------------------------------------------------------
/src/view/components/tree-select/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 | 更新选中数据
16 | 更新树数据
17 |
18 |
19 |
20 |
87 |
88 |
91 |
--------------------------------------------------------------------------------
/src/components/main/components/a-back-top/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
91 |
--------------------------------------------------------------------------------
/src/view/single-page/home/home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ infor.title }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
78 |
79 |
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | iView Admin
9 | Vue.js 2.0 admin management system template based on iView.
10 |
11 |
12 | [](https://github.com/iview/iview-admin/releases)
13 | [](https://travis-ci.org/iview/iview-admin)
14 | [](https://github.com/vuejs/vue)
15 | [](https://github.com/iview/iview)
16 | []()
17 |
18 | ## Introduction
19 |
20 | iView Admin is a front-end management background integration solution. It based on [Vue.js](https://github.com/vuejs/vue) and use the UI Toolkit [iView](https://github.com/iview/iview).
21 |
22 | - [Document](https://lison16.github.io/iview-admin-doc/)
23 | - [Preview](https://admin.iviewui.com/)
24 | - [Base template recommends using](https://github.com/iview/iview-admin/tree/template)
25 |
26 | 
27 |
28 | ## Features
29 |
30 | - Login / Logout
31 | - Permission Authentication
32 | - A list of filters
33 | - Permission to switch
34 | - i18n
35 | - Components
36 | - Rich Text Editor
37 | - Markdown Editor
38 | - City Cascader
39 | - Photos preview and edit
40 | - Draggable list
41 | - File upload
42 | - Digital gradient
43 | - split-pane
44 | - Form
45 | - The article published
46 | - Workflow
47 | - Table
48 | - Drag-and-drop sort
49 | - Searchable form
50 | - Table export data
51 | - Export to Csv file
52 | - Export to Xls file
53 | - Table to picture
54 | - Error Page
55 | - 403
56 | - 404
57 | - 500
58 | - Router
59 | - Dynamic routing
60 | - With reference page
61 | - Theme
62 | - Shrink the sidebar
63 | - Tag navigation
64 | - Breadcrumb navigation
65 | - Full screen / exit full screen
66 | - Lock screen
67 | - The message center
68 | - Personal center
69 |
70 | ## Getting started
71 | ```bush
72 | # clone the project
73 | git clone https://github.com/iview/iview-admin.git
74 |
75 | // install dependencies
76 | npm install
77 |
78 | // develop
79 | npm run dev
80 | ```
81 |
82 | ## Build
83 | ```bush
84 | npm run build
85 | ```
86 |
87 | ## License
88 | [MIT](http://opensource.org/licenses/MIT)
89 |
90 | Copyright (c) 2016-present, TalkingData
91 |
--------------------------------------------------------------------------------
/src/components/main/components/fullscreen/fullscreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
75 |
76 |
85 |
--------------------------------------------------------------------------------
/src/components/drag-list/drag-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ itemLeft }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{ itemRight }}
16 |
17 |
18 |
19 |
20 |
21 |
84 |
93 |
--------------------------------------------------------------------------------
/src/view/components/drag-drawer/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | drag-drawer组件是对iview的drawer组件的封装,在支持drawer所有api的基础上,支持可拖动和footer底部插槽
4 |
5 |
6 | 方向
7 |
8 | 左
9 | 右
10 |
11 |
12 |
13 | 是否可拖动
14 |
15 |
16 | {{ showContainerBDrawer ? '关闭' : '打开' }}容器内抽屉
17 | 打开全屏抽屉
18 |
19 |
20 |
29 |
30 |
31 | 这是标题
32 |
33 | {{ n }}
34 |
35 |
123123
36 |
21312
37 |
38 |
39 |
40 |
46 |
47 |
48 | 这是标题
49 |
50 | 显示多层
51 | {{ n }}
52 |
53 |
54 |
55 |
56 |
88 |
89 |
98 |
--------------------------------------------------------------------------------
/src/view/single-page/home/example.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
115 |
--------------------------------------------------------------------------------
/src/view/components/drag-list/drag-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 待办事项
9 | {{ left.itemLeft.name }}
10 | 完成事项
11 | {{ right.itemRight.name }}
12 |
13 |
14 |
15 |
21 |
24 |
27 |
28 |
29 |
30 |
62 |
114 |
--------------------------------------------------------------------------------
/src/assets/images/icon-social-twitter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/split-pane/index.less:
--------------------------------------------------------------------------------
1 | @split-prefix-cls: ~"ivu-split";
2 | @box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.4);
3 | @trigger-bar-background: rgba(23, 35, 61, 0.25);
4 | @trigger-background: #F8F8F9;
5 | @trigger-width: 6px;
6 | @trigger-bar-width: 4px;
7 | @trigger-bar-offset: (@trigger-width - @trigger-bar-width) / 2;
8 | @trigger-bar-interval: 3px;
9 | @trigger-bar-weight: 1px;
10 | @trigger-bar-con-height: (@trigger-bar-weight + @trigger-bar-interval) * 8;
11 |
12 | .@{split-prefix-cls}{
13 | &-wrapper{
14 | position: relative;
15 | width: 100%;
16 | height: 100%;
17 | }
18 | &-pane{
19 | position: absolute;
20 | &.left-pane, &.right-pane{
21 | top: 0px;
22 | bottom: 0px;
23 | }
24 | &.left-pane{
25 | left: 0px;
26 | }
27 | &.right-pane{
28 | right: 0px;
29 | }
30 | &.top-pane, &.bottom-pane{
31 | left: 0px;
32 | right: 0px;
33 | }
34 | &.top-pane{
35 | top: 0px;
36 | }
37 | &.bottom-pane{
38 | bottom: 0px;
39 | }
40 | }
41 | &-trigger{
42 | &-con{
43 | position: absolute;
44 | transform: translate(-50%, -50%);
45 | z-index: 10;
46 | }
47 | &-bar-con{
48 | position: absolute;
49 | overflow: hidden;
50 | &.vertical{
51 | left: @trigger-bar-offset;
52 | top: 50%;
53 | height: @trigger-bar-con-height;
54 | transform: translate(0, -50%);
55 | }
56 | &.horizontal{
57 | left: 50%;
58 | top: @trigger-bar-offset;
59 | width: @trigger-bar-con-height;
60 | transform: translate(-50%, 0);
61 | }
62 | }
63 | &-vertical{
64 | width: @trigger-width;
65 | height: 100%;
66 | background: @trigger-background;
67 | box-shadow: @box-shadow;
68 | cursor: col-resize;
69 | .@{split-prefix-cls}-trigger-bar{
70 | width: @trigger-bar-width;
71 | height: 1px;
72 | background: @trigger-bar-background;
73 | float: left;
74 | margin-top: @trigger-bar-interval;
75 | }
76 | }
77 | &-horizontal{
78 | height: @trigger-width;
79 | width: 100%;
80 | background: @trigger-background;
81 | box-shadow: @box-shadow;
82 | cursor: row-resize;
83 | .@{split-prefix-cls}-trigger-bar{
84 | height: @trigger-bar-width;
85 | width: 1px;
86 | background: @trigger-bar-background;
87 | float: left;
88 | margin-right: @trigger-bar-interval;
89 | }
90 | }
91 | }
92 | &-horizontal{
93 | .@{split-prefix-cls}-trigger-con{
94 | top: 50%;
95 | height: 100%;
96 | width: 0;
97 | }
98 | }
99 | &-vertical{
100 | .@{split-prefix-cls}-trigger-con{
101 | left: 50%;
102 | height: 0;
103 | width: 100%;
104 | }
105 | }
106 | .no-select{
107 | -webkit-touch-callout: none;
108 | -webkit-user-select: none;
109 | -khtml-user-select: none;
110 | -moz-user-select: none;
111 | -ms-user-select: none;
112 | user-select: none;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/view/directive/directive.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 显示可拖动弹窗
9 |
10 | 这个按钮也是可以拖动的
11 |
12 |
13 |
14 | <Modal v-draggable="options" v-model="visible">标题</Modal>
15 |
16 | options = {
17 | trigger: '.ivu-modal-body',
18 | body: '.ivu-modal'
19 | }
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 拖动这里即可拖动整个弹窗
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | copy
37 |
38 |
39 |
40 |
41 | <Input style="width: 60%" v-model="inputValue">
42 |
43 | <Button slot="append" v-clipboard="clipOptions">copy</Button>
44 |
45 | </Input>
46 |
47 | clipOptions: {
48 | value: this.inputValue,
49 | success: (e) => {
50 | this.$Message.success('复制成功')
51 | },
52 | error: () => {
53 | this.$Message.error('复制失败')
54 | }
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 拖动这里即可拖动整个弹窗
64 |
65 |
66 |
67 |
68 |
69 |
108 |
109 |
122 |
--------------------------------------------------------------------------------
/src/components/paste-editor/paste-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
113 |
116 |
--------------------------------------------------------------------------------
/src/store/module/app.js:
--------------------------------------------------------------------------------
1 | import {
2 | getBreadCrumbList,
3 | setTagNavListInLocalstorage,
4 | getMenuByRouter,
5 | getTagNavListFromLocalstorage,
6 | getHomeRoute,
7 | getNextRoute,
8 | routeHasExist,
9 | routeEqual,
10 | getRouteTitleHandled,
11 | localSave,
12 | localRead
13 | } from '@/libs/util'
14 | import { saveErrorLogger } from '@/api/data'
15 | import router from '@/router'
16 | import routers from '@/router/routers'
17 | import config from '@/config'
18 | const { homeName } = config
19 |
20 | const closePage = (state, route) => {
21 | const nextRoute = getNextRoute(state.tagNavList, route)
22 | state.tagNavList = state.tagNavList.filter(item => {
23 | return !routeEqual(item, route)
24 | })
25 | router.push(nextRoute)
26 | }
27 |
28 | export default {
29 | state: {
30 | breadCrumbList: [],
31 | tagNavList: [],
32 | homeRoute: {},
33 | local: localRead('local'),
34 | errorList: [],
35 | hasReadErrorPage: false
36 | },
37 | getters: {
38 | menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access),
39 | errorCount: state => state.errorList.length
40 | },
41 | mutations: {
42 | setBreadCrumb (state, route) {
43 | state.breadCrumbList = getBreadCrumbList(route, state.homeRoute)
44 | },
45 | setHomeRoute (state, routes) {
46 | state.homeRoute = getHomeRoute(routes, homeName)
47 | },
48 | setTagNavList (state, list) {
49 | let tagList = []
50 | if (list) {
51 | tagList = [...list]
52 | } else tagList = getTagNavListFromLocalstorage() || []
53 | if (tagList[0] && tagList[0].name !== homeName) tagList.shift()
54 | let homeTagIndex = tagList.findIndex(item => item.name === homeName)
55 | if (homeTagIndex > 0) {
56 | let homeTag = tagList.splice(homeTagIndex, 1)[0]
57 | tagList.unshift(homeTag)
58 | }
59 | state.tagNavList = tagList
60 | setTagNavListInLocalstorage([...tagList])
61 | },
62 | closeTag (state, route) {
63 | let tag = state.tagNavList.filter(item => routeEqual(item, route))
64 | route = tag[0] ? tag[0] : null
65 | if (!route) return
66 | closePage(state, route)
67 | },
68 | addTag (state, { route, type = 'unshift' }) {
69 | let router = getRouteTitleHandled(route)
70 | if (!routeHasExist(state.tagNavList, router)) {
71 | if (type === 'push') state.tagNavList.push(router)
72 | else {
73 | if (router.name === homeName) state.tagNavList.unshift(router)
74 | else state.tagNavList.splice(1, 0, router)
75 | }
76 | setTagNavListInLocalstorage([...state.tagNavList])
77 | }
78 | },
79 | setLocal (state, lang) {
80 | localSave('local', lang)
81 | state.local = lang
82 | },
83 | addError (state, error) {
84 | state.errorList.push(error)
85 | },
86 | setHasReadErrorLoggerStatus (state, status = true) {
87 | state.hasReadErrorPage = status
88 | }
89 | },
90 | actions: {
91 | addErrorLog ({ commit, rootState }, info) {
92 | if (!window.location.href.includes('error_logger_page')) commit('setHasReadErrorLoggerStatus', false)
93 | const { user: { token, userId, userName } } = rootState
94 | let data = {
95 | ...info,
96 | time: Date.parse(new Date()),
97 | token,
98 | userId,
99 | userName
100 | }
101 | saveErrorLogger(info).then(() => {
102 | commit('addError', data)
103 | })
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/view/excel/upload-excel.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 | 上传文件
10 |
11 |
12 |
13 |
14 |
15 | {{ file.name }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 成功
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
115 |
--------------------------------------------------------------------------------
/src/components/tree-select/tree-select-tree.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/src/assets/icons/iconfont.css:
--------------------------------------------------------------------------------
1 |
2 | @font-face {font-family: "iconfont";
3 | src: url('iconfont.eot?t=1541579316141'); /* IE9*/
4 | src: url('iconfont.eot?t=1541579316141#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAiEAAsAAAAADmgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8eUnXY21hcAAAAYAAAACjAAACLi+YJuBnbHlmAAACJAAABAgAAAcg4dRWHmhlYWQAAAYsAAAAMQAAADYTL8piaGhlYQAABmAAAAAgAAAAJAfdA4xobXR4AAAGgAAAABQAAAAsLAD//2xvY2EAAAaUAAAAGAAAABgImgpGbWF4cAAABqwAAAAfAAAAIAEcAG5uYW1lAAAGzAAAAUUAAAJtPlT+fXBvc3QAAAgUAAAAbgAAAI54roygeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeMTx/ytzwv4EhhrmBoRkozAiSAwDuUwzMeJzlkUEKwkAMRd/YabXFhQvxFF6qPYPrUujGY7jyIr1JoZNjtMnEhag3MOEN5MMk8D9QAoVyVSKEJwGrh6oh6wVN1iM3nc+cVImJVKdOehlklElmWdYVstp+ql8VdIv15a1NLW0zFXsO7Kjz3erH/3+rY37vr6kxnx1LKNWOJZlaxxJNnWOpSu+ot8jgqMvI6KjfyOSo88jsaAbI4tBsig89rQB4nLVUTWwbRRSeNzO767i2g7N/FP9s7MRrE5ON4/V6rSZyU0PiINSSNImES4IUoapWz6hEiqiMBDQqEojkAkiFStyKRC+9VSoFCeUEyqESVUAqEkcu3OAQb3hrJxAXwSGI3X0/szPz5vvm2x0i7O/vf8IJe5VkSJnUyUtklRBQJE1VIjRtUafkmk6pSu2ipleh4+xikkKxSksWTUeo8m8NoagpYtoslTmxrLl37z64e33esuJjU8P5Wd262LxoPVnPZ06Pxfe+C0YjkhSJygPhQCA8ABPOykwuN7NyuRvgUnAgLEnhATkaCQQiUe/7XKUyV6nQz+t2o7l66+rs7NVbq82GXTdrdjxjRGU5amTids2bUDMFtzCsqsMYMqr3IDY6OT05GjsI8Exv/6CSkOWEQigh+y3clxY5QVTcEZFIGtHLxDUJs6WsHR1y9SFKdr1HggCp3V1ICYL36OOpVmvKN9bC1u6R3vZ0qwWtVovgJfqOfUvfIYxIWL+fyETHNVJqSkIT1JTjW8ZWh3yDJDz0ctvsyt51etvrg9/QHhqGlzMM+vbmizPnDWPLMNbW19e7tffvsBzL99aWEfBRY46t+tbe3PypXv/IMDYN43WsQBe9HL2NC33RuxABrPsG+xH3o4bVRE2KgCRqulbWNf8W/UYVHM129aKra24VshZkq+CWD/Oy6Xt8cGYEthgHVlVliCfynAlqjo6oysTKlYUAD4docMI5/1ZioN+GwZNBcTwWUmTdBUqhTwX29QebXzF4An4JJMzwfMl+WQ01+IlQZVR4yhie53ycA16pOI/ODiYNGK4MChdCgXNnX5gIJXPCSYnf2OF850aQ+zJIyOs+u8+mMO8jQdwtg1TIWVRjKAnFcslMi8KfGUPoSUCergUyUk77dMyS69Ms6tijKZKYwUGKbpfdzu+iYeZYAHMFiOVi+MD7h9mb99qC0L7X8c+XatMfTj97KZ5IxJt/pd43tYYQKEjAnXMOB6kQEBrwg+LPjindAPOHNdC3q3ait0I3/ZIunZEARLNYNEUA6czSP3N/7j9wz6ZESdX0VNl1zGNS/szbQaQSIGk4DtVPcZf8AgXpf9A2OyTit5s2syZmand46bhEe2WtodLHkvaoqtTXuXN2/c42WADP9HGfbUcUW7JgqHss4xHtlMys679FqUomdP9VJBQBdnlPABBubpuNwqnmQj6/0HwNQzKxDUJFgKiXurBG6dqFjmeBzsvtRPJgGIZThYa5fdOvsReOticPh6JHHXxsv7ItJpOniYPYsmZ/x0QD/o5P105DeQwF6MH33ogoLi+KQp7zpY3HQV5bFMURzheXeds7gpP+jKNXljjHuYvXHke7cdCxLLZf6YX7B63UcCV4nGNgZGBgAOKAN2ZR8fw2Xxm4WRhA4AbHYRMY/f///1oWBuYGIJeDgQkkCgAvWgs2AAAAeJxjYGRgYG7438AQw8Lw/z8DAwsDA1AEBXADAHXiBHJ4nGNhYGBgYfj/nwVM48cATwECKwAAAAAAjAC6AOgBFAGAAf4CbgLqAzgDkHicY2BkYGDgZkhiYGcAASYg5gJCBob/YD4DABOmAYsAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicbYhdDoIwEAb3a6k/YIIX8VArWewmdJFWJOnpJTG+OQ+TzJCjLy39p4ODR4OAA4444YwWHS7U3IVzn6Voldtb8ksHnvohrlqjjmw1rmzXsvdT7fEbblnCmOfNfJIYStJJfGIL27yb6AOCGR89AAA=') format('woff'),
6 | url('iconfont.ttf?t=1541579316141') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
7 | url('iconfont.svg?t=1541579316141#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family:"iconfont" !important;
12 | font-size:16px;
13 | font-style:normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-bear:before { content: "\e600"; }
19 |
20 | .icon-resize-vertical:before { content: "\e7c3"; }
21 |
22 | .icon-chuizhifanzhuan:before { content: "\e661"; }
23 |
24 | .icon-shuipingfanzhuan:before { content: "\e662"; }
25 |
26 | .icon-qq:before { content: "\e609"; }
27 |
28 | .icon-frown:before { content: "\e77e"; }
29 |
30 | .icon-meh:before { content: "\e780"; }
31 |
32 | .icon-smile:before { content: "\e783"; }
33 |
34 | .icon-man:before { content: "\e7e2"; }
35 |
36 | .icon-woman:before { content: "\e7e5"; }
37 |
38 |
--------------------------------------------------------------------------------
/src/libs/excel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import XLSX from 'xlsx';
3 |
4 | function auto_width(ws, data){
5 | /*set worksheet max width per col*/
6 | const colWidth = data.map(row => row.map(val => {
7 | /*if null/undefined*/
8 | if (val == null) {
9 | return {'wch': 10};
10 | }
11 | /*if chinese*/
12 | else if (val.toString().charCodeAt(0) > 255) {
13 | return {'wch': val.toString().length * 2};
14 | } else {
15 | return {'wch': val.toString().length};
16 | }
17 | }))
18 | /*start in the first row*/
19 | let result = colWidth[0];
20 | for (let i = 1; i < colWidth.length; i++) {
21 | for (let j = 0; j < colWidth[i].length; j++) {
22 | if (result[j]['wch'] < colWidth[i][j]['wch']) {
23 | result[j]['wch'] = colWidth[i][j]['wch'];
24 | }
25 | }
26 | }
27 | ws['!cols'] = result;
28 | }
29 |
30 | function json_to_array(key, jsonData){
31 | return jsonData.map(v => key.map(j => { return v[j] }));
32 | }
33 |
34 | // fix data,return string
35 | function fixdata(data) {
36 | let o = ''
37 | let l = 0
38 | const w = 10240
39 | for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
40 | o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
41 | return o
42 | }
43 |
44 | // get head from excel file,return array
45 | function get_header_row(sheet) {
46 | const headers = []
47 | const range = XLSX.utils.decode_range(sheet['!ref'])
48 | let C
49 | const R = range.s.r /* start in the first row */
50 | for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
51 | var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
52 | var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
53 | if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
54 | headers.push(hdr)
55 | }
56 | return headers
57 | }
58 |
59 | export const export_table_to_excel= (id, filename) => {
60 | const table = document.getElementById(id);
61 | const wb = XLSX.utils.table_to_book(table);
62 | XLSX.writeFile(wb, filename);
63 |
64 | /* the second way */
65 | // const table = document.getElementById(id);
66 | // const wb = XLSX.utils.book_new();
67 | // const ws = XLSX.utils.table_to_sheet(table);
68 | // XLSX.utils.book_append_sheet(wb, ws, filename);
69 | // XLSX.writeFile(wb, filename);
70 | }
71 |
72 | export const export_json_to_excel = ({data, key, title, filename, autoWidth}) => {
73 | const wb = XLSX.utils.book_new();
74 | data.unshift(title);
75 | const ws = XLSX.utils.json_to_sheet(data, {header: key, skipHeader: true});
76 | if(autoWidth){
77 | const arr = json_to_array(key, data);
78 | auto_width(ws, arr);
79 | }
80 | XLSX.utils.book_append_sheet(wb, ws, filename);
81 | XLSX.writeFile(wb, filename + '.xlsx');
82 | }
83 |
84 | export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => {
85 | const wb = XLSX.utils.book_new();
86 | const arr = json_to_array(key, data);
87 | arr.unshift(title);
88 | const ws = XLSX.utils.aoa_to_sheet(arr);
89 | if(autoWidth){
90 | auto_width(ws, arr);
91 | }
92 | XLSX.utils.book_append_sheet(wb, ws, filename);
93 | XLSX.writeFile(wb, filename + '.xlsx');
94 | }
95 |
96 | export const read = (data, type) => {
97 | /* if type == 'base64' must fix data first */
98 | // const fixedData = fixdata(data)
99 | // const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
100 | const workbook = XLSX.read(data, { type: type });
101 | const firstSheetName = workbook.SheetNames[0];
102 | const worksheet = workbook.Sheets[firstSheetName];
103 | const header = get_header_row(worksheet);
104 | const results = XLSX.utils.sheet_to_json(worksheet);
105 | return {header, results};
106 | }
107 |
108 | export default {
109 | export_table_to_excel,
110 | export_array_to_excel,
111 | export_json_to_excel,
112 | read
113 | }
114 |
--------------------------------------------------------------------------------
/src/components/cropper/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
46 |
47 |
48 |
49 |
140 |
--------------------------------------------------------------------------------
/src/components/main/components/side-menu/side-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
112 |
115 |
--------------------------------------------------------------------------------
/src/components/count-to/count-to.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ init }} {{ unitText }}
5 |
6 |
7 |
8 |
9 |
175 |
--------------------------------------------------------------------------------
/src/components/drag-drawer/drag-drawer.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
41 |
42 |
43 |
44 |
45 |
46 |
157 |
--------------------------------------------------------------------------------
/src/view/components/org-tree/components/org-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
170 |
171 |
173 |
--------------------------------------------------------------------------------