lrf402788946 5 سال پیش
کامیت
8e63adc2c2
79فایلهای تغییر یافته به همراه8662 افزوده شده و 0 حذف شده
  1. 3 0
      .env
  2. 7 0
      .eslintignore
  3. 32 0
      .eslintrc.js
  4. 23 0
      .gitignore
  5. 10 0
      README.md
  6. 13 0
      babel.config.js
  7. 49 0
      package.json
  8. BIN
      public/favicon.ico
  9. 23 0
      public/index.html
  10. 370 0
      public/naf-icons/demo.css
  11. 850 0
      public/naf-icons/demo_fontclass.html
  12. 1143 0
      public/naf-icons/demo_symbol.html
  13. 888 0
      public/naf-icons/demo_unicode.html
  14. 287 0
      public/naf-icons/iconfont.css
  15. BIN
      public/naf-icons/iconfont.eot
  16. 1 0
      public/naf-icons/iconfont.js
  17. 431 0
      public/naf-icons/iconfont.svg
  18. BIN
      public/naf-icons/iconfont.ttf
  19. BIN
      public/naf-icons/iconfont.woff
  20. 40 0
      src/App.vue
  21. 60 0
      src/AppFrame.vue
  22. BIN
      src/assets/logo.png
  23. 1 0
      src/assets/logo.svg
  24. 1 0
      src/assets/logo1.svg
  25. 91 0
      src/components/editor/file-upload.vue
  26. 80 0
      src/components/editor/tags.vue
  27. 78 0
      src/components/editor/wang-editor.vue
  28. 135 0
      src/components/jobs/column-form.vue
  29. 51 0
      src/components/jobs/column-info.vue
  30. 156 0
      src/components/jobs/content-form.vue
  31. 79 0
      src/components/jobs/link-form.vue
  32. 116 0
      src/components/jobs/menu-form.vue
  33. 45 0
      src/components/jobs/menu-info.vue
  34. 113 0
      src/components/jobs/module-form.vue
  35. 101 0
      src/components/jobs/news-form.vue
  36. 45 0
      src/components/jobs/news-info.vue
  37. 150 0
      src/components/jobs/upload-file.vue
  38. 75 0
      src/components/jobs/upload.vue
  39. 80 0
      src/components/news-form.vue
  40. 36 0
      src/components/preview/attachment.vue
  41. 22 0
      src/components/preview/content.vue
  42. 29 0
      src/components/preview/header.vue
  43. 24 0
      src/components/preview/index.vue
  44. 88 0
      src/components/site-form.vue
  45. 25 0
      src/main.js
  46. 6 0
      src/plugins/antd-vue.js
  47. 84 0
      src/router.js
  48. 7 0
      src/store/.mutation.js
  49. 39 0
      src/store/index.js
  50. 52 0
      src/store/jobsNew/column.js
  51. 42 0
      src/store/jobsNew/dictionary.js
  52. 47 0
      src/store/jobsNew/link.js
  53. 48 0
      src/store/jobsNew/list.js
  54. 47 0
      src/store/jobsNew/menu.js
  55. 47 0
      src/store/jobsNew/module.js
  56. 48 0
      src/store/jobsNew/news.js
  57. 47 0
      src/store/jobsNew/site.js
  58. 140 0
      src/store/menu.js
  59. 15 0
      src/store/naf/.dict.js
  60. 97 0
      src/store/naf/dict.js
  61. 87 0
      src/store/news.js
  62. 82 0
      src/store/site.js
  63. 10 0
      src/util/init-user.js
  64. 10 0
      src/util/methods.js
  65. 152 0
      src/views/column/index.vue
  66. 68 0
      src/views/config.vue
  67. 14 0
      src/views/home.vue
  68. 146 0
      src/views/link/index.vue
  69. 153 0
      src/views/menu/index.vue
  70. 144 0
      src/views/new-views/column.vue
  71. 147 0
      src/views/new-views/content.vue
  72. 140 0
      src/views/new-views/list.vue
  73. 138 0
      src/views/new-views/menu.vue
  74. 138 0
      src/views/new-views/module.vue
  75. 173 0
      src/views/news.vue
  76. 156 0
      src/views/news/index.vue
  77. 118 0
      src/views/site/index.vue
  78. 111 0
      src/views/sites.vue
  79. 58 0
      vue.config.js

+ 3 - 0
.env

@@ -0,0 +1,3 @@
+VUE_APP_AXIOS_BASE_URL=
+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/

+ 32 - 0
.eslintrc.js

