lrf402788946 5 years ago
commit
6546fb716e
100 changed files with 10038 additions and 0 deletions
  1. 3 0
      .env
  2. 7 0
      .eslintignore
  3. 33 0
      .eslintrc.js
  4. 23 0
      .gitignore
  5. 6 0
      README.md
  6. 12 0
      babel.config.js
  7. 15 0
      config/index.js
  8. 3 0
      lib/layouts/README.md
  9. 33 0
      lib/layouts/bread.vue
  10. 136 0
      lib/layouts/frame.vue
  11. 34 0
      lib/layouts/litebar.vue
  12. 43 0
      lib/layouts/logo.vue
  13. 40 0
      lib/layouts/user.vue
  14. 1 0
      lib/plugins/README.md
  15. 22 0
      lib/plugins/axios.js
  16. 40 0
      lib/plugins/check-res.js
  17. 6 0
      lib/plugins/element.js
  18. 4 0
      lib/plugins/meta.js
  19. 10 0
      lib/plugins/mint-ui.js
  20. 26 0
      lib/plugins/naf-dict.js
  21. 65 0
      lib/plugins/stomp.js
  22. 17 0
      lib/store/naf/.dict.js
  23. 100 0
      lib/store/naf/dict.js
  24. 8 0
      lib/store/naf/index.js
  25. 35 0
      lib/style/index.less
  26. 56 0
      lib/style/lite.less
  27. 49 0
      lib/style/mixed.less
  28. 120 0
      lib/utils/axios-wrapper.js
  29. 18 0
      lib/utils/filters.js
  30. 124 0
      lib/utils/store.js
  31. 46 0
      lib/utils/user-util.js
  32. 25 0
      mock/menu/cms.js
  33. 72 0
      mock/menu/docflow.js
  34. 66 0
      mock/menu/index.js
  35. 123 0
      mock/menu/jobs.js
  36. 40 0
      mock/menu/link.js
  37. 42 0
      mock/menu/system.js
  38. 137 0
      naf/chart/tendency.vue
  39. 87 0
      naf/data/README.md
  40. 66 0
      naf/data/code-select.vue
  41. 96 0
      naf/data/demo-table.vue
  42. 148 0
      naf/data/filter-grid.vue
  43. 89 0
      naf/data/form-dlg.vue
  44. 102 0
      naf/data/form.vue
  45. 104 0
      naf/data/lite-grid.vue
  46. 128 0
      naf/data/meta-util.js
  47. 105 0
      naf/data/naf-table.vue
  48. 79 0
      naf/data/wang-editor.vue
  49. 12 0
      naf/error/403.vue
  50. 12 0
      naf/error/404.vue
  51. 12 0
      naf/error/500.vue
  52. 98 0
      naf/error/error-page.vue
  53. 33 0
      naf/frame/bread.vue
  54. 30 0
      naf/frame/footer.vue
  55. 125 0
      naf/frame/header/header-dropdown.vue
  56. 48 0
      naf/frame/header/index.vue
  57. 32 0
      naf/frame/header/litebar.vue
  58. 57 0
      naf/frame/header/logo.vue
  59. 44 0
      naf/frame/header/navbar.vue
  60. 42 0
      naf/frame/header/user.vue
  61. 64 0
      naf/frame/menu-item.vue
  62. 64 0
      naf/frame/sider.vue
  63. 32 0
      naf/layouts/footer-page.vue
  64. 31 0
      naf/layouts/scroll-page.vue
  65. 60 0
      naf/user/dept-tree.vue
  66. 151 0
      naf/user/user-select.vue
  67. 49 0
      package.json
  68. 0 0
      public/.gitkeep
  69. BIN
      public/favicon.ico
  70. 23 0
      public/index.html
  71. 370 0
      public/naf-icons/demo.css
  72. 850 0
      public/naf-icons/demo_fontclass.html
  73. 1143 0
      public/naf-icons/demo_symbol.html
  74. 888 0
      public/naf-icons/demo_unicode.html
  75. 287 0
      public/naf-icons/iconfont.css
  76. BIN
      public/naf-icons/iconfont.eot
  77. 1 0
      public/naf-icons/iconfont.js
  78. 431 0
      public/naf-icons/iconfont.svg
  79. BIN
      public/naf-icons/iconfont.ttf
  80. BIN
      public/naf-icons/iconfont.woff
  81. 69 0
      public/static/bg.svg
  82. BIN
      public/static/favicon.ico
  83. 508 0
      public/static/image1.svg
  84. 314 0
      public/static/image2.svg
  85. 208 0
      public/static/image3.svg
  86. BIN
      public/static/logo.png
  87. 1 0
      public/static/logo.svg
  88. 33 0
      src/App.vue
  89. 69 0
      src/assets/bg.svg
  90. BIN
      src/assets/home.png
  91. 314 0
      src/assets/image1.svg
  92. 208 0
      src/assets/image2.svg
  93. 508 0
      src/assets/image3.svg
  94. BIN
      src/assets/logo.png
  95. 1 0
      src/assets/logo.svg
  96. 1 0
      src/assets/logo1.svg
  97. 41 0
      src/main.js
  98. 59 0
      src/router.js
  99. 71 0
      src/store/index.js
  100. 0 0
      src/store/login.js

+ 3 - 0
.env

@@ -0,0 +1,3 @@
+VUE_APP_AXIOS_BASE_URL=/platform/api
+VUE_APP_ROUTER_MODE=history
+VUE_APP_ROOT_URL=/admin/

+ 7 - 0
.eslintignore

@@ -0,0 +1,7 @@
+/build/
+/build_bak/
+/config/
+/dist/
+/bak/
+/static/
+/node_modules/

+ 33 - 0
.eslintrc.js

@@ -0,0 +1,33 @@
+// https://eslint.org/docs/user-guide/configuring
+
+module.exports = {
+  root: true,
+  env: {
+    node: true,
+  },
+  extends: ['plugin:vue/essential', '@vue/prettier'],
+  plugins: ['vue'],
+  rules: {
+    'max-len': [
+      'warn',
+      {
+        code: 250,
+      },
+    ],
+    'no-unused-vars': 'off',
+    'no-console': 'off',
+    'prettier/prettier': [
+      'warn',
+      {
+        singleQuote: true,
+        trailingComma: 'es5',
+        bracketSpacing: true,
+        jsxBracketSameLine: true,
+        printWidth: 160,
+      },
+    ],
+  },
+  parserOptions: {
+    parser: 'babel-eslint',
+  },
+};

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+/dist
+package-lock.json
+.history
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*

+ 6 - 0
README.md

@@ -0,0 +1,6 @@
+# admin-frame
+
+后台管理页面框架
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 12 - 0
babel.config.js

@@ -0,0 +1,12 @@
+module.exports = {
+  presets: ['@vue/app'],
+  plugins: [
+    [
+      'component',
+      {
+        libraryName: 'element-ui',
+        styleLibraryName: 'theme-chalk',
+      },
+    ],
+  ],
+};

+ 15 - 0
config/index.js

@@ -0,0 +1,15 @@
+export default {
+  productName: '智慧就业',
+  shortName: '智慧就业',
+  rootName: '单位部门',
+  description: '业务综合管理平台',
+  copyright: '吉林省高等学校毕业生就业指导中心 版权所有 © 2018 ',
+  layout: {
+    breadHeight: '24px',
+    headerHeight: '64px',
+    footerHeight: '48px',
+    asideExpandWidth: '256px',
+    asideCollapseWidth: '64px',
+  },
+  pageSize: 10,
+};

+ 3 - 0
lib/layouts/README.md

@@ -0,0 +1,3 @@
+# 框架布局组件
+## 针对单一应用模块的布局框架
+## 包含页面头和左侧菜单

+ 33 - 0
lib/layouts/bread.vue

@@ -0,0 +1,33 @@
+<template>
+  <el-breadcrumb separator="/">
+    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+    <el-breadcrumb-item v-for="(item, index) in catalog" :key="index">{{ item }}</el-breadcrumb-item>
+  </el-breadcrumb>
+</template>
+<script>
+const DeepFind = (menus, path) => {
+  for (const k in menus) {
+    const item = menus[k];
+    //if (item.options.path == path) return menus[k];
+    if (path.endsWith(item.options.path)) return menus[k];
+    if (item.children) {
+      const res = DeepFind(item.children, path);
+      if (res) return res;
+    }
+  }
+  return false;
+};
+export default {
+  computed: {
+    catalog() {
+      // console.log(this.$route)
+      // return this.$route.meta.catalog;
+      const menu = DeepFind(this.menuItems, this.$route.path);
+      return (menu && menu.options && menu.options.meta && menu.options.meta.catalog) || [];
+    },
+    menuItems() {
+      return this.$store.state.menu.items;
+    },
+  },
+};
+</script>

+ 136 - 0
lib/layouts/frame.vue

@@ -0,0 +1,136 @@
+<template>
+  <el-container class="layout" direction="vertical">
+    <el-header class="header" :height="layout.headerHeight" :style="{ lineHeight: layout.headerHeight }">
+      <div class="header-box">
+        <naf-logo :width="asideWidth" :shortName="shortName" />
+        <naf-lite-bar :menu-collapse="menuCollapse" @toggle-menu="toggleMenu" />
+      </div>
+    </el-header>
+    <el-main style="padding: 0;display: flex;">
+      <el-container class="main">
+        <el-aside :width="asideWidth" class="sider" v-show="asideShow">
+          <naf-sider :menu-items="menuItems" :style="{ width: asideWidth }" theme="light" :is-collapse="menuCollapse" />
+        </el-aside>
+        <el-main class="content">
+          <div class="bread" :height="layout.breadHeight" v-show="asideShow">
+            <naf-bread></naf-bread>
+          </div>
+          <div class="page" ref="pageContainer">
+            <el-alert :title="errMsg" type="info" :description="errDesc" show-icon v-if="showError"> </el-alert>
+            <router-view v-else />
+          </div>
+        </el-main>
+      </el-container>
+    </el-main>
+  </el-container>
+</template>
+
+<script>
+import config from '@frame/config';
+import NafSider from '@naf/frame/sider';
+import NafLogo from './logo';
+import NafLiteBar from './litebar';
+import NafBread from './bread';
+
+const defaultConfig = {
+  breadHeight: '24px',
+  headerHeight: '64px',
+  footerHeight: '48px',
+  asideExpandWidth: '256px',
+  asideCollapseWidth: '64px',
+};
+
+const { layout = {} } = config;
+
+export default {
+  name: 'Frame',
+  components: {
+    NafSider,
+    NafLogo,
+    NafLiteBar,
+    NafBread,
+  },
+  props: {
+    menuItems: { type: Array, required: true },
+    shortName: { type: String, default: '智慧就业' },
+    // menuCollapse: { type: Boolean, default: false },
+  },
+  data() {
+    return {
+      layout: { ...defaultConfig, ...layout },
+      showError: false,
+      errMsg: '',
+      errDesc: '',
+      menuCollapse: false,
+    };
+  },
+  methods: {
+    toggleMenu() {
+      this.menuCollapse = !this.menuCollapse;
+    },
+  },
+  computed: {
+    asideWidth() {
+      return this.menuCollapse ? layout.asideCollapseWidth : layout.asideExpandWidth;
+    },
+    asideShow() {
+      return true;
+    },
+  },
+  created() {
+    // eslint-disable-next-line no-undef
+    // if (!dd) {
+    //   throw new BusinessError();
+    // }
+  },
+  errorCaptured(err, vm, info) {
+    this.showError = true;
+    this.errMsg = err.message || '处理发生错误';
+    this.errDesc = err.details || info || '页面加载过程中发生错误';
+  },
+};
+</script>
+<style scoped lang="less">
+.layout {
+  height: 100%;
+  width: 100%;
+  overflow: hidden;
+}
+.header {
+  padding: 0;
+  .header-box {
+    background: #20a0ff;
+    color: #fff;
+    display: flex;
+    flex-direction: row;
+    padding: 0;
+    height: 100%;
+  }
+}
+.sider {
+  background: #fff;
+  height: 100%;
+  overflow-y: auto;
+  overflow-x: hidden;
+  border-right: solid 1px #e6e6e6;
+}
+.main {
+  // FOR EDGE
+  overflow: hidden;
+}
+.content {
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  padding: 0;
+  .bread {
+    padding: 10px 20px;
+  }
+  .page {
+    flex: 1;
+    overflow: auto;
+    display: block;
+    padding: 10px;
+  }
+}
+</style>

+ 34 - 0
lib/layouts/litebar.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="banner">
+    <i class="naf-icons" :class="{ 'naf-icon-unfold': menuCollapse, 'naf-icon-fold': !menuCollapse }" @click="toggleMenu"></i>
+    <naf-user class="right" />
+  </div>
+</template>
+<script>
+import NafUser from './user';
+
+export default {
+  components: {
+    NafUser,
+  },
+  props: {
+    menuCollapse: Boolean,
+  },
+  methods: {
+    toggleMenu() {
+      this.$emit('toggle-menu');
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.banner {
+  flex: 1;
+  display: block;
+  align-items: center;
+  padding: 0 20px;
+  .right {
+    float: right;
+  }
+}
+</style>

+ 43 - 0
lib/layouts/logo.vue

@@ -0,0 +1,43 @@
+<template>
+  <div class="logo" :style="{ width: width }">
+    <router-link to="/">
+      <img src="@/assets/logo1.svg" alt="logo" style="height:32px;width:32px;" />
+    </router-link>
+    <h1>{{ shortName }}</h1>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    shortName: String,
+    width: {
+      type: String,
+      default: '256px',
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.logo {
+  display: table;
+  box-sizing: border-box;
+  border-right: solid 1px #e6e6e6;
+  padding: 0 16px;
+  overflow: hidden;
+  img,
+  h1 {
+    vertical-align: middle;
+  }
+  h1 {
+    display: inline-block;
+    margin: 0 0 0 12px;
+    font-size: 1.3em;
+  }
+
+  .el-switch {
+    vertical-align: middle;
+    text-align: right;
+    display: table-cell;
+  }
+}
+</style>

+ 40 - 0
lib/layouts/user.vue

@@ -0,0 +1,40 @@
+<template>
+  <!--简洁用户菜单-->
+  <div class="right lite">
+    <span class="name">{{ (userinfo && userinfo.name) || '管理員' }}</span>
+  </div>
+</template>
+<script>
+import { mapActions, mapGetters } from 'vuex';
+
+export default {
+  props: {
+    menuCollapse: Boolean,
+  },
+  methods: {
+    ...mapActions({
+      logout: 'login/logout',
+    }),
+    async handleLogout() {
+      // console.log(this.userinfo);
+      // console.log(this);
+      const res = await this.logout();
+      // console.log(res);
+      // if (!res.errcode) {
+      //   this.$router.push(this.$route.query.redirect || '/login');
+      // }
+    },
+  },
+  computed: {
+    ...mapGetters(['userinfo']),
+  },
+};
+</script>
+<style lang="less" scoped>
+.right.lite {
+  font-size: 14px;
+}
+.el-button--text {
+  color: white;
+}
+</style>

+ 1 - 0
lib/plugins/README.md

@@ -0,0 +1 @@
+### 框架使用的 vue plugin

+ 22 - 0
lib/plugins/axios.js

@@ -0,0 +1,22 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import Vue from 'vue';
+import AxiosWrapper from '../utils/axios-wrapper';
+
+const Plugin = {
+  install(vue, options) {
+    // 3. 注入组件
+    vue.mixin({
+      created() {
+        if (this.$store && !this.$store.$axios) {
+          this.$store.$axios = this.$axios;
+        }
+      },
+    });
+    // 4. 添加实例方法
+    vue.prototype.$axios = new AxiosWrapper(options);
+  },
+};
+
+Vue.use(Plugin, { baseUrl: process.env.VUE_APP_AXIOS_BASE_URL, unwrap: false });

+ 40 - 0
lib/plugins/check-res.js

@@ -0,0 +1,40 @@
+/* eslint-disable no-underscore-dangle */
+/* eslint-disable no-param-reassign */
+/* eslint-disable no-unused-vars */
+/* eslint-disable import/no-extraneous-dependencies */
+/* eslint-disable no-shadow */
+import Vue from 'vue';
+import _ from 'lodash';
+import { Message } from 'element-ui';
+
+const vm = new Vue({});
+const Plugin = {
+  install(Vue, options) {
+    // 4. 添加实例方法
+    Vue.prototype.$checkRes = (res, okText, errText) => {
+      let _okText = okText;
+      let _errText = errText;
+      if (!_.isFunction(okText) && _.isObject(okText) && okText != null) {
+        ({ okText: _okText, errText: _errText } = okText);
+      }
+      const { errcode = 0, errmsg } = res || {};
+      if (errcode === 0) {
+        if (_.isFunction(_okText)) {
+          return _okText();
+        }
+        if (_okText) {
+          Message.success(_okText);
+        }
+        return true;
+      }
+      if (_.isFunction(_errText)) {
+        return _errText();
+      }
+      Message.error(_errText || errmsg);
+      // Message({ message: _errText || errmsg, duration: 60000 });
+      return false;
+    };
+  },
+};
+
+Vue.use(Plugin);

+ 6 - 0
lib/plugins/element.js

@@ -0,0 +1,6 @@
+import Vue from 'vue';
+import Element from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+
+// 注册element-ui组件
+Vue.use(Element);

+ 4 - 0
lib/plugins/meta.js

@@ -0,0 +1,4 @@
+import Vue from 'vue';
+import Meta from 'vue-meta';
+
+Vue.use(Meta);

+ 10 - 0
lib/plugins/mint-ui.js

@@ -0,0 +1,10 @@
+/* eslint-disable object-curly-newline */
+import Vue from 'vue';
+// eslint-disable-next-line no-unused-vars
+import { Cell, Field, Popup, Radio, MessageBox } from 'mint-ui';
+import 'mint-ui/lib/style.css';
+
+Vue.use(Cell);
+Vue.use(Field);
+Vue.use(Popup);
+Vue.use(Radio);

+ 26 - 0
lib/plugins/naf-dict.js

@@ -0,0 +1,26 @@
+/**
+ * 字典数据处理插件
+ */
+
+import Vue from 'vue';
+import _ from 'lodash';
+import assert from 'assert';
+
+const Plugin = {
+  install(vue, options) {
+    // 4. 添加实例方法
+    vue.prototype.$dict = function(category, code) {
+      assert(_.isString(category));
+      const state = this.$store.state.naf.dict;
+      if (!state) {
+        throw new Error("can't find store for naf dict");
+      }
+      if (_.isString(code)) {
+        return (state.codes[category] && state.codes[category][code]) || code;
+      } else {
+        return state.items[category];
+      }
+    };
+  },
+};
+Vue.use(Plugin);

+ 65 - 0
lib/plugins/stomp.js

@@ -0,0 +1,65 @@
+/**
+ * 基于WebStomp的消息处理插件
+ */
+
+import Vue from 'vue';
+import _ from 'lodash';
+import assert from 'assert';
+import { Client } from '@stomp/stompjs/esm5/client';
+
+const Plugin = {
+  install(Vue, options) {
+    assert(_.isObject(options));
+    if (options.debug && !_.isFunction(options.debug)) {
+      options.debug = str => {
+        console.log(str);
+      };
+    }
+    assert(_.isString(options.brokerURL));
+    if (!options.brokerURL.startsWith('ws://')) {
+      options.brokerURL = `ws://${location.host}${options.brokerURL}`;
+    }
+
+    // 3. 注入组件
+    Vue.mixin({
+      beforeDestroy: function() {
+        if (this.$stompClient) {
+          this.$stompClient.deactivate();
+          delete this.$stompClient;
+        }
+      },
+    });
+
+    // 4. 添加实例方法
+    Vue.prototype.$stomp = function(subscribes = {}) {
+      // connect to mq
+      const client = new Client(options);
+      client.onConnect = frame => {
+        // Do something, all subscribes must be done is this callback
+        // This is needed because this will be executed after a (re)connect
+        console.log('[stomp] connected');
+        Object.keys(subscribes)
+          .filter(p => _.isFunction(subscribes[p]))
+          .forEach(key => {
+            client.subscribe(key, subscribes[key]);
+          });
+      };
+
+      client.onStompError = frame => {
+        // Will be invoked in case of error encountered at Broker
+        // Bad login/passcode typically will cause an error
+        // Complaint brokers will set `message` header with a brief message. Body may contain details.
+        // Compliant brokers will terminate the connection after any error
+        console.log('Broker reported error: ' + frame.headers['message']);
+        console.log('Additional details: ' + frame.body);
+      };
+
+      client.activate();
+
+      this.$stompClient = client;
+    };
+  },
+};
+export default () => {
+  Vue.use(Plugin, Vue.config.stomp);
+};

+ 17 - 0
lib/store/naf/.dict.js

@@ -0,0 +1,17 @@
+// mutation types
+export const LOADED = 'LOADED';
+
+export const PRESET = {
+  status: [{ code: '0', name: '正常' }, { code: '1', name: '挂起' }, { code: '2', name: '注销' }],
+  usage: [{ code: '0', name: '正常' }, { code: '1', name: '停用' }],
+  corpcode: [{ code: '0', name: '统一社会信用代码' }, { code: '1', name: '单位组织机构代码' }],
+  xb: [{ code: '1', name: '男' }, { code: '2', name: '女' }],
+  xl: [
+    { code: '41', name: '专科' },
+    { code: '31', name: '本科' },
+    { code: '11', name: '硕士' },
+    { code: '01', name: '博士' },
+    { code: '51', name: '中专' },
+    { code: '61', name: '高职' },
+  ],
+};

+ 100 - 0
lib/store/naf/dict.js

@@ -0,0 +1,100 @@
+/* eslint-disable no-param-reassign */
+/* eslint-disable no-shadow */
+// import * as types from './.dict.js';
+import assert from 'assert';
+import _ from 'lodash';
+import { LOADED, PRESET } from './.dict';
+
+const api = {
+  listItem: '/naf/code/:catg/list',
+  listUnit: '/naf/unit/list',
+  listXzqh: '/naf/code/xzqh/list',
+};
+
+// initial state
+export const state = () => ({
+  categories: [], // 字典分类
+  items: {
+    // 分项映射表
+    status: [{ code: '0', name: '正常' }, { code: '1', name: '挂起' }, { code: '2', name: '注销' }],
+    usage: [{ code: '0', name: '正常' }, { code: '1', name: '停用' }],
+  },
+  codes: {
+    // 代码映射表
+    status: {
+      0: '正常',
+      1: '挂起',
+      2: '注销',
+    },
+    usage: {
+      0: '正常',
+      1: '停用',
+    },
+  },
+});
+
+// actions
+export const actions = {
+  async load({ state, commit }, payload) {
+    assert(payload);
+
+    if (state.items[payload]) {
+      return state.items[payload];
+    }
+
+    // LOAD PRESET DICT
+    if (PRESET[payload]) {
+      commit(LOADED, { category: payload, items: PRESET[payload] });
+      return PRESET[payload];
+    }
+
+    let res;
+    if (payload === 'unit') {
+      // LOAD UNIT DICT
+      res = await this.$axios.$get(api.listUnit);
+    } else if (payload === 'xzqh') {
+      // LOAD XZQH DICT
+      res = await this.$axios.$get(api.listXzqh, { level: 1 });
+      if (res.errcode) return res;
+      const rs1 = res.data || res;
+      res = await this.$axios.$get(api.listXzqh, { level: 2 });
+      if (res.errcode) return res;
+      const rs2 = res.data || res;
+      res = rs1.map(p => {
+        const prefix = p.code.substr(0, 2);
+        const children = rs2.filter(c => c.code !== p.code && c.code.startsWith(prefix));
+        return { ...p, children };
+      });
+    } else if (payload === 'city') {
+      // 吉林省内地市
+      res = await this.$axios.$get(api.listXzqh, { level: 2, parent: '220000' });
+    } else {
+      // LOAD COMMONS DICT
+      res = await this.$axios.$get(api.listItem, { catg: payload });
+    }
+
+    if (!res.errcode) {
+      commit(LOADED, { category: payload, items: res.data || res });
+      return res.data || res;
+    }
+    return res;
+  },
+};
+
+// mutations
+export const mutations = {
+  [LOADED](state, { category, items }) {
+    state.items[category] = items;
+    state.codes[category] = items.reduce((acc, item) => {
+      acc[item.code] = item.name;
+      if (_.isArray(item.children) && item.children.length > 0) {
+        _.forEach(item.children, p => {
+          acc[p.code] = p.name;
+        });
+      }
+      return acc;
+    }, {});
+  },
+};
+
+export const namespaced = true;

+ 8 - 0
lib/store/naf/index.js

@@ -0,0 +1,8 @@
+import * as dict from './dict';
+
+export default {
+  namespaced: true,
+  modules: {
+    dict,
+  },
+};

+ 35 - 0
lib/style/index.less

@@ -0,0 +1,35 @@
+html, body, #app{
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  background: #fff;
+}
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+[class*=" el-icon-naf"], [class^=el-icon-naf] {
+  font-family: naf-icons!important;
+}
+::-webkit-scrollbar {/*滚动条整体样式*/
+  width: 8px;     /*高宽分别对应横竖滚动条的尺寸*/
+  height: 8px;
+}
+::-webkit-scrollbar-thumb {/*滚动条里面小方块*/
+  box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
+  border-radius: 5px;
+  background: hsla(220,4%,58%,.3)
+}
+::-webkit-scrollbar-track {/*滚动条里面轨道*/
+  box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
+  background: #EDEDED;
+}
+.el-menu-item [class^=naf-icon],.el-submenu [class^=naf-icon] {
+  vertical-align: middle;
+  margin-right: 5px;
+  width: 24px;
+  text-align: center;
+  font-size: 18px;
+}

+ 56 - 0
lib/style/lite.less

@@ -0,0 +1,56 @@
+.lite {
+  //min-height: 100%;
+  min-width: 720px;
+  min-height: 500px;
+  height: 100%;
+  width: 100%;
+  padding-right: 10px;
+  // display: flex;
+  // justify-content: flex-start;
+  // flex-direction: row;
+  .el-card {
+    min-height: 100%;
+    margin-bottom: 10px;
+    display: flex;
+    flex-direction: column;
+  }
+  .el-card /deep/ .el-card__header {
+    padding: 10px;
+    .title {
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+    }
+    .action {
+      padding: 0px 10px;
+      float: right;
+      .el-button--text {
+        padding: 0px;   
+      }
+      .el-button + .el-button {
+        margin-left: 5px;   
+      }
+    }
+  }
+  .el-card /deep/ .el-card__body {
+    flex: 1;
+    padding: 0;
+  }
+  .el-card.details /deep/ .el-card__body {
+    padding: 10px;
+  }
+}
+
+.right.list /deep/ .el-card__body {
+  padding: 0;
+  /deep/ .el-table__body-wrapper {
+    min-height: 200px;
+  }
+}
+.el-table--mini .naf-icons {
+  font-size: 12px;
+}
+
+.el-table--mini .icon + .icon {
+  margin-left: 3px;
+}

+ 49 - 0
lib/style/mixed.less

@@ -0,0 +1,49 @@
+.mixed {
+  //min-height: 100%;
+  min-width: 800px;
+  min-height: 500px;
+  height: 100%;
+  width: 100%;
+  padding-right: 10px;
+  display: flex;
+  justify-content: flex-start;
+  flex-direction: row;
+}
+.el-card {
+  min-height: 100%;
+}
+.el-card /deep/ .el-card__header {
+  padding: 10px;
+}
+.left {
+  width: 260px;
+}
+.left .top {
+  justify-content: space-around;
+  align-items: left;
+}
+.right {
+  flex: 1;
+}
+.el-form {
+  max-width: 500px;
+}
+.el-card.left {
+  display: flex;
+  flex-direction: column;
+  /deep/ &>.el-card__body {
+    flex: 1;
+    display: flex;
+    // flex-direction: column;
+    
+  /deep/ &>.el-scrollbar {
+    flex: 1;
+    /deep/ &>.el-scrollbar__wrap {
+      overflow-x: hidden;
+    }
+  }
+  /deep/ &>* {
+    flex: 1;
+    }
+  }
+}

+ 120 - 0
lib/utils/axios-wrapper.js

@@ -0,0 +1,120 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import _ from 'lodash';
+import Axios from 'axios';
+import { Util, Error } from 'naf-core';
+import { Indicator } from 'mint-ui';
+import UserUtil from './user-util';
+
+const { trimData, isNullOrUndefined } = Util;
+const { ErrorCode } = Error;
+
+let currentRequests = 0;
+
+export default class AxiosWrapper {
+  constructor({ baseUrl = '', unwrap = true } = {}) {
+    this.baseUrl = baseUrl;
+    this.unwrap = unwrap;
+  }
+
+  // 替换uri中的参数变量
+  static merge(uri, query = {}) {
+    if (!uri.includes(':')) {
+      return uri;
+    }
+    const keys = [];
+    const regexp = /\/:([a-z0-9_]+)/gi;
+    let res;
+    // eslint-disable-next-line no-cond-assign
+    while ((res = regexp.exec(uri)) != null) {
+      keys.push(res[1]);
+    }
+    keys.forEach(key => {
+      if (!isNullOrUndefined(query[key])) {
+        uri = uri.replace(`:${key}`, query[key]);
+      }
+    });
+    return uri;
+  }
+
+  $get(uri, query, options) {
+    return this.$request(uri, null, query, options);
+  }
+
+  $post(uri, data = {}, query, options) {
+    return this.$request(uri, data, query, options);
+  }
+  $delete(uri, data = {}, query, options) {
+    options = { ...options, method: 'delete' };
+    return this.$request(uri, data, query, options);
+  }
+
+  async $request(uri, data, query, options) {
+    if (!uri) console.error('uri不能为空');
+    // TODO: 合并query和options
+    if (_.isObject(query) && _.isObject(options)) {
+      options = { ...options, params: query, method: 'get' };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    if (!options) options = {};
+    if (options.params) options.params = trimData(options.params);
+    const url = AxiosWrapper.merge(uri, options.params);
+
+    currentRequests += 1;
+    Indicator.open({
+      spinnerType: 'fading-circle',
+    });
+
+    try {
+      const axios = Axios.create({
+        baseURL: this.baseUrl,
+      });
+      if (UserUtil.token) {
+        axios.defaults.headers.common.Authorization = UserUtil.token;
+      } else if (sessionStorage.getItem('token')) {
+        axios.defaults.headers.common.Authorization = UserUtil.token;
+      }
+      let res = await axios.request({
+        method: isNullOrUndefined(data) ? 'get' : 'post',
+        url,
+        data,
+        responseType: 'json',
+        ...options,
+      });
+      res = res.data;
+      const { errcode, errmsg, details } = res;
+      if (errcode) {
+        console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`);
+        return res;
+      }
+      // unwrap data
+      if (this.unwrap) {
+        res = _.omit(res, ['errcode', 'errmsg', 'details']);
+        const keys = Object.keys(res);
+        if (keys.length === 1 && keys.includes('data')) {
+          res = res.data;
+        }
+      }
+      return res;
+    } catch (err) {
+      let errmsg = '接口请求失败,请稍后重试';
+      if (err.response) {
+        const { status } = err.response;
+        if (status === 401) errmsg = '用户认证失败,请重新登录';
+        if (status === 403) errmsg = '当前用户不允许执行该操作';
+      }
+      console.error(`[AxiosWrapper] 接口请求失败: ${err.config && err.config.url} - ${err.message}`);
+      return { errcode: ErrorCode.SERVICE_FAULT, errmsg, details: err.message };
+    } finally {
+      currentRequests -= 1;
+      if (currentRequests <= 0) {
+        currentRequests = 0;
+        Indicator.close();
+      }
+    }
+  }
+}

+ 18 - 0
lib/utils/filters.js

@@ -0,0 +1,18 @@
+/* eslint-disable func-names */
+/* eslint-disable no-param-reassign */
+import _ from 'lodash';
+import moment from 'moment';
+
+export function dict(value, codes) {
+  if (!value) return '';
+  value = value.toString();
+  if (codes) {
+    value = _.get(codes, [value]) || value;
+  }
+  return value;
+}
+
+export function date(value, formmat) {
+  if (!value) return '';
+  return moment(value).format(formmat);
+}

+ 124 - 0
lib/utils/store.js

@@ -0,0 +1,124 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+
+Vue.use(Vuex);
+
+const files = require.context('@/store', true, /^\.\/(?!-)[^.]+\.(js|mjs)$/);
+const filenames = files.keys();
+
+// Store
+let storeData = {};
+
+// Check if {dir.store}/index.js exists
+const indexFilename = filenames.find(filename => filename.includes('./index.'));
+
+if (indexFilename) {
+  storeData = getModule(indexFilename);
+}
+
+// If store is not an exported method = modules store
+if (typeof storeData !== 'function') {
+  // Store modules
+  if (!storeData.modules) {
+    storeData.modules = {};
+  }
+
+  for (const filename of filenames) {
+    let name = filename.replace(/^\.\//, '').replace(/\.(js|mjs)$/, '');
+    if (name === 'index') continue;
+
+    const namePath = name.split(/\//);
+
+    name = namePath[namePath.length - 1];
+    if (['state', 'getters', 'actions', 'mutations'].includes(name)) {
+      const module = getModuleNamespace(storeData, namePath, true);
+      appendModule(module, filename, name);
+      continue;
+    }
+
+    // If file is foo/index.js, it should be saved as foo
+    const isIndex = name === 'index';
+    if (isIndex) {
+      namePath.pop();
+    }
+
+    const module = getModuleNamespace(storeData, namePath);
+    const fileModule = getModule(filename);
+
+    name = namePath.pop();
+    module[name] = module[name] || {};
+
+    // if file is foo.js, existing properties take priority
+    // because it's the least specific case
+    if (!isIndex) {
+      module[name] = Object.assign({}, fileModule, module[name]);
+      module[name].namespaced = true;
+      continue;
+    }
+
+    // if file is foo/index.js we want to overwrite properties from foo.js
+    // but not from appended mods like foo/actions.js
+    const appendedMods = {};
+    if (module[name].appends) {
+      appendedMods.appends = module[name].appends;
+      for (const append of module[name].appends) {
+        appendedMods[append] = module[name][append];
+      }
+    }
+
+    module[name] = Object.assign({}, module[name], fileModule, appendedMods);
+    module[name].namespaced = true;
+  }
+}
+
+// createStore
+export const createStore =
+  storeData instanceof Function
+    ? storeData
+    : () => {
+        return new Vuex.Store(
+          Object.assign(
+            {
+              strict: process.env.NODE_ENV !== 'production',
+            },
+            storeData,
+            {
+              state: storeData.state instanceof Function ? storeData.state() : {},
+            }
+          )
+        );
+      };
+
+// Dynamically require module
+function getModule(filename) {
+  const file = files(filename);
+  const module = file.default || file;
+  if (module.commit) {
+    throw new Error('[nuxt] store/' + filename.replace('./', '') + ' should export a method which returns a Vuex instance.');
+  }
+  if (module.state && typeof module.state !== 'function') {
+    throw new Error('[nuxt] state should be a function in store/' + filename.replace('./', ''));
+  }
+  return module;
+}
+
+function getModuleNamespace(storeData, namePath, forAppend = false) {
+  if (namePath.length === 1) {
+    if (forAppend) {
+      return storeData;
+    }
+    return storeData.modules;
+  }
+  const namespace = namePath.shift();
+  storeData.modules[namespace] = storeData.modules[namespace] || {};
+  storeData.modules[namespace].namespaced = true;
+  storeData.modules[namespace].modules = storeData.modules[namespace].modules || {};
+  return getModuleNamespace(storeData.modules[namespace], namePath, forAppend);
+}
+
+function appendModule(module, filename, name) {
+  const file = files(filename);
+  module.appends = module.appends || [];
+  module.appends.push(name);
+  module[name] = file.default || file;
+}

+ 46 - 0
lib/utils/user-util.js

@@ -0,0 +1,46 @@
+/* eslint-disable no-console */
+export default {
+  get user() {
+    const val = sessionStorage.getItem('user');
+    try {
+      if (val) return JSON.parse(val);
+    } catch (err) {
+      console.error(err);
+    }
+    return null;
+  },
+  set user(userinfo) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+    if (this.unit) {
+      this.lastUnit = this.unit;
+    }
+  },
+  get token() {
+    return sessionStorage.getItem('token') || '';
+  },
+  set token(token) {
+    sessionStorage.setItem('token', token);
+  },
+  get isGuest() {
+    return !this.user || this.user.role === 'guest';
+  },
+  get unit() {
+    if (!this.user || this.user.iss !== 'platform') return undefined;
+    const unit = this.user.sub.split('@', 2)[1] || 'master';
+    return unit;
+  },
+  get platform() {
+    const unit = this.unit || this.lastUnit;
+    return unit === 'master' ? 'master' : 'school';
+  },
+  set lastUnit(value) {
+    localStorage.setItem('unit', value);
+  },
+  get lastUnit() {
+    return localStorage.getItem('unit');
+  },
+  save({ userinfo, token }) {
+    this.user = userinfo;
+    this.token = token;
+  },
+};

+ 25 - 0
mock/menu/cms.js

@@ -0,0 +1,25 @@
+module.exports = [
+  {
+    title: '信息发布',
+    path: '/cms',
+    icon: 'news',
+    module: 'cms',
+    children: [
+      {
+        title: '通知公告',
+        path: '/cms/notice',
+        icon: 'column',
+      },
+      {
+        title: '政策法规',
+        path: '/cms/policy',
+        icon: 'column',
+      },
+      {
+        title: '新闻栏目',
+        path: '/cms/news',
+        icon: 'column',
+      },
+    ],
+  },
+];

+ 72 - 0
mock/menu/docflow.js

@@ -0,0 +1,72 @@
+module.exports = [
+  {
+    title: '我的发文',
+    icon: 'news',
+    module: 'docflow',
+    platform: 'master',
+    children: [
+      {
+        title: '待发公文',
+        path: '/docflow/draft',
+        icon: 'caogao',
+      },
+      {
+        title: '已发公文',
+        path: '/docflow/draft/other',
+        icon: 'doc1',
+      },
+    ],
+  },
+  {
+    title: '中心发文',
+    icon: 'news',
+    module: 'docflow',
+    platform: 'master',
+    children: [
+      {
+        title: '在办公文',
+        path: '/docflow/outbox',
+        icon: 'doc1',
+      },
+      {
+        title: '已办公文',
+        path: '/docflow/outbox/done',
+        icon: 'column',
+      },
+      {
+        title: '归档公文',
+        path: '/docflow/outbox/archive',
+        icon: 'column',
+      },
+      {
+        title: '公文回执',
+        path: '/docflow/outbox/feedback',
+        icon: 'column',
+      },
+    ],
+  },
+  {
+    title: '收文管理',
+    path: '/docflow',
+    icon: 'news',
+    module: 'docflow',
+    platform: 'school',
+    children: [
+      {
+        title: '待收公文',
+        path: '/docflow/inbox/new',
+        icon: 'caogao',
+      },
+      {
+        title: '在办公文',
+        path: '/docflow/inbox/read',
+        icon: 'doc1',
+      },
+      {
+        title: '已办公文',
+        path: '/docflow/inbox/done',
+        icon: 'column',
+      },
+    ],
+  },
+];

+ 66 - 0
mock/menu/index.js

@@ -0,0 +1,66 @@
+const { Router } = require('express');
+const system = require('./system');
+const link = require('./link');
+const jobs = require('./jobs');
+const docflow = require('./docflow');
+const cms = require('./cms');
+
+const router = Router();
+
+const navDatas = [
+  {
+    title: '系统管理',
+    path: '/system',
+    module: 'system',
+  },
+  {
+    title: '招聘管理',
+    path: '/jobs',
+    module: 'jobs',
+  },
+  // {
+  //   title: '信息发布',
+  //   path: '/cms',
+  //   module: 'cms',
+  // },
+  {
+    title: '公文系统',
+    path: '/docflow',
+    module: 'docflow',
+  },
+  ...link,
+];
+
+const datas = [...system, ...jobs, ...cms, ...docflow, ...link];
+
+const MapMenu = (catalog = []) => item => ({
+  title: item.title,
+  options: {
+    icon: item.icon,
+    path: item.path,
+    url: item.url,
+    target: item.target,
+    tooltip: item.tooltip,
+    module: item.module,
+    platform: item.platform,
+    roles: item.roels,
+    tags: item.tags,
+    meta: { catalog: catalog.concat(item.title) },
+  },
+  children: (item.children || []).map(MapMenu(catalog.concat(item.title))),
+});
+
+const menus = datas.map(MapMenu());
+const modules = navDatas.map(MapMenu());
+
+/* GET menus define. */
+router.get('/menu/load', function(req, res, next) {
+  res.json({ errcode: 0, errmsg: 'ok', data: { items: menus, modules } });
+});
+router.get('/menu/:module', function(req, res, next) {
+  const module = req.params.module;
+  const items = menus.filter(p => p.options.module == module);
+  res.json({ errcode: 0, errmsg: 'ok', data: { items, modules } });
+});
+
+module.exports = router;

+ 123 - 0
mock/menu/jobs.js

@@ -0,0 +1,123 @@
+module.exports = [
+  {
+    title: '企业管理',
+    path: '/corp',
+    icon: 'corp',
+    module: 'jobs',
+    children: [
+      {
+        title: '注册审核',
+        path: '/check',
+        icon: 'shenhe',
+        children: [
+          {
+            title: '已审核',
+            path: '/jobs/corp/0/register',
+            icon: 'shenhe',
+          },
+          {
+            title: '待审核',
+            path: '/jobs/corp/2/register',
+            icon: 'shenhe',
+          },
+          {
+            title: '审核拒绝',
+            path: '/jobs/corp/3/register',
+            icon: 'shenhe',
+          },
+          {
+            title: '信息未完善',
+            path: '/jobs/corp/1/register',
+            icon: 'shenhe',
+          },
+        ],
+      },
+      {
+        title: '企业信息总库',
+        path: '/jobs/corp/info',
+        icon: 'renzheng',
+      },
+      // {
+      //   title: '积分体系',
+      //   path: '/jobs/corp/points',
+      //   icon: 'jifen',
+      // },
+      // {
+      //   title: '企业用户',
+      //   path: '/jobs/corp/user',
+      //   icon: 'corpuser',
+      // },
+    ],
+  },
+  {
+    title: '招聘信息',
+    path: '/jobinfo',
+    icon: 'job',
+    module: 'jobs',
+    children: [
+      {
+        title: '待审核信息',
+        path: '/jobs/jobinfo/1',
+        icon: 'info',
+      },
+      {
+        title: '已发布信息',
+        path: '/jobs/jobinfo/0',
+        icon: 'info',
+      },
+      {
+        title: '审核失败信息',
+        path: '/jobs/jobinfo/2',
+        icon: 'info',
+      },
+    ],
+  },
+  {
+    title: '招聘会',
+    path: '/jobfair',
+    icon: 'job',
+    module: 'jobs',
+    children: [
+      {
+        title: '筹备中',
+        path: '/jobs/jobfair/0',
+        icon: 'info',
+      },
+      {
+        title: '已发布',
+        path: '/jobs/jobfair/1',
+        icon: 'info',
+      },
+    ],
+  },
+  {
+    title: '校园宣讲会',
+    path: '/campus',
+    icon: 'job',
+    module: 'jobs',
+    children: [
+      {
+        title: '待审核',
+        path: '/jobs/campus/1',
+        icon: 'info',
+      },
+      {
+        title: '已发布',
+        path: '/jobs/campus/0',
+        icon: 'info',
+      },
+    ],
+  },
+  {
+    title: '栏目管理',
+    path: '/column/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+  {
+    title: '菜单管理',
+    path: '/menu/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+];

+ 40 - 0
mock/menu/link.js

@@ -0,0 +1,40 @@
+module.exports = [
+  {
+    title: '友情链接',
+    icon: 'menu',
+    module: 'links',
+    children: [
+      {
+        title: '中心网站',
+        url: 'http://www.jilinjobs.cn',
+        target: '_blank',
+        icon: 'lianjie',
+      },
+      {
+        title: '吉林省教育厅',
+        url: 'http://www.jledu.gov.cn/jyt/',
+        target: '_blank',
+        icon: 'lianjie',
+      },
+      {
+        title: '学信网',
+        url: 'http://www.chsi.com.cn/',
+        target: '_blank',
+        icon: 'lianjie',
+      },
+      {
+        title: '全国大学生就业一站式服务系统',
+        url: 'http://jilinbys.ncss.org.cn/',
+        target: '_blank',
+        icon: 'lianjie',
+      },
+      {
+        title: '新职业',
+        tooltip: '教育部大学生就业网',
+        url: 'http://www.ncss.org.cn/',
+        target: '_blank',
+        icon: 'lianjie',
+      },
+    ],
+  },
+];

+ 42 - 0
mock/menu/system.js

@@ -0,0 +1,42 @@
+module.exports = [
+  {
+    title: '系统管理',
+    path: '/system',
+    icon: 'system',
+    module: 'system',
+    children: [
+      {
+        title: '用户管理',
+        path: '/system/user',
+        icon: 'account',
+      },
+      {
+        title: '部门管理',
+        path: '/system/dept',
+        icon: 'dept',
+      },
+      {
+        title: '标签用户',
+        path: '/system/tag',
+        icon: 'tag',
+      },
+      {
+        title: '单位管理',
+        path: '/system/unit',
+        icon: 'corp',
+        platform: 'master',
+      },
+      {
+        title: '字典管理',
+        path: '/system/dict',
+        icon: 'dict',
+        platform: 'master',
+      },
+      // {
+      //   title: '操作日志',
+      //   path: '/system/log',
+      //   icon: 'log',
+      // },
+    ],
+  },
+];

+ 137 - 0
naf/chart/tendency.vue

@@ -0,0 +1,137 @@
+<template>
+  <div class="line1">
+    <div id="line1" class="" style="width: 90%;height:450px;"></div>
+  </div>
+</template>
+
+<script>
+import echarts from 'echarts/lib/echarts';
+// 引入柱状图
+import 'echarts/lib/chart/bar';
+import 'echarts/lib/chart/line';
+import 'echarts/lib/component/title';
+import 'echarts/lib/component/legend';
+import 'echarts/lib/component/toolbox';
+import 'echarts/lib/component/markPoint';
+import 'echarts/lib/component/tooltip';
+
+export default {
+  mounted() {
+    this.myChart = echarts.init(document.getElementById('line1'));
+    this.initData();
+  },
+  props: ['sevenDate', 'sevenDay'],
+  methods: {
+    initData() {
+      const colors = ['#5793f3', '#675bba', '#d14a61'];
+      const option = {
+        color: colors,
+        title: {
+          text: '走势图',
+          subtext: ''
+        },
+        tooltip: {
+          trigger: 'axis'
+        },
+        legend: {
+          data: ['新注册用户', '新增信息', '新增管理员']
+        },
+        toolbox: {
+          show: true,
+          feature: {
+            dataZoom: {
+              yAxisIndex: 'none'
+            },
+            dataView: { readOnly: false },
+            magicType: { type: ['bar', 'line'] },
+            restore: {}
+          }
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: this.sevenDay
+        },
+        yAxis: [
+          {
+            type: 'value',
+            name: '用户',
+            min: 0,
+            max: 200,
+            position: 'left',
+            axisLine: {
+              lineStyle: {
+                color: '#999'
+              }
+            },
+            axisLabel: {
+              formatter: '{value}'
+            }
+          },
+          {
+            type: 'value',
+            name: '信息',
+            min: 0,
+            max: 200,
+            position: 'right',
+            axisLine: {
+              lineStyle: {
+                color: '#999'
+              }
+            },
+            axisLabel: {
+              formatter: '{value}'
+            }
+          }
+        ],
+        series: [
+          {
+            name: '新注册用户',
+            type: 'line',
+            data: this.sevenDate[0],
+            yAxisIndex: 1,
+            markPoint: {
+              data: [{ type: 'max', name: '最大值' }, { type: 'min', name: '最小值' }]
+            }
+          },
+          {
+            name: '新增信息',
+            type: 'line',
+            data: this.sevenDate[1],
+            yAxisIndex: 1,
+            markPoint: {
+              data: [{ type: 'max', name: '最大值' }, { type: 'min', name: '最小值' }]
+            }
+          },
+          {
+            name: '新增管理员',
+            type: 'line',
+            data: this.sevenDate[2],
+            yAxisIndex: 1,
+            markPoint: {
+              data: [{ type: 'max', name: '最大值' }, { type: 'min', name: '最小值' }]
+            }
+          }
+        ]
+      };
+      this.myChart.setOption(option);
+    }
+  },
+  watch: {
+    sevenDate() {
+      this.initData();
+    },
+    sevenDay() {
+      this.initData();
+    }
+  }
+};
+</script>
+
+<style lang="less">
+@import '~@/style/mixin';
+.line1 {
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 87 - 0
naf/data/README.md

@@ -0,0 +1,87 @@
+# 基于数据驱动的数据视图,具备增删改查基础功能
+## 组件说明
+### list
+弃用,用filter-grid代替
+### lite-grid
+简单数据列表,不包含查询和分页
+### filter-grid
+组合数据列表,包含查询和分页功能
+### meta-util
+数据定义处理工具包
+### 其他
+demo-table 演示数据列表
+naf-table 最早构建的代码框架,已无用
+
+## 字段定义
+### Meta定义形式1
+{
+  name: String, //字段名称
+  label: String, //显示名称
+  required: Boolean, //是否必须
+  readonly: Boolean, //字段是否只读,默认false
+  editable: Boolean, //字段是否支持编辑,默认true
+  slots: Array, // 显示区域,默认为['list', 'form'],可选值:'list'、'form'、'filter'
+  rules: Array, //表单校验规则
+  order: Number, // 显示顺序,默认为0,数字越大越靠前
+  listOpts: Object, //数据列表可选参数
+  formOpts: Object, //数据表单可选参数
+}
+### Meta定义形式2
+{
+  field: {
+    name: String, //字段名称
+    label: String, //显示名称
+    required: Boolean, //是否必须
+    readonly: Boolean, //字段是否只读,默认false
+    editable: Boolean, //字段是否支持编辑,默认true
+  },
+  slots: Array, // 显示区域,默认为['list', 'form'],可选值:'list'、'form'、'filter'
+  rules: Array, //表单校验规则
+  order: Number, // 显示顺序,默认为0,数字越大越靠前
+  listOpts: Object, //数据列表可选参数
+  formOpts: Object, //数据表单可选参数
+}
+### Meta定义形式3
+{
+  field: [name,label,required,readonly,editable,filter],
+  slots: Object, // 显示区域,示例:{ filter: false, list: true, form: true }
+  rules: Array, //表单校验规则
+  order: Number, // 显示顺序,默认为0,数字越大越靠前
+  listOpts: Object, //数据列表可选参数
+  formOpts: Object, //数据表单可选参数
+}
+### Meta定义形式4(预留,暂不支持)
+[
+  [name,label,required,readonly,editable,filter],
+  [slots: Array], // 显示区域,默认为['list', 'form'],可选值:'list'、'form'、'filter'
+  [rules: Array], //表单校验规则
+  [
+    order: Number, // 显示顺序,默认为0,数字越大越靠前
+    listOpts: Object, //数据列表可选参数
+    formOpts: Object, //数据表单可选参数
+  ]
+]
+
+## 列表操作定义
+### 定义形式1-简单对象
+{
+  edit: '编辑',
+  delete: '删除',
+  view: '查看',
+}
+
+### 定义形式2-简单数组
+[
+  [ 'edit', '编辑' ],
+  [ 'delete', '删除', true /*是否进行确认提示*/ ],
+  [ 'view', '查看' ],
+]
+
+### 定义形式3-数组对象(终极形态)
+[
+  { event: 'edit', label: '编辑' },
+  { event: 'delete', label: '删除', confirm: true },
+  { event: 'view', label: '查看' },
+]
+
+

+ 66 - 0
naf/data/code-select.vue

@@ -0,0 +1,66 @@
+<template>
+  <el-select v-model="selected" :placeholder="placeholder || '请选择'" @change="handleChange" :disabled="disabled">
+    <template v-for="(item, _index) in datas">
+      <el-option-group :key="'option-group-' + _index" :label="item.name" v-if="item.children && item.children.length > 0">
+        <el-option
+          v-for="(child, _index2) in item.children"
+          :key="'option-item-' + _index + '-' + _index2"
+          :label="child.name"
+          :value="child.code"
+          :disabled="child.status == '1'"
+        ></el-option>
+      </el-option-group>
+      <el-option :key="'option-item-' + _index" :label="item.name" :value="item.code" :disabled="item.status == '1'" v-else></el-option>
+    </template>
+  </el-select>
+</template>
+<script>
+import { createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('naf/dict');
+
+export default {
+  name: 'code-select',
+  props: {
+    value: { required: true },
+    category: { type: String, required: true },
+    placeholder: String,
+    disabled: Boolean,
+    mode: { type: String, default: 'code' }, // 选值模式:code、name、pair
+  },
+  data() {
+    return {
+      selected: this.value,
+      datas: [],
+    };
+  },
+  async mounted() {
+    const res = await this.load(this.category);
+    if (!res.errcode) {
+      this.datas = res.data || res;
+    } else {
+      // eslint-disable-next-line no-console
+      console.error(`数据字典[${this.category}]加载失败:`, res);
+    }
+  },
+  methods: {
+    ...mapActions(['load']),
+    handleChange() {
+      if (this.selected) {
+        const items = this.datas || [];
+        const item = items.find(p => p.code === this.selected);
+        if (item && this.mode === 'name') {
+          this.$emit('input', item.name);
+          return;
+        }
+        if (this.mode === 'pair') {
+          this.$emit('input', item);
+          return;
+        }
+      }
+
+      this.$emit('input', this.selected);
+      // this.$emit('change', this.selected);
+    },
+  },
+};
+</script>

+ 96 - 0
naf/data/demo-table.vue

@@ -0,0 +1,96 @@
+<template>
+  <el-container class="container">
+    <el-header height="36px" style="line-height:36px;">
+      <div class="filter-box">
+        <el-input placeholder="请输入内容" class="input-with-select" :clearable="true" size="mini" v-model="fieldValue">
+          <el-select slot="prepend" placeholder="请选择" width="110" v-model="fieldName">
+            <el-option v-for="(item, index) in filters" :label="item" :value="item" :key="'filter' + index"></el-option>
+          </el-select>
+          <el-button slot="append" icon="el-icon-search" @click="query"></el-button>
+        </el-input>
+      </div>
+      <el-button icon="el-icon-plus" type="primary" size="mini" v-if="showAction">添加</el-button>
+    </el-header>
+    <el-main>
+      <el-table border style="width: 100%;overflow: auto;" size="mini">
+        <el-table-column v-for="(item, index) in fields" :label="item" :key="'field' + index"></el-table-column>
+        <el-table-column label="操作" v-if="showAction"></el-table-column>
+      </el-table>
+    </el-main>
+    <el-footer height="36px">
+      <el-pagination
+        background
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="page"
+        :page-sizes="[10, 20, 50, 100, 200]"
+        :page-size="size"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+      ></el-pagination>
+    </el-footer>
+  </el-container>
+</template>
+<script>
+export default {
+  name: 'demo-table',
+  props: {
+    fields: Array,
+    filters: Array,
+    readonly: Boolean,
+  },
+  data() {
+    return {
+      loading: false,
+      dataSource: [],
+      total: 0,
+      page: 1,
+      size: 20,
+      fieldName: '',
+      fieldValue: '',
+      showAction: !this.readonly,
+    };
+  },
+  mounted() {
+    this.query();
+  },
+  methods: {
+    async query() {
+      this.loading = true;
+      setTimeout(() => {
+        this.loading = false;
+      }, 1000);
+    },
+    handleSizeChange(val) {
+      console.log(`每页 ${val} 条`);
+      this.size = val;
+      if (this.total === 0) return;
+      const pages = Math.floor((this.total + val) / val);
+      if (pages < this.page) this.page = pages;
+      this.query();
+    },
+    handleCurrentChange(val) {
+      console.log(`当前页: ${val}`);
+      this.page = val;
+      this.query();
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.container {
+  width: 100%;
+  height: 100%;
+}
+.el-table {
+  height: 100%;
+  overflow: auto;
+}
+.filter-box {
+  width: 280px;
+  display: inline-block;
+  .el-select {
+    width: 100px;
+  }
+}
+</style>

+ 148 - 0
naf/data/filter-grid.vue

@@ -0,0 +1,148 @@
+<template>
+  <el-container class="container">
+    <el-header height="36px" style="line-height:36px;" v-if="filter || action">
+      <slot name="filter" v-if="filter">
+        <div class="filter-box">
+          <el-input placeholder="请输入内容" class="input-with-select" :clearable="true" size="mini" v-model="filterData.value">
+            <el-select slot="prepend" placeholder="请选择" width="110" v-model="filterData.name">
+              <el-option v-for="(item, index) in filterFields" :label="item.label" :value="item.name" :key="'filter' + index"></el-option>
+            </el-select>
+            <el-button slot="append" icon="el-icon-search" @click="query"></el-button>
+          </el-input>
+        </div>
+      </slot>
+      <slot name="action" v-if="action">
+        <el-button icon="el-icon-plus" type="primary" size="mini" v-if="!readonly" @click="$emit('add-new')">添加</el-button>
+      </slot>
+    </el-header>
+    <el-main class="table-area">
+      <lite-grid :data="data" :meta="meta" :options="options" :readonly="readonly" :operation="operation" @oper="handleOper">
+        <template slot="pre">
+          <slot name="pre"> </slot>
+        </template>
+        <slot> </slot>
+        <template slot="oper">
+          <slot name="oper"> </slot>
+        </template>
+        <template slot="ext">
+          <slot name="ext"> </slot>
+        </template>
+        <template slot="post">
+          <slot name="post"> </slot>
+        </template>
+      </lite-grid>
+    </el-main>
+    <el-footer height="36px" v-if="paging">
+      <el-pagination
+        background
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="page"
+        :page-sizes="[10, 20, 50, 100, 200]"
+        :page-size="size"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+      ></el-pagination>
+    </el-footer>
+  </el-container>
+</template>
+<script>
+import { FieldMeta } from './meta-util';
+import LiteGrid from './lite-grid';
+
+export default {
+  name: 'filter-grid',
+  components: {
+    LiteGrid,
+  },
+  props: {
+    meta: { type: Array, required: true },
+    readonly: Boolean /* 是否显示操作列 */,
+    filter: { type: Boolean, default: false } /* 是否显示查询 */,
+    action: { type: Boolean, default: false } /* 是否显操作按钮 */,
+    paging: { type: Boolean, default: false } /* 是否显示分页 */,
+    options: {
+      type: Object,
+      default: () => ({ size: 'mini' }),
+    } /* 表格扩展属性 */,
+    operation: Array,
+    data: Array,
+    total: { type: Number, default: 0 } /* 总数据条数 */,
+    pageSize: { type: Number, default: 10 },
+  },
+  data() {
+    return {
+      page: 1,
+      size: this.pageSize,
+      filterData: {
+        name: '',
+        value: '',
+      },
+    };
+  },
+  methods: {
+    async query() {
+      let filter = { [this.filterData.name]: this.filterData.value };
+      if (this.filterData.name == undefined || this.filterData.value == undefined || this.filterData.value == '') {
+        filter = undefined;
+      }
+      this.$emit('query', {
+        filter,
+        paging: { page: this.page, size: this.size },
+      });
+    },
+    handleSizeChange(val) {
+      console.log(`每页 ${val} 条`);
+      this.size = val;
+      if (this.total === 0) return;
+      const pages = Math.floor((this.total + val) / val);
+      if (pages < this.page) this.page = pages;
+      this.query();
+    },
+    handleCurrentChange(val) {
+      console.log(`当前页: ${val}`);
+      this.page = val;
+      this.query();
+    },
+    async handleOper({ event, data }) {
+      this.$emit(event, data);
+    },
+    resetPage() {
+      this.page = 1;
+    },
+  },
+  computed: {
+    filterFields() {
+      return this.meta
+        .map(FieldMeta)
+        .filter(p => p.slots.filter)
+        .sort((a, b) => b.order - a.order)
+        .map(p => p.field);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.container {
+  width: 100%;
+  height: 100%;
+}
+.el-table {
+  height: 100%;
+  overflow: auto;
+}
+.filter-box {
+  width: 280px;
+  display: inline-block;
+  margin-right: 20px;
+  .el-select {
+    width: 100px;
+  }
+}
+.el-main {
+  padding: 10px;
+}
+// .table-area {
+//   padding: 0;
+// }
+</style>

+ 89 - 0
naf/data/form-dlg.vue

@@ -0,0 +1,89 @@
+<template>
+  <el-dialog :title="title" :visible.sync="visible" :width="width" :close-on-click-modal="false" @close="$emit('cancel')">
+    <el-form ref="form" :model="form" :rules="rules" v-bind="options">
+      <slot>
+        <el-form-item
+          v-for="(item, index) in fields"
+          :key="'form-field-' + index"
+          :label="item.field.label"
+          :prop="item.field.name"
+          :required="item.field.required"
+          :rules="item.rules"
+          v-bind="item.formOpts"
+        >
+          <el-select v-if="item.dict" v-model="form[item.field.name]" placeholder="请选择">
+            <el-option
+              v-for="(_item, _index) in item.dict"
+              :key="'option-item-' + _index"
+              :label="_item.name"
+              :value="_item.code"
+              :disabled="_item.status == '1'"
+            ></el-option>
+          </el-select>
+          <el-checkbox
+            v-else-if="item.formOpts && item.formOpts.inputType == 'checkbox'"
+            v-model="form[item.field.name]"
+            :disabled="readonly || item.field.readonly || (!isNew && item.field.editable === false)"
+            >{{ item.formOpts && item.formOpts.placeholder }}</el-checkbox
+          >
+          <el-input
+            v-else
+            v-model="form[item.field.name]"
+            :disabled="readonly || item.field.readonly || (!isNew && item.field.editable === false)"
+            :placeholder="item.formOpts && item.formOpts.placeholder"
+            :type="item.formOpts && item.formOpts.inputType"
+          ></el-input>
+        </el-form-item>
+      </slot>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="$emit('cancel')" :size="options.size">取 消</el-button>
+      <el-button type="primary" @click="handleSave" :size="options.size" v-show="!readonly">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import { FieldMeta } from './meta-util';
+
+export default {
+  name: 'data-dlg',
+  props: {
+    data: { type: Object, required: true },
+    meta: { type: Array, required: true },
+    rules: Object,
+    readonly: { type: Boolean, default: false } /* 是否只读 */,
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+    options: {
+      type: Object,
+      default: () => ({ size: 'small' }),
+    } /* form options */,
+    width: String,
+    title: String,
+    visible: { type: Boolean, default: true },
+  },
+  data() {
+    return {
+      form: { ...this.data },
+    };
+  },
+  methods: {
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          this.$emit('save', { isNew: this.isNew, data: this.form });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+  },
+  computed: {
+    fields() {
+      return this.meta
+        .map(FieldMeta)
+        .filter(p => p.slots.form)
+        .sort((a, b) => b.order - a.order);
+    },
+  },
+};
+</script>

+ 102 - 0
naf/data/form.vue

@@ -0,0 +1,102 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" v-bind="options">
+    <slot>
+      <el-form-item
+        v-for="(item, index) in fields"
+        :key="'form-field-' + index"
+        :label="item.field.label"
+        :prop="item.field.name"
+        :required="item.field.required"
+        :rules="item.rules"
+        v-bind="item.formOpts"
+      >
+        <el-select v-if="item.dict" v-model="form[item.field.name]" placeholder="请选择">
+          <el-option
+            v-for="(_item, _index) in item.dict"
+            :key="'option-item-' + _index"
+            :label="_item.name"
+            :value="_item.code"
+            :disabled="_item.status == '1'"
+          ></el-option>
+        </el-select>
+        <el-checkbox
+          v-else-if="item.formOpts && item.formOpts.inputType == 'checkbox'"
+          v-model="form[item.field.name]"
+          :disabled="readonly || item.field.readonly || (!isNew && item.field.editable === false)"
+          >{{ item.formOpts && item.formOpts.placeholder }}</el-checkbox
+        >
+        <el-input
+          v-else
+          v-model="form[item.field.name]"
+          :disabled="readonly || item.field.readonly || (!isNew && item.field.editable === false)"
+          :placeholder="item.formOpts && item.formOpts.placeholder"
+          :type="item.formOpts && item.formOpts.inputType"
+        ></el-input>
+      </el-form-item>
+      <el-form-item v-show="!readonly">
+        <el-button type="primary" @click="handleSave">保存</el-button>
+        <el-button type="info" @click="$emit('cancel')">取消</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import { FieldMeta } from './meta-util';
+
+export default {
+  name: 'data-form',
+  props: {
+    data: { type: Object, required: true },
+    meta: { type: Array, required: true },
+    rules: Object,
+    readonly: { type: Boolean, default: false } /* 是否只读 */,
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+    options: Object,
+  },
+  data() {
+    return {
+      form: { ...this.data },
+    };
+  },
+  methods: {
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          this.$emit('save', { isNew: this.isNew, data: this.form });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    mergeRules(meta) {
+      if (
+        meta.field.required &&
+        (!this.rules || !this.rules[meta.field.name] || !this.rules[meta.field.name].some(p => p.required)) &&
+        (!meta.rules || !meta.rules || !meta.rules.some(p => p.required))
+      ) {
+        const rules = meta.rules || [];
+        rules.push({ required: true, message: '不能为空', trigger: 'blur' });
+        return rules;
+      } else {
+        return meta.rules;
+      }
+    },
+    validateField(payload) {
+      this.$refs['form'].validateField(payload);
+    },
+  },
+  computed: {
+    fields() {
+      return this.meta
+        .map(FieldMeta)
+        .filter(p => p.slots.form)
+        .sort((a, b) => b.order - a.order)
+        .map(p => ({
+          ...p,
+          dict: this.$dict && p.formatter && p.formatter.name === 'dict' && this.$dict(p.formatter.param),
+          rules: this.mergeRules(p),
+        }));
+    },
+  },
+};
+</script>

+ 104 - 0
naf/data/lite-grid.vue

@@ -0,0 +1,104 @@
+<template>
+  <el-table border style="width: 100%;overflow: auto;" :size="options.size || 'mini'" v-bind="options" :data="data">
+    <slot name="pre"> </slot>
+    <slot>
+      <el-table-column
+        v-for="(item, index) in listFields"
+        :key="'field' + index"
+        :label="item.label"
+        :prop="item.name"
+        :formatter="item.formatter"
+        v-bind="item.options"
+        show-overflow-tooltip
+      />
+    </slot>
+    <slot name="ext"> </slot>
+    <slot name="oper">
+      <el-table-column label="操作" :width="options.operWidth || '100'" v-if="!readonly">
+        <template slot-scope="scope">
+          <el-button
+            v-for="(item, index) in operItems"
+            :key="'field' + index"
+            @click="handleOper(item, scope.row, scope.$index)"
+            type="text"
+            :size="options.size || 'mini'"
+          >
+            <el-tooltip v-if="item.icon" :content="item.label"><i :class="item.icon"></i></el-tooltip>
+            <span v-else>{{ item.label }}</span>
+          </el-button>
+        </template>
+      </el-table-column>
+    </slot>
+    <slot name="post"> </slot>
+  </el-table>
+</template>
+<script>
+import _ from 'lodash';
+import { FieldMeta, Operation, Formatter, MergeFilters } from './meta-util';
+
+export default {
+  name: 'lite-grid',
+  props: {
+    meta: { type: Array, required: true },
+    readonly: Boolean /* 是否显示操作列 */,
+    options: {
+      type: Object,
+      default: () => ({ size: 'mini' }),
+    } /* 表格扩展属性 */,
+    operation: {
+      default: () => [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete', true]],
+    } /* 操作类型 */,
+    data: Array,
+  },
+  methods: {
+    async handleOper({ event, label, confirm }, data, index) {
+      try {
+        if (confirm) {
+          const msg = _.isString(confirm) ? confirm : `是否${label}此数据?`;
+          await this.$confirm(msg, '请确认', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          });
+        }
+        this.$emit(event, data, index);
+        this.$emit('oper', { event, data, index });
+      } catch (err) {
+        if (err == 'cancel') {
+          this.$message({
+            type: 'info',
+            message: `已取消${label}`,
+          });
+        }
+      }
+    },
+  },
+  computed: {
+    listFields() {
+      const res = this.meta
+        .map(FieldMeta)
+        .filter(p => p.slots.list)
+        // .sort((a, b) => b.order - a.order)
+        .map(p => ({
+          ...p.field,
+          formatter: Formatter(p, this),
+          options: MergeFilters(p, this),
+        }));
+      // console.log('listFields: ', res);
+      return res;
+    },
+    operItems() {
+      return Operation(this.operation);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-table {
+  height: 100%;
+  overflow: auto;
+}
+.el-button + .el-button {
+  margin-left: 5px;
+}
+</style>

+ 128 - 0
naf/data/meta-util.js

@@ -0,0 +1,128 @@
+import _ from 'lodash';
+import moment from 'moment';
+
+/* 字段定义 */
+export const FieldMeta = meta => {
+  let { field, slots, listOpts } = meta;
+  const { rules, formOpts, order = 0 } = meta;
+  if (field === undefined) {
+    const { name, label, required = false, readonly = false, editable = true } = meta;
+    field = { name, label, required, readonly, editable };
+  }
+  if (_.isArray(field)) {
+    const [name, label, required = false, readonly = false, editable = true] = field;
+    field = { name, label, required, readonly, editable };
+  }
+
+  if (slots === undefined) {
+    // 从meta对象中提取slots属性
+    const { filter = false, list = true, form = true } = meta;
+    slots = { filter, list, form };
+  } else if (_.isObject(slots)) {
+    // 处理slots默认值
+    const { filter = false, list = true, form = true } = slots;
+    slots = { filter, list, form };
+  } else if (_.isArray(slots)) {
+    slots = { filter: slots.includes('filter'), list: slots.includes('list'), form: slots.includes('form') };
+  }
+
+  // 处理formatter
+  let { formatter } = meta;
+  if (!_.isFunction(formatter) && (_.isObject(formatter) || _.isString(formatter) || _.isArray(formatter))) {
+    let { name, param } = _.isObject(formatter) ? formatter : {};
+    if (_.isString(formatter)) {
+      [name, param] = formatter.split(':', 2);
+    } else if (_.isArray(formatter)) {
+      [name, param] = formatter;
+    }
+
+    if (name === undefined) {
+      formatter = undefined;
+    } else if (name === 'dict' && param === undefined) {
+      console.warn(`use ${formatter} formatter must set param,example: 'dict:status' `);
+      formatter = undefined;
+    } else {
+      formatter = { name, param };
+    }
+  }
+
+  return { field, rules, slots, order, formOpts, listOpts, formatter };
+};
+
+/* 列表操作列定义 */
+export const Operation = meta => {
+  let items = Object.entries(meta);
+  if (_.isArray(meta)) {
+    items = Object.values(meta);
+  }
+  return items.map(item => {
+    if (_.isArray(item)) {
+      let [event, label, icon, confirm = false] = item;
+      if (_.isBoolean(icon)) {
+        confirm = icon;
+        icon = undefined;
+      }
+      return { event, label, icon, confirm };
+    }
+    return item;
+  });
+};
+
+// 预置formatter函数
+export const formatters = {
+  date: param => (row, column, cellValue, index) => {
+    if (cellValue) {
+      return moment(cellValue).format(param || 'YYYY-MM-DD');
+    }
+    return cellValue;
+  },
+  dict: param => {
+    return function(row, column, cellValue, index) {
+      if (_.isString(cellValue)) {
+        return this.$dict(param, cellValue);
+      }
+      return cellValue;
+    };
+  },
+  bool: param => (row, column, cellValue, index) => {
+    if (cellValue === undefined) {
+      return '';
+    }
+    return cellValue ? '是' : '否';
+  },
+};
+
+export const Formatter = (meta, _this) => {
+  // 处理formatter
+  let { formatter } = meta;
+  if (!_.isFunction(formatter) && _.isObject(formatter)) {
+    const { name, param } = formatter;
+    formatter = formatters[name](param);
+    if (_this !== undefined) {
+      formatter = formatter.bind(_this);
+    }
+  }
+  if (!_.isFunction(formatter)) {
+    formatter = undefined;
+  }
+
+  return formatter;
+};
+
+export const MergeFilters = (meta, _this) => {
+  // 生成column filters
+  let { formatter, listOpts } = meta;
+  if (listOpts && listOpts.filterable && _.isObject(formatter) && formatter.name === 'dict') {
+    let items = _this.$dict(formatter.param);
+    if (!items || items.length > 20) return undefined;
+
+    const filterMethod = (value, row, column) => {
+      const property = column['property'];
+      return row[property] === value;
+    };
+
+    const filters = items.map(p => ({ text: p.name, value: p.code }));
+    return { filters, filterMethod, ...listOpts };
+  }
+  return listOpts;
+};

+ 105 - 0
naf/data/naf-table.vue

@@ -0,0 +1,105 @@
+<template>
+  <el-container class="container">
+    <el-header height="36px" style="line-height:36px;">
+      <div class="filter-box" v-if="filters && filters.length > 0">
+        <el-input placeholder="请输入内容" class="input-with-select" :clearable="true" size="mini" v-model="fieldValue">
+          <el-select slot="prepend" placeholder="请选择" width="110" v-model="fieldName">
+            <el-option v-for="(item, index) in filters" :label="item" :value="item" :key="'filter' + index"></el-option>
+          </el-select>
+          <el-button slot="append" icon="el-icon-search" @click="query"></el-button>
+        </el-input>
+      </div>
+      <el-button icon="el-icon-plus" type="primary" size="mini" v-if="showAction">添加</el-button>
+      <slot name="actionBar"></slot>
+    </el-header>
+    <el-main>
+      <el-table border style="width: 100%;overflow: auto;" size="mini">
+        <slot></slot>
+      </el-table>
+    </el-main>
+    <el-footer height="36px">
+      <el-pagination
+        background
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="page"
+        :page-sizes="[10, 20, 50, 100, 200]"
+        :page-size="size"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+      ></el-pagination>
+    </el-footer>
+  </el-container>
+</template>
+<script>
+export default {
+  name: 'naf-table',
+  props: {
+    dataSource: Array,
+    fields: Array,
+    filters: Array,
+    readonly: Boolean,
+    showQuery: Boolean,
+    showPage: Boolean,
+    total: Number,
+  },
+  data() {
+    return {
+      loading: false,
+      // dataSource: [],
+      // total: 0,
+      page: 1,
+      size: 20,
+      fieldName: '',
+      fieldValue: '',
+      showAction: !this.readonly,
+    };
+  },
+  mounted() {
+    this.query();
+  },
+  methods: {
+    async query() {
+      this.loading = true;
+      setTimeout(() => {
+        this.loading = false;
+      }, 1000);
+    },
+    handleSizeChange(val) {
+      console.log(`每页 ${val} 条`);
+      this.size = val;
+      if (this.total === 0) return;
+      const pages = Math.floor((this.total + val) / val);
+      if (pages < this.page) this.page = pages;
+      this.query();
+    },
+    handleCurrentChange(val) {
+      console.log(`当前页: ${val}`);
+      this.page = val;
+      this.query();
+    },
+  },
+};
+</script>
+<style lang="less">
+.container {
+  width: 100%;
+  height: 100%;
+}
+.main {
+  width: 100%;
+  height: 100%;
+  margin: 0 auto;
+}
+.el-table {
+  height: 100%;
+  overflow: auto;
+}
+.filter-box {
+  width: 280px;
+  display: inline-block;
+  .el-select {
+    width: 100px;
+  }
+}
+</style>

+ 79 - 0
naf/data/wang-editor.vue

@@ -0,0 +1,79 @@
+<template>
+  <div ref="editor" style="text-align:left"></div>
+</template>
+<script>
+import E from 'wangeditor';
+
+const menus = [
+  'head', // 标题
+  'bold', // 粗体
+  'fontSize', // 字号
+  'fontName', // 字体
+  'italic', // 斜体
+  'underline', // 下划线
+  'strikeThrough', // 删除线
+  'foreColor', // 文字颜色
+  'backColor', // 背景颜色
+  'link', // 插入链接
+  'list', // 列表
+  'justify', // 对齐方式
+  'quote', // 引用
+  // 'emoticon', // 表情
+  'image', // 插入图片
+  'table', // 表格
+  // 'video', // 插入视频
+  // 'code', // 插入代码
+  'undo', // 撤销
+  'redo', // 重复
+];
+
+export default {
+  name: 'wang-editor',
+  model: {
+    prop: 'value',
+    event: 'change', // 默认为input时间,此处改为change
+  },
+  props: {
+    value: { type: String, required: false, default: '' },
+    uploadImgServer: { type: String, required: false, default: '/files/editor/images/upload' },
+  },
+  data() {
+    return {
+      editorContent: this.value,
+    };
+  },
+  mounted() {
+    var editor = new E(this.$refs.editor);
+    editor.customConfig.onchange = html => {
+      this.editorContent = html;
+      this.$emit('change', html);
+    };
+    // 自定义菜单配置
+    editor.customConfig.menus = menus;
+    editor.customConfig.zIndex = 0;
+    editor.customConfig.uploadImgServer = this.uploadImgServer;
+    editor.customConfig.uploadImgMaxLength = 1;
+    editor.customConfig.uploadImgHooks = {
+      // 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式,可使用该配置
+      // (但是,服务器端返回的必须是一个 JSON 格式字符串!!!否则会报错)
+      customInsert: function(insertImg, result, editor) {
+        // 图片上传并返回结果,自定义插入图片的事件(而不是编辑器自动插入图片!!!)
+        // insertImg 是插入图片的函数,editor 是编辑器对象,result 是服务器端返回的结果
+
+        // 举例:假如上传图片成功后,服务器端返回的是 {url:'....'} 这种格式,即可这样插入图片:
+        var url = result.uri;
+        insertImg(url);
+
+        // result 必须是一个 JSON 格式字符串!!!否则报错
+      },
+    };
+    editor.create();
+    editor.txt.html(this.value);
+  },
+  methods: {
+    getContent: function() {
+      return this.editorContent;
+    },
+  },
+};
+</script>

+ 12 - 0
naf/error/403.vue

@@ -0,0 +1,12 @@
+<template>
+  <error-page title="403" desc="抱歉,你无权访问该页面" img-url="static/image1.svg"></error-page>
+</template>
+<script>
+import ErrorPage from './error-page';
+
+export default {
+  components: {
+    ErrorPage,
+  },
+};
+</script>

+ 12 - 0
naf/error/404.vue

@@ -0,0 +1,12 @@
+<template>
+  <error-page title="404" desc="抱歉,你访问的页面不存在" img-url="static/image2.svg"></error-page>
+</template>
+<script>
+import ErrorPage from './error-page';
+
+export default {
+  components: {
+    ErrorPage,
+  },
+};
+</script>

+ 12 - 0
naf/error/500.vue

@@ -0,0 +1,12 @@
+<template>
+  <error-page title="500" desc="抱歉,服务器出错了" img-url="static/image3.svg"></error-page>
+</template>
+<script>
+import ErrorPage from './error-page';
+
+export default {
+  components: {
+    ErrorPage,
+  },
+};
+</script>

+ 98 - 0
naf/error/error-page.vue

@@ -0,0 +1,98 @@
+<template>
+  <div class="exception">
+      <div class="imgBlock"><div class="imgEle" :style="{backgroundImage: 'url(' + this.imgUrl + ')'}"></div></div>
+      <div class="content">
+        <h1>{{title}}</h1>
+        <div class="desc">{{desc}}</div>
+        <div class="actions">
+          <router-link to="/"><el-button type="primary">返回首页</el-button></router-link>
+        </div>
+      </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    title: String,
+    desc: String,
+    'img-url': String,
+  },
+  computed: {
+    styleObject() {
+      return {
+        backgroundImage: `url("${this.imgUrl}")`,
+      };
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.exception {
+  display: flex;
+  align-items: center;
+  height: 100%;
+  font-family: "Helvetica Neue For Number", -apple-system, BlinkMacSystemFont,
+    "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
+    "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+  .imgBlock {
+    flex: 0 0 50%;
+    width: 50%;
+    padding-right: 152px;
+
+    .imgEle {
+      height: 360px;
+      width: 100%;
+      max-width: 430px;
+      float: right;
+      background-repeat: no-repeat;
+      background-position: 50% 50%;
+      background-size: 100% 100%;
+    }
+  }
+
+  .content {
+    flex: auto;
+
+    h1 {
+      color: #434e59;
+      font-size: 72px;
+      font-weight: 600;
+      line-height: 72px;
+      margin-top: 0;
+      margin-bottom: 24px;
+    }
+    .desc {
+      color: rgba(0, 0, 0, 0.45);
+      font-size: 20px;
+      line-height: 28px;
+      margin-bottom: 16px;
+    }
+  }
+}
+@media screen and (max-width: 1200px) {
+  .exception .imgBlock {
+    flex: 0 0 62.5%;
+    width: 62.5%;
+    padding-right: 88px;
+  }
+}
+@media screen and (max-width: 576px) {
+  .exception {
+    display: block;
+    text-align: center;
+  }
+  .exception .imgBlock {
+    padding-right: 0;
+    margin: 0 auto 24px;
+  }
+}
+@media screen and (max-width: 480px) {
+  .exception .imgBlock {
+    margin-bottom: -24px;
+    overflow: hidden;
+  }
+}
+</style>
+

+ 33 - 0
naf/frame/bread.vue

@@ -0,0 +1,33 @@
+<template>
+  <el-breadcrumb separator="/">
+    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+    <el-breadcrumb-item v-for="(item, index) in catalog" :key="index">{{ item }}</el-breadcrumb-item>
+  </el-breadcrumb>
+</template>
+<script>
+const DeepFind = (menus, path) => {
+  for (const k in menus) {
+    const item = menus[k];
+    //if (item.options.path == path) return menus[k];
+    if (path.endsWith(item.options.path)) return menus[k];
+    if (item.children) {
+      const res = DeepFind(item.children, path);
+      if (res) return res;
+    }
+  }
+  return false;
+};
+export default {
+  computed: {
+    catalog() {
+      // console.log(this.$route)
+      // return this.$route.meta.catalog;
+      const menu = DeepFind(this.menuItems, this.$route.path);
+      return (menu && menu.options && menu.options.meta && menu.options.meta.catalog) || [];
+    },
+    menuItems() {
+      return this.$store.getters.menuItems;
+    },
+  },
+};
+</script>

+ 30 - 0
naf/frame/footer.vue

@@ -0,0 +1,30 @@
+<template>
+  <span> {{copyright}}</span>
+</template>
+<script>
+import config from '@frame/config';
+
+export default {
+  data() {
+    return {
+      copyright: config.copyright,
+    };
+  },
+};
+</script>
+<style>
+.el-footer {
+  height: 48px;
+  line-height: 48px;
+  text-align: center;
+  font-size: 12px;
+  color: #999;
+  background: #fff;
+  -webkit-box-shadow: 4px 4px 40px 0 rgba(0, 0, 0, 0.05);
+  box-shadow: 4px 4px 40px 0 rgba(0, 0, 0, 0.05);
+  width: 100%;
+}
+.footer {
+  border-top: solid 1px #e6e6e6;
+}
+</style>

+ 125 - 0
naf/frame/header/header-dropdown.vue

@@ -0,0 +1,125 @@
+<template>
+  <div class="header-box">
+      <div class="logo" :style="{width: logoWidth}">
+        <router-link to="/">
+          <img src="@/assets/logo1.svg" alt="logo" style="height:32px;width:32px;" />
+        </router-link>
+        <h1>{{shortName}}</h1>
+      </div>
+      <div class="banner">
+        <i class="naf-icons" :class="{'naf-icon-unfold': menuCollapse, 'naf-icon-fold': !menuCollapse,}" @click="toggleMenu"></i>
+        <!--下拉用户菜单-->
+        <el-dropdown class="right" @command="handleUserCommand" v-if="false">
+          <span class="el-dropdown-link">
+            <i class="naf-icons naf-icon-avatar"></i>
+            <span class="name">{{userinfo && userinfo.fullname || '管理員'}}</span>
+          </span>
+          <el-dropdown-menu class="action-menu" slot="dropdown">
+            <el-dropdown-item>
+              <i class="naf-icons naf-icon-user"></i>
+              <span>个人中心</span>
+            </el-dropdown-item>
+            <el-dropdown-item>
+              <i class="naf-icons naf-icon-setting"></i>
+              <span>设置</span>
+            </el-dropdown-item>
+            <el-dropdown-item command="logout" divided>
+              <i class="naf-icons naf-icon-quit"></i>
+              <span>退出</span>
+            </el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+  </div>    
+</template>
+<script>
+import { mapActions, mapState } from 'vuex';
+
+export default {
+  props: {
+    shortName: String,
+    logoWidth: {
+      type: String,
+      default: '256px',
+    },
+    menuCollapse: Boolean,
+  },
+  methods: {
+    ...mapActions({
+      logout: 'login/logout',
+    }),
+    toggleMenu() {
+      this.$emit('toggle-menu');
+    },
+    async handleUserCommand(command) {
+      if (command === 'logout') {
+        await this.handleLogout();
+      } else {
+        this.$message({
+          type: 'info',
+          message: '即将上线,敬请期待...',
+        });
+      }
+    },
+    async handleLogout() {
+      console.log(this.userinfo);
+      console.log(this);
+      const res = await this.logout();
+      // console.log(res);
+      if (!res.errcode) {
+        this.$router.push(this.$route.query.redirect || '/login');
+      }
+    },
+  },
+  computed: {
+    userinfo() {
+      return this.$store.getters.userinfo;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.header-box {
+  border-bottom: solid 1px #e6e6e6;
+  background: #20a0ff;
+  color: #fff;
+  display: flex;
+  flex-direction: row;
+  padding: 0;
+  height: 100%;
+  .logo {
+    border-right: solid 1px #e6e6e6;
+    padding: 0 16px;
+    overflow: hidden;
+    img,
+    h1 {
+      vertical-align: middle;
+    }
+    h1 {
+      display: inline-block;
+      margin: 0 0 0 12px;
+    }
+  }
+  .banner {
+    flex: 1;
+    padding: 0 20px;
+    .right {
+      float: right;
+    }
+    .naf-icon-avatar {
+      margin-right: 4px;
+      color: rgba(255, 255, 255, 0.8);
+      font-size: 20px;
+      border-radius: 14px;
+      background: grey;
+      padding: 4px;
+    }
+    .right.lite {
+      font-size: 14px;
+    }
+  }
+}
+.el-button--text {
+  color: white;
+}
+</style>

+ 48 - 0
naf/frame/header/index.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="header-box">
+    <naf-logo :width="logoWidth" :shortName="shortName" :nav-mode="navMode" @switch-mode="switchMode"/>
+    <naf-nav-bar v-if="navMode == 'nested'" :menu-items="menuItems" />
+    <naf-lite-bar v-else :menu-collapse="menuCollapse" @toggle-menu="toggleMenu" />
+  </div>
+</template>
+<script>
+import NafLogo from './logo';
+import NafLiteBar from './litebar';
+import NafNavBar from './navbar';
+
+export default {
+  components: {
+    NafLogo,
+    NafLiteBar,
+    NafNavBar,
+  },
+  props: {
+    shortName: String,
+    logoWidth: {
+      type: String,
+      default: '256px',
+    },
+    menuCollapse: Boolean,
+    menuItems: Array,
+    navMode: String,
+  },
+  methods: {
+    switchMode(payload) {
+      this.$emit('switch-mode', payload);
+    },
+    toggleMenu(payload) {
+      this.$emit('toggle-menu', payload);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.header-box {
+  background: #20a0ff;
+  color: #fff;
+  display: flex;
+  flex-direction: row;
+  padding: 0;
+  height: 100%;
+}
+</style>

+ 32 - 0
naf/frame/header/litebar.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="banner">
+    <i class="naf-icons" :class="{ 'naf-icon-unfold': menuCollapse, 'naf-icon-fold': !menuCollapse }" @click="toggleMenu"></i>
+    <naf-user />
+  </div>
+</template>
+<script>
+import NafUser from './user';
+
+export default {
+  components: {
+    NafUser,
+  },
+  props: {
+    menuCollapse: Boolean,
+  },
+  methods: {
+    toggleMenu() {
+      this.$emit('toggle-menu');
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.banner {
+  flex: 1;
+  display: block;
+  flex-direction: row;
+  align-items: center;
+  padding: 0 20px;
+}
+</style>

+ 57 - 0
naf/frame/header/logo.vue

@@ -0,0 +1,57 @@
+<template>
+  <div class="logo" :style="{width: width}">
+    <router-link to="/">
+      <img src="@/assets/logo1.svg" alt="logo" style="height:32px;width:32px;" />
+    </router-link>
+    <h1>{{shortName}}</h1>
+    <el-tooltip effect="dark" :content="switchTip" placement="bottom">
+    <el-switch :value="navMode" active-color="#13ce66"
+                active-value="nested" inactive-value="lite" @change="switchMode">
+    </el-switch>
+    </el-tooltip>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    shortName: String,
+    width: {
+      type: String,
+      default: '256px',
+    },
+    navMode: String,
+  },
+  methods: {
+    switchMode(payload) {
+      this.$emit('switch-mode', payload);
+    },
+  },
+  computed: {
+    switchTip() {
+      return this.navMode == 'nested' ? '切换到简单导航模式' : '切换到经典导航模式';
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.logo {
+  display: table;
+  border-right: solid 1px #e6e6e6;
+  padding: 0 16px;
+  overflow: hidden;
+  img,
+  h1 {
+    vertical-align: middle;
+  }
+  h1 {
+    display: inline-block;
+    margin: 0 0 0 12px;
+  }
+
+  .el-switch {
+    vertical-align: middle;
+    text-align: right;
+    display: table-cell;
+  }
+}
+</style>

+ 44 - 0
naf/frame/header/navbar.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="banner">
+    <el-menu class="nav-menu" mode="horizontal" background-color="#20a0ff" text-color="#fff" active-text-color="#ffd04b">
+      <naf-menu-item
+        v-for="(item, idx) in menuItems"
+        :key="idx"
+        :index="idx.toString()"
+        :title="item.title"
+        :options="item.options"
+        :children="item.children"
+        :target="item.target"
+      >
+      </naf-menu-item>
+    </el-menu>
+    <naf-user />
+  </div>
+</template>
+<script>
+import NafMenuItem from '../menu-item';
+import NafUser from './user';
+
+export default {
+  components: {
+    NafMenuItem,
+    NafUser,
+  },
+  props: {
+    menuItems: Array,
+  },
+};
+</script>
+<style lang="less" scoped>
+.banner {
+  flex: 1;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  padding: 0 20px;
+}
+.nav-menu {
+  flex: 1;
+  border-bottom: 0;
+}
+</style>

+ 42 - 0
naf/frame/header/user.vue

@@ -0,0 +1,42 @@
+<template>
+  <!--简洁用户菜单-->
+  <div class="right lite">
+    <span class="name">{{userinfo && userinfo.name || '管理員'}}</span>
+    <span style="margin: 5px;">|</span>
+    <el-button type="text" @click="handleLogout">退出</el-button>
+  </div>
+</template>
+<script>
+import { mapActions, mapGetters } from 'vuex';
+
+export default {
+  props: {
+    menuCollapse: Boolean,
+  },
+  methods: {
+    ...mapActions({
+      logout: 'login/logout',
+    }),
+    async handleLogout() {
+      // console.log(this.userinfo);
+      // console.log(this);
+      const res = await this.logout();
+      // console.log(res);
+      // if (!res.errcode) {
+      //   this.$router.push(this.$route.query.redirect || '/login');
+      // }
+    },
+  },
+  computed: {
+    ...mapGetters(['userinfo']),
+  },
+};
+</script>
+<style lang="less" scoped>
+.right.lite {
+  font-size: 14px;
+}
+.el-button--text {
+  color: white;
+}
+</style>

+ 64 - 0
naf/frame/menu-item.vue

@@ -0,0 +1,64 @@
+<template>
+  <el-submenu :index="index" v-if="hasChildren">
+    <template slot="title">
+      <i :class="iconCls" v-if="hasIcon"></i>
+      <span slot="title">{{ title }}</span>
+    </template>
+    <naf-menu-item
+      v-for="(item, idx) in children"
+      :key="idx"
+      :index="index + '-' + idx"
+      :title="item.title"
+      :children="item.children"
+      :options="item.options"
+      :prefix="prefix"
+    >
+    </naf-menu-item>
+  </el-submenu>
+  <el-menu-item :index="index" @click="menuClick" v-else
+    ><i :class="iconCls"></i>
+    <span slot="title" v-if="title.length < 10 && !hasTooltip">{{ title }}</span>
+    <el-tooltip slot="title" v-else :content="hasTooltip ? options.tooltip : title" placement="top" effect="light">
+      <span>{{ title.length > 9 ? title.substr(0, 9) + '...' : title }}</span>
+    </el-tooltip>
+  </el-menu-item>
+</template>
+<script>
+export default {
+  name: 'naf-menu-item',
+  props: {
+    title: String,
+    index: String,
+    options: Object,
+    children: Array,
+    prefix: { type: String, default: '' },
+  },
+  methods: {
+    menuClick() {
+      console.log('click menu item....');
+      if (this.options.url) {
+        window.open(this.options.url, this.options.target);
+      } else if (this.options.path) {
+        this.$router.push(`${this.prefix}${this.options.path}`);
+      }
+    },
+  },
+  computed: {
+    hasChildren() {
+      return this.children && this.children.length > 0;
+    },
+    hasIcon() {
+      return this.options.icon && this.options.icon.length > 0;
+    },
+    hasTooltip() {
+      return this.options.tooltip && this.options.tooltip.length > 0;
+    },
+    iconCls() {
+      if (this.options.icon && !(this.options.icon.indexOf('el-') === 0)) {
+        return `naf-icons naf-icon-${this.options.icon}`;
+      }
+      return this.options.icon;
+    },
+  },
+};
+</script>

+ 64 - 0
naf/frame/sider.vue

@@ -0,0 +1,64 @@
+<template>
+  <el-menu ref="menu" default-active="0" class="nav-menu" v-bind="themeStyles" :collapse="isCollapse" :router="false">
+    <naf-menu-item
+      v-for="(item, idx) in menuItems"
+      :key="idx"
+      :index="idx.toString()"
+      :title="item.title"
+      :options="item.options"
+      :children="item.children"
+      :target="item.target"
+      :prefix="routerPrefix"
+    >
+    </naf-menu-item>
+  </el-menu>
+</template>
+<script>
+import NafMenuItem from './menu-item';
+
+export default {
+  components: {
+    NafMenuItem,
+  },
+  props: {
+    theme: String,
+    isCollapse: Boolean,
+    menuItems: Array,
+    routerPrefix: { type: String, default: '' },
+  },
+  data() {
+    return {
+      msg: 'Use Vue 2.0 Today!',
+      // menus,
+    };
+  },
+  // mounted: function() {
+  //   this.$nextTick(_ => {
+  //     // Code that will run only after the
+  //     // entire view has been rendered
+  //     this.$refs.menu.open('0');
+  //   });
+  // },
+  computed: {
+    // 计算属性的 getter
+    themeStyles() {
+      // `this` 指向 vm 实例
+      if (this.theme === 'dark') {
+        // dark styles
+        return {
+          backgroundColor: '#545c64',
+          textColor: '#fff',
+          activeTextColor: '#ffd04b',
+        };
+      }
+      // default styles
+      return {
+        backgroundColor: undefined,
+        textColor: undefined,
+        activeTextColor: undefined,
+      };
+    },
+  },
+};
+</script>
+<style lang="less" scoped></style>

+ 32 - 0
naf/layouts/footer-page.vue

@@ -0,0 +1,32 @@
+<!--登录页面布局,只有footer-->
+<template>
+  <el-container class="layout" direction="vertical">
+    <el-main style="padding: 0;display: flex;">
+      <transition name="form-fade" mode="in-out">
+        <slot></slot>
+      </transition>
+    </el-main>
+    <el-footer class="footer" height="layout.footerHeight">
+      <slot name="footer">
+        <naf-footer></naf-footer>
+      </slot>
+    </el-footer>
+  </el-container>
+</template>
+<script>
+import NafFooter from '@naf/frame/footer';
+import config from '@frame/config';
+
+const { layout } = config;
+
+export default {
+  components: {
+    NafFooter,
+  },
+  data() {
+    return {
+      layout,
+    };
+  },
+};
+</script>

+ 31 - 0
naf/layouts/scroll-page.vue

@@ -0,0 +1,31 @@
+<!--登录页面布局,只有footer-->
+<template functional>
+  <el-scrollbar class="scroll-page">
+    <slot></slot>
+  </el-scrollbar>
+</template>
+
+<style lang="less">
+html,
+body {
+  width: 100%;
+  height: 100%;
+}
+</style>
+<style lang="less">
+.el-scrollbar.scroll-page {
+  height: 100%;
+  width: 100%;
+  & > .el-scrollbar__wrap {
+    overflow-x: hidden;
+    display: flex;
+    & > .el-scrollbar__view {
+      padding: 0px;
+      display: flex;
+      flex: 1;
+      // flex-direction: column;
+      // overflow: auto;
+    }
+  }
+}
+</style>

+ 60 - 0
naf/user/dept-tree.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="nav-tree">
+    <el-tree ref="tree" :data="treeItems" :props="navProps" node-key="id" @node-click="handleNavClick" :highlight-current="true"></el-tree>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    navItems: Array,
+    dataItems: Array,
+  },
+  data() {
+    return {
+      navProps: {
+        children: 'children',
+        label: 'name',
+      },
+    };
+  },
+  methods: {
+    handleNavClick(data) {
+      this.$emit('selected', data);
+    },
+    setCurrentKey(key) {
+      this.$refs['tree'].setCurrentKey(key);
+    },
+  },
+  computed: {
+    treeItems() {
+      if (this.navItems) return this.navItems;
+      const items = this.dataItems || [];
+      const root = items.filter(a => !items.some(b => b.id === a.parentid));
+      const fetchChildren = item => {
+        if (!item.path) item.path = [item.name];
+        const children = items.filter(p => p.parentid === item.id).map(p => fetchChildren({ ...p, parent: item, path: item.path.concat(p.name) }));
+        return { ...item, children };
+      };
+      return root.map(p => fetchChildren(p));
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.nav-tree {
+  /deep/ .el-tree-node.is-current > .el-tree-node__content {
+    background-color: #409eff;
+    color: white;
+    .naf-icon-dian {
+      display: inline;
+      color: white;
+    }
+  }
+  /deep/ .naf-icon-dian {
+    display: none;
+  }
+  /deep/ .el-tree-node__content:hover .naf-icon-dian {
+    display: inline;
+  }
+}
+</style>

+ 151 - 0
naf/user/user-select.vue

@@ -0,0 +1,151 @@
+<template>
+  <el-dialog :title="title" :visible.sync="visible" width="600px" :close-on-click-modal="false">
+    <div class="content">
+      <div class="left">
+        <el-scrollbar>
+          <el-tree ref="tree" :data="treeItems" :props="navProps" node-key="_id" @node-click="handleNavClick"
+                   :highlight-current="true">
+            <span class="custom-tree-node" slot-scope="{ node, data }">
+              <span>
+                <i class="prefix naf-icons naf-icon-user1" v-if="data.userid" />
+                <i class="prefix naf-icons naf-icon-folder1" v-else />
+                {{ node.label }}
+              </span>
+              <span>
+                <i class="suffix naf-icons naf-icon-ok" v-show="inSelected(data)" />
+              </span>
+            </span>
+          </el-tree>
+        </el-scrollbar>
+      </div>
+      <div class="right">
+        <el-scrollbar>
+          <el-tree ref="selected" :data="selected" :props="navProps" node-key="id" :highlight-current="true">
+            <span class="custom-tree-node" slot-scope="{ node, data }">
+              <span>
+                <i class="prefix naf-icons naf-icon-user1" v-if="data.userid" />
+                <i class="prefix naf-icons naf-icon-folder1" v-else />
+                {{ node.label }}
+              </span>
+              <span style="float: right">
+                <i class="suffix naf-icons naf-icon-close" />
+              </span>
+            </span>
+          </el-tree>
+        </el-scrollbar>
+      </div>
+    </div>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="$emit('cancel')" :size="options.size">取 消</el-button>
+      <el-button type="primary" @click="$emit('ok', selected)" :size="options.size">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import { mapState } from 'vuex';
+import _ from 'lodash';
+
+export default {
+  props: {
+    options: {
+      type: Object,
+      default: () => ({ size: 'small' }),
+    } /* form options */,
+    title: String,
+    visible: { type: Boolean, default: true },
+  },
+  data() {
+    return {
+      navProps: {
+        children: 'children',
+        label: 'name',
+      },
+      selected: [],
+    };
+  },
+  methods: {
+    handleNavClick(data) {
+      // this.$emit('selected', data);
+      const idx = this.selected.findIndex(p => (_.isNumber(data.id) && p.id === data.id) || (_.isString(data.userid) && p.userid === data.userid));
+      console.log('idx:', idx);
+      if (idx === -1) {
+        this.selected.push(_.omit(data, ['children']));
+      } else {
+        this.selected.splice(idx, 1);
+      }
+    },
+    inSelected(data) {
+      return this.selected.some(p => (_.isNumber(data.id) && p.id === data.id) || (_.isString(data.userid) && p.userid === data.userid));
+    },
+  },
+  computed: {
+    ...mapState({
+      deptItems: state => state.system.dept.items,
+      userItems: state => state.system.user.items,
+    }),
+    treeItems() {
+      if (this.navItems) return this.navItems;
+      const items = this.deptItems || [];
+      const root = items.filter(a => !items.some(b => b.id === a.parentid));
+      const fetchChildren = item => {
+        const children = items.filter(p => p.parentid === item.id).map(p => fetchChildren(p));
+        const users = this.userItems.filter(p => p.department && p.department.includes(item.id));
+        return { ...item, children: [...children, ...users] };
+      };
+      const rootUsers = this.userItems.filter(p => p.department && p.department.includes(0));
+      return root.map(p => fetchChildren(p)).concat(rootUsers);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.nav-tree {
+  /deep/ .el-tree-node.is-current > .el-tree-node__content {
+    background-color: #409eff;
+    color: white;
+    .naf-icon-dian {
+      display: inline;
+      color: white;
+    }
+  }
+  /deep/ .naf-icon-dian {
+    display: none;
+  }
+  /deep/ .el-tree-node__content:hover .naf-icon-dian {
+    display: inline;
+  }
+}
+
+.content {
+  display: flex;
+  flex-direction: row;
+  height: 340px;
+}
+
+.left {
+  flex: 1;
+}
+.right {
+  width: 240px;
+}
+
+.naf-icons.prefix {
+  color: grey;
+}
+.naf-icons.suffix {
+  color: lightgrey;
+}
+
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+
+.el-scrollbar {
+  height: 100%;
+}
+</style>

+ 49 - 0
package.json

@@ -0,0 +1,49 @@
+{
+  "name": "admin-docflow",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@stomp/stompjs": "^5.2.0",
+    "axios": "^0.18.0",
+    "element-ui": "^2.6.1",
+    "js-cookie": "^2.2.0",
+    "jsonwebtoken": "^8.5.0",
+    "mint-ui": "^2.2.13",
+    "naf-core": "0.1.2",
+    "qrcode": "^1.3.3",
+    "url-join": "^4.0.0",
+    "vue": "^2.6.8",
+    "vue-meta": "^1.5.8",
+    "vue-router": "^3.0.2",
+    "vuex": "^3.1.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "^3.4.1",
+    "@vue/cli-plugin-eslint": "^3.4.1",
+    "@vue/cli-service": "^3.4.1",
+    "@vue/eslint-config-prettier": "^4.0.1",
+    "babel-eslint": "^10.0.1",
+    "babel-plugin-component": "^1.1.1",
+    "eslint": "^5.15.1",
+    "eslint-plugin-vue": "^5.2.2",
+    "less": "^3.9.0",
+    "less-loader": "^4.1.0",
+    "vue-cli-plugin-element": "^1.0.1",
+    "vue-template-compiler": "^2.6.8"
+  },
+  "postcss": {
+    "plugins": {
+      "autoprefixer": {}
+    }
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 0 - 0
public/.gitkeep


BIN
public/favicon.ico


+ 23 - 0
public/index.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <link rel="stylesheet" href="<%= BASE_URL %>naf-icons/iconfont.css">
+    <link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/1.1.3/weui.min.css">
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css">
+    <script type="text/javascript" src="https://res.wx.qq.com/open/libs/weuijs/1.1.4/weui.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>
+    <title>加载中...</title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but admin-frame doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 370 - 0
public/naf-icons/demo.css

@@ -0,0 +1,370 @@
+*{margin: 0;padding: 0;list-style: none;}
+/*
+KISSY CSS Reset
+理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
+2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
+3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
+特色:1. 适应中文;2. 基于最新主流浏览器。
+维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com>
+ */
+
+/** 清除内外边距 **/
+body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
+dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
+pre, /* text formatting elements 文本格式元素 */
+form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
+th, td /* table elements 表格元素 */ {
+  margin: 0;
+  padding: 0;
+}
+
+/** 设置默认字体 **/
+body,
+button, input, select, textarea /* for ie */ {
+  font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
+}
+h1, h2, h3, h4, h5, h6 { font-size: 100%; }
+address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
+code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
+small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
+
+/** 重置列表元素 **/
+ul, ol { list-style: none; }
+
+/** 重置文本格式元素 **/
+a { text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+
+/** 重置表单元素 **/
+legend { color: #000; } /* for ie6 */
+fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
+button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
+/* 注:optgroup 无法扶正 */
+
+/** 重置表格元素 **/
+table { border-collapse: collapse; border-spacing: 0; }
+
+/* 清除浮动 */
+.ks-clear:after, .clear:after {
+  content: '\20';
+  display: block;
+  height: 0;
+  clear: both;
+}
+.ks-clear, .clear {
+  *zoom: 1;
+}
+
+.main {
+  padding: 30px 100px;
+width: 960px;
+margin: 0 auto;
+}
+.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
+
+.helps{margin-top:40px;}
+.helps pre{
+  padding:20px;
+  margin:10px 0;
+  border:solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists{
+  width: 100% !important;
+
+}
+
+.icon_lists li{
+  float:left;
+  width: 100px;
+  height:180px;
+  text-align: center;
+  list-style: none !important;
+}
+.icon_lists .icon{
+  font-size: 42px;
+  line-height: 100px;
+  margin: 10px 0;
+  color:#333;
+  -webkit-transition: font-size 0.25s ease-out 0s;
+  -moz-transition: font-size 0.25s ease-out 0s;
+  transition: font-size 0.25s ease-out 0s;
+
+}
+.icon_lists .icon:hover{
+  font-size: 100px;
+}
+
+
+
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p,
+.markdown pre {
+  margin: 1em 0;
+}
+
+.markdown > p,
+.markdown > blockquote,
+.markdown > .highlight,
+.markdown > ol,
+.markdown > ul {
+  width: 80%;
+}
+
+.markdown ul > li {
+  list-style: circle;
+}
+
+.markdown > ul li,
+.markdown blockquote ul > li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown > ul li p,
+.markdown > ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol > li {
+  list-style: decimal;
+}
+
+.markdown > ol li,
+.markdown blockquote ol > li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown pre {
+  border-radius: 6px;
+  background: #f7f7f7;
+  padding: 20px;
+}
+
+.markdown pre code {
+  border: none;
+  background: #f7f7f7;
+  margin: 0;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown > table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown > table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+
+}
+
+.markdown > table th,
+.markdown > table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown > table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+  font-style: italic;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown > br,
+.markdown > p > br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+pre{
+  background: #fff;
+}
+
+
+
+
+

+ 850 - 0
public/naf-icons/demo_fontclass.html

@@ -0,0 +1,850 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8"/>
+    <title>IconFont</title>
+    <link rel="stylesheet" href="demo.css">
+    <link rel="stylesheet" href="iconfont.css">
+</head>
+<body>
+    <div class="main markdown">
+        <h1>IconFont 图标</h1>
+        <ul class="icon_lists clear">
+            
+                <li>
+                <i class="icon naf-icons naf-icon-xinxi"></i>
+                    <div class="name">信息</div>
+                    <div class="fontclass">.naf-icon-xinxi</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-avatar"></i>
+                    <div class="name">user</div>
+                    <div class="fontclass">.naf-icon-avatar</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-idok"></i>
+                    <div class="name">身份证号</div>
+                    <div class="fontclass">.naf-icon-idok</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-folder"></i>
+                    <div class="name">cc-folder</div>
+                    <div class="fontclass">.naf-icon-folder</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfont5"></i>
+                    <div class="name">iconfont-5</div>
+                    <div class="fontclass">.naf-icon-iconfont5</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-doc1"></i>
+                    <div class="name">发文</div>
+                    <div class="fontclass">.naf-icon-doc1</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbbaobiao"></i>
+                    <div class="name">wxb报表</div>
+                    <div class="fontclass">.naf-icon-wxbbaobiao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbbiaowang"></i>
+                    <div class="name">wxb标王</div>
+                    <div class="fontclass">.naf-icon-wxbbiaowang</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbgongju"></i>
+                    <div class="name">wxb工具</div>
+                    <div class="fontclass">.naf-icon-wxbgongju</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbmingxingdianpu"></i>
+                    <div class="name">wxb明星店铺</div>
+                    <div class="fontclass">.naf-icon-wxbmingxingdianpu</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbpinpaibao"></i>
+                    <div class="name">wxb品牌宝</div>
+                    <div class="fontclass">.naf-icon-wxbpinpaibao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-idcard"></i>
+                    <div class="name">wxb账户</div>
+                    <div class="fontclass">.naf-icon-idcard</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbzhuye"></i>
+                    <div class="name">wxb主页</div>
+                    <div class="fontclass">.naf-icon-wxbzhuye</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbsousuotuiguang"></i>
+                    <div class="name">wxb搜索推广</div>
+                    <div class="fontclass">.naf-icon-wxbsousuotuiguang</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wxbdingwei"></i>
+                    <div class="name">wxb定位</div>
+                    <div class="fontclass">.naf-icon-wxbdingwei</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-jifen"></i>
+                    <div class="name">积分</div>
+                    <div class="fontclass">.naf-icon-jifen</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-erweima"></i>
+                    <div class="name">二维码</div>
+                    <div class="fontclass">.naf-icon-erweima</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-jushoucang"></i>
+                    <div class="name">聚收藏</div>
+                    <div class="fontclass">.naf-icon-jushoucang</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-lajixiang"></i>
+                    <div class="name">垃圾箱</div>
+                    <div class="fontclass">.naf-icon-lajixiang</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-lianjie"></i>
+                    <div class="name">链接</div>
+                    <div class="fontclass">.naf-icon-lianjie</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-naozhong"></i>
+                    <div class="name">闹钟</div>
+                    <div class="fontclass">.naf-icon-naozhong</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-saoyisao"></i>
+                    <div class="name">扫一扫</div>
+                    <div class="fontclass">.naf-icon-saoyisao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-shezhi"></i>
+                    <div class="name">设置</div>
+                    <div class="fontclass">.naf-icon-shezhi</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-shengyin"></i>
+                    <div class="name">声音</div>
+                    <div class="fontclass">.naf-icon-shengyin</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-shijian"></i>
+                    <div class="name">时间</div>
+                    <div class="fontclass">.naf-icon-shijian</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-location"></i>
+                    <div class="name">收货地址</div>
+                    <div class="fontclass">.naf-icon-location</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-shouye"></i>
+                    <div class="name">首页</div>
+                    <div class="fontclass">.naf-icon-shouye</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-sousuo"></i>
+                    <div class="name">搜索</div>
+                    <div class="fontclass">.naf-icon-sousuo</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-suo"></i>
+                    <div class="name">锁</div>
+                    <div class="fontclass">.naf-icon-suo</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-tishi"></i>
+                    <div class="name">提示</div>
+                    <div class="fontclass">.naf-icon-tishi</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wancheng"></i>
+                    <div class="name">完成</div>
+                    <div class="fontclass">.naf-icon-wancheng</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wodedingdan"></i>
+                    <div class="name">我的订单</div>
+                    <div class="fontclass">.naf-icon-wodedingdan</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-msg2"></i>
+                    <div class="name">我的反馈</div>
+                    <div class="fontclass">.naf-icon-msg2</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wodehongbao"></i>
+                    <div class="name">我的红包</div>
+                    <div class="fontclass">.naf-icon-wodehongbao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wodejuhuasuan"></i>
+                    <div class="name">我的聚划算</div>
+                    <div class="fontclass">.naf-icon-wodejuhuasuan</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-wodeyouhuiquan"></i>
+                    <div class="name">我的优惠券</div>
+                    <div class="fontclass">.naf-icon-wodeyouhuiquan</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-xiala"></i>
+                    <div class="name">下拉</div>
+                    <div class="fontclass">.naf-icon-xiala</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-yanjing"></i>
+                    <div class="name">眼睛</div>
+                    <div class="fontclass">.naf-icon-yanjing</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-receipt"></i>
+                    <div class="name">意见反馈</div>
+                    <div class="fontclass">.naf-icon-receipt</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-zhaoxiangji"></i>
+                    <div class="name">照相机</div>
+                    <div class="fontclass">.naf-icon-zhaoxiangji</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-ok"></i>
+                    <div class="name">正确</div>
+                    <div class="fontclass">.naf-icon-ok</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-msg1"></i>
+                    <div class="name">消息中心</div>
+                    <div class="fontclass">.naf-icon-msg1</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-lingcunwei"></i>
+                    <div class="name">另存为</div>
+                    <div class="fontclass">.naf-icon-lingcunwei</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-new"></i>
+                    <div class="name">new</div>
+                    <div class="fontclass">.naf-icon-new</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-huo"></i>
+                    <div class="name">火</div>
+                    <div class="fontclass">.naf-icon-huo</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-password"></i>
+                    <div class="name">password</div>
+                    <div class="fontclass">.naf-icon-password</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-doc4"></i>
+                    <div class="name">收文</div>
+                    <div class="fontclass">.naf-icon-doc4</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontyouhuiquan"></i>
+                    <div class="name">iconfont-youhuiquan</div>
+                    <div class="fontclass">.naf-icon-iconfontyouhuiquan</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontxingxing"></i>
+                    <div class="name">iconfont-xingxing</div>
+                    <div class="fontclass">.naf-icon-iconfontxingxing</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontmingpian"></i>
+                    <div class="name">iconfont-mingpian</div>
+                    <div class="fontclass">.naf-icon-iconfontmingpian</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-mobile"></i>
+                    <div class="name">iconfont-shouji</div>
+                    <div class="fontclass">.naf-icon-mobile</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontriyongbaihuo"></i>
+                    <div class="name">iconfont-riyongbaihuo</div>
+                    <div class="fontclass">.naf-icon-iconfontriyongbaihuo</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-setting"></i>
+                    <div class="name">iconfont-jixieqimo</div>
+                    <div class="fontclass">.naf-icon-setting</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontxiangjiaosuliao"></i>
+                    <div class="name">iconfont-xiangjiaosuliao</div>
+                    <div class="fontclass">.naf-icon-iconfontxiangjiaosuliao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontyiqiyibiao"></i>
+                    <div class="name">iconfont-yiqiyibiao</div>
+                    <div class="fontclass">.naf-icon-iconfontyiqiyibiao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontzhaomingdianzi"></i>
+                    <div class="name">iconfont-zhaomingdianzi</div>
+                    <div class="fontclass">.naf-icon-iconfontzhaomingdianzi</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontfuwushichang"></i>
+                    <div class="name">iconfont-fuwushichang</div>
+                    <div class="fontclass">.naf-icon-iconfontfuwushichang</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontfangzhipige"></i>
+                    <div class="name">iconfont-fangzhipige</div>
+                    <div class="fontclass">.naf-icon-iconfontfangzhipige</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-iconfontbaozhuang"></i>
+                    <div class="name">iconfont-baozhuang</div>
+                    <div class="fontclass">.naf-icon-iconfontbaozhuang</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-gerenshimingrz"></i>
+                    <div class="name">个人实名认证</div>
+                    <div class="fontclass">.naf-icon-gerenshimingrz</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-renzheng"></i>
+                    <div class="name">企业名称认证</div>
+                    <div class="fontclass">.naf-icon-renzheng</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-shendurz"></i>
+                    <div class="name">深度认证</div>
+                    <div class="fontclass">.naf-icon-shendurz</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-clearup"></i>
+                    <div class="name">Clearup</div>
+                    <div class="fontclass">.naf-icon-clearup</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-site"></i>
+                    <div class="name">网站</div>
+                    <div class="fontclass">.naf-icon-site</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-jushoucanggift"></i>
+                    <div class="name">聚收藏gift</div>
+                    <div class="fontclass">.naf-icon-jushoucanggift</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-liwu"></i>
+                    <div class="name">礼物</div>
+                    <div class="fontclass">.naf-icon-liwu</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-yuyin"></i>
+                    <div class="name">语音</div>
+                    <div class="fontclass">.naf-icon-yuyin</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-user"></i>
+                    <div class="name">user2</div>
+                    <div class="fontclass">.naf-icon-user</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-zhengshu"></i>
+                    <div class="name">证书</div>
+                    <div class="fontclass">.naf-icon-zhengshu</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-user1"></i>
+                    <div class="name">User</div>
+                    <div class="fontclass">.naf-icon-user1</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-feedback"></i>
+                    <div class="name">feedback</div>
+                    <div class="fontclass">.naf-icon-feedback</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-doc3"></i>
+                    <div class="name">发文</div>
+                    <div class="fontclass">.naf-icon-doc3</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-job"></i>
+                    <div class="name">招聘 </div>
+                    <div class="fontclass">.naf-icon-job</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-cert"></i>
+                    <div class="name">证书</div>
+                    <div class="fontclass">.naf-icon-cert</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-all"></i>
+                    <div class="name">all</div>
+                    <div class="fontclass">.naf-icon-all</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-cart"></i>
+                    <div class="name">cart</div>
+                    <div class="fontclass">.naf-icon-cart</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-set"></i>
+                    <div class="name">set</div>
+                    <div class="fontclass">.naf-icon-set</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-arrowdown"></i>
+                    <div class="name">arrow-down</div>
+                    <div class="fontclass">.naf-icon-arrowdown</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-arrowleft"></i>
+                    <div class="name">arrow-left</div>
+                    <div class="fontclass">.naf-icon-arrowleft</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-arrowright"></i>
+                    <div class="name">arrow-right</div>
+                    <div class="fontclass">.naf-icon-arrowright</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-arrowup"></i>
+                    <div class="name">arrow-up</div>
+                    <div class="fontclass">.naf-icon-arrowup</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-favorite"></i>
+                    <div class="name">favorite</div>
+                    <div class="fontclass">.naf-icon-favorite</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-good"></i>
+                    <div class="name">good</div>
+                    <div class="fontclass">.naf-icon-good</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-close"></i>
+                    <div class="name">close</div>
+                    <div class="fontclass">.naf-icon-close</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-refresh"></i>
+                    <div class="name">refresh</div>
+                    <div class="fontclass">.naf-icon-refresh</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-map"></i>
+                    <div class="name">map</div>
+                    <div class="fontclass">.naf-icon-map</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-account"></i>
+                    <div class="name">account</div>
+                    <div class="fontclass">.naf-icon-account</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-search"></i>
+                    <div class="name">search</div>
+                    <div class="fontclass">.naf-icon-search</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-download"></i>
+                    <div class="name">download</div>
+                    <div class="fontclass">.naf-icon-download</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-compass"></i>
+                    <div class="name">compass</div>
+                    <div class="fontclass">.naf-icon-compass</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-comments"></i>
+                    <div class="name">comments</div>
+                    <div class="fontclass">.naf-icon-comments</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-down"></i>
+                    <div class="name">down</div>
+                    <div class="fontclass">.naf-icon-down</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-up"></i>
+                    <div class="name">up</div>
+                    <div class="fontclass">.naf-icon-up</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-play"></i>
+                    <div class="name">play</div>
+                    <div class="fontclass">.naf-icon-play</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-error"></i>
+                    <div class="name">error</div>
+                    <div class="fontclass">.naf-icon-error</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-prompt"></i>
+                    <div class="name">prompt</div>
+                    <div class="fontclass">.naf-icon-prompt</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-success"></i>
+                    <div class="name">success</div>
+                    <div class="fontclass">.naf-icon-success</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-stop"></i>
+                    <div class="name">stop</div>
+                    <div class="fontclass">.naf-icon-stop</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-help"></i>
+                    <div class="name">help</div>
+                    <div class="fontclass">.naf-icon-help</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-time"></i>
+                    <div class="name">time</div>
+                    <div class="fontclass">.naf-icon-time</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-cry"></i>
+                    <div class="name">cry</div>
+                    <div class="fontclass">.naf-icon-cry</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-add"></i>
+                    <div class="name">add</div>
+                    <div class="fontclass">.naf-icon-add</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-minus"></i>
+                    <div class="name">minus</div>
+                    <div class="fontclass">.naf-icon-minus</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-link"></i>
+                    <div class="name">link</div>
+                    <div class="fontclass">.naf-icon-link</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-atm"></i>
+                    <div class="name">atm</div>
+                    <div class="fontclass">.naf-icon-atm</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-skip"></i>
+                    <div class="name">skip</div>
+                    <div class="fontclass">.naf-icon-skip</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-attachment"></i>
+                    <div class="name">attachment</div>
+                    <div class="fontclass">.naf-icon-attachment</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-browse"></i>
+                    <div class="name">browse</div>
+                    <div class="fontclass">.naf-icon-browse</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-phone"></i>
+                    <div class="name">phone</div>
+                    <div class="fontclass">.naf-icon-phone</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-bad"></i>
+                    <div class="name">bad</div>
+                    <div class="fontclass">.naf-icon-bad</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-text"></i>
+                    <div class="name">text</div>
+                    <div class="fontclass">.naf-icon-text</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-corpuser"></i>
+                    <div class="name">企业用户</div>
+                    <div class="fontclass">.naf-icon-corpuser</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-erweima1688"></i>
+                    <div class="name">二维码</div>
+                    <div class="fontclass">.naf-icon-erweima1688</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-quit"></i>
+                    <div class="name">quit</div>
+                    <div class="fontclass">.naf-icon-quit</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-folder1"></i>
+                    <div class="name">folder</div>
+                    <div class="fontclass">.naf-icon-folder1</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-dept"></i>
+                    <div class="name">部门</div>
+                    <div class="fontclass">.naf-icon-dept</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-report"></i>
+                    <div class="name">报表</div>
+                    <div class="fontclass">.naf-icon-report</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-shenhe"></i>
+                    <div class="name">审核</div>
+                    <div class="fontclass">.naf-icon-shenhe</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-info"></i>
+                    <div class="name">企业信息</div>
+                    <div class="fontclass">.naf-icon-info</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-corp"></i>
+                    <div class="name">企业</div>
+                    <div class="fontclass">.naf-icon-corp</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-doc"></i>
+                    <div class="name">公文</div>
+                    <div class="fontclass">.naf-icon-doc</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-log"></i>
+                    <div class="name">日志</div>
+                    <div class="fontclass">.naf-icon-log</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-verifycode"></i>
+                    <div class="name">验证码</div>
+                    <div class="fontclass">.naf-icon-verifycode</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-tag"></i>
+                    <div class="name">标签</div>
+                    <div class="fontclass">.naf-icon-tag</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-caogao"></i>
+                    <div class="name">草稿</div>
+                    <div class="fontclass">.naf-icon-caogao</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-dian"></i>
+                    <div class="name">点</div>
+                    <div class="fontclass">.naf-icon-dian</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-doc2"></i>
+                    <div class="name">发文</div>
+                    <div class="fontclass">.naf-icon-doc2</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-fold"></i>
+                    <div class="name">fold</div>
+                    <div class="fontclass">.naf-icon-fold</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-unfold"></i>
+                    <div class="name">unfold</div>
+                    <div class="fontclass">.naf-icon-unfold</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-news"></i>
+                    <div class="name">信息管理</div>
+                    <div class="fontclass">.naf-icon-news</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-reply"></i>
+                    <div class="name">回复</div>
+                    <div class="fontclass">.naf-icon-reply</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-column"></i>
+                    <div class="name">栏目管理</div>
+                    <div class="fontclass">.naf-icon-column</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-dict"></i>
+                    <div class="name">字典</div>
+                    <div class="fontclass">.naf-icon-dict</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-system"></i>
+                    <div class="name">系统管理</div>
+                    <div class="fontclass">.naf-icon-system</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons naf-icon-menu"></i>
+                    <div class="name">菜单</div>
+                    <div class="fontclass">.naf-icon-menu</div>
+                </li>
+            
+        </ul>
+
+        <h2 id="font-class-">font-class引用</h2>
+        <hr>
+
+        <p>font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。</p>
+        <p>与unicode使用方式相比,具有如下特点:</p>
+        <ul>
+        <li>兼容性良好,支持ie8+,及所有现代浏览器。</li>
+        <li>相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。</li>
+        <li>因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。</li>
+        <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的fontclass代码:</h3>
+
+
+        <pre><code class="lang-js hljs javascript"><span class="hljs-comment">&lt;link rel="stylesheet" type="text/css" href="./iconfont.css"&gt;</span></code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+        <pre><code class="lang-css hljs">&lt;<span class="hljs-selector-tag">i</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">naf-icons</span> <span class="hljs-selector-tag">naf-icon-xxx</span>"&gt;&lt;/<span class="hljs-selector-tag">i</span>&gt;</code></pre>
+        <blockquote>
+        <p>"naf-icons"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p>
+        </blockquote>
+    </div>
+</body>
+</html>

File diff suppressed because it is too large
+ 1143 - 0
public/naf-icons/demo_symbol.html


+ 888 - 0
public/naf-icons/demo_unicode.html

@@ -0,0 +1,888 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8"/>
+    <title>IconFont</title>
+    <link rel="stylesheet" href="demo.css">
+
+    <style type="text/css">
+
+        @font-face {font-family: "naf-icons";
+          src: url('iconfont.eot'); /* IE9*/
+          src: url('iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
+          url('iconfont.woff') format('woff'), /* chrome, firefox */
+          url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
+          url('iconfont.svg#naf-icons') format('svg'); /* iOS 4.1- */
+        }
+
+        .naf-icons {
+          font-family:"naf-icons" !important;
+          font-size:16px;
+          font-style:normal;
+          -webkit-font-smoothing: antialiased;
+          -webkit-text-stroke-width: 0.2px;
+          -moz-osx-font-smoothing: grayscale;
+        }
+
+    </style>
+</head>
+<body>
+    <div class="main markdown">
+        <h1>IconFont 图标</h1>
+        <ul class="icon_lists clear">
+            
+                <li>
+                <i class="icon naf-icons">&#xe60a;</i>
+                    <div class="name">信息</div>
+                    <div class="code">&amp;#xe60a;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a0;</i>
+                    <div class="name">user</div>
+                    <div class="code">&amp;#xe6a0;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe64a;</i>
+                    <div class="name">身份证号</div>
+                    <div class="code">&amp;#xe64a;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe65e;</i>
+                    <div class="name">cc-folder</div>
+                    <div class="code">&amp;#xe65e;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe63a;</i>
+                    <div class="name">iconfont-5</div>
+                    <div class="code">&amp;#xe63a;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe60d;</i>
+                    <div class="name">发文</div>
+                    <div class="code">&amp;#xe60d;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe618;</i>
+                    <div class="name">wxb报表</div>
+                    <div class="code">&amp;#xe618;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe61a;</i>
+                    <div class="name">wxb标王</div>
+                    <div class="code">&amp;#xe61a;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe61b;</i>
+                    <div class="name">wxb工具</div>
+                    <div class="code">&amp;#xe61b;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe61d;</i>
+                    <div class="name">wxb明星店铺</div>
+                    <div class="code">&amp;#xe61d;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe61e;</i>
+                    <div class="name">wxb品牌宝</div>
+                    <div class="code">&amp;#xe61e;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe61f;</i>
+                    <div class="name">wxb账户</div>
+                    <div class="code">&amp;#xe61f;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe620;</i>
+                    <div class="name">wxb主页</div>
+                    <div class="code">&amp;#xe620;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe621;</i>
+                    <div class="name">wxb搜索推广</div>
+                    <div class="code">&amp;#xe621;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe624;</i>
+                    <div class="name">wxb定位</div>
+                    <div class="code">&amp;#xe624;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe625;</i>
+                    <div class="name">积分</div>
+                    <div class="code">&amp;#xe625;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe642;</i>
+                    <div class="name">二维码</div>
+                    <div class="code">&amp;#xe642;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe643;</i>
+                    <div class="name">聚收藏</div>
+                    <div class="code">&amp;#xe643;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe645;</i>
+                    <div class="name">垃圾箱</div>
+                    <div class="code">&amp;#xe645;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe646;</i>
+                    <div class="name">链接</div>
+                    <div class="code">&amp;#xe646;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe648;</i>
+                    <div class="name">闹钟</div>
+                    <div class="code">&amp;#xe648;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe649;</i>
+                    <div class="name">扫一扫</div>
+                    <div class="code">&amp;#xe649;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe64b;</i>
+                    <div class="name">设置</div>
+                    <div class="code">&amp;#xe64b;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe64c;</i>
+                    <div class="name">声音</div>
+                    <div class="code">&amp;#xe64c;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe64d;</i>
+                    <div class="name">时间</div>
+                    <div class="code">&amp;#xe64d;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe64e;</i>
+                    <div class="name">收货地址</div>
+                    <div class="code">&amp;#xe64e;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe64f;</i>
+                    <div class="name">首页</div>
+                    <div class="code">&amp;#xe64f;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe651;</i>
+                    <div class="name">搜索</div>
+                    <div class="code">&amp;#xe651;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe652;</i>
+                    <div class="name">锁</div>
+                    <div class="code">&amp;#xe652;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe653;</i>
+                    <div class="name">提示</div>
+                    <div class="code">&amp;#xe653;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe654;</i>
+                    <div class="name">完成</div>
+                    <div class="code">&amp;#xe654;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe655;</i>
+                    <div class="name">我的订单</div>
+                    <div class="code">&amp;#xe655;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe656;</i>
+                    <div class="name">我的反馈</div>
+                    <div class="code">&amp;#xe656;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe657;</i>
+                    <div class="name">我的红包</div>
+                    <div class="code">&amp;#xe657;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe659;</i>
+                    <div class="name">我的聚划算</div>
+                    <div class="code">&amp;#xe659;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe65a;</i>
+                    <div class="name">我的优惠券</div>
+                    <div class="code">&amp;#xe65a;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe65c;</i>
+                    <div class="name">下拉</div>
+                    <div class="code">&amp;#xe65c;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe661;</i>
+                    <div class="name">眼睛</div>
+                    <div class="code">&amp;#xe661;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe662;</i>
+                    <div class="name">意见反馈</div>
+                    <div class="code">&amp;#xe662;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe663;</i>
+                    <div class="name">照相机</div>
+                    <div class="code">&amp;#xe663;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe664;</i>
+                    <div class="name">正确</div>
+                    <div class="code">&amp;#xe664;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe665;</i>
+                    <div class="name">消息中心</div>
+                    <div class="code">&amp;#xe665;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe666;</i>
+                    <div class="name">另存为</div>
+                    <div class="code">&amp;#xe666;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe667;</i>
+                    <div class="name">new</div>
+                    <div class="code">&amp;#xe667;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe66d;</i>
+                    <div class="name">火</div>
+                    <div class="code">&amp;#xe66d;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6cf;</i>
+                    <div class="name">password</div>
+                    <div class="code">&amp;#xe6cf;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe65b;</i>
+                    <div class="name">收文</div>
+                    <div class="code">&amp;#xe65b;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe627;</i>
+                    <div class="name">iconfont-youhuiquan</div>
+                    <div class="code">&amp;#xe627;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe628;</i>
+                    <div class="name">iconfont-xingxing</div>
+                    <div class="code">&amp;#xe628;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe629;</i>
+                    <div class="name">iconfont-mingpian</div>
+                    <div class="code">&amp;#xe629;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe62b;</i>
+                    <div class="name">iconfont-shouji</div>
+                    <div class="code">&amp;#xe62b;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe62c;</i>
+                    <div class="name">iconfont-riyongbaihuo</div>
+                    <div class="code">&amp;#xe62c;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe639;</i>
+                    <div class="name">iconfont-jixieqimo</div>
+                    <div class="code">&amp;#xe639;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe644;</i>
+                    <div class="name">iconfont-xiangjiaosuliao</div>
+                    <div class="code">&amp;#xe644;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe647;</i>
+                    <div class="name">iconfont-yiqiyibiao</div>
+                    <div class="code">&amp;#xe647;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe669;</i>
+                    <div class="name">iconfont-zhaomingdianzi</div>
+                    <div class="code">&amp;#xe669;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe658;</i>
+                    <div class="name">iconfont-fuwushichang</div>
+                    <div class="code">&amp;#xe658;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe66b;</i>
+                    <div class="name">iconfont-fangzhipige</div>
+                    <div class="code">&amp;#xe66b;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe66c;</i>
+                    <div class="name">iconfont-baozhuang</div>
+                    <div class="code">&amp;#xe66c;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe66e;</i>
+                    <div class="name">个人实名认证</div>
+                    <div class="code">&amp;#xe66e;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe66f;</i>
+                    <div class="name">企业名称认证</div>
+                    <div class="code">&amp;#xe66f;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe668;</i>
+                    <div class="name">深度认证</div>
+                    <div class="code">&amp;#xe668;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe65d;</i>
+                    <div class="name">Clearup</div>
+                    <div class="code">&amp;#xe65d;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe697;</i>
+                    <div class="name">网站</div>
+                    <div class="code">&amp;#xe697;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe684;</i>
+                    <div class="name">聚收藏gift</div>
+                    <div class="code">&amp;#xe684;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe685;</i>
+                    <div class="name">礼物</div>
+                    <div class="code">&amp;#xe685;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe687;</i>
+                    <div class="name">语音</div>
+                    <div class="code">&amp;#xe687;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe601;</i>
+                    <div class="name">user2</div>
+                    <div class="code">&amp;#xe601;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe608;</i>
+                    <div class="name">证书</div>
+                    <div class="code">&amp;#xe608;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe743;</i>
+                    <div class="name">User</div>
+                    <div class="code">&amp;#xe743;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6de;</i>
+                    <div class="name">feedback</div>
+                    <div class="code">&amp;#xe6de;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe604;</i>
+                    <div class="name">发文</div>
+                    <div class="code">&amp;#xe604;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe617;</i>
+                    <div class="name">招聘 </div>
+                    <div class="code">&amp;#xe617;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe650;</i>
+                    <div class="name">证书</div>
+                    <div class="code">&amp;#xe650;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe68d;</i>
+                    <div class="name">all</div>
+                    <div class="code">&amp;#xe68d;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe68e;</i>
+                    <div class="name">cart</div>
+                    <div class="code">&amp;#xe68e;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe690;</i>
+                    <div class="name">set</div>
+                    <div class="code">&amp;#xe690;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe692;</i>
+                    <div class="name">arrow-down</div>
+                    <div class="code">&amp;#xe692;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe693;</i>
+                    <div class="name">arrow-left</div>
+                    <div class="code">&amp;#xe693;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe694;</i>
+                    <div class="name">arrow-right</div>
+                    <div class="code">&amp;#xe694;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe695;</i>
+                    <div class="name">arrow-up</div>
+                    <div class="code">&amp;#xe695;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe696;</i>
+                    <div class="name">favorite</div>
+                    <div class="code">&amp;#xe696;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe699;</i>
+                    <div class="name">good</div>
+                    <div class="code">&amp;#xe699;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe69a;</i>
+                    <div class="name">close</div>
+                    <div class="code">&amp;#xe69a;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a1;</i>
+                    <div class="name">refresh</div>
+                    <div class="code">&amp;#xe6a1;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a2;</i>
+                    <div class="name">map</div>
+                    <div class="code">&amp;#xe6a2;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a3;</i>
+                    <div class="name">account</div>
+                    <div class="code">&amp;#xe6a3;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a4;</i>
+                    <div class="name">search</div>
+                    <div class="code">&amp;#xe6a4;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a5;</i>
+                    <div class="name">download</div>
+                    <div class="code">&amp;#xe6a5;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a6;</i>
+                    <div class="name">compass</div>
+                    <div class="code">&amp;#xe6a6;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a7;</i>
+                    <div class="name">comments</div>
+                    <div class="code">&amp;#xe6a7;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a8;</i>
+                    <div class="name">down</div>
+                    <div class="code">&amp;#xe6a8;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6a9;</i>
+                    <div class="name">up</div>
+                    <div class="code">&amp;#xe6a9;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b0;</i>
+                    <div class="name">play</div>
+                    <div class="code">&amp;#xe6b0;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b1;</i>
+                    <div class="name">error</div>
+                    <div class="code">&amp;#xe6b1;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b2;</i>
+                    <div class="name">prompt</div>
+                    <div class="code">&amp;#xe6b2;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b3;</i>
+                    <div class="name">success</div>
+                    <div class="code">&amp;#xe6b3;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b5;</i>
+                    <div class="name">stop</div>
+                    <div class="code">&amp;#xe6b5;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b6;</i>
+                    <div class="name">help</div>
+                    <div class="code">&amp;#xe6b6;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b7;</i>
+                    <div class="name">time</div>
+                    <div class="code">&amp;#xe6b7;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b8;</i>
+                    <div class="name">cry</div>
+                    <div class="code">&amp;#xe6b8;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6b9;</i>
+                    <div class="name">add</div>
+                    <div class="code">&amp;#xe6b9;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6ba;</i>
+                    <div class="name">minus</div>
+                    <div class="code">&amp;#xe6ba;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6bc;</i>
+                    <div class="name">link</div>
+                    <div class="code">&amp;#xe6bc;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6bd;</i>
+                    <div class="name">atm</div>
+                    <div class="code">&amp;#xe6bd;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6be;</i>
+                    <div class="name">skip</div>
+                    <div class="code">&amp;#xe6be;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6bf;</i>
+                    <div class="name">attachment</div>
+                    <div class="code">&amp;#xe6bf;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6c0;</i>
+                    <div class="name">browse</div>
+                    <div class="code">&amp;#xe6c0;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6c2;</i>
+                    <div class="name">phone</div>
+                    <div class="code">&amp;#xe6c2;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6c3;</i>
+                    <div class="name">bad</div>
+                    <div class="code">&amp;#xe6c3;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6c4;</i>
+                    <div class="name">text</div>
+                    <div class="code">&amp;#xe6c4;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe717;</i>
+                    <div class="name">企业用户</div>
+                    <div class="code">&amp;#xe717;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6c8;</i>
+                    <div class="name">二维码</div>
+                    <div class="code">&amp;#xe6c8;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe7f8;</i>
+                    <div class="name">quit</div>
+                    <div class="code">&amp;#xe7f8;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe671;</i>
+                    <div class="name">folder</div>
+                    <div class="code">&amp;#xe671;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe603;</i>
+                    <div class="name">部门</div>
+                    <div class="code">&amp;#xe603;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6d6;</i>
+                    <div class="name">报表</div>
+                    <div class="code">&amp;#xe6d6;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe612;</i>
+                    <div class="name">审核</div>
+                    <div class="code">&amp;#xe612;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe60c;</i>
+                    <div class="name">企业信息</div>
+                    <div class="code">&amp;#xe60c;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe60b;</i>
+                    <div class="name">企业</div>
+                    <div class="code">&amp;#xe60b;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe802;</i>
+                    <div class="name">公文</div>
+                    <div class="code">&amp;#xe802;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe605;</i>
+                    <div class="name">日志</div>
+                    <div class="code">&amp;#xe605;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe60f;</i>
+                    <div class="name">验证码</div>
+                    <div class="code">&amp;#xe60f;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe622;</i>
+                    <div class="name">标签</div>
+                    <div class="code">&amp;#xe622;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe600;</i>
+                    <div class="name">草稿</div>
+                    <div class="code">&amp;#xe600;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe796;</i>
+                    <div class="name">点</div>
+                    <div class="code">&amp;#xe796;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe606;</i>
+                    <div class="name">发文</div>
+                    <div class="code">&amp;#xe606;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe634;</i>
+                    <div class="name">fold</div>
+                    <div class="code">&amp;#xe634;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe635;</i>
+                    <div class="name">unfold</div>
+                    <div class="code">&amp;#xe635;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe619;</i>
+                    <div class="name">信息管理</div>
+                    <div class="code">&amp;#xe619;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6c1;</i>
+                    <div class="name">回复</div>
+                    <div class="code">&amp;#xe6c1;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe6aa;</i>
+                    <div class="name">栏目管理</div>
+                    <div class="code">&amp;#xe6aa;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe716;</i>
+                    <div class="name">字典</div>
+                    <div class="code">&amp;#xe716;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe610;</i>
+                    <div class="name">系统管理</div>
+                    <div class="code">&amp;#xe610;</div>
+                </li>
+            
+                <li>
+                <i class="icon naf-icons">&#xe7f9;</i>
+                    <div class="name">菜单</div>
+                    <div class="code">&amp;#xe7f9;</div>
+                </li>
+            
+        </ul>
+        <h2 id="unicode-">unicode引用</h2>
+        <hr>
+
+        <p>unicode是字体在网页端最原始的应用方式,特点是:</p>
+        <ul>
+        <li>兼容性最好,支持ie6+,及所有现代浏览器。</li>
+        <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+        <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+        </ul>
+        <blockquote>
+        <p>注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式</p>
+        </blockquote>
+        <p>unicode使用步骤如下:</p>
+        <h3 id="-font-face">第一步:拷贝项目下面生成的font-face</h3>
+        <pre><code class="lang-js hljs javascript">@font-face {
+  font-family: <span class="hljs-string">'naf-icons'</span>;
+  src: url(<span class="hljs-string">'iconfont.eot'</span>);
+  src: url(<span class="hljs-string">'iconfont.eot?#iefix'</span>) format(<span class="hljs-string">'embedded-opentype'</span>),
+  url(<span class="hljs-string">'iconfont.woff'</span>) format(<span class="hljs-string">'woff'</span>),
+  url(<span class="hljs-string">'iconfont.ttf'</span>) format(<span class="hljs-string">'truetype'</span>),
+  url(<span class="hljs-string">'iconfont.svg#naf-icons'</span>) format(<span class="hljs-string">'svg'</span>);
+}
+</code></pre>
+        <h3 id="-iconfont-">第二步:定义使用iconfont的样式</h3>
+        <pre><code class="lang-js hljs javascript">.naf-icons{
+  font-family:<span class="hljs-string">"naf-icons"</span> !important;
+  font-size:<span class="hljs-number">16</span>px;font-style:normal;
+  -webkit-font-smoothing: antialiased;
+  -webkit-text-stroke-width: <span class="hljs-number">0.2</span>px;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+        <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+        <pre><code class="lang-js hljs javascript">&lt;i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"naf-icons"</span>&gt;&amp;#x33;<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span></span></code></pre>
+
+        <blockquote>
+        <p>"naf-icons"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p>
+        </blockquote>
+    </div>
+
+
+</body>
+</html>

File diff suppressed because it is too large
+ 287 - 0
public/naf-icons/iconfont.css


BIN
public/naf-icons/iconfont.eot


File diff suppressed because it is too large
+ 1 - 0
public/naf-icons/iconfont.js


File diff suppressed because it is too large
+ 431 - 0
public/naf-icons/iconfont.svg


BIN
public/naf-icons/iconfont.ttf


BIN
public/naf-icons/iconfont.woff


+ 69 - 0
public/static/bg.svg

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 21</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
+            <g id="Group-21" transform="translate(77.000000, 73.000000)">
+                <g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
+                    <ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
+                    <ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
+                    <path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
+                    <path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
+                    <path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
+                        <ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
+                        <path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
+                    </g>
+                </g>
+                <g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
+                    <ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
+                    <ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
+                    <path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
+                    <g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
+                        <ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
+                        <path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
+                    </g>
+                    <ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
+                    <path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
+                </g>
+                <g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
+                    <ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
+                    <g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
+                        <ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
+                        <path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
+                    </g>
+                    <path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                    <ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
+                    <ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
+                    <path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                </g>
+                <g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
+                    <g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
+                        <circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
+                        <path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
+                    </g>
+                    <circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
+                    <path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
+                    <path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
+                    <path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
+                    <circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
+                    <circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
+                    <circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
public/static/favicon.ico


File diff suppressed because it is too large
+ 508 - 0
public/static/image1.svg


File diff suppressed because it is too large
+ 314 - 0
public/static/image2.svg


File diff suppressed because it is too large
+ 208 - 0
public/static/image3.svg


BIN
public/static/logo.png


File diff suppressed because it is too large
+ 1 - 0
public/static/logo.svg


+ 33 - 0
src/App.vue

@@ -0,0 +1,33 @@
+<template>
+  <footer-page id="app">
+    <div class="weui-loadmore" v-if="loading">
+      <i class="weui-loading"></i>
+      <span class="weui-loadmore__tips">正在加载</span>
+    </div>
+    <router-view v-else/>
+  </footer-page>
+</template>
+
+<script>
+import { mapActions, mapState } from 'vuex';
+import FooterPage from '@naf/layouts/footer-page';
+
+export default {
+  name: 'App',
+  components: {
+    FooterPage,
+  },
+  metaInfo: {
+    title: '智慧就业',
+  },
+  computed: {
+    ...mapState(['loading']),
+  },
+  methods: {
+    ...mapActions(['load']),
+  },
+  async created() {
+    await this.load();
+  },
+};
+</script>

+ 69 - 0
src/assets/bg.svg

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 21</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
+            <g id="Group-21" transform="translate(77.000000, 73.000000)">
+                <g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
+                    <ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
+                    <ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
+                    <path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
+                    <path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
+                    <path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
+                        <ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
+                        <path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
+                    </g>
+                </g>
+                <g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
+                    <ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
+                    <ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
+                    <path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
+                    <g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
+                        <ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
+                        <path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
+                    </g>
+                    <ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
+                    <path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
+                </g>
+                <g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
+                    <ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
+                    <g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
+                        <ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
+                        <path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
+                    </g>
+                    <path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                    <ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
+                    <ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
+                    <path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                </g>
+                <g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
+                    <g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
+                        <circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
+                        <path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
+                    </g>
+                    <circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
+                    <path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
+                    <path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
+                    <path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
+                    <circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
+                    <circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
+                    <circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
src/assets/home.png


File diff suppressed because it is too large
+ 314 - 0
src/assets/image1.svg


File diff suppressed because it is too large
+ 208 - 0
src/assets/image2.svg


File diff suppressed because it is too large
+ 508 - 0
src/assets/image3.svg


BIN
src/assets/logo.png


File diff suppressed because it is too large
+ 1 - 0
src/assets/logo.svg


File diff suppressed because it is too large
+ 1 - 0
src/assets/logo1.svg


+ 41 - 0
src/main.js

@@ -0,0 +1,41 @@
+import Vue from 'vue';
+import App from './App.vue';
+import router from './router';
+import store from './store';
+import '@lib/plugins/meta';
+import '@lib/plugins/mint-ui';
+import '@lib/plugins/axios';
+import '@lib/plugins/check-res';
+import '@lib/plugins/naf-dict';
+import '@/style/index.less';
+import '@/style/common.less';
+import InitStomp from '@lib/plugins/stomp';
+
+Vue.config.productionTip = false;
+Vue.config.weixin = {
+  baseUrl: process.env.BASE_URL + 'weixin',
+};
+Vue.config.stomp = {
+  // brokerURL: 'ws://192.168.1.190:15674/ws',
+  brokerURL: '/ws', // ws://${location.host}/ws
+  connectHeaders: {
+    host: 'smart',
+    login: 'web',
+    passcode: 'web123',
+  },
+  // debug: true,
+  reconnectDelay: 5000,
+  heartbeatIncoming: 4000,
+  heartbeatOutgoing: 4000,
+};
+
+store.$router = router;
+router.$store = store;
+
+new Vue({
+  router,
+  store,
+  render: h => h(App),
+}).$mount('#app');
+
+InitStomp();

+ 59 - 0
src/router.js

@@ -0,0 +1,59 @@
+import Vue from 'vue';
+import Router from 'vue-router';
+import Home from './views/Home.vue';
+
+Vue.use(Router);
+
+const router = new Router({
+  mode: process.env.VUE_APP_ROUTER_MODE || 'history',
+  base: process.env.BASE_URL,
+  routes: [
+    {
+      path: '/',
+      redirect: '/frame',
+    },
+    {
+      path: '/login',
+      component: () => import(/* webpackChunkName: "login" */ './views/Login.vue'),
+      children: [
+        {
+          path: '/:unit/login',
+        },
+      ],
+    },
+    {
+      path: '/frame',
+      component: () => import(/* webpackChunkName: "frame" */ './views/Frame.vue'),
+      children: [
+        {
+          path: '/frame',
+          component: Home,
+        },
+        {
+          path: '/frame/:module/:path(.*)',
+        },
+        {
+          path: '/frame/:module',
+        },
+      ],
+    },
+  ],
+});
+
+router.beforeEach((to, from, next) => {
+  const { isAuthenticated, platform } = router.$store.getters;
+  if (!isAuthenticated && !/\/login$/.test(to.path)) {
+    console.warn('not login, redirect login page...');
+    if (platform === 'master') {
+      next(`/${platform}/login`);
+    } else {
+      next('/login');
+    }
+    return;
+  }
+  console.log('to: ', to);
+  router.$store.commit('naf/menu/NAV_MODULE_SELECTED', to.params.module);
+  next();
+});
+
+export default router;

+ 71 - 0
src/store/index.js

@@ -0,0 +1,71 @@
+/* eslint-disable no-underscore-dangle */
+/* eslint-disable object-curly-newline */
+/* eslint-disable no-param-reassign */
+import Vue from 'vue';
+import Vuex from 'vuex';
+
+import * as types from './mutation-types';
+import * as menu from '@/store/naf/menu';
+import * as dict from '@lib/store/naf/dict';
+import util from '@lib/utils/user-util';
+import * as login from './login';
+
+Vue.use(Vuex);
+
+export default new Vuex.Store({
+  modules: {
+    naf: {
+      namespaced: true,
+      modules: {
+        menu,
+        dict,
+      },
+    },
+    login,
+  },
+  state: {
+    loading: false,
+    platform: 'school',
+    unit: null,
+    name: null,
+  },
+  getters: {
+    platform: state => state.login.platform,
+    isAuthenticated: state => state.login.isAuthenticated,
+    userinfo: state => state.login.userinfo,
+    // access_token: state => state.login.access_token,
+    // unitcode: state => state.login.unit,
+    menuItems: state => state.naf.menu.items,
+  },
+  mutations: {
+    [types.SHOW_LOADING](state) {
+      state.loading = true;
+    },
+    [types.HIDE_LOADING](state) {
+      state.loading = false;
+    },
+    [types.USER_INFO](state, { userinfo }) {
+      state.userinfo = userinfo;
+    },
+    [types.PLATFORM_INIT](state, { unit = 'master', name }) {
+      state.name = name;
+      if (unit === 'master') {
+        state.platform = 'master';
+        state.unit = null;
+      } else {
+        state.platform = 'school';
+        state.unit = unit;
+      }
+    },
+  },
+  actions: {
+    async load({ commit, dispatch }) {
+      console.log('start loading data...');
+      commit(types.SHOW_LOADING);
+      await dispatch('naf/menu/load');
+      await dispatch('naf/dict/load', 'unit');
+      commit(types.HIDE_LOADING);
+      console.log('load data ok!');
+    },
+  },
+});

+ 0 - 0
src/store/login.js


Some files were not shown because too many files changed in this diff