@@ -0,0 +1,32 @@
+// 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': [
+      'error',
+      {
+        code: 250,
+      },
+    ],
+    'no-unused-vars': 'off',
+    'no-console': 'off',
+    'prettier/prettier': [
+      'warn',
+      {
+        singleQuote: true,
+        trailingComma: 'es5',
+        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*

+ 10 - 0
README.md

@@ -0,0 +1,10 @@
+# admin-cms
+
+网站管理模块后台页面
+
+### 测试
+for huian
+测试链接1:http://localhost:3004/ddapi/auth?redirect_uri=/admin/cms/&test=226217043733448926
+测试链接2:http://localhost:3004/ddapi/auth?redirect_uri=/admin/cms/&test=232525326333609162
+for jilinjobs
+测试链接3:http://localhost:3004/ddapi/auth?redirect_uri=/admin/cms/&test=6814590833448926

+ 13 - 0
babel.config.js

@@ -0,0 +1,13 @@
+module.exports = {
+  presets: ['@vue/app'],
+  plugins: [
+    [
+      'component',
+      {
+        libraryName: 'element-ui',
+        styleLibraryName: 'theme-chalk',
+      },
+    ],
+    // ['import', { libraryName: 'ant-design-vue', libraryDirectory: 'es', style: 'css' }],
+  ],
+};

+ 49 - 0
package.json

@@ -0,0 +1,49 @@
+{
+  "name": "web-cms",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.18.0",
+    "element-ui": "^2.6.1",
+    "jsonwebtoken": "^8.5.0",
+    "mint-ui": "^2.2.13",
+    "moment": "^2.24.0",
+    "naf-core": "0.1.2",
+    "vue": "^2.6.8",
+    "vue-meta": "^1.5.8",
+    "vue-router": "^3.0.2",
+    "vuex": "^3.1.0",
+    "wangeditor": "^3.1.1"
+  },
+  "devDependencies": {
+    "@babel/polyfill": "^7.2.5",
+    "@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",
+    "babel-plugin-import": "^1.11.0",
+    "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"
+  ]
+}

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>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 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>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 287 - 0
public/naf-icons/iconfont.css


BIN
public/naf-icons/iconfont.eot


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
public/naf-icons/iconfont.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 431 - 0
public/naf-icons/iconfont.svg


BIN
public/naf-icons/iconfont.ttf


BIN
public/naf-icons/iconfont.woff


+ 40 - 0
src/App.vue

@@ -0,0 +1,40 @@
+<template>
+  <div class="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 />
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex';
+
+export default {
+  name: 'App',
+  metaInfo: {
+    title: '网站管理',
+    titleTemplate: '网站管理 - %s',
+  },
+  async mounted() {
+    // const res = await this.load();
+    // this.$checkRes(res, () => {});
+  },
+  computed: {
+    ...mapState(['loading']),
+  },
+};
+</script>
+
+<style scoped>
+.weui-loadmore {
+  position: absolute;
+  top: 40%;
+  width: 100%;
+}
+.page {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 60 - 0
src/AppFrame.vue

@@ -0,0 +1,60 @@
+<template>
+  <div id="app">
+    <div class="weui-loadmore" v-if="loading">
+      <i class="weui-loading"></i>
+      <span class="weui-loadmore__tips">正在加载</span>
+    </div>
+    <frame :menuItems="menus" short-name="网站管理" v-else> </frame>
+  </div>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex';
+import Frame from '@lib/layouts/frame';
+
+export default {
+  components: {
+    Frame,
+  },
+  name: 'App',
+  metaInfo: {
+    title: '网站管理',
+    titleTemplate: '网站管理 - %s',
+  },
+  mounted() {
+    this.init();
+  },
+  computed: {
+    ...mapState({
+      loading: 'loading',
+      platform: 'platform',
+      menuItems: state => state.menu.items,
+    }),
+    menus() {
+      if (this.menuItems) {
+        const filter = p => p.options && (!p.options.platform || p.options.platform === this.platform);
+        return this.menuItems.filter(filter).map(p => {
+          if (p.children) return { ...p, children: p.children.filter(filter) };
+          return p;
+        });
+      }
+      return [];
+    },
+  },
+  methods: {
+    ...mapActions(['init']),
+  },
+};
+</script>
+
+<style scoped lang="less">
+#app {
+  height: 100%;
+  //width: 100%;
+}
+.weui-loadmore {
+  position: absolute;
+  top: 40%;
+  width: 100%;
+}
+</style>

BIN
src/assets/logo.png


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
src/assets/logo.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
src/assets/logo1.svg


+ 91 - 0
src/components/editor/file-upload.vue

@@ -0,0 +1,91 @@
+<template>
+  <el-upload
+    class="upload-demo"
+    action="/files/cms/attachment/upload"
+    :limit="limit"
+    v-once
+    :file-list="[...this.fileList]"
+    :on-preview="handlePreview"
+    :before-remove="beforeRemove"
+    :on-exceed="handleExceed"
+    :before-upload="beforeUpload"
+    :on-success="handleSuccess"
+  >
+    <el-button size="mini" type="primary">点击上传</el-button>
+    <div slot="tip" class="el-upload__tip">文件大小不能超过5MB</div>
+  </el-upload>
+</template>
+<script>
+export default {
+  name: 'file-upload',
+  model: {
+    prop: 'value',
+    event: 'change', // 默认为input时间,此处改为change
+  },
+  props: {
+    value: { type: Array, required: false, default: () => [] },
+    limit: { type: Number, required: false, default: 3 },
+  },
+  data() {
+    return {
+      fileList: [...this.value],
+    };
+  },
+  methods: {
+    handlePreview(file) {
+      console.log(file);
+    },
+    handleExceed(files, fileList) {
+      this.$message.warning(`当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
+    },
+    handleSuccess(res, file) {
+      console.log({ res, file });
+      if (res.errcode !== 0) {
+        this.$notify.error({
+          title: '错误',
+          message: '文件上传失败',
+        });
+        return;
+      }
+      this.fileList.push({ name: file.name, uri: res.uri, uid: file.uid });
+      this.$emit('change', this.fileList);
+      this.$message({ type: 'success', message: '文件上传成功' });
+      return true;
+    },
+    beforeRemove(file, fileList) {
+      const isExisted = this.fileList.some(p => p.uid === file.uid);
+      if (!isExisted) {
+        return true;
+      }
+      return this.$confirm(`确定移除 ${file.name}?`).then(() => {
+        const idx = this.fileList.findIndex(p => p.name === file.name);
+        if (idx != -1) {
+          this.fileList.splice(idx, 1);
+          this.$emit('change', this.fileList);
+        }
+      });
+    },
+    beforeUpload(file) {
+      // TODO: 检查文件是否已上传
+      const isExisted = this.fileList.some(p => p.name === file.name);
+      if (isExisted) {
+        console.warn(`文件${file.name}已存在,不能重复上传!`);
+        return false;
+      }
+
+      // TODO: 检查文件大小
+      const isLt5M = file.size / 1024 / 1024 < 5;
+      if (!isLt5M) {
+        //this.$message.error("上传确认函图片大小不能超过 2MB!");
+        this.$message({ type: 'error', message: '上传文件大小不能超过 5MB!', duration: 3000 });
+        return false;
+      }
+      return true;
+    },
+    handleChange(file, fileList) {
+      const newList = fileList.map(p => ({ name: p.name, uri: p.uri }));
+      this.$emit('change', newList);
+    },
+  },
+};
+</script>

+ 80 - 0
src/components/editor/tags.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="container">
+    <el-tag size="medium" :key="tag" v-for="tag in dynamicTags" closable :disable-transitions="false" @close="handleClose(tag)">
+      {{ tag }}
+    </el-tag>
+    <el-input
+      class="input-new-tag"
+      v-if="inputVisible"
+      v-model="inputValue"
+      ref="saveTagInput"
+      size="mini"
+      @keyup.enter.native="handleInputConfirm"
+      @blur="handleInputConfirm"
+    >
+    </el-input>
+    <el-button v-else class="button-new-tag" size="mini" @click="showInput">+ {{ addText }}</el-button>
+  </div>
+</template>
+<script>
+export default {
+  model: {
+    prop: 'value',
+    event: 'change', // 默认为input时间,此处改为change
+  },
+  props: {
+    value: { type: Array, required: false, default: () => [] },
+    addText: { type: String, required: false, default: '添加' },
+  },
+  data() {
+    return {
+      dynamicTags: [...this.value],
+      inputVisible: false,
+      inputValue: '',
+    };
+  },
+  methods: {
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+      this.$emit('change', this.dynamicTags);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue && !this.dynamicTags.includes(inputValue)) {
+        this.dynamicTags.push(inputValue);
+        this.$emit('change', this.dynamicTags);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.container {
+  display: flex;
+  flex-wrap: wrap;
+}
+//.el-tag + .el-tag {
+.el-tag {
+  margin-right: 10px;
+  margin-bottom: 10px;
+}
+.button-new-tag {
+  height: 28px;
+  line-height: 26px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+</style>

+ 78 - 0
src/components/editor/wang-editor.vue

@@ -0,0 +1,78 @@
+<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: '' },
+  },
+  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 = '/files/cms/images/upload';
+    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>

+ 135 - 0
src/components/jobs/column-form.vue

@@ -0,0 +1,135 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item label="栏目名称" prop="title" :disabled="`${form.news_type}` === '2'">
+        <el-input v-model="form.title"></el-input>
+      </el-form-item>
+      <el-form-item label="选择类型" prop="type">
+        <el-select v-model="form.type" @change="selectType">
+          <el-option v-for="(item, index) in typeList" :key="index" :value="item.value" :label="item.name"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="`所属类型`" prop="parent_type">
+        <el-select v-model="form.parent_type" @change="selectType">
+          <el-option v-for="(item, index) in partList" :key="index" :value="item.value" :label="item.name"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item
+        :label="`所属${form.parent_type === 'menu' ? '菜单' : '模块'}`"
+        prop="parent_type"
+        v-if="form.parent_type === 'module' || form.parent_type === 'menu'"
+      >
+        <el-select v-model="form.parent_id" filterable @change="selectChild">
+          <el-option v-for="(item, index) in parentList" :key="index" :value="item.id" :label="item.title"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="`外部链接`" prop="url" v-if="form.type === 'url'">
+        <el-input v-model="form.url"></el-input>
+      </el-form-item>
+      <el-form-item :label="`选择信息`" prop="content_id" v-if="form.type === 'content'">
+        <el-select v-model="form.content_id" filterable>
+          <el-option v-for="(item, index) in children" :key="index" :value="item.id" :label="item.title"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否使用" prop="is_use">
+        <el-switch v-model="form.is_use" :active-value="`0`" :inactive-value="`1`"> </el-switch>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">{{ isNew ? '创建' : '保存' }}</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import CodeSelect from '@naf/data/code-select';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/dictionary');
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: {},
+  name: 'column-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+  },
+  data() {
+    return {
+      form: { limit: { count: 0 }, ..._.cloneDeep(this.data) },
+      limits: true,
+      rules: {
+        title: requiredAndMaxlen('栏目名称', 40),
+        type: requiredAndMaxlen('栏目类型', 40),
+        parent_type: requiredAndMaxlen('所属类型'),
+      },
+      typeList: [{ name: '常规栏目', value: 'column' }, { name: '外部链接', value: 'url' }, { name: '信息', value: 'content' }],
+      parentList: [],
+      partList: [{ name: '菜单', value: 'menu' }, { name: '模块', value: 'module' }],
+      children: [],
+    };
+  },
+  created() {
+    if (!this.isNew) this.checkData();
+  },
+  methods: {
+    ...mapActions(['allSearch']),
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const limit = { ...this.form.limit };
+          if (!this.limits) limit.count = -1;
+          const data = { ...this.form, limit };
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    async selectType(item, type) {
+      if (type !== `init`) {
+        this.form.parent_id = '';
+        this.form.parent = '';
+      }
+      let result;
+      if (item === 'content') {
+        result = await this.allSearch({ type: 'content', site: this.form.site });
+        if (`${result.errcode}` === '0') this.$set(this, `children`, result.data);
+      } else if (item !== 'url') {
+        result = await this.allSearch({ type: item, site: this.$user.unit.code, is_use: '0' });
+        if (`${result.errcode}` === '0') {
+          let arr = result.data.filter(fil => fil.type !== 'url' && fil.type !== 'content');
+          this.$set(this, `parentList`, arr);
+        }
+      }
+    },
+    selectChild(parent_id) {
+      let res = this.parentList.filter(fil => fil.id === parent_id);
+      if (res.length > 0) {
+        this.$set(this.form, `parent`, res[0].title);
+      }
+      this.$forceUpdate();
+    },
+    checkData() {
+      this.selectType(this.form.type, `init`);
+      if (this.form.parent_type) this.selectType(this.form.parent_type, 'init');
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+</style>

+ 51 - 0
src/components/jobs/column-info.vue

@@ -0,0 +1,51 @@
+<template>
+  <el-tabs v-model="activeName" style="min-height: 400px">
+    <el-tab-pane label="基本信息" name="first">
+      <el-form label-width="100px">
+        <el-form-item label="栏目模块">
+          {{ getFieldValue('moudle') }}
+        </el-form-item>
+        <el-form-item label="栏目名称">
+          {{ getFieldValue('columnname') }}
+        </el-form-item>
+        <el-form-item label="栏目描述">
+          <el-row v-html="data.description"></el-row>
+        </el-form-item>
+        <el-form-item label="展现方式">
+          {{ getFieldValue('showModes') }}
+        </el-form-item>
+      </el-form>
+    </el-tab-pane>
+    <!-- <el-tab-pane label="菜单管理" name="second">
+      菜单管理
+    </el-tab-pane> -->
+  </el-tabs>
+</template>
+<script>
+import _ from 'lodash';
+
+export default {
+  name: 'fair-info',
+  props: {
+    data: { type: Object, required: true },
+  },
+  data() {
+    return {
+      activeName: 'first',
+    };
+  },
+  methods: {
+    getFieldValue(path) {
+      return _.get(this.data, path);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  margin-bottom: 0;
+  /deep/ .el-form-item__content {
+    padding-left: 20px;
+  }
+}
+</style>

+ 156 - 0
src/components/jobs/content-form.vue

@@ -0,0 +1,156 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item label="所属栏目" prop="parent_id">
+        <el-select v-model="form.parent_id" @change="selectColumnn">
+          <el-option v-for="(item, index) in parentList" :key="index" :value="item.id" :label="item.title"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="`信息标题`" prop="title">
+        <el-input v-model="form.title"></el-input>
+      </el-form-item>
+      <el-form-item :label="`标题图片`" prop="pic">
+        <upload :limit="1" :data="form.pic" type="pic" :url="`/files/cms/content/upload`" @upload="uploadSuccess"></upload>
+      </el-form-item>
+      <el-form-item label="信息内容" prop="content">
+        <wang-editor v-model="form.content" placeholder="请输入信息内容" upload-img-server="/files/admin/cms/upload"></wang-editor>
+      </el-form-item>
+      <el-form-item label="附件" prop="content">
+        <upload-file
+          :url="`/files/cms/content/upload`"
+          desc="只能上传不超过2MB文件"
+          :limit="100"
+          @upload="uploadSuccess"
+          @changeName="changeName"
+          @toRemove="toRemove"
+          type="attachment"
+          :data="form.attachment"
+        ></upload-file>
+      </el-form-item>
+      <el-form-item label="是否使用" prop="is_use">
+        <el-switch v-model="form.is_use" :active-value="`0`" :inactive-value="`1`"> </el-switch>
+      </el-form-item>
+      <!-- <el-form-item label="菜单优先顺序" prop="position">
+        <el-input-number v-model="form.position" :min="1"></el-input-number>
+      </el-form-item> -->
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">{{ isNew ? '创建' : '保存' }}</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import WangEditor from '@naf/data/wang-editor';
+import CodeSelect from '@naf/data/code-select';
+import upload from '@/components/jobs/upload';
+import uploadFile from '@/components/jobs/upload-file';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/dictionary');
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: {
+    // CodeSelect,
+    WangEditor,
+    upload,
+    uploadFile,
+  },
+  name: 'content-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+    title: { type: String, default: '' },
+  },
+  data() {
+    return {
+      form: { limit: { count: 0 }, ..._.cloneDeep(this.data) },
+      limits: true,
+      rules: {
+        title: requiredAndMaxlen(`${this.title}名称`, 40),
+        type: requiredAndMaxlen(`${this.title}类型`, 40),
+      },
+      parentList: [],
+      typeList: [],
+      childrenList: [],
+    };
+  },
+  created() {
+    this.getColumn();
+  },
+  methods: {
+    ...mapActions(['allSearch']),
+    async getColumn() {
+      let result = await this.allSearch({ type: 'column', site: this.$user.unit.code, is_use: '0' });
+      if (`${result.errcode}` === '0') {
+        this.$set(this, `parentList`, result.data);
+      }
+    },
+    selectColumnn(parent_id) {
+      let res = this.parentList.filter(fil => fil.id === parent_id);
+      if (res.length > 0) {
+        this.$set(this.form, `parent`, res[0].title);
+        this.$set(this.form, `type`, 'column');
+      }
+    },
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const limit = { ...this.form.limit };
+          if (!this.limits) limit.count = -1;
+          const data = { ...this.form, limit };
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    uploadSuccess({ type, data }) {
+      if (type !== 'pic') {
+        let arr = _.get(this.form, type);
+        if (arr !== undefined) {
+          this.form[type].push({ name: data.name, uri: data.uri });
+        } else {
+          let newArr = [{ name: data.name, uri: data.uri }];
+          this.$set(this.form, `${type}`, newArr);
+        }
+      } else {
+        this.$set(this.form, `${type}`, data.uri);
+      }
+    },
+    toRemove({ type, data }) {
+      if (type !== 'pic') {
+        let arr = _.get(this.form, type);
+        let newArr = arr.filter(item => item.uri !== data.url);
+        this.$set(this.form, `${type}`, newArr);
+      }
+    },
+    changeName({ type, data }) {
+      let newObject = { name: data.name, uri: data.url };
+      let list = _.get(this.form, type);
+      if (list.length > 0) {
+        let index = _.findIndex(list, item => {
+          return item.uri === data.url;
+        });
+        this.$set(list, `${index}`, newObject);
+      }
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+</style>

+ 79 - 0
src/components/jobs/link-form.vue

@@ -0,0 +1,79 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item label="单位名称" prop="title">
+        <el-input v-model="form.title"></el-input>
+      </el-form-item>
+      <el-form-item label="单位主页地址" prop="url">
+        <el-input v-model="form.url"></el-input>
+      </el-form-item>
+      <el-form-item label="单位logo" prop="pic">
+        <upload :limit="1" :data="form.pic" type="pic" :url="`/files/cms/link/upload`" @upload="uploadSuccess"></upload>
+      </el-form-item>
+      <el-form-item label="是否使用" prop="is_use">
+        <el-switch v-model="form.is_use" :active-value="`0`" :inactive-value="`1`"> </el-switch>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">{{ isNew ? '创建' : '保存' }}</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import upload from '@/components/jobs/upload';
+import CodeSelect from '@naf/data/code-select';
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: { upload },
+  name: 'link-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+  },
+  data() {
+    return {
+      form: { limit: { count: 0 }, ..._.cloneDeep(this.data) },
+      limits: true,
+      rules: {
+        title: requiredAndMaxlen('单位名称', 40),
+        url: requiredAndMaxlen('单位主页地址', 40),
+      },
+    };
+  },
+  created() {},
+  methods: {
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const limit = { ...this.form.limit };
+          if (!this.limits) limit.count = -1;
+          const data = { ...this.form, limit };
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    uploadSuccess({ type, data }) {
+      this.$set(this.form, `${type}`, data.uri);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+</style>

+ 116 - 0
src/components/jobs/menu-form.vue

@@ -0,0 +1,116 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item :label="`${title}名称`" prop="title">
+        <el-input v-model="form.title"></el-input>
+      </el-form-item>
+      <el-form-item :label="`选择类型`" prop="type">
+        <el-select v-model="form.type" @change="selectType">
+          <el-option v-for="(item, index) in typeList" :key="index" :value="item.value" :label="item.name"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="`外部链接`" prop="url" v-if="form.type === 'url'">
+        <el-input v-model="form.url"></el-input>
+      </el-form-item>
+      <el-form-item :label="`选择信息`" prop="content_id" v-if="form.type === 'content'">
+        <el-select v-model="form.content_id" filterable>
+          <el-option v-for="(item, index) in children" :key="index" :value="item.id" :label="item.title"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否使用" prop="is_use">
+        <el-switch v-model="form.is_use" :active-value="`0`" :inactive-value="`1`"> </el-switch>
+      </el-form-item>
+      <!-- <el-form-item label="菜单优先顺序" prop="position">
+        <el-input-number v-model="form.position" :min="1"></el-input-number>
+      </el-form-item> -->
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">{{ isNew ? '创建' : '保存' }}</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import CodeSelect from '@naf/data/code-select';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/dictionary');
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: {
+    // CodeSelect,
+  },
+  name: 'menu-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+    title: { type: String, default: '' },
+  },
+  data() {
+    return {
+      form: { limit: { count: 0 }, ..._.cloneDeep(this.data) },
+      limits: true,
+      rules: {
+        title: requiredAndMaxlen(`${this.title}名称`, 40),
+        type: requiredAndMaxlen(`${this.title}类型`, 40),
+      },
+      typeList: [{ name: '栏目', value: 'column' }, { name: '外部链接', value: 'url' }, { name: '信息', value: 'content' }],
+      children: [],
+    };
+  },
+  created() {
+    if (!this.isNew) this.selectType(this.form.type, 'init');
+  },
+  methods: {
+    ...mapActions(['allSearch']),
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const limit = { ...this.form.limit };
+          if (!this.limits) limit.count = -1;
+          let newData = JSON.parse(JSON.stringify(this.form));
+          newData.child_id ? (newData.child_id = JSON.stringify(newData.child_id)) : '';
+          const data = { ...newData, limit };
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    async selectType(item, type) {
+      if (type !== 'init') {
+        delete this.form.url;
+        delete this.form.content_id;
+      }
+      //选择类型:栏目,外部链接,信息
+      //栏目:栏目与菜单的关系是,栏目存有菜单的id.所以在菜单部分,无需选择栏目,在前台查询时,是用菜单id查出所有栏目
+      //外部链接:点击这个菜单直接跳开,需要填写完整地址
+      //信息:需要选择此菜单关联哪个信息,需要查询出信息,点击之后进入信息详情
+      let result;
+      if (item === 'content') {
+        result = await this.allSearch({ type: 'content', site: this.form.site });
+        if (`${result.errcode}` === '0') this.$set(this, `children`, result.data);
+      }
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+.el-select {
+  width: 100%;
+}
+</style>

+ 45 - 0
src/components/jobs/menu-info.vue

@@ -0,0 +1,45 @@
+<template>
+  <el-tabs v-model="activeName" style="min-height: 400px">
+    <el-tab-pane label="基本信息" name="first">
+      <el-form label-width="100px">
+        <el-form-item label="菜单名称">
+          {{ getFieldValue('name') }}
+        </el-form-item>
+        <el-form-item label="栏目描述">
+          <el-row v-html="data.description"></el-row>
+        </el-form-item>
+      </el-form>
+    </el-tab-pane>
+    <!-- <el-tab-pane label="菜单管理" name="second">
+      菜单管理
+    </el-tab-pane> -->
+  </el-tabs>
+</template>
+<script>
+import _ from 'lodash';
+
+export default {
+  name: 'fair-info',
+  props: {
+    data: { type: Object, required: true },
+  },
+  data() {
+    return {
+      activeName: 'first',
+    };
+  },
+  methods: {
+    getFieldValue(path) {
+      return _.get(this.data, path);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  margin-bottom: 0;
+  /deep/ .el-form-item__content {
+    padding-left: 20px;
+  }
+}
+</style>

+ 113 - 0
src/components/jobs/module-form.vue

@@ -0,0 +1,113 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item :label="`选择模块`" prop="category">
+        <el-select v-model="form.category" @change="moduleSelect">
+          <el-option v-for="(item, index) in moduleType" :key="index" :value="item.value" :label="item.name"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否使用" prop="is_use">
+        <el-switch v-model="form.is_use" :active-value="`0`" :inactive-value="`1`"> </el-switch>
+      </el-form-item>
+      <!-- <el-form-item label="菜单优先顺序" prop="position">
+        <el-input-number v-model="form.position" :min="1"></el-input-number>
+      </el-form-item> -->
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">{{ isNew ? '创建' : '保存' }}</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import CodeSelect from '@naf/data/code-select';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/dictionary');
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: {
+    // CodeSelect,
+  },
+  name: 'module-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+    title: { type: String, default: '' },
+  },
+  data() {
+    return {
+      form: { limit: { count: 0 }, ..._.cloneDeep(this.data) },
+      limits: true,
+      rules: {
+        title: requiredAndMaxlen(`${this.title}名称`, 40),
+      },
+      moduleType: [],
+    };
+  },
+  created() {
+    this.createType();
+  },
+  methods: {
+    ...mapActions(['allSearch']),
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const limit = { ...this.form.limit };
+          if (!this.limits) limit.count = -1;
+          let newData = JSON.parse(JSON.stringify(this.form));
+          const data = { ...newData, limit };
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    //模块选择类别
+    moduleSelect(item) {
+      let res = this.moduleType.filter(fil => fil.value === item);
+      if (res.length > 0) this.$set(this.form, `title`, res[0].name);
+    },
+    async createType() {
+      if (this.title.includes('模块') || this.title.includes('首页')) {
+        let moduleArr = [
+          { name: '新闻模块', value: 'news' },
+          { name: '公告模块', value: 'notice' },
+          // { name: '招聘模块', value: 'jobs' },
+          { name: '自定义模块1', value: 'self1' },
+          { name: '自定义模块2', value: 'self2' },
+        ];
+        if (this.isNew) {
+          let result = await this.allSearch({ type: 'module', site: this.$user.unit.code, is_use: '0' });
+          let selArr = result.data.map(item => {
+            return { value: item.category };
+          });
+          let dif = _.differenceBy(moduleArr, selArr, 'value');
+          this.$set(this, `moduleType`, dif);
+        } else {
+          this.$set(this, `moduleType`, moduleArr);
+        }
+      }
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+.el-select {
+  width: 100%;
+}
+</style>

+ 101 - 0
src/components/jobs/news-form.vue

@@ -0,0 +1,101 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item label="新闻名称" prop="title">
+        <el-input v-model="form.title"></el-input>
+      </el-form-item>
+      <el-form-item label="新闻标题图片" prop="picurl" :required="true">
+        <upload :limit="1" :data="form.picurl" type="picurl" :url="`/files/cms/news/upload`" @upload="uploadSuccess"></upload>
+      </el-form-item>
+      <el-form-item label="新闻描述" prop="content">
+        <wang-editor v-model="form.content" placeholder="请输入新闻描述" upload-img-server="/files/jobs/jobfair/upload"></wang-editor>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">{{ isNew ? '创建' : '保存' }}</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import upload from '@/components/jobs/upload';
+import WangEditor from '@naf/data/wang-editor';
+import CodeSelect from '@naf/data/code-select';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/dictionary');
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: {
+    WangEditor,
+    // CodeSelect,
+    upload,
+  },
+  name: 'news-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+  },
+  data() {
+    return {
+      form: { limit: { count: 0 }, ..._.cloneDeep(this.data) },
+      limits: true,
+      rules: {
+        name: requiredAndMaxlen('栏目名称', 40),
+        description: requiredAndMaxlen('栏目描述', 10240),
+      },
+      parentList: [],
+    };
+  },
+  created() {
+    this.getColumn();
+  },
+  methods: {
+    ...mapActions(['allSearch']),
+    handleSave() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const limit = { ...this.form.limit };
+          if (!this.limits) limit.count = -1;
+          const data = { ...this.form, limit };
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    async getColumn() {
+      let result = await this.allSearch({ type: 'column', site: this.$user.unit.code, is_use: '0' });
+      if (`${result.errcode}` === '0') {
+        this.$set(this, `parentList`, result.data);
+      }
+    },
+    selectColumnn(parent_id) {
+      let res = this.parentList.filter(fil => fil.id === parent_id);
+      if (res.length > 0) {
+        this.$set(this.form, `parent`, res[0].title);
+        this.$set(this.form, `type`, 'column');
+      }
+    },
+    uploadSuccess({ type, data }) {
+      this.$set(this.form, `${type}`, data.uri);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+</style>

+ 45 - 0
src/components/jobs/news-info.vue

@@ -0,0 +1,45 @@
+<template>
+  <el-tabs v-model="activeName" style="min-height: 400px">
+    <el-tab-pane label="基本信息" name="first">
+      <el-form label-width="100px">
+        <el-form-item label="新闻名称">
+          {{ getFieldValue('title') }}
+        </el-form-item>
+        <el-form-item label="新闻描述">
+          <el-row v-html="data.content"></el-row>
+        </el-form-item>
+      </el-form>
+    </el-tab-pane>
+    <!-- <el-tab-pane label="菜单管理" name="second">
+      菜单管理
+    </el-tab-pane> -->
+  </el-tabs>
+</template>
+<script>
+import _ from 'lodash';
+
+export default {
+  name: 'fair-info',
+  props: {
+    data: { type: Object, required: true },
+  },
+  data() {
+    return {
+      activeName: 'first',
+    };
+  },
+  methods: {
+    getFieldValue(path) {
+      return _.get(this.data, path);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  margin-bottom: 0;
+  /deep/ .el-form-item__content {
+    padding-left: 20px;
+  }
+}
+</style>

+ 150 - 0
src/components/jobs/upload-file.vue

@@ -0,0 +1,150 @@
+<template>
+  <div id="upload-file">
+    <el-upload
+      ref="uploadFile"
+      :action="url"
+      :before-remove="handleRemove"
+      :before-upload="changeFile"
+      :on-success="onSuccess"
+      :limit="limit"
+      multiple
+      :on-exceed="outLimit"
+      :file-list="fileList"
+      :on-preview="onPreview"
+      :on-remove="remove"
+      list-type="picture"
+    >
+      <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
+      <div slot="tip" class="el-upload__tip">{{ desc === undefined ? '只能上传不超过2MB的文件' : desc }}</div>
+    </el-upload>
+    <el-dialog title="查看" :visible.sync="dialog" center>
+      <el-row>
+        <el-form :model="disObject" label-position="left" label-width="auto">
+          <el-form-item label="文件名" prop="name">
+            <el-input v-model="disObject.name" placeholder="请输入新文件名"></el-input>
+          </el-form-item>
+          <el-image style="width: 100%; height: 100%" :src="disObject.url" fit="scale-down" v-if="disObject.type === 'pic'"></el-image>
+        </el-form>
+      </el-row>
+      <template #footer>
+        <el-row type="flex" align="middle" justify="center">
+          <el-col :span="6"><el-button type="info" @click="dialog = false">返回 </el-button></el-col>
+          <el-col :span="6" v-if="disObject.type === 'file'"><el-button @click="downLoad(disObject.url)">下载文件</el-button></el-col>
+          <el-col :span="6"><el-button type="primary" @click="changeName()">修改文件名</el-button></el-col>
+        </el-row>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import _ from 'lodash';
+export default {
+  name: 'upload-file',
+  props: {
+    url: { type: null },
+    type: { type: String },
+    limit: { type: Number },
+    data: { type: null },
+    desc: { type: String },
+  },
+  components: {},
+  data: () => ({
+    fileList: [],
+    dialog: false,
+    disObject: {},
+    test: {},
+  }),
+  created() {
+    if (this.data) {
+      this.defalutProcess(this.data);
+    }
+  },
+  computed: {},
+  watch: {
+    data: {
+      handler(val) {
+        this.defalutProcess(val);
+      },
+    },
+  },
+  methods: {
+    handleRemove(file) {
+      return true;
+    },
+    changeFile(file, fileList) {
+      let size = file.size / 1024 / 1024;
+      if (size > 2) {
+        return false;
+      }
+    },
+    onSuccess(response, file, fileList) {
+      //将文件整理好传回父组件
+      this.$emit('upload', { type: this.type, data: response });
+    },
+    outLimit() {
+      this.$message.error(`只允许上传${this.limit}个文件`);
+    },
+    onPreview(file) {
+      let duplicate = JSON.parse(JSON.stringify(file));
+      let res = this.isPic(duplicate.url);
+      if (this.isPic(duplicate.url)) {
+        this.disObject.type = 'pic';
+      } else {
+        this.disObject.type = 'file';
+      }
+      this.disObject.url = duplicate.url;
+      this.dialog = true;
+    },
+    defalutProcess(val) {
+      if (typeof val === 'object' && _.get(val, length) !== undefined) {
+        let newArr = [];
+        val.map(item => {
+          let object = {};
+          object.name = item.name;
+          object.url = item.uri;
+          newArr.push(object);
+        });
+        this.$set(this, `fileList`, newArr);
+      } else if (typeof val === 'object' && _.get(val, length) === undefined) {
+        let object = {};
+        object.name = val.name;
+        object.url = val.uri;
+        this.$set(this, `fileList`, [object]);
+      } else {
+        this.$set(this, `fileList`, [{ name: '附件', url: val }]);
+      }
+    },
+    isPic(url) {
+      if (url.includes('.jpg')) {
+        return true;
+      }
+      if (url.includes('.bmp')) {
+        return true;
+      }
+      if (url.includes('.jpge')) {
+        return true;
+      }
+      if (url.includes('.png')) {
+        return true;
+      }
+      if (url.includes('.gif')) {
+        return true;
+      }
+    },
+    downLoad(url) {
+      window.open(url);
+    },
+    changeName() {
+      this.$emit('changeName', { type: this.type, data: this.disObject });
+      this.dialog = false;
+      this.disObject = {};
+    },
+    remove(file) {
+      this.$emit('toRemove', { type: this.type, data: file });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 75 - 0
src/components/jobs/upload.vue

@@ -0,0 +1,75 @@
+<template>
+  <div id="upload">
+    <el-upload
+      v-if="url"
+      ref="upload"
+      :action="url"
+      list-type="picture-card"
+      :file-list="fileList"
+      :limit="limit"
+      :on-exceed="outLimit"
+      :on-preview="handlePictureCardPreview"
+      :before-remove="handleRemove"
+      :on-success="onSuccess"
+    >
+      <template>
+        <i class="el-icon-plus"></i>
+      </template>
+    </el-upload>
+    <el-dialog :visible.sync="dialogVisible">
+      <img width="100%" :src="dialogImageUrl" alt="" />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'upload',
+  props: {
+    url: { type: null },
+    limit: { type: Number },
+    data: { type: null },
+    type: { type: String },
+  },
+  components: {},
+  data: () => ({
+    dialogVisible: false,
+    dialogImageUrl: '',
+    fileList: [],
+  }),
+  created() {
+    if (this.data) {
+      this.defalutProcess(this.data);
+    }
+  },
+  watch: {
+    data: {
+      handler(val) {
+        this.defalutProcess(val);
+      },
+    },
+  },
+  computed: {},
+  methods: {
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    handleRemove(file) {
+      return true;
+    },
+    outLimit() {
+      this.$message.error('只允许上传1张图片');
+    },
+    onSuccess(response, file, fileList) {
+      //将文件整理好传回父组件
+      this.$emit('upload', { type: this.type, data: response });
+    },
+    defalutProcess(val) {
+      this.$set(this, `fileList`, [{ name: this.type, url: this.data }]);
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 80 - 0
src/components/news-form.vue

@@ -0,0 +1,80 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item label="标题" prop="title" :required="true">
+        <el-input v-model="form.title"></el-input>
+      </el-form-item>
+      <el-form-item label="发布单位" prop="issuer" :required="true">
+        <el-input v-model="form.issuer"></el-input>
+      </el-form-item>
+      <el-form-item label="内容" prop="content" :required="true">
+        <wang-editor v-model="form.content"></wang-editor>
+      </el-form-item>
+      <el-form-item label="附件" prop="attachment">
+        <file-upload v-model="form.attachment"></file-upload>
+      </el-form-item>
+      <el-form-item label="标签" prop="tags">
+        <tags v-model="form.tags" add-text="添加标签"></tags>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="$emit('cancel')" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">保存</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import { createNamespacedHelpers } from 'vuex';
+import WangEditor from './editor/wang-editor';
+import FileUpload from './editor/file-upload';
+import Tags from './editor/tags';
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+const { mapActions } = createNamespacedHelpers('naf/dict');
+
+export default {
+  components: {
+    WangEditor,
+    FileUpload,
+    Tags,
+  },
+  name: 'news-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+  },
+  data() {
+    return {
+      form: _.cloneDeep(this.data),
+      rules: {
+        title: requiredAndMaxlen('标题', 100),
+        issuer: requiredAndMaxlen('发布单位', 64),
+        content: requiredAndMaxlen('内容', 102400),
+      },
+      units: [],
+    };
+  },
+  methods: {
+    handleSave({ action }) {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          this.$emit('save', { isNew: this.isNew, data: this.form, action });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+</style>

+ 36 - 0
src/components/preview/attachment.vue

@@ -0,0 +1,36 @@
+<template>
+  <section class="attachment" v-if="hasData">
+    <h4>附件:</h4>
+    <ol>
+      <li v-for="(item, index) in data" :key="index">
+        <a target="_blank" :href="item.uri">{{ item.name }}</a>
+      </li>
+    </ol>
+  </section>
+</template>
+<script>
+import _ from 'lodash';
+
+export default {
+  name: 'news-attachment',
+  props: {
+    data: { type: Array, required: true },
+  },
+  computed: {
+    hasData() {
+      return _.isArray(this.data) && this.data.length > 0;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.attachment {
+  padding: 2em;
+  h4 {
+    color: gray;
+  }
+  ol {
+    list-style-position: inside;
+  }
+}
+</style>

+ 22 - 0
src/components/preview/content.vue

@@ -0,0 +1,22 @@
+<template>
+  <section class="main">
+    <div class="content" v-html="data.content"></div>
+  </section>
+</template>
+<script>
+export default {
+  name: 'news-content',
+  props: {
+    data: { type: Object, required: true },
+  },
+};
+</script>
+<style lang="less" scoped>
+.main {
+  padding: 10px 20px;
+  .content {
+    margin-top: 20px;
+    text-indent: 2em;
+  }
+}
+</style>

+ 29 - 0
src/components/preview/header.vue

@@ -0,0 +1,29 @@
+<template>
+  <section class="header">
+    <h1 class="title">{{ data.title }}</h1>
+    <p class="desc">{{ data.docno }}</p>
+  </section>
+</template>
+<script>
+export default {
+  name: 'news-header',
+  props: {
+    data: { type: Object, required: true },
+  },
+};
+</script>
+<style lang="less" scoped>
+.header {
+  text-align: center;
+  padding: 10px 20px;
+  .title {
+    text-align: center;
+    font-size: 1.5em;
+    padding: 10px 20px;
+  }
+  .desc {
+    color: gray;
+    padding: 10px 20px;
+  }
+}
+</style>

+ 24 - 0
src/components/preview/index.vue

@@ -0,0 +1,24 @@
+<template>
+  <article>
+    <news-header :data="data"></news-header>
+    <news-content :data="data"></news-content>
+    <news-attachment :data="data.attachment"></news-attachment>
+  </article>
+</template>
+<script>
+import NewsHeader from './header';
+import NewsAttachment from './attachment';
+import NewsContent from './content';
+
+export default {
+  components: {
+    NewsHeader,
+    NewsAttachment,
+    NewsContent,
+  },
+  name: 'preview',
+  props: {
+    data: { type: Object, required: true },
+  },
+};
+</script>

+ 88 - 0
src/components/site-form.vue

@@ -0,0 +1,88 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+    <slot>
+      <el-form-item label="所属高校" prop="site" :required="true" v-if="isNew">
+        <code-select category="unit" v-model="form.site" placeholder="请选择分站所属高校" :disabled="$route.params.unit != undefined"> </code-select>
+      </el-form-item>
+      <el-form-item label="网站名称" prop="name" :required="true">
+        <el-input v-model="form.name"></el-input>
+      </el-form-item>
+      <el-form-item label="网站域名" prop="domain" :required="true">
+        <el-input v-model="form.domain"></el-input>
+      </el-form-item>
+      <el-form-item label="版权声明" prop="copyright" :required="true">
+        <el-input v-model="form.copyright"></el-input>
+      </el-form-item>
+      <el-form-item label="关于内容" prop="content" :required="true">
+        <wang-editor v-model="form.content"></wang-editor>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleCancel" size="mini">取 消</el-button>
+        <el-button type="primary" @click="handleSave" size="mini">保存</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import { createNamespacedHelpers } from 'vuex';
+import WangEditor from './editor/wang-editor';
+import CodeSelect from '@naf/data/code-select';
+
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+const { mapActions } = createNamespacedHelpers('naf/dict');
+
+export default {
+  components: {
+    WangEditor,
+    CodeSelect,
+  },
+  name: 'site-form',
+  props: {
+    data: { type: Object, required: true },
+    isNew: { type: Boolean, default: false } /* 是否新创建 */,
+  },
+  data() {
+    return {
+      form: _.cloneDeep(this.data),
+      rules: {
+        site: requiredAndMaxlen('网站表示', 6),
+        name: requiredAndMaxlen('网站名称', 20),
+        domain: requiredAndMaxlen('网站域名', 40),
+        copyright: requiredAndMaxlen('版权声明', 100),
+        content: requiredAndMaxlen('内容', 102400),
+      },
+      units: [],
+    };
+  },
+  async mounted() {
+    this.units = await this.load('unit');
+  },
+  methods: {
+    ...mapActions(['load']),
+    handleSave({ action }) {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          this.$emit('save', { isNew: this.isNew, data: this.form, action });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    handleCancel(value) {
+      this.form = _.cloneDeep(this.data);
+      this.$emit('cancel');
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+</style>

+ 25 - 0
src/main.js

@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import App from './AppFrame.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 { createStore } from '@lib/utils/store';
+import '@lib/style/index.less';
+import '@/util/methods';
+import '@/util/init-user';
+
+Vue.config.productionTip = false;
+
+const store = createStore();
+// Add this.$router into store actions/mutations
+store.$router = router;
+
+new Vue({
+  router,
+  store,
+  render: h => h(App),
+}).$mount('#app');

+ 6 - 0
src/plugins/antd-vue.js

@@ -0,0 +1,6 @@
+/* eslint-disable object-curly-newline */
+import Vue from 'vue';
+// eslint-disable-next-line no-unused-vars
+import { List } from 'ant-design-vue';
+
+Vue.use(List.name, List);

+ 84 - 0
src/router.js

@@ -0,0 +1,84 @@
+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: '/',
+      component: Home,
+    },
+    {
+      path: '/site/config',
+      component: () => import(/* webpackChunkName: "cms_config" */ './views/config.vue'),
+    },
+    {
+      path: '/site/list',
+      component: () => import(/* webpackChunkName: "cms_sites" */ './views/sites.vue'),
+    },
+    {
+      path: '/news',
+      component: () => import(/* webpackChunkName: "cms_news" */ './views/news.vue'),
+      children: [
+        {
+          path: '/news/:column',
+        },
+      ],
+    },
+    {
+      path: '/service',
+      component: () => import(/* webpackChunkName: "cms_news" */ './views/news.vue'),
+      children: [
+        {
+          path: '/service/:column',
+        },
+      ],
+    },
+    {
+      name: 'column',
+      path: '/column/index',
+      component: () => import(/* webpackChunkName: "column_index" */ './views/new-views/column.vue'),
+    },
+    {
+      name: 'menu',
+      path: '/menu/index',
+      component: () => import(/* webpackChunkName: "menu_index" */ './views/new-views/menu.vue'), //'./views/menu/index.vue'
+    },
+    {
+      name: 'module',
+      path: '/module/index',
+      component: () => import(/* webpackChunkName: "news_index" */ './views/new-views/module.vue'),
+    },
+    {
+      name: 'list',
+      path: '/list/index',
+      component: () => import(/* webpackChunkName: "news_index" */ './views/new-views/list.vue'),
+    },
+    {
+      name: 'content',
+      path: '/content/index',
+      component: () => import(/* webpackChunkName: "news_index" */ './views/new-views/content.vue'),
+    },
+    {
+      name: 'news',
+      path: '/news/index/:id',
+      component: () => import(/* webpackChunkName: "news_index" */ './views/news/index.vue'),
+    },
+    {
+      name: 'site',
+      path: '/site/index',
+      component: () => import(/* webpackChunkName: "site_index" */ './views/site/index.vue'),
+    },
+    {
+      name: 'link',
+      path: '/link/index/:status',
+      component: () => import(/* webpackChunkName: "news_index" */ './views/link/index.vue'),
+    },
+  ],
+});
+
+export default router;

+ 7 - 0
src/store/.mutation.js

@@ -0,0 +1,7 @@
+// mutation types
+export const LOADED = 'LOADED';
+export const SUB_LOADED = 'SUB_LOADED';
+export const SELECTED = 'SELECTED';
+export const UPDATED = 'UPDATED';
+export const CREATED = 'CREATED';
+export const DELETED = 'DELETED';

+ 39 - 0
src/store/index.js

@@ -0,0 +1,39 @@
+import * as types from './.mutation';
+import util from '@lib/utils/user-util';
+
+export const state = () => {
+  return {
+    loading: true,
+    platform: 'school',
+    userinfo: util.user,
+    unit: null,
+    unitName: null,
+  };
+};
+
+export const mutations = {
+  [types.LOADED](state) {
+    state.userinfo = util.user;
+    const { unit } = util.user;
+    if (unit) {
+      state.platform = 'school';
+      state.unit = unit.code;
+      state.unitName = unit.name;
+    } else {
+      state.platform = 'master';
+      state.unit = null;
+      state.unitName = '中心';
+    }
+    state.loading = false;
+  },
+};
+export const actions = {
+  async init({ commit }) {
+    console.log('call init...');
+    commit(types.LOADED);
+  },
+};
+export const getters = {
+  userinfo: state => state.userinfo,
+  platform: state => state.platform,
+};

+ 52 - 0
src/store/jobsNew/column.js

@@ -0,0 +1,52 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  column: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/column/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/column/query`,
+  fetch: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/column/fetch/${id}`,
+  update: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/column/update/${id}`,
+  delete: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/column/delete/${id}`,
+  // column: '/adminapi/column/create',
+  // query: '/adminapi/column/query',
+  // fetch: id => `/adminapi/column/fetch/${id}`,
+  // update: id => `/adminapi/column/update/${id}`,
+  // delete: id => `/adminapi/column/delete/${id}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async columnOperation({ state }, { type, data }) {
+    let result;
+    if (type === 'add') {
+      let { info, site } = data;
+      result = await this.$axios.$post(api.column, info, { site: site });
+    }
+    if (type === 'list') {
+      let { site } = data;
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      result = await this.$axios.$get(api.query, { site: site, ...options });
+    }
+    if (type === 'search') {
+      let { id } = data;
+      result = await this.$axios.$get(api.fetch(id));
+    }
+    if (type === 'update') {
+      let { info, id } = data;
+      result = await this.$axios.$post(api.update(id), info);
+    }
+    if (type === 'delete') {
+      let { id } = data;
+      result = await this.$axios.$post(api.delete(id));
+    }
+    return result;
+  },
+};

+ 42 - 0
src/store/jobsNew/dictionary.js

@@ -0,0 +1,42 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+
+Vue.use(Vuex);
+const api = {
+  dictionary: type => `/code/${type}/items`, //type === xzqh:query:level(1/2);parent(无/code)
+  findOne: '/code/xzqh/findOne', //query:name
+  menu: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/menu/query`,
+  column: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/column/query`, //栏目
+  module: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/modules/query`,
+  list: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/newslist/query`, //信息列表
+  content: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/news/query`, //信息
+};
+
+export const state = () => ({});
+export const mutations = {};
+export const actions = {
+  // 字典表
+  async dicOperation({ state }, type) {
+    let result;
+    if (!_.isObject(type)) {
+      result = await this.$axios.$get(api.dictionary, { type: type });
+    } else {
+      let { level, parent, name } = type;
+      if (name) {
+        result = await this.$axios.$get(api.findOne, { name: name });
+      } else {
+        result = await this.$axios.$get(api.dictionary('xzqh'), { level: level, parent: parent });
+      }
+    }
+
+    return result;
+  },
+  //cms综合查询
+  async allSearch({ state }, { type, site }) {
+    console.log(type);
+    console.log(_.get(api, type));
+    let result = await this.$axios.$get(_.get(api, type), { site: site });
+    return result;
+  },
+};

+ 47 - 0
src/store/jobsNew/link.js

@@ -0,0 +1,47 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  link: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/img/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/img/query`,
+  fetch: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/img/fetch/${id}`,
+  update: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/img/update/${id}`,
+  delete: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/img/delete/${id}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async linkOperation({ state }, { type, data }) {
+    let result;
+    if (type === 'add') {
+      let { info, site, column } = data;
+      result = await this.$axios.$post(api.link, info, { site: site, column: column });
+    }
+    if (type === 'list') {
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      let { site, type } = data;
+      result = await this.$axios.$get(api.query, { site: site, type: type, ...options });
+    }
+    if (type === 'search') {
+      let { id } = data;
+      result = await this.$axios.$get(api.fetch(id));
+    }
+    if (type === 'update') {
+      let { info, id } = data;
+      result = await this.$axios.$post(api.update(id), info);
+    }
+    if (type === 'delete') {
+      let { id } = data;
+      result = await this.$axios.$post(api.delete(id));
+    }
+    return result;
+  },
+};

+ 48 - 0
src/store/jobsNew/list.js

@@ -0,0 +1,48 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  newslist: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/newslist/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/newslist/query`,
+  fetch: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/newslist/fetch/${id}`,
+  update: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/newslist/update/${id}`,
+  delete: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/newslist/delete/${id}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async newsListOperation({ state }, { type, data }) {
+    let { skip, limit } = data;
+    let result;
+    if (type === 'add') {
+      let { info, site } = data;
+      result = await this.$axios.$post(api.newslist, info, { site: site });
+    }
+    if (type === 'list') {
+      let { site } = data;
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      result = await this.$axios.$get(api.query, { site: site, ...options });
+    }
+    if (type === 'search') {
+      let { id } = data;
+      result = await this.$axios.$get(api.fetch(id));
+    }
+    if (type === 'update') {
+      let { info, id } = data;
+      result = await this.$axios.$post(api.update(id), info);
+    }
+    if (type === 'delete') {
+      let { id } = data;
+      result = await this.$axios.$post(api.delete(id));
+    }
+    return result;
+  },
+};

+ 47 - 0
src/store/jobsNew/menu.js

@@ -0,0 +1,47 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  menu: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/menu/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/menu/query`,
+  fetch: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/menu/fetch/${id}`,
+  update: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/menu/update/${id}`,
+  delete: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/menu/delete/${id}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async menuOperation({ state }, { type, data }) {
+    let result;
+    if (type === 'add') {
+      let { info, site } = data;
+      result = await this.$axios.$post(api.menu, info, { site: site });
+    }
+    if (type === 'list') {
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      let { site, level } = data;
+      result = await this.$axios.$get(api.query, { site: site, level: level, ...options });
+    }
+    if (type === 'search') {
+      let { id } = data;
+      result = await this.$axios.$get(api.fetch(id));
+    }
+    if (type === 'update') {
+      let { info, id } = data;
+      result = await this.$axios.$post(api.update(id), info);
+    }
+    if (type === 'delete') {
+      let { id } = data;
+      result = await this.$axios.$post(api.delete(id));
+    }
+    return result;
+  },
+};

+ 47 - 0
src/store/jobsNew/module.js

@@ -0,0 +1,47 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  modules: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/modules/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/modules/query`,
+  fetch: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/modules/fetch/${id}`,
+  update: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/modules/update/${id}`,
+  delete: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/modules/delete/${id}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async moduleOperation({ state }, { type, data }) {
+    let result;
+    if (type === 'add') {
+      let { info, site } = data;
+      result = await this.$axios.$post(api.modules, info, { site: site });
+    }
+    if (type === 'list') {
+      let { site } = data;
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      result = await this.$axios.$get(api.query, { site: site, ...options });
+    }
+    if (type === 'search') {
+      let { id } = data;
+      result = await this.$axios.$get(api.fetch(id));
+    }
+    if (type === 'update') {
+      let { info, id } = data;
+      result = await this.$axios.$post(api.update(id), info);
+    }
+    if (type === 'delete') {
+      let { id } = data;
+      result = await this.$axios.$post(api.delete(id));
+    }
+    return result;
+  },
+};

+ 48 - 0
src/store/jobsNew/news.js

@@ -0,0 +1,48 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  news: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/news/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/news/query`,
+  fetch: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/news/fetch/${id}`,
+  update: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/news/update/${id}`,
+  delete: id => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/news/delete/${id}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async newsOperation({ state }, { type, data }) {
+    let { skip, limit } = data;
+    let result;
+    if (type === 'add') {
+      let { info, site, column } = data;
+      result = await this.$axios.$post(api.news, info, { site: site, column: column });
+    }
+    if (type === 'list') {
+      let { site, column } = data;
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      result = await this.$axios.$get(api.query, { site: site, column: column, ...options });
+    }
+    if (type === 'search') {
+      let { id } = data;
+      result = await this.$axios.$get(api.fetch(id));
+    }
+    if (type === 'update') {
+      let { info, id } = data;
+      result = await this.$axios.$post(api.update(id), info);
+    }
+    if (type === 'delete') {
+      let { id } = data;
+      result = await this.$axios.$post(api.delete(id));
+    }
+    return result;
+  },
+};

+ 47 - 0
src/store/jobsNew/site.js

@@ -0,0 +1,47 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+Vue.use(Vuex);
+const api = {
+  site: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/site/create`,
+  query: `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/site/query`,
+  fetch: site => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/site/fetch/${site}`,
+  update: site => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/site/update/${site}`,
+  delete: site => `/adminapi${process.env.NODE_ENV === 'development' ? '' : '/cms'}/site/delete/${site}`,
+};
+export const state = () => ({});
+
+export const mutations = {};
+
+export const actions = {
+  async siteOperation({ state }, { type, data }) {
+    let result;
+    if (type === 'add') {
+      let { info, site, column } = data;
+      result = await this.$axios.$post(api.site, info, { site: site, column: column });
+    }
+    if (type === 'list') {
+      let { site, column } = data;
+      const { page = 1, size = pageSize } = data;
+      const skip = Math.max(0, (page - 1) * size);
+      let options = { skip, limit: size };
+      result = await this.$axios.$get(api.query, { site: site, column: column, ...options });
+    }
+    if (type === 'search') {
+      let { site } = data;
+      result = await this.$axios.$get(api.fetch(site));
+    }
+    if (type === 'update') {
+      let { info, site } = data;
+      result = await this.$axios.$post(api.update(site), info);
+    }
+    if (type === 'delete') {
+      let { site } = data;
+      result = await this.$axios.$post(api.delete(site));
+    }
+    return result;
+  },
+};

+ 140 - 0
src/store/menu.js

@@ -0,0 +1,140 @@
+const items = [
+  // {
+  //   title: '网站设置',
+  //   icon: 'system',
+  //   module: 'cms',
+  //   children: [
+  //     {
+  //       title: '信息配置',
+  //       path: '/site/config',
+  //       icon: 'set',
+  //     },
+  //     {
+  //       title: '分站管理',
+  //       path: '/site/list',
+  //       icon: 'site',
+  //       platform: 'master',
+  //     },
+  //   ],
+  // },
+  // {
+  //   title: '就业服务',
+  //   icon: 'news',
+  //   module: 'cms',
+  //   children: [
+  //     {
+  //       title: '就业指导',
+  //       path: '/service/guide',
+  //       icon: 'column',
+  //     },
+  //     {
+  //       title: '就业政策',
+  //       path: '/service/policy',
+  //       icon: 'column',
+  //     },
+  //     {
+  //       title: '常见问题',
+  //       path: '/service/faq',
+  //       icon: 'column',
+  //     },
+  //   ],
+  // },
+  // {
+  //   title: '新闻公告',
+  //   icon: 'news',
+  //   module: 'cms',
+  //   children: [
+  //     {
+  //       title: '焦点新闻',
+  //       path: '/news/focus',
+  //       icon: 'column',
+  //     },
+  //     {
+  //       title: '就业快讯',
+  //       path: '/news/flash',
+  //       icon: 'column',
+  //     },
+  //     {
+  //       title: '通知公告',
+  //       path: '/news/notice',
+  //       icon: 'column',
+  //     },
+  //   ],
+  // },
+  {
+    title: '栏目管理',
+    path: '/column/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+  {
+    title: '菜单管理',
+    path: '/menu/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+  {
+    title: '首页模块管理',
+    path: '/module/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+  // {
+  //   title: '信息列表管理',
+  //   path: '/list/index',
+  //   icon: 'job',
+  //   module: 'jobs',
+  // },
+  {
+    title: '信息管理',
+    path: '/content/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+  {
+    title: '站点管理',
+    path: '/site/index',
+    icon: 'job',
+    module: 'jobs',
+  },
+  {
+    title: '链接管理',
+    path: '/link',
+    icon: 'job',
+    module: 'jobs',
+    children: [
+      {
+        title: '友情链接',
+        path: '/link/index/link',
+        icon: 'info',
+      },
+      {
+        title: '合作单位',
+        path: '/link/index/cooperation',
+        icon: 'info',
+      },
+    ],
+  },
+];
+
+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))),
+});
+
+// initial state
+export const state = () => ({
+  items: items.map(MapMenu()),
+});

+ 15 - 0
src/store/naf/.dict.js

@@ -0,0 +1,15 @@
+// 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: '停用' }],
+  column: [
+    { code: 'focus', name: '焦点新闻' },
+    { code: 'flash', name: '新闻快讯' },
+    { code: 'notice', name: '通知公告' },
+    { code: 'guide', name: '就业指导' },
+    { code: 'faq', name: '常见问题' },
+    { code: 'policy', name: '政策文件' },
+  ],
+};

+ 97 - 0
src/store/naf/dict.js

@@ -0,0 +1,97 @@
+/* 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;
+      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 {
+      // 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;

+ 87 - 0
src/store/news.js

@@ -0,0 +1,87 @@
+import * as types from './.mutation.js';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+const api = {
+  create: '/cms/news/create',
+  update: '/cms/news/update',
+  delete: '/cms/news/delete',
+  fetch: '/cms/news/fetch',
+  query: '/cms/news/query',
+  restore: '/cms/news/restore',
+};
+// initial state
+export const state = () => ({
+  items: [],
+  current: null,
+  total: 0,
+  column: null,
+});
+export const actions = {
+  async query({ commit, state }, { column, paging = {} }) {
+    // 栏目变化时先清空列表
+    if (state.column != column) {
+      commit(types.LOADED, { data: [], total: 0, column });
+    }
+
+    const { page = 1, size = pageSize } = paging;
+    const skip = Math.max(0, (page - 1) * size);
+    const res = await this.$axios.$get(api.query, { column, skip, limit: size });
+    if (res.errcode === 0) {
+      commit(types.LOADED, res);
+    } else {
+      commit(types.LOADED, { data: [], total: 0 });
+    }
+    return res;
+  },
+  async create({ commit }, { column, data }) {
+    const res = await this.$axios.$post(api.create, data, { column });
+    if (res.errcode === 0) commit(types.CREATED, res.data);
+    return res;
+  },
+  async update({ commit }, { id, column, data }) {
+    const res = await this.$axios.$post(api.update, data, { id, column });
+    if (res.errcode === 0) commit(types.UPDATED, res.data);
+    return res;
+  },
+  async fetch({ commit }, { id, column }) {
+    const res = await this.$axios.$get(api.fetch, { id, column });
+    if (res.errcode === 0) commit(types.SELECTED, res.data);
+    return res;
+  },
+  async delete({ commit }, { id, column }) {
+    const res = await this.$axios.$post(api.delete, {}, { id, column });
+    // if (res.errcode === 0) commit(types.DELETED, { id });
+    if (res.errcode === 0) commit(types.UPDATED, res.data);
+    return res;
+  },
+  async restore({ commit }, { id, column }) {
+    const res = await this.$axios.$post(api.restore, {}, { id, column });
+    if (res.errcode === 0) commit(types.UPDATED, res.data);
+    return res;
+  },
+};
+
+// mutations
+export const mutations = {
+  [types.LOADED](state, { data, total, column }) {
+    state.items = data;
+    state.total = total;
+    if (column) state.column = column;
+  },
+  [types.SELECTED](state, payload) {
+    state.current = payload;
+  },
+  [types.CREATED](state, payload) {
+    state.items.push(payload);
+  },
+  [types.UPDATED](state, payload) {
+    const idx = state.items.findIndex(p => p.id === payload.id);
+    state.items.splice(idx, 1, payload);
+  },
+  [types.DELETED](state, { id }) {
+    const idx = state.items.findIndex(p => p.id === id);
+    state.items.splice(idx, 1);
+  },
+};
+export const namespaced = true;

+ 82 - 0
src/store/site.js

@@ -0,0 +1,82 @@
+import * as types from './.mutation.js';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+const api = {
+  config: '/cms/site/config',
+  query: '/cms/site/query',
+  create: '/cms/site/create',
+  delete: '/cms/site/delete',
+  update: '/cms/site/update',
+  fetch: '/cms/site/fetch',
+};
+// initial state
+export const state = () => ({
+  items: [],
+  current: null,
+  total: 0,
+});
+export const actions = {
+  async getConfig() {
+    const res = await this.$axios.$get(api.config);
+    return res;
+  },
+  async setConfig({ commit }, { data }) {
+    const res = await this.$axios.$post(api.config, data);
+    return res;
+  },
+  async query({ commit }, { paging = {} }) {
+    const { page = 1, size = pageSize } = paging;
+    const skip = Math.max(0, (page - 1) * size);
+    const res = await this.$axios.$get(api.query, { skip, limit: size });
+    if (res.errcode === 0) {
+      commit(types.LOADED, res);
+    } else {
+      commit(types.LOADED, { data: [], total: 0 });
+    }
+    return res;
+  },
+  async create({ commit }, { data }) {
+    const res = await this.$axios.$post(api.create, data);
+    if (res.errcode === 0) commit(types.CREATED, res.data);
+    return res;
+  },
+  async update({ commit }, { site, data }) {
+    const res = await this.$axios.$post(api.update, data, { site });
+    if (res.errcode === 0) commit(types.UPDATED, res.data);
+    return res;
+  },
+  async fetch({ commit }, { site }) {
+    const res = await this.$axios.$get(api.fetch, { site });
+    if (res.errcode === 0) commit(types.SELECTED, res.data);
+    return res;
+  },
+  async delete({ commit }, { site }) {
+    const res = await this.$axios.$post(api.delete, {}, { site });
+    if (res.errcode === 0) commit(types.DELETED, { site });
+    return res;
+  },
+};
+
+// mutations
+export const mutations = {
+  [types.LOADED](state, { data, total }) {
+    state.items = data;
+    state.total = total;
+  },
+  [types.SELECTED](state, payload) {
+    state.current = payload;
+  },
+  [types.CREATED](state, payload) {
+    state.items.push(payload);
+  },
+  [types.UPDATED](state, payload) {
+    const idx = state.items.findIndex(p => p.site === payload.site);
+    state.items.splice(idx, 1, payload);
+  },
+  [types.DELETED](state, { site }) {
+    const idx = state.items.findIndex(p => p.site === site);
+    state.items.splice(idx, 1);
+  },
+};
+export const namespaced = true;

+ 10 - 0
src/util/init-user.js

@@ -0,0 +1,10 @@
+let user = sessionStorage.getItem('user');
+if (!user) {
+  let object = {
+    isAdmin: true,
+    mobile: '13089419810',
+    name: '管理员',
+    unit: { name: '中心管理', code: 'master' },
+  };
+  sessionStorage.setItem('user', JSON.stringify(object));
+}

+ 10 - 0
src/util/methods.js

@@ -0,0 +1,10 @@
+import Vue from 'vue';
+import _ from 'lodash';
+const Plugin = {
+  install(Vue, options) {
+    let user = JSON.parse(sessionStorage.getItem('user'));
+    if (user !== undefined && user !== null) Vue.prototype.$user = user;
+  },
+};
+
+Vue.use(Plugin);

+ 152 - 0
src/views/column/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>栏目列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建栏目</el-button>
+      </div>
+      <data-grid
+        :data="corpData"
+        :meta="fields"
+        :operation="operation"
+        @open="handleOpen"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="details" size="mini" v-else-if="view == 'details'">
+      <div slot="header">
+        <span>栏目信息</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-info :data="corpInfo"> </data-info>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建栏目' : '修改栏目信息' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/column-form';
+import DataInfo from '@/components/jobs/column-info';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/column');
+
+const JobfairStatus = {
+  OPENING: '0', // 开放申请
+  CLOSED: '1', // 已关闭
+  IN_PROGRESS: '2', // 进行中
+};
+
+export default {
+  components: {
+    DataInfo,
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'moudle', label: '栏目模块' }, { name: 'columnname', label: '栏目名称' }, { name: 'showModes', label: '展现方式' }],
+      /* 操作类型 */
+      operation: [['open', '查看', 'el-icon-view'], ['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      corpData: [],
+      corpInfo: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['columnOperation']),
+    async search() {
+      // 1直接拿着参数发送请求
+      let result = await this.columnOperation({ type: 'list', data: { site: this.$user.unit.code } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        this.$set(this, `corpData`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleOpen(data) {
+      this.$router.push({ name: 'news', params: { id: data.id } });
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该栏目吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.columnOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.columnOperation({ type: 'search', data: { id: id } });
+      console.log(res);
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.columnOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+        console.log(payload.data);
+        console.log(result);
+      } else {
+        let result = await this.columnOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { type: '创建栏目', unit: this.unit }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    ...mapGetters(['unit', 'platform']),
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 68 - 0
src/views/config.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="lite">
+    <el-card class="right details" size="mini" v-if="form.data && view == 'form'">
+      <div slot="header">
+        <span>网站信息配置</span>
+      </div>
+      <site-form :data="form.data" :is-new="form.isNew" @save="handleSave"> </site-form>
+    </el-card>
+    <div v-if="view == 'loading'">
+      <div class="weui-loadmore" v-if="loading">
+        <i class="weui-loading"></i>
+        <span class="weui-loadmore__tips">正在加载</span>
+      </div>
+    </div>
+    <el-alert :title="message" type="info" description="页面加载过程中发生错误" show-icon v-if="view == 'error'"> </el-alert>
+  </div>
+</template>
+<script>
+import _ from 'lodash';
+import { mapState, createNamespacedHelpers } from 'vuex';
+import SiteForm from '@/components/site-form';
+
+const { mapActions } = createNamespacedHelpers('site');
+
+export default {
+  components: {
+    SiteForm,
+  },
+  metaInfo: {
+    title: '网站配置',
+  },
+  async mounted() {
+    const res = await this.getConfig();
+    if (this.$checkRes(res)) {
+      if (!res.data) {
+        this.message = '分站还未开通';
+        this.view = 'error';
+      } else {
+        this.form = { data: res.data, isNew: false };
+        this.view = 'form';
+      }
+    } else {
+      this.message = res.message;
+      this.view = 'error';
+    }
+  },
+  data() {
+    return {
+      view: 'loading',
+      message: '',
+      form: {},
+    };
+  },
+  methods: {
+    ...mapActions(['getConfig', 'setConfig']),
+    async handleSave(payload) {
+      const res = await this.setConfig(payload);
+      this.$checkRes(res, '配置保存成功');
+    },
+  },
+  computed: {
+    ...mapState(['loading']),
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 14 - 0
src/views/home.vue

@@ -0,0 +1,14 @@
+<template>
+  <div>
+    <header class="section_title">网站管理</header>
+  </div>
+</template>
+
+<script>
+export default {
+  metaInfo: {
+    title: '网站管理',
+    titleTemplate: '%s',
+  },
+};
+</script>

+ 146 - 0
src/views/link/index.vue

@@ -0,0 +1,146 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>{{ pageName }}列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建{{ pageName }}</el-button>
+      </div>
+      <data-grid
+        :data="list"
+        :meta="fields"
+        :operation="operation"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? `创建${pageName}` : `修改${pageName}` }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form :title="pageName" :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/link-form';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/link');
+
+export default {
+  metaInfo: {
+    title: '栏目管理',
+  },
+  components: {
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'title', label: `单位` }, { name: 'is_use_word', label: '是否使用' }],
+      /* 操作类型 */
+      operation: [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      list: [],
+      info: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['linkOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.linkOperation({ type: 'list', data: { site: this.$user.unit.code, type: this.status, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        result.data.map(item => {
+          item.is_use_word = `${item.is_use}` === '0' ? `使用中` : '已禁止';
+          return item;
+        });
+        this.$set(this, `list`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该栏目吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.linkOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.linkOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.linkOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.linkOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { is_use: `0`, site: this.$user.unit.code, type: this.status }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    status() {
+      return this.$route.params.status;
+    },
+    pageName() {
+      let status = this.$route.params.status;
+      let name = status === 'link' ? '友情链接' : '合作单位';
+      return name;
+    },
+  },
+  watch: {
+    status: 'search',
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 153 - 0
src/views/menu/index.vue

@@ -0,0 +1,153 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>菜单列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建菜单</el-button>
+      </div>
+      <data-grid
+        :data="corpData"
+        :meta="fields"
+        :operation="operation"
+        @open="handleOpen"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="details" size="mini" v-else-if="view == 'details'">
+      <div slot="header">
+        <span>菜单信息</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-info :data="corpInfo"> </data-info>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建菜单' : '修改菜单' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/menu-form';
+import DataInfo from '@/components/jobs/menu-info';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/menu');
+
+const JobfairStatus = {
+  OPENING: '0', // 开放申请
+  CLOSED: '1', // 已关闭
+  IN_PROGRESS: '2', // 进行中
+};
+
+export default {
+  components: {
+    DataInfo,
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'parent_name', label: '父级' }, { name: 'name', label: '菜单名称' }],
+      /* 操作类型 */
+      operation: [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      corpData: [],
+      corpInfo: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['menuOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.menuOperation({ type: 'list', data: { site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        this.$set(this, `corpData`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleOpen(data) {
+      let res = await this.menuOperation({ type: 'search', data: { id: data.id } });
+      this.$set(this, 'corpInfo', res.data);
+      this.view = 'details';
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该栏目吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.menuOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.menuOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.menuOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.menuOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { type: '创建菜单', path: '/', unit: this.unit }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    ...mapGetters(['unit', 'platform']),
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 144 - 0
src/views/new-views/column.vue

@@ -0,0 +1,144 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>栏目列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建栏目</el-button>
+      </div>
+      <data-grid
+        :data="list"
+        :meta="fields"
+        :operation="operation"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建栏目' : '修改栏目' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form title="栏目" :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/column-form';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/column');
+
+export default {
+  metaInfo: {
+    title: '栏目管理',
+  },
+  components: {
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [
+        { name: 'title', label: '栏目名称' },
+        { name: 'parent', label: '所属' },
+        { name: 'is_use_word', label: '是否使用' },
+        { name: 'news_type_word', label: '内容分类' },
+      ],
+      /* 操作类型 */
+      operation: [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      list: [],
+      info: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['columnOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.columnOperation({ type: 'list', data: { site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        result.data.map(item => {
+          item.is_use_word = `${item.is_use}` === '0' ? `使用中` : '已禁止';
+          item.news_type_word = `${item.news_type}` === `1` ? '自定义栏目' : '抓取栏目';
+          return item;
+        });
+        this.$set(this, `list`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该栏目吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.columnOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.columnOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.columnOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.columnOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { is_use: `0`, site: this.$user.unit.code }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 147 - 0
src/views/new-views/content.vue

@@ -0,0 +1,147 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>信息</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建信息</el-button>
+      </div>
+      <data-grid
+        :data="list"
+        :meta="fields"
+        :operation="operation"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建信息' : '修改信息' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form title="" :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import DataForm from '@/components/jobs/content-form';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/news');
+export default {
+  metaInfo: { title: '信息管理' },
+  name: 'contents',
+  props: {},
+  components: {
+    DataForm,
+    DataGrid,
+  },
+  data: () => ({
+    view: 'list',
+    fields: [{ name: 'title', label: '名称' }, { name: 'parent', label: '所属栏目' }, { name: 'is_use_word', label: '是否使用' }],
+    /* 操作类型 */
+    operation: [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+    list: [],
+    info: {},
+    total: 0,
+  }),
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+  computed: {
+    status() {
+      return this.$route.params.status;
+    },
+  },
+  methods: {
+    ...mapActions(['newsOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.newsOperation({ type: 'list', data: { site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        result.data.map(item => {
+          item.is_use_word = `${item.is_use}` === '0' ? `使用中` : '已禁止';
+          return item;
+        });
+        this.$set(this, `list`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该信息吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.newsOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.newsOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let data = JSON.parse(JSON.stringify(payload.data));
+        let { type, ...info } = data;
+        let result = await this.newsOperation({ type: 'add', data: { info: info, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.newsOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = {
+        data: {
+          is_use: `0`,
+          site: this.$user.unit.code,
+          type: 'list',
+          publish_time: new Date()
+            .toLocaleDateString()
+            .replace('/', '-')
+            .replace('/', '-'),
+        },
+        isNew: true,
+      };
+      this.view = 'form';
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 140 - 0
src/views/new-views/list.vue

@@ -0,0 +1,140 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>信息列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建信息列表</el-button>
+      </div>
+      <data-grid
+        :data="list"
+        :meta="fields"
+        :operation="operation"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建信息列表' : '修改信息列表' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form title="列表" :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/menu-form';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/list');
+
+export default {
+  metaInfo: {
+    title: '信息列表管理',
+  },
+  components: {
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'title', label: '列表名称' }, { name: 'is_use_word', label: '是否使用' }],
+      /* 操作类型 */
+      operation: [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      list: [],
+      info: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['newsListOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.newsListOperation({ type: 'list', data: { site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        result.data.map(item => {
+          item.is_use_word = `${item.is_use}` === '0' ? `使用中` : '已禁止';
+          return item;
+        });
+        this.$set(this, `list`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该信息列表吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.newsListOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.newsListOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data, type: 'content' }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let data = JSON.parse(JSON.stringify(payload.data));
+        let { type, ...info } = data;
+        let result = await this.newsListOperation({ type: 'add', data: { info: info, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.newsListOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { is_use: `0`, site: this.$user.unit.code, type: 'list' }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 138 - 0
src/views/new-views/menu.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>菜单列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建菜单</el-button>
+      </div>
+      <data-grid
+        :data="list"
+        :meta="fields"
+        :operation="operation"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建菜单' : '修改菜单' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form title="菜单" :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/menu-form';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/menu');
+
+export default {
+  metaInfo: {
+    title: '菜单管理',
+  },
+  components: {
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'title', label: '菜单名称' }, { name: 'is_use_word', label: '是否使用' }],
+      /* 操作类型 */
+      operation: [['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      list: [],
+      info: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['menuOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.menuOperation({ type: 'list', data: { site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        result.data.map(item => {
+          item.is_use_word = `${item.is_use}` === '0' ? `使用中` : '已禁止';
+          return item;
+        });
+        this.$set(this, `list`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该栏目吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.menuOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.menuOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.menuOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.menuOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { is_use: `0`, site: this.$user.unit.code }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 138 - 0
src/views/new-views/module.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>首页模块列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建首页模块</el-button>
+      </div>
+      <data-grid
+        :data="list"
+        :meta="fields"
+        :operation="operation"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @query="search"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建首页模块' : '修改首页模块' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form title="模块" :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/module-form';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/module');
+
+export default {
+  metaInfo: {
+    title: '首页模块管理',
+  },
+  components: {
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'title', label: '模块名称' }, { name: 'is_use_word', label: '是否使用' }],
+      /* 操作类型 */
+      operation: [['edit', '编辑', 'el-icon-edit']] /* 操作类型 */,
+      list: [],
+      info: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['moduleOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.moduleOperation({ type: 'list', data: { site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        result.data.map(item => {
+          item.is_use_word = `${item.is_use}` === '0' ? `使用中` : '已禁止';
+          return item;
+        });
+        this.$set(this, `list`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该首页模块吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.moduleOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.moduleOperation({ type: 'search', data: { id: id } });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.moduleOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code } });
+        msg = '信息添加成功';
+      } else {
+        let result = await this.moduleOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { is_use: `0`, site: this.$user.unit.code }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 173 - 0
src/views/news.vue

@@ -0,0 +1,173 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>{{ columnName }} - 信息列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">发布信息</el-button>
+      </div>
+      <data-grid
+        :data="items"
+        :meta="fields"
+        :operation="listOper"
+        :paging="true"
+        :total="total"
+        @query="handleQuery"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @restore="handleRestore"
+        @preview="handlePreview"
+      >
+        <template slot="post">
+          <el-table-column width="48" label="..." align="center">
+            <div slot-scope="scope">
+              <el-tooltip content="包含附件" class="icon" v-if="scope.row.attachment &amp;&amp; scope.row.attachment.length &gt; 0">
+                <span><i class="naf-icons naf-icon-attachment"></i></span>
+              </el-tooltip>
+            </div>
+          </el-table-column>
+        </template>
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ columnName }} - {{ form.isNew ? '发布信息' : '修改信息' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <news-form :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </news-form>
+    </el-card>
+    <el-card class="right details" size="mini" v-else>
+      <div slot="header">
+        <span>{{ columnName }} - 信息预览</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <preview :data="current" />
+    </el-card>
+  </div>
+</template>
+<script>
+import DataGrid from '@naf/data/filter-grid';
+// import NewsForm from '@/components/news-form';
+import Preview from '@/components/preview';
+import { createNamespacedHelpers } from 'vuex';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+const { mapState, mapActions } = createNamespacedHelpers('news');
+const { mapActions: mapDict } = createNamespacedHelpers('naf/dict');
+
+export default {
+  components: {
+    // NewsForm,
+    DataGrid,
+    Preview,
+  },
+  metaInfo: {
+    title: '信息管理',
+  },
+  created() {
+    this.loadDict('column');
+  },
+  mounted() {
+    this.handleQuery();
+  },
+  data() {
+    return {
+      view: 'list',
+      form: {},
+      fields: [
+        { name: 'column', label: '栏目', formatter: 'dict:column' },
+        { name: 'title', label: '标题', listOpts: { width: 200 } },
+        { name: 'meta.state', label: '状态', formatter: this.statusLabel },
+        { name: 'meta.createdAt', label: '创建时间', formatter: ['date', 'YYYY-MM-DD HH:mm'] },
+        { name: 'meta.updatedAt', label: '修改时间', formatter: ['date', 'YYYY-MM-DD HH:mm'] },
+      ],
+      listOper: [
+        ['preview', '预览', 'el-icon-view'],
+        ['edit', '编辑', 'el-icon-edit'],
+        ['delete', '删除', 'el-icon-delete', true],
+        ['restore', '恢复', 'el-icon-refresh', true],
+      ] /* 操作类型 */,
+    };
+  },
+  methods: {
+    ...mapActions(['query', 'create', 'delete', 'restore', 'update', 'fetch']),
+    ...mapDict({ loadDict: 'load' }),
+    async handleEdit({ id }) {
+      const res = await this.fetch({ id });
+      this.$checkRes(res, () => {
+        this.form = { data: res.data, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handlePreview({ id }) {
+      const res = await this.fetch({ id });
+      this.$checkRes(res, () => {
+        this.view = 'preview';
+      });
+    },
+    handleNew() {
+      this.form = { data: {}, isNew: true };
+      this.view = 'form';
+    },
+    async handleSave(payload) {
+      let res, msg;
+      if (payload.isNew) {
+        res = await this.create({ column: this.column, ...payload });
+        msg = '信息添加成功';
+      } else {
+        const { id } = payload.data;
+        res = await this.update({ id, ...payload });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(res, msg)) {
+        this.view = 'list';
+      }
+    },
+    async handleDelete({ id }) {
+      const res = await this.delete({ id });
+      this.$checkRes(res, '删除数据成功');
+    },
+    async handleRestore({ id }) {
+      const res = await this.restore({ id });
+      this.$checkRes(res, '恢复数据成功');
+    },
+    async handlePost({ id }) {
+      this.view = 'list';
+      const res = await this.post({ id });
+      this.$checkRes(res, '递送公文成功');
+    },
+    async handleQuery({ filter, paging } = {}) {
+      this.view = 'list';
+      const res = await this.query({ column: this.column, paging });
+      this.$checkRes(res);
+    },
+    statusLabel: (row, column, cellValue, index) => {
+      switch (cellValue) {
+        case 0:
+          return '正常';
+        case 1:
+          return '删除';
+        default:
+          return cellValue;
+      }
+    },
+  },
+  computed: {
+    ...mapState(['items', 'current', 'total']),
+    column() {
+      return this.$route.params.column;
+    },
+    columnName() {
+      if (this.column) return this.$dict('column', this.column);
+      return '';
+    },
+  },
+  watch: {
+    // call again the method if the route changes
+    column: 'handleQuery',
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 156 - 0
src/views/news/index.vue

@@ -0,0 +1,156 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>新闻列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">创建新闻</el-button>
+      </div>
+      <data-grid
+        :data="corpData"
+        :meta="fields"
+        :operation="operation"
+        @open="handleOpen"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        :paging="true"
+        :filter="true"
+        :total="total"
+      >
+        <template slot="ext"> </template>
+      </data-grid>
+    </el-card>
+    <el-card class="details" size="mini" v-else-if="view == 'details'">
+      <div slot="header">
+        <span>新闻信息</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-info :data="corpInfo"> </data-info>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '创建新闻' : '修改新闻' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <data-form :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </data-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import DataForm from '@/components/jobs/news-form';
+import DataInfo from '@/components/jobs/news-info';
+import DataGrid from '@naf/data/filter-grid';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/news');
+
+const JobfairStatus = {
+  OPENING: '0', // 开放申请
+  CLOSED: '1', // 已关闭
+  IN_PROGRESS: '2', // 进行中
+};
+
+export default {
+  components: {
+    DataInfo,
+    DataForm,
+    DataGrid,
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [{ name: 'title', label: '新闻名称' }],
+      /* 操作类型 */
+      operation: [['open', '查看', 'el-icon-view'], ['edit', '编辑', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete']] /* 操作类型 */,
+      corpData: [],
+      corpInfo: {},
+      total: 0,
+    };
+  },
+  validate({ params }) {
+    // Must be a number
+    return /^[0-2]$/.test(params.status);
+  },
+  created() {
+    this.search();
+  },
+
+  methods: {
+    ...mapActions(['newsOperation']),
+    async search({ filter = {}, paging } = {}) {
+      let data = { ...filter, ...paging };
+      // 1直接拿着参数发送请求
+      let result = await this.newsOperation({ type: 'list', data: { column: this.$route.params.id, site: this.$user.unit.code, ...data } });
+      if (`${result.errcode}` === '0') {
+        //给this=>vue的实例下在中的list属性,赋予result。data的值
+        this.$set(this, `total`, result.total);
+        this.$set(this, `corpData`, result.data);
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : 'error');
+      }
+    },
+    async handleOpen(data) {
+      let res = await this.newsOperation({ type: 'search', data: { id: data.id } });
+      this.$set(this, 'corpInfo', res.data);
+      console.log(res);
+      this.view = 'details';
+    },
+    async handleDelete({ id }) {
+      this.$confirm('是否删除该栏目吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.toDelete(id);
+        })
+        .catch(() => {});
+    },
+    async toDelete(id) {
+      let result = await this.newsOperation({ type: 'delete', data: { id: id } });
+      if (`${result.errcode}` === '0') {
+        this.$message.success('删除成功');
+        this.search();
+      } else {
+        this.$message.error(result.errmsg ? result.errmsg : '删除失败');
+      }
+    },
+    async handleEdit({ id }) {
+      let res = await this.newsOperation({ type: 'search', data: { id: id } });
+      console.log(res);
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let result, msg;
+      if (payload.isNew) {
+        let result = await this.newsOperation({ type: 'add', data: { info: payload.data, site: this.$user.unit.code, column: this.$route.params.id } });
+        msg = '信息添加成功';
+        console.log(payload.data);
+        console.log(result);
+      } else {
+        let result = await this.newsOperation({ type: 'update', data: { info: payload.data, id: payload.data.id } });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(result, msg)) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    handleNew() {
+      this.form = { data: { type: '创建新闻信息', unit: this.unit }, isNew: true };
+      this.view = 'form';
+    },
+  },
+  computed: {
+    ...mapGetters(['unit', 'platform']),
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 118 - 0
src/views/site/index.vue

@@ -0,0 +1,118 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px" v-if="loading">
+    <slot>
+      <el-form-item label="站点状态" prop="status">
+        {{ form.status }}
+      </el-form-item>
+      <el-form-item label="网站名称" prop="name">
+        <el-input v-model="form.name"></el-input>
+      </el-form-item>
+      <el-form-item label="网站logo" prop="logo">
+        <upload :limit="1" :data="form.logo" type="logo" :url="`/files/admin/site/${$user.unit.code}logo/upload`" @upload="uploadSuccess"></upload>
+      </el-form-item>
+      <el-form-item label="网站背景图片" prop="banner">
+        <upload :limit="1" :data="form.banner" type="banner" :url="`/files/admin/site/${$user.unit.code}banner/upload`" @upload="uploadSuccess"></upload>
+      </el-form-item>
+      <el-form-item label="网站域名" prop="domain">
+        <el-input v-model="form.domain"></el-input>
+      </el-form-item>
+      <el-form-item label="版权声明" prop="copyright">
+        <el-input type="textarea" v-model="form.copyright"></el-input>
+      </el-form-item>
+      <el-form-item label="样式主题" prop="theme">
+        <el-input v-model="form.theme"></el-input>
+      </el-form-item>
+      <el-form-item label="站点介绍/联系方式" prop="content">
+        <wang-editor v-model="form.content" placeholder="请输入站点介绍/联系方式" upload-img-server="/files/jobs/jobfair/upload"></wang-editor>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <wang-editor v-model="form.remark" placeholder="请输入备注信息" upload-img-server="/files/jobs/jobfair/upload"></wang-editor>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleSave" size="mini">保存</el-button>
+      </el-form-item>
+    </slot>
+  </el-form>
+</template>
+<script>
+import _ from 'lodash';
+import upload from '@/components/jobs/upload';
+import WangEditor from '@naf/data/wang-editor';
+import CodeSelect from '@naf/data/code-select';
+import { createNamespacedHelpers, mapGetters } from 'vuex';
+const { mapState, mapActions } = createNamespacedHelpers('jobsNew/site');
+const requiredAndMaxlen = (name, len = 0) => {
+  const rules = [{ required: true, message: `${name}不能为空`, trigger: 'blur' }];
+  if (len > 0) rules.push({ max: len, message: `长度不能大于${len}个字符`, trigger: 'blur' });
+  return rules;
+};
+
+export default {
+  components: {
+    WangEditor,
+    // CodeSelect,
+    upload,
+  },
+  name: 'fair-form',
+  props: {},
+  data() {
+    return {
+      form: {},
+      limits: true,
+      rules: {
+        name: requiredAndMaxlen('栏目名称', 40),
+        status: requiredAndMaxlen('网站状态', 40),
+        domain: requiredAndMaxlen('域名', 40),
+        banner: requiredAndMaxlen('banner图片', 40),
+        copyright: requiredAndMaxlen('版权声明', 10240),
+        theme: requiredAndMaxlen('主题', 40),
+        content: requiredAndMaxlen('介绍/联系方式', 10240),
+        remark: requiredAndMaxlen('备注', 10240),
+      },
+      loading: false,
+      dialogImageUrl: '',
+      dialogVisible: false,
+      disabled: false,
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...mapActions(['siteOperation']),
+    async search() {
+      let result = await this.siteOperation({ type: 'search', data: { site: this.$user.unit.code } });
+      let object = JSON.parse(JSON.stringify(result.data));
+      object.status = `${object.status}` === '0' ? '正常' : `${object.status}` === '1' ? '未激活' : '已注销';
+      this.$set(this, 'form', object);
+      this.$set(this, `loading`, true);
+    },
+    async handleSave() {
+      let msg;
+      let result = await this.siteOperation({ type: 'update', data: { info: this.form, site: this.$user.unit.code } });
+      msg = '信息修改成功';
+      if (this.$checkRes(result, msg)) {
+        this.search();
+      }
+    },
+    uploadSuccess({ type, data }) {
+      this.$set(this.form, `${type}`, data.uri);
+    },
+  },
+  computed: {
+    ...mapGetters(['unit', 'platform']),
+    status() {
+      return this.$route.params.status;
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-form-item {
+  width: 700px;
+}
+.desc {
+  color: gray;
+  margin-left: 20px;
+}
+</style>

+ 111 - 0
src/views/sites.vue

@@ -0,0 +1,111 @@
+<template>
+  <div class="lite">
+    <el-card class="right list" size="mini" v-if="view == 'list'">
+      <div slot="header">
+        <span>高校分站列表</span>
+        <el-button icon="el-icon-plus" style="float: right; padding: 3px 0" type="text" @click="handleNew">添加分站</el-button>
+      </div>
+      <data-grid
+        :data="items"
+        :meta="fields"
+        :operation="listOper"
+        :paging="true"
+        :total="total"
+        @query="handleQuery"
+        @edit="handleEdit"
+        @delete="handleDelete"
+      >
+      </data-grid>
+    </el-card>
+    <el-card class="right details" size="mini" v-else-if="view == 'form'">
+      <div slot="header">
+        <span>{{ form.isNew ? '添加分站信息' : '修改分站配置' }}</span>
+        <el-button icon="el-icon-arrow-left" style="float: right; padding: 3px 10px;" type="text" @click="view = 'list'">返回</el-button>
+      </div>
+      <site-form :data="form.data" :is-new="form.isNew" @save="handleSave" @cancel="view = 'list'"> </site-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import _ from 'lodash';
+import moment from 'moment';
+import DataGrid from '@naf/data/filter-grid';
+import SiteForm from '@/components/site-form';
+import { createNamespacedHelpers } from 'vuex';
+import config from '@frame/config';
+const { pageSize = 10 } = config;
+
+const { mapState, mapActions } = createNamespacedHelpers('site');
+
+export default {
+  components: {
+    DataGrid,
+    SiteForm,
+  },
+  metaInfo: {
+    title: '分站管理',
+  },
+  mounted() {
+    this.handleQuery();
+  },
+  data() {
+    return {
+      view: 'list',
+      fields: [
+        { name: 'site', label: '分站标识' },
+        { name: 'name', label: '分站名称' },
+        { name: 'domain', label: '分站域名' },
+        { name: 'meta.createdAt', label: '创建时间', formatter: ['date', 'YYYY-MM-DD HH:mm'] },
+      ],
+      listOper: [['edit', '修改', 'el-icon-edit'], ['delete', '删除', 'el-icon-delete', true]],
+      feedbackItems: [],
+    };
+  },
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async handleQuery({ filter, paging } = {}) {
+      this.view = 'list';
+      const res = await this.query({ status: this.status, paging });
+      this.$checkRes(res);
+    },
+    handleNew() {
+      this.form = { data: {}, isNew: true };
+      this.view = 'form';
+    },
+    async handleEdit({ site }) {
+      const res = await this.fetch({ site });
+      this.$checkRes(res, () => {
+        this.form = { data: { ...res.data }, isNew: false };
+        this.view = 'form';
+      });
+    },
+    async handleSave(payload) {
+      let res, msg;
+      if (payload.isNew) {
+        res = await this.create(payload);
+        msg = '分站添加成功';
+      } else {
+        const { site } = payload.data;
+        res = await this.update({ site, ...payload });
+        msg = '信息修改成功';
+      }
+      if (this.$checkRes(res, msg)) {
+        this.view = 'list';
+      }
+    },
+    async handleDelete({ site }) {
+      const res = await this.delete({ site });
+      this.$checkRes(res, '删除分站成功');
+    },
+  },
+  computed: {
+    ...mapState(['items', 'current', 'total']),
+    status() {
+      return this.$route.params.status || 'new';
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '~@lib/style/lite.less';
+</style>

+ 58 - 0
vue.config.js

@@ -0,0 +1,58 @@
+const path = require('path');
+
+const frameSrc = path.resolve(__dirname, '../admin-frame');
+
+module.exports = {
+  // baseUrl: './',
+  publicPath: process.env.VUE_APP_ROOT_URL + 'cms',
+
+  // pages: {
+  //   index: 'src/main.js',
+  // },
+
+  // transpileDependencies: ['naf-core'],
+
+  configureWebpack: {
+    externals: {
+      'element-ui': 'Element',
+      vue: 'Vue',
+    },
+    resolve: {
+      alias: {
+        '@frame': frameSrc,
+        '@naf': path.join(frameSrc, '/naf'),
+        '@lib': path.join(frameSrc, '/lib'),
+      },
+    },
+  },
+
+  devServer: {
+    port: 3004,
+    disableHostCheck: true,
+    before(app) {
+      app.use((req, res, next) => {
+        // eslint-disable-next-line no-console
+        console.log(`[${req.method}]`, req.path);
+        next();
+      });
+    },
+    proxy: {
+      '/platform/api': {
+        // target: 'http://smart.localhost:8000',
+        target: 'http://smart.cc-lotus.info',
+      },
+      '/files': {
+        target: 'http://smart.cc-lotus.info',
+      },
+      '/ddapi': {
+        target: 'http://smart.cc-lotus.info',
+        // target: 'http://smart.localhost:8008',
+        // pathRewrite: { '^/ddapi': '' },
+      },
+      '/adminapi': {
+        target: 'http://10.16.5.15:8105', //http://10.16.5.15:8105// http://smart.cc-lotus.info
+        // pathRewrite: { '^/ddapi': '' },
+      },
+    },
+  },
+};