Jelajahi Sumber

提交admin后台页面

qxp 3 tahun lalu
induk
melakukan
ab103ef38b
100 mengubah file dengan 17520 tambahan dan 84 penghapusan
  1. 54 84
      .idea/workspace.xml
  2. 12 0
      dorm-service-admin/.babelrc
  3. 14 0
      dorm-service-admin/.editorconfig
  4. 3 0
      dorm-service-admin/.eslintignore
  5. 199 0
      dorm-service-admin/.eslintrc.js
  6. 19 0
      dorm-service-admin/.gitignore
  7. 10 0
      dorm-service-admin/.postcssrc.js
  8. 5 0
      dorm-service-admin/.travis.yml
  9. 48 0
      dorm-service-admin/build/build.js
  10. 54 0
      dorm-service-admin/build/check-versions.js
  11. TEMPAT SAMPAH
      dorm-service-admin/build/logo.png
  12. 101 0
      dorm-service-admin/build/utils.js
  13. 22 0
      dorm-service-admin/build/vue-loader.conf.js
  14. 101 0
      dorm-service-admin/build/webpack.base.conf.js
  15. 88 0
      dorm-service-admin/build/webpack.dev.conf.js
  16. 175 0
      dorm-service-admin/build/webpack.prod.conf.js
  17. 5 0
      dorm-service-admin/config/dev.env.js
  18. 83 0
      dorm-service-admin/config/index.js
  19. 5 0
      dorm-service-admin/config/prod.env.js
  20. TEMPAT SAMPAH
      dorm-service-admin/favicon.ico
  21. 15 0
      dorm-service-admin/index.html
  22. 13250 0
      dorm-service-admin/package-lock.json
  23. 90 0
      dorm-service-admin/package.json
  24. 11 0
      dorm-service-admin/src/App.vue
  25. 33 0
      dorm-service-admin/src/api/activitytag.js
  26. 49 0
      dorm-service-admin/src/api/admin.js
  27. 41 0
      dorm-service-admin/src/api/banner.js
  28. 36 0
      dorm-service-admin/src/api/consultant.js
  29. 9 0
      dorm-service-admin/src/api/dashboard.js
  30. 52 0
      dorm-service-admin/src/api/items.js
  31. 60 0
      dorm-service-admin/src/api/login.js
  32. 87 0
      dorm-service-admin/src/api/news.js
  33. 82 0
      dorm-service-admin/src/api/organize.js
  34. 36 0
      dorm-service-admin/src/api/organizeuser.js
  35. 50 0
      dorm-service-admin/src/api/questions.js
  36. 73 0
      dorm-service-admin/src/api/role.js
  37. 63 0
      dorm-service-admin/src/api/storage.js
  38. 108 0
      dorm-service-admin/src/api/user.js
  39. TEMPAT SAMPAH
      dorm-service-admin/src/assets/401_images/401.gif
  40. TEMPAT SAMPAH
      dorm-service-admin/src/assets/404_images/404.png
  41. TEMPAT SAMPAH
      dorm-service-admin/src/assets/404_images/404_cloud.png
  42. 199 0
      dorm-service-admin/src/assets/echarts-macarons.js
  43. TEMPAT SAMPAH
      dorm-service-admin/src/assets/images/defaulImg.png
  44. 112 0
      dorm-service-admin/src/components/BackToTop/index.vue
  45. 52 0
      dorm-service-admin/src/components/Breadcrumb/index.vue
  46. 150 0
      dorm-service-admin/src/components/Charts/keyboard.vue
  47. 225 0
      dorm-service-admin/src/components/Charts/lineMarker.vue
  48. 268 0
      dorm-service-admin/src/components/Charts/mixChart.vue
  49. 45 0
      dorm-service-admin/src/components/Hamburger/index.vue
  50. 65 0
      dorm-service-admin/src/components/Screenfull/index.vue
  51. 57 0
      dorm-service-admin/src/components/ScrollBar/index.vue
  52. 72 0
      dorm-service-admin/src/components/ScrollPane/index.vue
  53. 76 0
      dorm-service-admin/src/components/Sticky/index.vue
  54. 42 0
      dorm-service-admin/src/components/SvgIcon/index.vue
  55. 181 0
      dorm-service-admin/src/components/Tinymce/index.vue
  56. 7 0
      dorm-service-admin/src/components/Tinymce/plugins.js
  57. 6 0
      dorm-service-admin/src/components/Tinymce/toolbar.js
  58. 123 0
      dorm-service-admin/src/components/Upload/singleImage.vue
  59. 118 0
      dorm-service-admin/src/components/Upload/singleImage2.vue
  60. 145 0
      dorm-service-admin/src/components/Upload/singleImage3.vue
  61. 91 0
      dorm-service-admin/src/directive/sticky.js
  62. 13 0
      dorm-service-admin/src/directive/waves/index.js
  63. 26 0
      dorm-service-admin/src/directive/waves/waves.css
  64. 42 0
      dorm-service-admin/src/directive/waves/waves.js
  65. 9 0
      dorm-service-admin/src/icons/index.js
  66. 1 0
      dorm-service-admin/src/icons/svg/404.svg
  67. 1 0
      dorm-service-admin/src/icons/svg/bug.svg
  68. 1 0
      dorm-service-admin/src/icons/svg/chart.svg
  69. 1 0
      dorm-service-admin/src/icons/svg/clipboard.svg
  70. 1 0
      dorm-service-admin/src/icons/svg/component.svg
  71. 1 0
      dorm-service-admin/src/icons/svg/dashboard.svg
  72. 1 0
      dorm-service-admin/src/icons/svg/documentation.svg
  73. 1 0
      dorm-service-admin/src/icons/svg/drag.svg
  74. 43 0
      dorm-service-admin/src/icons/svg/edit.svg
  75. 1 0
      dorm-service-admin/src/icons/svg/email.svg
  76. 1 0
      dorm-service-admin/src/icons/svg/example.svg
  77. 1 0
      dorm-service-admin/src/icons/svg/excel.svg
  78. 1 0
      dorm-service-admin/src/icons/svg/eye.svg
  79. 1 0
      dorm-service-admin/src/icons/svg/form.svg
  80. 72 0
      dorm-service-admin/src/icons/svg/group.svg
  81. 1 0
      dorm-service-admin/src/icons/svg/icon.svg
  82. 1 0
      dorm-service-admin/src/icons/svg/international.svg
  83. 1 0
      dorm-service-admin/src/icons/svg/language.svg
  84. 1 0
      dorm-service-admin/src/icons/svg/lock.svg
  85. 52 0
      dorm-service-admin/src/icons/svg/magnifying-glass.svg
  86. 1 0
      dorm-service-admin/src/icons/svg/message.svg
  87. 1 0
      dorm-service-admin/src/icons/svg/money.svg
  88. 1 0
      dorm-service-admin/src/icons/svg/password.svg
  89. 1 0
      dorm-service-admin/src/icons/svg/people.svg
  90. 1 0
      dorm-service-admin/src/icons/svg/peoples.svg
  91. 1 0
      dorm-service-admin/src/icons/svg/qq.svg
  92. 56 0
      dorm-service-admin/src/icons/svg/raise-your-hand-to-ask.svg
  93. 1 0
      dorm-service-admin/src/icons/svg/shoppingCard.svg
  94. 1 0
      dorm-service-admin/src/icons/svg/star.svg
  95. 1 0
      dorm-service-admin/src/icons/svg/tab.svg
  96. 1 0
      dorm-service-admin/src/icons/svg/table.svg
  97. 1 0
      dorm-service-admin/src/icons/svg/theme.svg
  98. 1 0
      dorm-service-admin/src/icons/svg/user.svg
  99. 1 0
      dorm-service-admin/src/icons/svg/wechat.svg
  100. 0 0
      dorm-service-admin/src/icons/svg/zip.svg

+ 54 - 84
.idea/workspace.xml

@@ -3,14 +3,6 @@
   <component name="ChangeListManager">
     <list default="true" id="f5deea9c-9428-4e1b-a432-6064341c1bb8" name="Default Changelist" comment="">
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/student/menu/menu.js" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/student/menu/menu.js" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/student/proposal/proposal.js" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/student/proposal/proposal.js" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/student/proposalDetails/proposalDetails.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/student/proposalDetails/proposalDetails.wxml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/test/test.js" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/test/test.js" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/test/test.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/test/test.wxml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/test/test.wxss" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/test/test.wxss" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/pages/user/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/pages/user/index.js" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/dorm-manager-wx/project.config.json" beforeDir="false" afterPath="$PROJECT_DIR$/dorm-manager-wx/project.config.json" afterDir="false" />
     </list>
     <ignored path="$PROJECT_DIR$/out/" />
     <ignored path="$PROJECT_DIR$/dorm-manager-db/target/" />
@@ -18,6 +10,7 @@
     <ignored path="$PROJECT_DIR$/dorm-manager-wx-api/target/" />
     <ignored path="$PROJECT_DIR$/target/" />
     <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
+    <option name="TRACKING_ENABLED" value="true" />
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
     <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -27,13 +20,7 @@
     <option name="isMigrated" value="true" />
   </component>
   <component name="FileEditorManager">
-    <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
-      <file pinned="false" current-in-tab="true">
-        <entry file="file://$PROJECT_DIR$/dorm-manager-wx/utils/api.js">
-          <provider selected="true" editor-type-id="text-editor" />
-        </entry>
-      </file>
-    </leaf>
+    <leaf SIDE_TABS_SIZE_LIMIT_KEY="300" />
   </component>
   <component name="FindInProjectRecents">
     <findStrings>
@@ -57,6 +44,18 @@
       </list>
     </option>
   </component>
+  <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
+  <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
+  <component name="JsGulpfileManager">
+    <detection-done>true</detection-done>
+    <sorting>DEFINITION_ORDER</sorting>
+  </component>
+  <component name="MavenProjectNavigator">
+    <treeState>
+      <expand />
+      <select />
+    </treeState>
+  </component>
   <component name="ProjectFrameBounds" extendedState="6">
     <option name="x" value="417" />
     <option name="y" value="71" />
@@ -76,22 +75,12 @@
               <item name="dorm-manager" type="b2602c69:ProjectViewProjectNode" />
               <item name="dorm-manager" type="462c0819:PsiDirectoryNode" />
             </path>
-            <path>
-              <item name="dorm-manager" type="b2602c69:ProjectViewProjectNode" />
-              <item name="dorm-manager" type="462c0819:PsiDirectoryNode" />
-              <item name="dorm-manager-wx" type="462c0819:PsiDirectoryNode" />
-            </path>
-            <path>
-              <item name="dorm-manager" type="b2602c69:ProjectViewProjectNode" />
-              <item name="dorm-manager" type="462c0819:PsiDirectoryNode" />
-              <item name="dorm-manager-wx" type="462c0819:PsiDirectoryNode" />
-              <item name="utils" type="462c0819:PsiDirectoryNode" />
-            </path>
           </expand>
           <select />
         </subPane>
       </pane>
       <pane id="Scope" />
+      <pane id="AndroidView" />
     </panes>
   </component>
   <component name="PropertiesComponent">
@@ -129,17 +118,15 @@
     <configuration name="AdminApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
       <module name="dorm-manager-admin-api" />
       <option name="SPRING_BOOT_MAIN_CLASS" value="com.dgtis.dorm.manager.admin.AdminApplication" />
-      <method v="2">
-        <option name="Make" enabled="true" />
-      </method>
     </configuration>
     <configuration name="WxApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
       <module name="dorm-manager-wx-api" />
       <option name="SPRING_BOOT_MAIN_CLASS" value="com.dgtis.dorm.manager.wx.WxApplication" />
-      <method v="2">
-        <option name="Make" enabled="true" />
-      </method>
     </configuration>
+    <list>
+      <item itemvalue="Spring Boot.AdminApplication" />
+      <item itemvalue="Spring Boot.WxApplication" />
+    </list>
   </component>
   <component name="SvnConfiguration">
     <configuration />
@@ -169,6 +156,7 @@
       <workItem from="1574839358293" duration="1295000" />
       <workItem from="1574932561099" duration="1219000" />
       <workItem from="1575257478262" duration="239000" />
+      <workItem from="1624501166333" duration="312000" />
     </task>
     <task id="LOCAL-00001" summary="更新代码10-28">
       <created>1572234111796</created>
@@ -230,7 +218,7 @@
     <servers />
   </component>
   <component name="TimeTrackingManager">
-    <option name="totallyTimeSpent" value="23921000" />
+    <option name="totallyTimeSpent" value="24233000" />
   </component>
   <component name="TodoView">
     <todo-panel id="selected-file">
@@ -244,43 +232,45 @@
   <component name="ToolWindowManager">
     <frame x="-8" y="-8" width="1382" height="744" extended-state="6" />
     <layout>
-      <window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.22087745" />
-      <window_info id="Structure" order="1" side_tool="true" weight="0.25" />
-      <window_info id="Designer" order="2" />
-      <window_info id="JRebel" order="3" side_tool="true" />
-      <window_info id="Image Layers" order="4" />
+      <window_info anchor="right" id="Palette" order="4" />
+      <window_info anchor="bottom" id="Event Log" order="10" side_tool="true" weight="0.3295082" />
+      <window_info anchor="right" id="Maven Projects" visible="true" weight="0.329296" />
+      <window_info anchor="bottom" id="Database Changes" order="12" />
       <window_info id="Capture Tool" order="5" />
+      <window_info id="Designer" order="2" />
+      <window_info anchor="bottom" id="Docker" order="9" show_stripe_button="false" />
+      <window_info anchor="right" id="Database" order="6" />
+      <window_info id="Structure" order="1" side_tool="true" weight="0.25" />
+      <window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
       <window_info id="UI Designer" order="6" />
-      <window_info id="Favorites" order="7" side_tool="true" />
-      <window_info id="Web" order="8" side_tool="true" />
-      <window_info anchor="bottom" id="Message" order="0" />
-      <window_info anchor="bottom" id="Find" order="1" />
-      <window_info anchor="bottom" id="Run" order="2" weight="0.704918" />
       <window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
-      <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
-      <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
       <window_info anchor="bottom" id="TODO" order="6" sideWeight="0.49924356" weight="0.3295082" />
+      <window_info anchor="right" id="Palette&#9;" order="7" />
+      <window_info id="Image Layers" order="4" />
+      <window_info anchor="bottom" id="Java Enterprise" order="11" weight="0.3295082" />
+      <window_info anchor="right" id="Capture Analysis" order="5" />
+      <window_info anchor="bottom" id="Version Control" order="13" sideWeight="0.49092284" weight="0.4264463" />
+      <window_info anchor="right" id="leetcode" side_tool="true" />
+      <window_info anchor="bottom" id="Run" order="2" weight="0.704918" />
       <window_info anchor="bottom" id="Spring" order="7" />
       <window_info anchor="bottom" id="Terminal" order="8" weight="0.3295082" />
-      <window_info anchor="bottom" id="Docker" order="9" show_stripe_button="false" />
-      <window_info anchor="bottom" id="Event Log" order="10" side_tool="true" weight="0.3295082" />
-      <window_info anchor="bottom" id="Java Enterprise" order="11" weight="0.3295082" />
-      <window_info anchor="bottom" id="Database Changes" order="12" />
-      <window_info active="true" anchor="bottom" id="Version Control" order="13" sideWeight="0.49092284" visible="true" weight="0.42786884" />
-      <window_info anchor="bottom" id="JRebel Console" order="14" sideWeight="0.50907713" side_tool="true" visible="true" weight="0.42786884" />
+      <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.22407266" />
+      <window_info anchor="right" id="Bean Validation" order="9" />
+      <window_info id="Web" order="8" side_tool="true" />
+      <window_info anchor="right" id="Theme Preview" order="8" />
+      <window_info id="Favorites" order="7" side_tool="true" />
       <window_info anchor="bottom" id="JRebel Executor" order="15" />
+      <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
+      <window_info anchor="right" id="JRebel Setup Guide" order="10" weight="0.32980332" />
+      <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
+      <window_info anchor="right" id="Maven" order="3" />
+      <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
+      <window_info id="JRebel" order="3" side_tool="true" />
       <window_info anchor="bottom" id="Messages" order="16" />
+      <window_info anchor="bottom" id="Find" order="1" />
       <window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
-      <window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
-      <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
-      <window_info anchor="right" id="Maven" order="3" />
-      <window_info anchor="right" id="Palette" order="4" />
-      <window_info anchor="right" id="Capture Analysis" order="5" />
-      <window_info anchor="right" id="Database" order="6" />
-      <window_info anchor="right" id="Palette&#9;" order="7" />
-      <window_info anchor="right" id="Theme Preview" order="8" />
-      <window_info anchor="right" id="Bean Validation" order="9" />
-      <window_info anchor="right" id="JRebel Setup Guide" order="10" weight="0.32980332" />
+      <window_info anchor="bottom" id="Message" order="0" />
+      <window_info anchor="bottom" id="JRebel Console" order="14" sideWeight="0.50907713" side_tool="true" visible="true" weight="0.42786884" />
     </layout>
   </component>
   <component name="TypeScriptGeneratedFilesManager">
@@ -311,20 +301,9 @@
         </entry>
       </map>
     </option>
-    <option name="RECENT_FILTERS">
-      <map>
-        <entry key="Branch">
-          <value>
-            <list />
-          </value>
-        </entry>
-        <entry key="User">
-          <value>
-            <list />
-          </value>
-        </entry>
-      </map>
-    </option>
+  </component>
+  <component name="VcsContentAnnotationSettings">
+    <option name="myLimit" value="2678400000" />
   </component>
   <component name="VcsManagerConfiguration">
     <MESSAGE value="更新代码10-28" />
@@ -332,12 +311,6 @@
     <option name="LAST_COMMIT_MESSAGE" value="整合学生端和教师端" />
   </component>
   <component name="editorHistoryManager">
-    <entry file="file://$PROJECT_DIR$/dorm-manager-wx-api/src/main/resources/application-dev.properties">
-      <provider selected="true" editor-type-id="text-editor" />
-    </entry>
-    <entry file="file://$PROJECT_DIR$/dorm-manager-wx-api/src/main/resources/application.properties">
-      <provider selected="true" editor-type-id="text-editor" />
-    </entry>
     <entry file="file://$PROJECT_DIR$/dorm-manager-wx-api/src/main/java/com/dgtis/dorm/manager/wx/web/NewsController.java">
       <provider selected="true" editor-type-id="text-editor">
         <state relative-caret-position="-3534">
@@ -383,8 +356,5 @@
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/dorm-manager-wx/utils/api.js">
-      <provider selected="true" editor-type-id="text-editor" />
-    </entry>
   </component>
 </project>

+ 12 - 0
dorm-service-admin/.babelrc

@@ -0,0 +1,12 @@
+{
+  "presets": [
+    ["env", {
+      "modules": false,
+      "targets": {
+        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
+      }
+    }],
+    "stage-2"
+  ],
+  "plugins": ["transform-vue-jsx", "transform-runtime"]
+}

+ 14 - 0
dorm-service-admin/.editorconfig

@@ -0,0 +1,14 @@
+# http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 3 - 0
dorm-service-admin/.eslintignore

@@ -0,0 +1,3 @@
+build/*.js
+config/*.js
+src/assets

+ 199 - 0
dorm-service-admin/.eslintrc.js

@@ -0,0 +1,199 @@
+module.exports = {
+  root: true,
+  parser: 'babel-eslint',
+  parserOptions: {
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: 'eslint:recommended',
+  // required to lint *.vue files
+  plugins: [
+    'html'
+  ],
+  // check if imports actually resolve
+  'settings': {
+    'import/resolver': {
+      'webpack': {
+        'config': 'build/webpack.base.conf.js'
+      }
+    }
+  },
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  'rules': {
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': [2, 'allow-null'],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}
+

+ 19 - 0
dorm-service-admin/.gitignore

@@ -0,0 +1,19 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+test/unit/coverage
+test/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+

+ 10 - 0
dorm-service-admin/.postcssrc.js

@@ -0,0 +1,10 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  "plugins": {
+    "postcss-import": {},
+    "postcss-url": {},
+    // to edit target browsers: use "browserslist" field in package.json
+    "autoprefixer": {}
+  }
+}

+ 5 - 0
dorm-service-admin/.travis.yml

@@ -0,0 +1,5 @@
+language: node_js
+node_js: stable
+script: npm run test
+notifications:
+  email: false

+ 48 - 0
dorm-service-admin/build/build.js

@@ -0,0 +1,48 @@
+'use strict'
+require('./check-versions')()
+
+const ora = require('ora')
+const rm = require('rimraf')
+const path = require('path')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const config = require('../config')
+const webpackConfig = require('./webpack.prod.conf')
+const server = require('pushstate-server')
+
+var spinner = ora('building for '+ process.env.env_config+ ' environment...' )
+spinner.start()
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+  if (err) throw err
+  webpack(webpackConfig, (err, stats) => {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false,
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    if (stats.hasErrors()) {
+      console.log(chalk.red('  Build failed with errors.\n'))
+      process.exit(1)
+    }
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+    if(process.env.npm_config_preview){
+      server.start({
+          port: 9526,
+          directory: './dist',
+          file: '/index.html'
+      });
+      console.log('> Listening at ' +  'http://localhost:9526' + '\n')
+    }
+  })
+})

+ 54 - 0
dorm-service-admin/build/check-versions.js

@@ -0,0 +1,54 @@
+'use strict'
+const chalk = require('chalk')
+const semver = require('semver')
+const packageConfig = require('../package.json')
+const shell = require('shelljs')
+
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+const versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  }
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  const warnings = []
+
+  for (let i = 0; i < versionRequirements.length; i++) {
+    const mod = versionRequirements[i]
+
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+
+    for (let i = 0; i < warnings.length; i++) {
+      const warning = warnings[i]
+      console.log('  ' + warning)
+    }
+
+    console.log()
+    process.exit(1)
+  }
+}

TEMPAT SAMPAH
dorm-service-admin/build/logo.png


+ 101 - 0
dorm-service-admin/build/utils.js

@@ -0,0 +1,101 @@
+'use strict'
+const path = require('path')
+const config = require('../config')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const packageConfig = require('../package.json')
+
+exports.assetsPath = function (_path) {
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory
+
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+  options = options || {}
+
+  const cssLoader = {
+    loader: 'css-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  const postcssLoader = {
+    loader: 'postcss-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  // generate loader string to be used with extract text plugin
+  function generateLoaders (loader, loaderOptions) {
+    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
+
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return ExtractTextPlugin.extract({
+        use: loaders,
+        fallback: 'vue-style-loader'
+      })
+    } else {
+      return ['vue-style-loader'].concat(loaders)
+    }
+  }
+
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+  const output = []
+  const loaders = exports.cssLoaders(options)
+
+  for (const extension in loaders) {
+    const loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      use: loader
+    })
+  }
+
+  return output
+}
+
+exports.createNotifierCallback = () => {
+  const notifier = require('node-notifier')
+
+  return (severity, errors) => {
+    if (severity !== 'error') return
+
+    const error = errors[0]
+    const filename = error.file && error.file.split('!').pop()
+
+    notifier.notify({
+      title: packageConfig.name,
+      message: severity + ': ' + error.name,
+      subtitle: filename || '',
+      icon: path.join(__dirname, 'logo.png')
+    })
+  }
+}

+ 22 - 0
dorm-service-admin/build/vue-loader.conf.js

@@ -0,0 +1,22 @@
+'use strict'
+const utils = require('./utils')
+const config = require('../config')
+const isProduction = process.env.NODE_ENV === 'production'
+const sourceMapEnabled = isProduction
+  ? config.build.productionSourceMap
+  : config.dev.cssSourceMap
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: sourceMapEnabled,
+    extract: isProduction
+  }),
+  cssSourceMap: sourceMapEnabled,
+  cacheBusting: config.dev.cacheBusting,
+  transformToRequire: {
+    video: ['src', 'poster'],
+    source: 'src',
+    img: 'src',
+    image: 'xlink:href'
+  }
+}

+ 101 - 0
dorm-service-admin/build/webpack.base.conf.js

@@ -0,0 +1,101 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const config = require('../config')
+const vueLoaderConfig = require('./vue-loader.conf')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const createLintingRule = () => ({
+  test: /\.(js|vue)$/,
+  loader: 'eslint-loader',
+  enforce: 'pre',
+  include: [resolve('src'), resolve('test')],
+  options: {
+    formatter: require('eslint-friendly-formatter'),
+    emitWarning: !config.dev.showEslintErrorsInOverlay
+  }
+})
+
+module.exports = {
+  context: path.resolve(__dirname, '../'),
+  entry: {
+    app: './src/main.js'
+  },
+  output: {
+    path: config.build.assetsRoot,
+    filename: '[name].js',
+    publicPath: process.env.NODE_ENV === 'production'
+      ? config.build.assetsPublicPath
+      : config.dev.assetsPublicPath
+  },
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js',
+      '@': resolve('src'),
+    }
+  },
+  module: {
+    rules: [
+      ...(config.dev.useEslint ? [createLintingRule()] : []),
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader?cacheDirectory',
+        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
+      },
+      {
+        test: /\.svg$/,
+        loader: 'svg-sprite-loader',
+        include: [resolve('src/icons')],
+        options: {
+          symbolId: 'icon-[name]'
+        }
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        exclude: [resolve('src/icons')],
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  node: {
+    // prevent webpack from injecting useless setImmediate polyfill because Vue
+    // source contains it (although only uses it if it's native).
+    setImmediate: false,
+    // prevent webpack from injecting mocks to Node native modules
+    // that does not make sense for the client
+    dgram: 'empty',
+    fs: 'empty',
+    net: 'empty',
+    tls: 'empty',
+    child_process: 'empty'
+  }
+}

+ 88 - 0
dorm-service-admin/build/webpack.dev.conf.js

@@ -0,0 +1,88 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+const portfinder = require('portfinder')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const HOST = process.env.HOST
+const PORT = process.env.PORT && Number(process.env.PORT)
+
+const devWebpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: config.dev.devtool,
+
+  // these devServer options should be customized in /config/index.js
+  devServer: {
+    clientLogLevel: 'warning',
+    historyApiFallback: true,
+    hot: true,
+    compress: true,
+    host: HOST || config.dev.host,
+    port: PORT || config.dev.port,
+    open: config.dev.autoOpenBrowser,
+    overlay: config.dev.errorOverlay
+      ? { warnings: false, errors: true }
+      : false,
+    publicPath: config.dev.assetsPublicPath,
+    proxy: config.dev.proxyTable,
+    quiet: true, // necessary for FriendlyErrorsPlugin
+    watchOptions: {
+      poll: config.dev.poll,
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': require('../config/dev.env')
+    }),
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
+    new webpack.NoEmitOnErrorsPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      inject: true,
+      favicon: resolve('favicon.ico'),
+      title: 'zmall-admin',
+      path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
+    }),
+  ]
+})
+
+module.exports = new Promise((resolve, reject) => {
+  portfinder.basePort = process.env.PORT || config.dev.port
+  portfinder.getPort((err, port) => {
+    if (err) {
+      reject(err)
+    } else {
+      // publish the new Port, necessary for e2e tests
+      process.env.PORT = port
+      // add port to devServer config
+      devWebpackConfig.devServer.port = port
+
+      // Add FriendlyErrorsPlugin
+      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
+        compilationSuccessInfo: {
+          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
+        },
+        onErrors: config.dev.notifyOnErrors
+        ? utils.createNotifierCallback()
+        : undefined
+      }))
+
+      resolve(devWebpackConfig)
+    }
+  })
+})

+ 175 - 0
dorm-service-admin/build/webpack.prod.conf.js

@@ -0,0 +1,175 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const env = require('../config/'+process.env.env_config+'.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new UglifyJsPlugin({
+      uglifyOptions: {
+        compress: {
+          warnings: false
+        }
+      },
+      sourceMap: config.build.productionSourceMap,
+      parallel: true
+    }),
+    // extract css into its own file
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
+      // Setting the following option to `false` will not extract CSS from codesplit chunks.
+      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
+      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
+      allChunks: false,
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+        ? { safe: true, map: { inline: false } }
+        : { safe: true }
+    }),
+    // generate dist index.html with correct asset hash for caching.
+    // you can customize output by editing /index.html
+    // see https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: config.build.index,
+      template: 'index.html',
+      inject: true,
+      favicon: resolve('favicon.ico'),
+      title: 'vue-element-admin',
+      path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
+      minify: {
+        removeComments: true,
+        collapseWhitespace: true,
+        removeAttributeQuotes: true
+        // more options:
+        // https://github.com/kangax/html-minifier#options-quick-reference
+      },
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+      chunksSortMode: 'dependency'
+    }),
+    // keep module.id stable when vender modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // enable scope hoisting
+    new webpack.optimize.ModuleConcatenationPlugin(),
+    // split vendor js into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'vendor',
+      minChunks (module) {
+        // any required modules inside node_modules are extracted to vendor
+        return (
+          module.resource &&
+          /\.js$/.test(module.resource) &&
+          module.resource.indexOf(
+            path.join(__dirname, '../node_modules')
+          ) === 0
+        )
+      }
+    }),
+    // extract webpack runtime and module manifest to its own file in order to
+    // prevent vendor hash from being updated whenever app bundle is updated
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'manifest',
+      minChunks: Infinity
+    }),
+    // This instance extracts shared chunks from code splitted chunks and bundles them
+    // in a separate chunk, similar to the vendor chunk
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'app',
+      async: 'vendor-async',
+      children: true,
+      minChunks: 3
+    }),
+    // split echarts into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      async: 'echarts',
+      minChunks(module) {
+        var context = module.context;
+        return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
+      }
+    }),
+    // split xlsx into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      async: 'xlsx',
+      minChunks(module) {
+        var context = module.context;
+        return context && (context.indexOf('xlsx') >= 0);
+      }
+    }),
+     // split codemirror into its own file
+     new webpack.optimize.CommonsChunkPlugin({
+      async: 'codemirror',
+      minChunks(module) {
+        var context = module.context;
+        return context && (context.indexOf('codemirror') >= 0);
+      }
+    }),
+
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+  webpackConfig.plugins.push(
+    new CompressionWebpackPlugin({
+      asset: '[path].gz[query]',
+      algorithm: 'gzip',
+      test: new RegExp(
+        '\\.(' +
+        config.build.productionGzipExtensions.join('|') +
+        ')$'
+      ),
+      threshold: 10240,
+      minRatio: 0.8
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig

+ 5 - 0
dorm-service-admin/config/dev.env.js

@@ -0,0 +1,5 @@
+module.exports = {
+	NODE_ENV: '"development"',
+	ENV_CONFIG: '"dev"',
+  BASE_API: '"http://localhost:9200/admin"',
+}

+ 83 - 0
dorm-service-admin/config/index.js

@@ -0,0 +1,83 @@
+'use strict'
+// Template version: 1.2.6
+// see http://vuejs-templates.github.io/webpack for documentation.
+
+const path = require('path')
+
+module.exports = {
+  dev: {
+
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {},
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    port: 9202, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: true,
+    errorOverlay: true,
+    notifyOnErrors: false,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: '#cheap-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    // CSS Sourcemaps off by default because relative paths are "buggy"
+    // with this option, according to the CSS-Loader README
+    // (https://github.com/webpack/css-loader#sourcemaps)
+    // In our experience, they generally work as expected,
+    // just be aware of this issue when enabling this option.
+    cssSourceMap: false,
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+
+    // you can set by youself according to actual condition
+    assetsPublicPath: './',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: false,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}

+ 5 - 0
dorm-service-admin/config/prod.env.js

@@ -0,0 +1,5 @@
+module.exports = {
+	NODE_ENV: '"production"',
+	ENV_CONFIG: '"prod"',
+  BASE_API: '"http://dorm.dgtis.com/admin"',
+}

TEMPAT SAMPAH
dorm-service-admin/favicon.ico


+ 15 - 0
dorm-service-admin/index.html

@@ -0,0 +1,15 @@
+  <!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<meta name="renderer" content="webkit">
+		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+		<title>洛龙行政-后台管理</title>
+	</head>
+	<script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.11/tinymce.min.js></script>
+	<body>
+		<div id="app"></div>
+		<!-- built files will be auto injected -->
+	</body>
+</html>

File diff ditekan karena terlalu besar
+ 13250 - 0
dorm-service-admin/package-lock.json


+ 90 - 0
dorm-service-admin/package.json

@@ -0,0 +1,90 @@
+{
+  "name": "administrative-service-admin",
+  "version": "0.1.0",
+  "description": "administrative-service basing on vue-element-admin 3.6.2",
+  "author": "huanghaoqi<695851623@qq.com>",
+  "license": "MIT",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
+    "lint": "eslint --ext .js,.vue src",
+    "test": "npm run lint"
+  },
+  "dependencies": {
+    "axios": "0.17.1",
+    "clipboard": "1.7.1",
+    "echarts": "3.8.5",
+    "element-ui": "2.0.8",
+    "file-saver": "1.3.3",
+    "font-awesome": "4.7.0",
+    "js-cookie": "2.2.0",
+    "mockjs": "1.0.1-beta3",
+    "normalize.css": "7.0.0",
+    "nprogress": "0.2.0",
+    "screenfull": "3.3.2",
+    "vue": "2.5.10",
+    "vue-count-to": "1.0.13",
+    "vue-router": "3.0.1",
+    "vue-splitpane": "1.0.2",
+    "vuex": "3.0.1",
+    "xlsx": "^0.11.16"
+  },
+  "devDependencies": {
+    "autoprefixer": "7.2.3",
+    "babel-core": "6.26.0",
+    "babel-eslint": "8.0.3",
+    "babel-helper-vue-jsx-merge-props": "2.0.3",
+    "babel-loader": "7.1.2",
+    "babel-plugin-syntax-jsx": "6.18.0",
+    "babel-plugin-transform-runtime": "6.23.0",
+    "babel-plugin-transform-vue-jsx": "3.5.0",
+    "babel-preset-env": "1.6.1",
+    "babel-preset-stage-2": "6.24.1",
+    "chalk": "2.3.0",
+    "copy-webpack-plugin": "4.3.0",
+    "cross-env": "5.1.1",
+    "css-loader": "0.28.7",
+    "eslint": "4.13.1",
+    "eslint-friendly-formatter": "3.0.0",
+    "eslint-loader": "1.9.0",
+    "eslint-plugin-html": "4.0.1",
+    "extract-text-webpack-plugin": "3.0.2",
+    "file-loader": "1.1.5",
+    "friendly-errors-webpack-plugin": "1.6.1",
+    "html-webpack-plugin": "2.30.1",
+    "node-notifier": "5.1.2",
+    "node-sass": "^4.7.2",
+    "optimize-css-assets-webpack-plugin": "3.2.0",
+    "ora": "1.3.0",
+    "portfinder": "1.0.13",
+    "postcss-import": "11.0.0",
+    "postcss-loader": "2.0.9",
+    "postcss-url": "7.3.0",
+    "pushstate-server": "3.0.1",
+    "rimraf": "2.6.2",
+    "sass-loader": "6.0.6",
+    "script-loader": "0.7.2",
+    "semver": "5.4.1",
+    "shelljs": "0.7.8",
+    "svg-sprite-loader": "3.5.2",
+    "uglifyjs-webpack-plugin": "1.1.3",
+    "url-loader": "0.6.2",
+    "vue-loader": "13.5.0",
+    "vue-style-loader": "3.0.3",
+    "vue-template-compiler": "2.5.10",
+    "webpack": "3.10.0",
+    "webpack-bundle-analyzer": "2.9.1",
+    "webpack-dev-server": "2.9.7",
+    "webpack-merge": "4.1.1"
+  },
+  "engines": {
+    "node": ">= 4.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 11 - 0
dorm-service-admin/src/App.vue

@@ -0,0 +1,11 @@
+<template>
+	<div id="app">
+		<router-view></router-view>
+	</div>
+</template>
+
+<script>
+  export default{
+    name: 'APP'
+  }
+</script>

+ 33 - 0
dorm-service-admin/src/api/activitytag.js

@@ -0,0 +1,33 @@
+import request from '@/utils/request'
+
+export function listActivityTag(query) {
+  return request({
+    url: '/tag/list',
+    method: 'get',
+    param: query
+  })
+}
+
+export function createActivityTag(data) {
+  return request({
+    url: '/tag/create',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteActivityTag(data) {
+  return request({
+    url: '/tag/delete',
+    method: 'post',
+    data
+  })
+}
+
+export function ActivityUser(data) {
+  return request({
+    url: '/ActivityUser/listActUser',
+    method: 'get',
+    params: data
+  })
+}

+ 49 - 0
dorm-service-admin/src/api/admin.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+export function listAdmin(query) {
+  return request({
+    url: '/admin/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function createAdmin(data) {
+  return request({
+    url: '/admin/create',
+    method: 'post',
+    data
+  })
+}
+
+export function readminAdmin(data) {
+  return request({
+    url: '/admin/readmin',
+    method: 'get',
+    data
+  })
+}
+
+export function updateAdmin(data) {
+  return request({
+    url: '/admin/update',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteAdmin(data) {
+  return request({
+    url: '/admin/delete',
+    method: 'post',
+    data
+  })
+}
+
+export function getWxUserId(query) {
+  return request({
+    url: '/admin/getWxUserId',
+    method: 'get',
+    params: query
+  })
+}

+ 41 - 0
dorm-service-admin/src/api/banner.js

@@ -0,0 +1,41 @@
+import request from '@/utils/request'
+
+export function listBanner(query) {
+  return request({
+    url: '/banner/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function createBanner(data) {
+  return request({
+    url: '/banner/create',
+    method: 'post',
+    data
+  })
+}
+
+export function readBanner(data) {
+  return request({
+    url: '/banner/read',
+    method: 'get',
+    data
+  })
+}
+
+export function updateBanner(data) {
+  return request({
+    url: '/banner/update',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteBanner(data) {
+  return request({
+    url: '/banner/delete',
+    method: 'post',
+    data
+  })
+}

+ 36 - 0
dorm-service-admin/src/api/consultant.js

@@ -0,0 +1,36 @@
+import request from '@/utils/request'
+
+export function list(query) {
+  return request({
+    url: '/consultant/list',
+    method: 'get',
+    params: query
+  })
+}
+
+
+
+export function updateData(data) {
+  return request({
+    url: '/consultant/answer',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteData(data) {
+  return request({
+    url: '/consultant/delete',
+    method: 'get',
+    params:data
+  })
+}
+
+export function getDeptList() {
+  return request({
+    url: '/deptinfo/list',
+    method: 'get'
+  })
+}
+
+

+ 9 - 0
dorm-service-admin/src/api/dashboard.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function info(query) {
+  return request({
+    url: '/dashboard',
+    method: 'get',
+    params: query
+  })
+}

+ 52 - 0
dorm-service-admin/src/api/items.js

@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+export function listItems(query) {
+  return request({
+    url: '/items/list',
+    method: 'post',
+    data: query
+  })
+}
+
+export function createItems(data) {
+  return request({
+    url: '/items/create',
+    method: 'post',
+    data: data
+  })
+}
+
+export function detail(data) {
+  return request({
+    url: '/items/detail?id=' + data,
+    method: 'get'
+  })
+}
+
+export function updateItems(data) {
+  return request({
+    url: '/items/update',
+    method: 'post',
+    data: data
+  })
+}
+
+export function deleteItems(data) {
+  return request({
+    url: '/items/delete?ids=' + data,
+    method: 'post'
+  })
+}
+
+export function parentTree(data) {
+  return request({
+    url: '/items/parentTree',
+    method: 'post'
+  })
+}
+export function createItemQrCode(id) {
+  return request({
+    url: '/items/createItemQrCode?id='+id,
+    method: 'get'
+  })
+}

+ 60 - 0
dorm-service-admin/src/api/login.js

@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+export function loginByUsername(username, password) {
+  const data = {
+    username,
+    password
+  }
+  return request({
+    url: '/login/login',
+    method: 'post',
+    data
+  })
+}
+
+/*根据工号查询用户信息*/
+export function loginByEno(employeNo) {
+  const data = {
+    employeNo
+  }
+  return request({
+    url: '/login/loginByEno',
+    method: 'post',
+    data
+  })
+}
+
+export function loginByCode(code) {
+  const data = {
+    code
+  }
+  return request({
+    url: '/oauthCtl/loginByCode',
+    method: 'post',
+    data
+  })
+}
+
+export function logout() {
+  return request({
+    url: '/login/logout',
+    method: 'post'
+  })
+}
+
+export function getUserInfo(token) {
+  return request({
+    url: '/admin/info',
+    method: 'get',
+    params: { token }
+  })
+}
+
+export function getUserMenu(token) {
+  return request({
+    url: '/role/selectAdminMenu',
+    method: 'post',
+    params: { token }
+  })
+}
+

+ 87 - 0
dorm-service-admin/src/api/news.js

@@ -0,0 +1,87 @@
+import request from '@/utils/request'
+
+export function listNews(query) {
+  return request({
+    url: '/news/list',
+    method: 'post',
+    data: query
+  })
+}
+
+export function createNews(data) {
+  return request({
+    url: '/news/create',
+    method: 'post',
+    data
+  })
+}
+
+export function readNews(data) {
+  return request({
+    url: '/news/read',
+    method: 'get',
+    data
+  })
+}
+
+export function updateNews(data) {
+  return request({
+    url: '/news/update',
+    method: 'post',
+    data
+  })
+}
+
+export function updateNewsAuth(data) {
+  return request({
+    url: '/news/updateNewsAuth',
+    method: 'post',
+    data
+  })
+}
+
+
+export function deleteNews(data) {
+  return request({
+    url: '/news/delete',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteAllNews(data) {
+  return request({
+    url: '/news/deleteQuantity',
+    method: 'post',
+    params: data
+  })
+}
+
+export function listActivityOrg(data) {
+  return request({
+    url: '/news/listActivityOrg',
+    method: 'get',
+    params: data
+  })
+}
+export function listCommon(data) {
+  return request({
+    url: '/newsComment/listCommon',
+    method: 'get',
+    params: data
+  })
+}
+export function deleteCommon(data) {
+  return request({
+    url: '/newsComment/deleteCommon',
+    method: 'post',
+    data
+  })
+}
+  export function deleteAllConent(data) {
+    return request({
+      url: '/newsComment/deleteQuantity',
+      method: 'post',
+      params: data
+    })
+}

+ 82 - 0
dorm-service-admin/src/api/organize.js

@@ -0,0 +1,82 @@
+import request from '@/utils/request'
+
+export function selectOrg(query) {
+  return request({
+    url: '/organize/selectOrganize',
+    method: 'post',
+    params: query
+  })
+}
+
+
+export function createOrg(query) {
+  return request({
+    url: '/organize/createOrganize',
+    method: 'post',
+    data: query
+  })
+}
+
+export function updateOrg(query) {
+  return request({
+    url: '/organize/updateOrganize',
+    method: 'post',
+    data: query
+  })
+}
+
+export function updateOrgAuth(data) {
+  return request({
+    url: '/organize/updateOrgAuth',
+    method: 'post',
+    data
+  })
+}
+
+export function sendWXMsg(query) {
+  return request({
+    url: '/organize/sendWXMsg',
+    method: 'post',
+    params: query
+  })
+}
+
+export function deleteOrg(data) {
+  return request({
+    url: '/organize/deleteOrgById',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteOrgList(query) {
+  return request({
+    url: '/organize/deleteOrgQuantity',
+    method: 'post',
+    params: query
+  })
+}
+
+export function auditOrganizeInterest(query) {
+  return request({
+    url: '/organize/auditOrganizeInterest',
+    method: 'post',
+    params: query
+  })
+}
+
+
+export function selectUserByUserName(query) {
+  return request({
+    url: '/organize/selectUserByUserName',
+    method: 'post',
+    params: query
+  })
+}
+
+export function detail(query) {
+  return request({
+    url: '/organize/detail?id=' + query,
+    method: 'post'
+  })
+}

+ 36 - 0
dorm-service-admin/src/api/organizeuser.js

@@ -0,0 +1,36 @@
+import request from '@/utils/request'
+
+export function selectOrganizeUserByOrgId(query) {
+  return request({
+    url: '/organizeuser/selectOrganizeUserByOrgId',
+    method: 'post',
+    params: query
+  })
+}
+
+export function selectOrganizeUserByOrgIdNoDel(query) {
+  return request({
+    url: '/organizeuser/selectOrganizeUserByOrgIdNoDel',
+    method: 'post',
+    params: query
+  })
+}
+
+
+export function updateOrganizeUserById(query) {
+  return request({
+    url: '/organizeuser/updateOrganizeUserById',
+    method: 'post',
+    params: query
+  })
+}
+
+
+
+export function sendWXMsg(query) {
+  return request({
+    url: '/organizeuser/sendWXMsg',
+    method: 'post',
+    params: query
+  })
+}

+ 50 - 0
dorm-service-admin/src/api/questions.js

@@ -0,0 +1,50 @@
+import request from '@/utils/request'
+
+export function listBanner(query) {
+  return request({
+    url: '/questions/list',
+    method: 'get',
+    params: query
+  })
+}
+
+
+export function createBanner(data) {
+  return request({
+    url: '/questions/create',
+    method: 'post',
+    data
+  })
+}
+
+export function readBanner(data) {
+  return request({
+    url: '/questions/read',
+    method: 'get',
+    data
+  })
+}
+
+export function updateBanner(data) {
+  return request({
+    url: '/questions/update',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteBanner(data) {
+  return request({
+    url: '/questions/delete',
+    method: 'post',
+    data
+  })
+}
+
+export function createContribute(data) {
+  return request({
+    url: '/contribute/create',
+    method: 'post',
+    data
+  })
+}

+ 73 - 0
dorm-service-admin/src/api/role.js

@@ -0,0 +1,73 @@
+import request from '@/utils/request'
+
+/* 权限添加 */
+export function updateRoleMenu(query) {
+  return request({
+    url: '/role/insertRoleMenu',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 查询权限 */
+export function getRoleMenu(query) {
+  return request({
+    url: '/role/selectMenuByRoleId',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 添加角色 */
+export function addRole(query) {
+  return request({
+    url: '/role/insertSelective',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 修改角色名称 */
+export function updateRoleName(query) {
+  return request({
+    url: '/role/updateByPrimaryKeySelective',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 角色列表 */
+export function roleList(query) {
+  return request({
+    url: '/role/selectByRoleName',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 查询用户拥有的角色 */
+export function selectAdminRole(query) {
+  return request({
+    url: '/role/selectAdminRole',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 添加用户与角色关联 */
+export function addAdminRole(query) {
+  return request({
+    url: '/role/insertAdminRole',
+    method: 'post',
+    params: query
+  })
+}
+
+/* 查询当前用户权限列表 */
+// export function addAdminRole(data) {
+//   return request({
+//     url: 'role/selectAdminMenu',
+//     method: 'post',
+//     data
+//   })
+// }

+ 63 - 0
dorm-service-admin/src/api/storage.js

@@ -0,0 +1,63 @@
+import axios from 'axios'
+
+// create an axios instance
+const service = axios.create({
+  // baseURL: process.env.OS_API, // api的base_url
+  baseURL: process.env.BASE_API,
+  timeout: 5000 // request timeout
+})
+
+export function listStorage(query) {
+  return service({
+    url: '/storage/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function createStorage(data) {
+  return service({
+    url: '/storage/create',
+    method: 'post',
+    data
+  })
+}
+export function uploadPic(data) {
+  return service({
+    url: '/storage/uploadPic',
+    method: 'post',
+    data
+  })
+}
+
+export function readStorage(data) {
+  return service({
+    url: '/storage/read',
+    method: 'get',
+    data
+  })
+}
+
+export function updateStorage(data) {
+  return service({
+    url: '/storage/update',
+    method: 'post',
+    params: data
+  })
+}
+
+export function deleteStorage(data) {
+  return service({
+    url: '/storage/delete',
+    method: 'post',
+    params: data
+  })
+}
+
+export function downloadZip(data) {
+  return service({
+    url: '/storage/downloadZip',
+    method: 'post',
+    data: data
+  })
+}

+ 108 - 0
dorm-service-admin/src/api/user.js

@@ -0,0 +1,108 @@
+import request from '@/utils/request'
+
+/*查询校友录列表*/
+export function fetchList(query) {
+  return request({
+    url: '/user/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function exportAllUser(query) {
+  return request({
+    url: '/user/exportAllUser',
+    method: 'get',
+    params: query
+  })
+}
+
+/*查询游客列表*/
+export function fetYKList(query) {
+  return request({
+    url:'/user/findYKList',
+    method:'get',
+    params:query
+  })
+
+}
+
+export function fetchCheckUserList(query) {
+  return request({
+    url: '/user/searchAwaitAuditUserList',
+    method: 'get',
+    params: query
+  })
+}
+
+export function createUser(data) {
+  return request({
+    url: '/user/create',
+    method: 'post',
+    data
+  })
+}
+
+export function readUser(data) {
+  return request({
+    url: '/user/detail',
+    method: 'get',
+    params: data
+  })
+}
+
+export function updateUser(data) {
+  return request({
+    url: '/user/update',
+    method: 'post',
+    data
+  })
+}
+
+export function auditUser(data) {
+  return request({
+    url: '/user/auditUser',
+    method: 'post',
+    data
+  })
+}
+
+export function getUserRole(data) {
+  return request({
+    url: '/role/selectAdminRole',
+    method: 'post',
+    data
+  })
+}
+
+export function passUserAudit(data) {
+  return request({
+    url: '/user/passAudit',
+    method: 'post',
+    params: data
+  })
+}
+
+export function getConcernedList(data) {
+  return request({
+    url: '/user/findUserConcerned',
+    method: 'post',
+    data
+  })
+}
+
+export function getMessageUser(data) {
+  return request({
+    url: '/message/list',
+    method: 'post',
+    params: data
+  })
+}
+
+export function getOrganizeList(data) {
+  return request({
+    url: '/user/findMyOrganize',
+    method: 'post',
+    params: data
+  })
+}

TEMPAT SAMPAH
dorm-service-admin/src/assets/401_images/401.gif


TEMPAT SAMPAH
dorm-service-admin/src/assets/404_images/404.png


TEMPAT SAMPAH
dorm-service-admin/src/assets/404_images/404_cloud.png


+ 199 - 0
dorm-service-admin/src/assets/echarts-macarons.js

@@ -0,0 +1,199 @@
+/* eslint-disable */
+(function (root, factory) {
+    if (typeof define === 'function' && define.amd) {
+        // AMD. Register as an anonymous module.
+        define(['exports', 'echarts'], factory);
+    } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
+        // CommonJS
+        factory(exports, require('echarts'));
+    } else {
+        // Browser globals
+        factory({}, root.echarts);
+    }
+}(this, function (exports, echarts) {
+    var log = function (msg) {
+        if (typeof console !== 'undefined') {
+            console && console.error && console.error(msg);
+        }
+    };
+    if (!echarts) {
+        log('ECharts is not Loaded');
+        return;
+    }
+
+    var colorPalette = [
+        '#2ec7c9','#b6a2de','#5ab1ef','#ffb980','#d87a80',
+        '#8d98b3','#e5cf0d','#97b552','#95706d','#dc69aa',
+        '#07a2a4','#9a7fd1','#588dd5','#f5994e','#c05050',
+        '#59678c','#c9ab00','#7eb00a','#6f5553','#c14089'
+    ];
+
+
+    var theme = {
+        color: colorPalette,
+
+        title: {
+            textStyle: {
+                fontWeight: 'normal',
+                color: '#008acd'
+            }
+        },
+
+        visualMap: {
+            itemWidth: 15,
+            color: ['#5ab1ef','#e0ffff']
+        },
+
+        toolbox: {
+            iconStyle: {
+                normal: {
+                    borderColor: colorPalette[0]
+                }
+            }
+        },
+
+        tooltip: {
+            backgroundColor: 'rgba(50,50,50,0.5)',
+            axisPointer : {
+                type : 'line',
+                lineStyle : {
+                    color: '#008acd'
+                },
+                crossStyle: {
+                    color: '#008acd'
+                },
+                shadowStyle : {
+                    color: 'rgba(200,200,200,0.2)'
+                }
+            }
+        },
+
+        dataZoom: {
+            dataBackgroundColor: '#efefff',
+            fillerColor: 'rgba(182,162,222,0.2)',
+            handleColor: '#008acd'
+        },
+
+        grid: {
+            borderColor: '#eee'
+        },
+
+        categoryAxis: {
+            axisLine: {
+                lineStyle: {
+                    color: '#008acd'
+                }
+            },
+            splitLine: {
+                lineStyle: {
+                    color: ['#eee']
+                }
+            }
+        },
+
+        valueAxis: {
+            axisLine: {
+                lineStyle: {
+                    color: '#008acd'
+                }
+            },
+            splitArea : {
+                show : true,
+                areaStyle : {
+                    color: ['rgba(250,250,250,0.1)','rgba(200,200,200,0.1)']
+                }
+            },
+            splitLine: {
+                lineStyle: {
+                    color: ['#eee']
+                }
+            }
+        },
+
+        timeline : {
+            lineStyle : {
+                color : '#008acd'
+            },
+            controlStyle : {
+                normal : { color : '#008acd'},
+                emphasis : { color : '#008acd'}
+            },
+            symbol : 'emptyCircle',
+            symbolSize : 3
+        },
+
+        line: {
+            smooth : true,
+            symbol: 'emptyCircle',
+            symbolSize: 3
+        },
+
+        candlestick: {
+            itemStyle: {
+                normal: {
+                    color: '#d87a80',
+                    color0: '#2ec7c9',
+                    lineStyle: {
+                        color: '#d87a80',
+                        color0: '#2ec7c9'
+                    }
+                }
+            }
+        },
+
+        scatter: {
+            symbol: 'circle',
+            symbolSize: 4
+        },
+
+        map: {
+            label: {
+                normal: {
+                    textStyle: {
+                        color: '#d87a80'
+                    }
+                }
+            },
+            itemStyle: {
+                normal: {
+                    borderColor: '#eee',
+                    areaColor: '#ddd'
+                },
+                emphasis: {
+                    areaColor: '#fe994e'
+                }
+            }
+        },
+
+        graph: {
+            color: colorPalette
+        },
+
+        gauge : {
+            axisLine: {
+                lineStyle: {
+                    color: [[0.2, '#2ec7c9'],[0.8, '#5ab1ef'],[1, '#d87a80']],
+                    width: 10
+                }
+            },
+            axisTick: {
+                splitNumber: 10,
+                length :15,
+                lineStyle: {
+                    color: 'auto'
+                }
+            },
+            splitLine: {
+                length :22,
+                lineStyle: {
+                    color: 'auto'
+                }
+            },
+            pointer : {
+                width : 5
+            }
+        }
+    };
+
+    echarts.registerTheme('macarons', theme);
+}));

TEMPAT SAMPAH
dorm-service-admin/src/assets/images/defaulImg.png


+ 112 - 0
dorm-service-admin/src/components/BackToTop/index.vue

@@ -0,0 +1,112 @@
+<template>
+  <transition :name="transitionName">
+    <div class="back-to-ceiling" @click="backToTop" v-show="visible" :style="customStyle">
+      <svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
+        <title>回到顶部</title>
+        <g>
+          <path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" fill-rule="evenodd"></path>
+        </g>
+      </svg>
+    </div>
+  </transition>
+</template>
+
+<script>
+export default {
+  name: 'BackToTop',
+  props: {
+    visibilityHeight: {
+      type: Number,
+      default: 400
+    },
+    backPosition: {
+      type: Number,
+      default: 0
+    },
+    customStyle: {
+      type: Object,
+      default: function() {
+        return {
+          right: '50px',
+          bottom: '50px',
+          width: '40px',
+          height: '40px',
+          'border-radius': '4px',
+          'line-height': '45px',
+          background: '#e7eaf1'
+        }
+      }
+    },
+    transitionName: {
+      type: String,
+      default: 'fade'
+    }
+  },
+  data() {
+    return {
+      visible: false,
+      interval: null
+    }
+  },
+  mounted() {
+    window.addEventListener('scroll', this.handleScroll)
+  },
+  beforeDestroy() {
+    window.removeEventListener('scroll', this.handleScroll)
+    if (this.interval) {
+      clearInterval(this.interval)
+    }
+  },
+  methods: {
+    handleScroll() {
+      this.visible = window.pageYOffset > this.visibilityHeight
+    },
+    backToTop() {
+      const start = window.pageYOffset
+      let i = 0
+      this.interval = setInterval(() => {
+        const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
+        if (next <= this.backPosition) {
+          window.scrollTo(0, this.backPosition)
+          clearInterval(this.interval)
+        } else {
+          window.scrollTo(0, next)
+        }
+        i++
+      }, 16.7)
+    },
+    easeInOutQuad(t, b, c, d) {
+      if ((t /= d / 2) < 1) return c / 2 * t * t + b
+      return -c / 2 * (--t * (t - 2) - 1) + b
+    }
+  }
+}
+</script>
+
+<style scoped>
+  .back-to-ceiling {
+    position: fixed;
+    display: inline-block;
+    text-align: center;
+    cursor: pointer;
+  }
+
+  .back-to-ceiling:hover {
+    background: #d5dbe7;
+  }
+
+  .fade-enter-active,
+  .fade-leave-active {
+    transition: opacity .5s;
+  }
+
+  .fade-enter,
+  .fade-leave-to {
+    opacity: 0
+  }
+
+  .back-to-ceiling .Icon {
+    fill: #9aaabf;
+    background: none;
+  }
+</style>

+ 52 - 0
dorm-service-admin/src/components/Breadcrumb/index.vue

@@ -0,0 +1,52 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item,index)  in levelList" :key="item.path" v-if='item.meta.title'>
+        <span v-if='item.redirect==="noredirect"||index==levelList.length-1' class="no-redirect">{{item.meta.title}}</span>
+        <router-link v-else :to="item.redirect||item.path">{{item.meta.title}}</router-link>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+
+export default {
+  created() {
+    this.getBreadcrumb()
+  },
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route() {
+      this.getBreadcrumb()
+    }
+  },
+  methods: {
+    getBreadcrumb() {
+      let matched = this.$route.matched.filter(item => item.name)
+      const first = matched[0]
+      if (first && first.name !== 'dashboard') {
+        matched = [{ path: '/dashboard', meta: { title: '主页' }}].concat(matched)
+      }
+      this.levelList = matched
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .app-breadcrumb.el-breadcrumb {
+    display: inline-block;
+    font-size: 14px;
+    line-height: 50px;
+    margin-left: 10px;
+    .no-redirect {
+      color: #97a8be;
+      cursor: text;
+    }
+  }
+</style>

+ 150 - 0
dorm-service-admin/src/components/Charts/keyboard.vue

@@ -0,0 +1,150 @@
+<template>
+  <div :class="className" :id="id" :style="{height:height,width:width}"></div>
+</template>
+
+<script>
+import echarts from 'echarts'
+
+export default {
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    id: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '200px'
+    },
+    height: {
+      type: String,
+      default: '200px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.initChart()
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(document.getElementById(this.id))
+
+      const xAxisData = []
+      const data = []
+      const data2 = []
+      for (let i = 0; i < 50; i++) {
+        xAxisData.push(i)
+        data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
+        data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
+      }
+      this.chart.setOption(
+        {
+          backgroundColor: '#08263a',
+          xAxis: [{
+            show: false,
+            data: xAxisData
+          }, {
+            show: false,
+            data: xAxisData
+          }],
+          visualMap: {
+            show: false,
+            min: 0,
+            max: 50,
+            dimension: 0,
+            inRange: {
+              color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
+            }
+          },
+          yAxis: {
+            axisLine: {
+              show: false
+            },
+            axisLabel: {
+              textStyle: {
+                color: '#4a657a'
+              }
+            },
+            splitLine: {
+              show: true,
+              lineStyle: {
+                color: '#08263f'
+              }
+            },
+            axisTick: {
+              show: false
+            }
+          },
+          series: [{
+            name: 'back',
+            type: 'bar',
+            data: data2,
+            z: 1,
+            itemStyle: {
+              normal: {
+                opacity: 0.4,
+                barBorderRadius: 5,
+                shadowBlur: 3,
+                shadowColor: '#111'
+              }
+            }
+          }, {
+            name: 'Simulate Shadow',
+            type: 'line',
+            data,
+            z: 2,
+            showSymbol: false,
+            animationDelay: 0,
+            animationEasing: 'linear',
+            animationDuration: 1200,
+            lineStyle: {
+              normal: {
+                color: 'transparent'
+              }
+            },
+            areaStyle: {
+              normal: {
+                color: '#08263a',
+                shadowBlur: 50,
+                shadowColor: '#000'
+              }
+            }
+          }, {
+            name: 'front',
+            type: 'bar',
+            data,
+            xAxisIndex: 1,
+            z: 3,
+            itemStyle: {
+              normal: {
+                barBorderRadius: 5
+              }
+            }
+          }],
+          animationEasing: 'elasticOut',
+          animationEasingUpdate: 'elasticOut',
+          animationDelay(idx) {
+            return idx * 20
+          },
+          animationDelayUpdate(idx) {
+            return idx * 20
+          }
+        })
+    }
+  }
+}
+</script>

+ 225 - 0
dorm-service-admin/src/components/Charts/lineMarker.vue

@@ -0,0 +1,225 @@
+<template>
+  <div :class="className" :id="id" :style="{height:height,width:width}"></div>
+</template>
+
+<script>
+import echarts from 'echarts'
+
+export default {
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    id: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '200px'
+    },
+    height: {
+      type: String,
+      default: '200px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.initChart()
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(document.getElementById(this.id))
+
+      this.chart.setOption({
+        backgroundColor: '#394056',
+        title: {
+          top: 20,
+          text: 'Requests',
+          textStyle: {
+            fontWeight: 'normal',
+            fontSize: 16,
+            color: '#F1F1F3'
+          },
+          left: '1%'
+        },
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            lineStyle: {
+              color: '#57617B'
+            }
+          }
+        },
+        legend: {
+          top: 20,
+          icon: 'rect',
+          itemWidth: 14,
+          itemHeight: 5,
+          itemGap: 13,
+          data: ['CMCC', 'CTCC', 'CUCC'],
+          right: '4%',
+          textStyle: {
+            fontSize: 12,
+            color: '#F1F1F3'
+          }
+        },
+        grid: {
+          top: 100,
+          left: '3%',
+          right: '4%',
+          bottom: '2%',
+          containLabel: true
+        },
+        xAxis: [{
+          type: 'category',
+          boundaryGap: false,
+          axisLine: {
+            lineStyle: {
+              color: '#57617B'
+            }
+          },
+          data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
+        }],
+        yAxis: [{
+          type: 'value',
+          name: '(%)',
+          axisTick: {
+            show: false
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#57617B'
+            }
+          },
+          axisLabel: {
+            margin: 10,
+            textStyle: {
+              fontSize: 14
+            }
+          },
+          splitLine: {
+            lineStyle: {
+              color: '#57617B'
+            }
+          }
+        }],
+        series: [{
+          name: 'CMCC',
+          type: 'line',
+          smooth: true,
+          symbol: 'circle',
+          symbolSize: 5,
+          showSymbol: false,
+          lineStyle: {
+            normal: {
+              width: 1
+            }
+          },
+          areaStyle: {
+            normal: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+                offset: 0,
+                color: 'rgba(137, 189, 27, 0.3)'
+              }, {
+                offset: 0.8,
+                color: 'rgba(137, 189, 27, 0)'
+              }], false),
+              shadowColor: 'rgba(0, 0, 0, 0.1)',
+              shadowBlur: 10
+            }
+          },
+          itemStyle: {
+            normal: {
+              color: 'rgb(137,189,27)',
+              borderColor: 'rgba(137,189,2,0.27)',
+              borderWidth: 12
+
+            }
+          },
+          data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
+        }, {
+          name: 'CTCC',
+          type: 'line',
+          smooth: true,
+          symbol: 'circle',
+          symbolSize: 5,
+          showSymbol: false,
+          lineStyle: {
+            normal: {
+              width: 1
+            }
+          },
+          areaStyle: {
+            normal: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+                offset: 0,
+                color: 'rgba(0, 136, 212, 0.3)'
+              }, {
+                offset: 0.8,
+                color: 'rgba(0, 136, 212, 0)'
+              }], false),
+              shadowColor: 'rgba(0, 0, 0, 0.1)',
+              shadowBlur: 10
+            }
+          },
+          itemStyle: {
+            normal: {
+              color: 'rgb(0,136,212)',
+              borderColor: 'rgba(0,136,212,0.2)',
+              borderWidth: 12
+
+            }
+          },
+          data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
+        }, {
+          name: 'CUCC',
+          type: 'line',
+          smooth: true,
+          symbol: 'circle',
+          symbolSize: 5,
+          showSymbol: false,
+          lineStyle: {
+            normal: {
+              width: 1
+            }
+          },
+          areaStyle: {
+            normal: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+                offset: 0,
+                color: 'rgba(219, 50, 51, 0.3)'
+              }, {
+                offset: 0.8,
+                color: 'rgba(219, 50, 51, 0)'
+              }], false),
+              shadowColor: 'rgba(0, 0, 0, 0.1)',
+              shadowBlur: 10
+            }
+          },
+          itemStyle: {
+            normal: {
+              color: 'rgb(219,50,51)',
+              borderColor: 'rgba(219,50,51,0.2)',
+              borderWidth: 12
+            }
+          },
+          data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
+        }]
+      })
+    }
+  }
+}
+</script>

+ 268 - 0
dorm-service-admin/src/components/Charts/mixChart.vue

@@ -0,0 +1,268 @@
+<template>
+  <div :class="className" :id="id" :style="{height:height,width:width}"></div>
+</template>
+
+<script>
+import echarts from 'echarts'
+
+export default {
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    id: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '200px'
+    },
+    height: {
+      type: String,
+      default: '200px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.initChart()
+    this.chart = null
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(document.getElementById(this.id))
+      const xData = (function() {
+        const data = []
+        for (let i = 1; i < 13; i++) {
+          data.push(i + 'month')
+        }
+        return data
+      }())
+      this.chart.setOption({
+        backgroundColor: '#344b58',
+        title: {
+          text: 'statistics',
+          x: '20',
+          top: '20',
+          textStyle: {
+            color: '#fff',
+            fontSize: '22'
+          },
+          subtextStyle: {
+            color: '#90979c',
+            fontSize: '16'
+          }
+        },
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            textStyle: {
+              color: '#fff'
+            }
+          }
+        },
+        grid: {
+          borderWidth: 0,
+          top: 110,
+          bottom: 95,
+          textStyle: {
+            color: '#fff'
+          }
+        },
+        legend: {
+          x: '5%',
+          top: '10%',
+          textStyle: {
+            color: '#90979c'
+          },
+          data: ['female', 'male', 'average']
+        },
+        calculable: true,
+        xAxis: [{
+          type: 'category',
+          axisLine: {
+            lineStyle: {
+              color: '#90979c'
+            }
+          },
+          splitLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          splitArea: {
+            show: false
+          },
+          axisLabel: {
+            interval: 0
+
+          },
+          data: xData
+        }],
+        yAxis: [{
+          type: 'value',
+          splitLine: {
+            show: false
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#90979c'
+            }
+          },
+          axisTick: {
+            show: false
+          },
+          axisLabel: {
+            interval: 0
+          },
+          splitArea: {
+            show: false
+          }
+        }],
+        dataZoom: [{
+          show: true,
+          height: 30,
+          xAxisIndex: [
+            0
+          ],
+          bottom: 30,
+          start: 10,
+          end: 80,
+          handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
+          handleSize: '110%',
+          handleStyle: {
+            color: '#d3dee5'
+
+          },
+          textStyle: {
+            color: '#fff' },
+          borderColor: '#90979c'
+
+        }, {
+          type: 'inside',
+          show: true,
+          height: 15,
+          start: 1,
+          end: 35
+        }],
+        series: [{
+          name: 'female',
+          type: 'bar',
+          stack: 'total',
+          barMaxWidth: 35,
+          barGap: '10%',
+          itemStyle: {
+            normal: {
+              color: 'rgba(255,144,128,1)',
+              label: {
+                show: true,
+                textStyle: {
+                  color: '#fff'
+                },
+                position: 'insideTop',
+                formatter(p) {
+                  return p.value > 0 ? p.value : ''
+                }
+              }
+            }
+          },
+          data: [
+            709,
+            1917,
+            2455,
+            2610,
+            1719,
+            1433,
+            1544,
+            3285,
+            5208,
+            3372,
+            2484,
+            4078
+          ]
+        },
+
+        {
+          name: 'male',
+          type: 'bar',
+          stack: 'total',
+          itemStyle: {
+            normal: {
+              color: 'rgba(0,191,183,1)',
+              barBorderRadius: 0,
+              label: {
+                show: true,
+                position: 'top',
+                formatter(p) {
+                  return p.value > 0 ? p.value : ''
+                }
+              }
+            }
+          },
+          data: [
+            327,
+            1776,
+            507,
+            1200,
+            800,
+            482,
+            204,
+            1390,
+            1001,
+            951,
+            381,
+            220
+          ]
+        }, {
+          name: 'average',
+          type: 'line',
+          stack: 'total',
+          symbolSize: 10,
+          symbol: 'circle',
+          itemStyle: {
+            normal: {
+              color: 'rgba(252,230,48,1)',
+              barBorderRadius: 0,
+              label: {
+                show: true,
+                position: 'top',
+                formatter(p) {
+                  return p.value > 0 ? p.value : ''
+                }
+              }
+            }
+          },
+          data: [
+            1036,
+            3693,
+            2962,
+            3810,
+            2519,
+            1915,
+            1748,
+            4675,
+            6209,
+            4323,
+            2865,
+            4298
+          ]
+        }
+        ]
+      })
+    }
+  }
+}
+</script>

+ 45 - 0
dorm-service-admin/src/components/Hamburger/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <div>
+    <svg t="1492500959545" @click="toggleClick" class="wscn-icon hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
+      version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
+      <path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
+        p-id="1692"></path>
+      <path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
+        p-id="1693"></path>
+      <path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
+        p-id="1694"></path>
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    },
+    toggleClick: {
+      type: Function,
+      default: null
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+	display: inline-block;
+	cursor: pointer;
+	width: 20px;
+	height: 20px;
+	transform: rotate(90deg);
+	transition: .38s;
+	transform-origin: 50% 50%;
+}
+
+.hamburger.is-active {
+	transform: rotate(0deg);
+}
+</style>

+ 65 - 0
dorm-service-admin/src/components/Screenfull/index.vue

@@ -0,0 +1,65 @@
+<template>
+  <div>
+    <svg t="1508738709248" @click='click' class="screenfull-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+      p-id="2069" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32">
+      <path d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
+        p-id="2070"></path>
+      <path d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
+        p-id="2071"></path>
+      <path d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
+        p-id="2072"></path>
+      <path d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
+        p-id="2073"></path>
+    </svg>
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'screenfull',
+  props: {
+    width: {
+      type: Number,
+      default: 22
+    },
+    height: {
+      type: Number,
+      default: 22
+    },
+    fill: {
+      type: String,
+      default: '#48576a'
+    }
+  },
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  methods: {
+    click() {
+      if (!screenfull.enabled) {
+        this.$message({
+          message: 'you browser can not work',
+          type: 'warning'
+        })
+        return false
+      }
+      screenfull.toggle()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>

+ 57 - 0
dorm-service-admin/src/components/ScrollBar/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll" >
+    <div class="scroll-wrapper" ref="scrollWrapper" :style="{top: top + 'px'}">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+const delta = 15
+
+export default {
+  name: 'scrollBar',
+  data() {
+    return {
+      top: 0
+    }
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 3
+      const $container = this.$refs.scrollContainer
+      const $containerHeight = $container.offsetHeight
+      const $wrapper = this.$refs.scrollWrapper
+      const $wrapperHeight = $wrapper.offsetHeight
+      if (eventDelta > 0) {
+        this.top = Math.min(0, this.top + eventDelta)
+      } else {
+        if ($containerHeight - delta < $wrapperHeight) {
+          if (this.top < -($wrapperHeight - $containerHeight + delta)) {
+            this.top = this.top
+          } else {
+            this.top = Math.max(this.top + eventDelta, $containerHeight - $wrapperHeight - delta)
+          }
+        } else {
+          this.top = 0
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import '../../styles/variables.scss';
+
+.scroll-container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  background-color: $menuBg;
+  .scroll-wrapper {
+    position: absolute;
+     width: 100%!important;
+  }
+}
+</style>

+ 72 - 0
dorm-service-admin/src/components/ScrollPane/index.vue

@@ -0,0 +1,72 @@
+<template>
+  <div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll">
+    <div class="scroll-wrapper" ref="scrollWrapper" :style="{left: left + 'px'}">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+const padding = 15 // tag's padding
+
+export default {
+  name: 'scrollPane',
+  data() {
+    return {
+      left: 0
+    }
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 3
+      const $container = this.$refs.scrollContainer
+      const $containerWidth = $container.offsetWidth
+      const $wrapper = this.$refs.scrollWrapper
+      const $wrapperWidth = $wrapper.offsetWidth
+
+      if (eventDelta > 0) {
+        this.left = Math.min(0, this.left + eventDelta)
+      } else {
+        if ($containerWidth - padding < $wrapperWidth) {
+          if (this.left < -($wrapperWidth - $containerWidth + padding)) {
+            this.left = this.left
+          } else {
+            this.left = Math.max(this.left + eventDelta, $containerWidth - $wrapperWidth - padding)
+          }
+        } else {
+          this.left = 0
+        }
+      }
+    },
+    moveToTarget($target) {
+      const $container = this.$refs.scrollContainer
+      const $containerWidth = $container.offsetWidth
+      const $targetLeft = $target.offsetLeft
+      const $targetWidth = $target.offsetWidth
+
+      if ($targetLeft < -this.left) {
+        // tag in the left
+        this.left = -$targetLeft + padding
+      } else if ($targetLeft + padding > -this.left && $targetLeft + $targetWidth < -this.left + $containerWidth - padding) {
+        // tag in the current view
+        // eslint-disable-line
+      } else {
+        // tag in the right
+        this.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)
+      }
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.scroll-container {
+  white-space: nowrap;
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+  .scroll-wrapper {
+    position: absolute;
+  }
+}
+</style>

+ 76 - 0
dorm-service-admin/src/components/Sticky/index.vue

@@ -0,0 +1,76 @@
+<template>
+  <div :style="{height:height+'px',zIndex:zIndex}">
+    <div :class="className" :style="{top:stickyTop+'px',zIndex:zIndex,position:position,width:width,height:height+'px'}">
+      <slot>
+        <div>sticky</div>
+      </slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Sticky',
+  props: {
+    stickyTop: {
+      type: Number,
+      default: 0
+    },
+    zIndex: {
+      type: Number,
+      default: 1
+    },
+    className: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      active: false,
+      position: '',
+      currentTop: '',
+      width: undefined,
+      height: undefined,
+      child: null,
+      stickyHeight: 0
+    }
+  },
+  mounted() {
+    this.height = this.$el.getBoundingClientRect().height
+    window.addEventListener('scroll', this.handleScroll)
+  },
+  activated() {
+    this.handleScroll()
+  },
+  destroyed() {
+    window.removeEventListener('scroll', this.handleScroll)
+  },
+  methods: {
+    sticky() {
+      if (this.active) {
+        return
+      }
+      this.position = 'fixed'
+      this.active = true
+      this.width = this.width + 'px'
+    },
+    reset() {
+      if (!this.active) {
+        return
+      }
+      this.position = ''
+      this.width = 'auto'
+      this.active = false
+    },
+    handleScroll() {
+      this.width = this.$el.getBoundingClientRect().width
+      const offsetTop = this.$el.getBoundingClientRect().top
+      if (offsetTop <= this.stickyTop) {
+        this.sticky()
+        return
+      }
+      this.reset()
+    }
+  }
+}
+</script>

+ 42 - 0
dorm-service-admin/src/components/SvgIcon/index.vue

@@ -0,0 +1,42 @@
+<template>
+  <svg :class="svgClass" aria-hidden="true">
+    <use :xlink:href="iconName"></use>
+  </svg>
+</template>
+
+<script>
+export default {
+  name: 'svg-icon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String
+    }
+  },
+  computed: {
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>

+ 181 - 0
dorm-service-admin/src/components/Tinymce/index.vue

@@ -0,0 +1,181 @@
+<template>
+  <div class="tinymce-container editor-container">
+    <textarea class="tinymce-textarea" :id="tinymceId"></textarea>
+  </div>
+</template>
+
+<script>
+import plugins from './plugins'
+import toolbar from './toolbar'
+import { uploadPic } from '@/api/storage'
+
+export default {
+  name: 'tinymce',
+  props: {
+    id: {
+      type: String
+    },
+    value: {
+      type: String,
+      default: ''
+    },
+    toolbar: {
+      type: Array,
+      required: false,
+      default() {
+        return []
+      }
+    },
+    menubar: {
+      default: 'file edit insert view format table'
+    },
+    height: {
+      type: Number,
+      required: false,
+      default: 360
+    }
+  },
+  data() {
+    return {
+      hasChange: false,
+      hasInit: false,
+      tinymceId: this.id || 'vue-tinymce-' + +new Date()
+    }
+  },
+  watch: {
+    value(val) {
+      if (!this.hasChange && this.hasInit) {
+        this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val))
+      }
+    }
+  },
+  mounted() {
+    this.initTinymce()
+  },
+  activated() {
+    this.initTinymce()
+  },
+  deactivated() {
+    this.destroyTinymce()
+  },
+  methods: {
+    initTinymce() {
+      const _this = this
+      window.tinymce.init({
+        selector: `#${this.tinymceId}`,
+        height: this.height,
+        language: 'zh_CN',
+        body_class: 'panel-body ',
+        object_resizing: false,
+        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
+        menubar: this.menubar,
+        plugins: plugins,
+        end_container_on_empty_block: true,
+        powerpaste_word_import: 'clean',
+        code_dialog_height: 450,
+        code_dialog_width: 1000,
+        advlist_bullet_styles: 'square',
+        advlist_number_styles: 'default',
+        default_link_target: '_blank',
+        relative_urls : false,
+		remove_script_host : false,
+		document_base_url : 'http://alumni.sppm.tsinghua.edu.cn/',
+        link_title: false,
+        init_instance_callback: editor => {
+          if (_this.value) {
+            editor.setContent(_this.value)
+          }
+          _this.hasInit = true
+          editor.on('NodeChange Change KeyUp', () => {
+            this.hasChange = true
+            this.$emit('input', editor.getContent({ format: 'raw' }))
+          })
+        },
+        images_upload_handler: function(blobInfo, success, failure) {
+          const formData = new FormData()
+          formData.append('file', blobInfo.blob())
+          uploadPic(formData).then(res => {
+          var resurl=res.data.data.url;
+          console.log(resurl);
+            success(resurl)
+          }).catch(() => {
+            failure('上传失败,请重新上传')
+          })
+        }
+        // 整合七牛上传
+        // images_dataimg_filter(img) {
+        //   setTimeout(() => {
+        //     const $image = $(img);
+        //     $image.removeAttr('width');
+        //     $image.removeAttr('height');
+        //     if ($image[0].height && $image[0].width) {
+        //       $image.attr('data-wscntype', 'image');
+        //       $image.attr('data-wscnh', $image[0].height);
+        //       $image.attr('data-wscnw', $image[0].width);
+        //       $image.addClass('wscnph');
+        //     }
+        //   }, 0);
+        //   return img
+        // },
+        // images_upload_handler(blobInfo, success, failure, progress) {
+        //   progress(0);
+        //   const token = _this.$store.getters.token;
+        //   getToken(token).then(response => {
+        //     const url = response.data.qiniu_url;
+        //     const formData = new FormData();
+        //     formData.append('token', response.data.qiniu_token);
+        //     formData.append('key', response.data.qiniu_key);
+        //     formData.append('file', blobInfo.blob(), url);
+        //     upload(formData).then(() => {
+        //       success(url);
+        //       progress(100);
+        //     })
+        //   }).catch(err => {
+        //     failure('出现未知问题,刷新页面,或者联系程序员')
+        //     console.log(err);
+        //   });
+        // },
+      })
+    },
+    destroyTinymce() {
+      if (window.tinymce.get(this.tinymceId)) {
+        window.tinymce.get(this.tinymceId).destroy()
+      }
+    },
+    setContent(value) {
+      window.tinymce.get(this.tinymceId).setContent(value)
+    },
+    getContent() {
+      window.tinymce.get(this.tinymceId).getContent()
+    },
+    imageSuccessCBK(arr) {
+      const _this = this
+      arr.forEach(v => {
+        window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
+      })
+    }
+  },
+  destroyed() {
+    this.destroyTinymce()
+  }
+}
+</script>
+
+<style scoped>
+.tinymce-container {
+  position: relative
+}
+.tinymce-textarea {
+  visibility: hidden;
+  z-index: -1;
+}
+.editor-custom-btn-container {
+  position: absolute;
+  right: 4px;
+  top: 4px;
+  /*z-index: 2005;*/
+}
+.editor-upload-btn {
+  display: inline-block;
+}
+</style>

+ 7 - 0
dorm-service-admin/src/components/Tinymce/plugins.js

@@ -0,0 +1,7 @@
+// Any plugins you want to use has to be imported
+// Detail plugins list see https://www.tinymce.com/docs/plugins/
+// Custom builds see https://www.tinymce.com/download/custom-builds/
+
+const plugins = ['advlist anchor autolink autoresize autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
+
+export default plugins

+ 6 - 0
dorm-service-admin/src/components/Tinymce/toolbar.js

@@ -0,0 +1,6 @@
+// Here is a list of the toolbar
+// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
+
+const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap	 preview anchor pagebreak fullscreen insertdatetime media table emoticons forecolor backcolor']
+
+export default toolbar

+ 123 - 0
dorm-service-admin/src/components/Upload/singleImage.vue

@@ -0,0 +1,123 @@
+<template>
+    <div class="upload-container">
+        <el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
+            :on-success="handleImageScucess">
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+        </el-upload>
+        <div class="image-preview">
+            <div class="image-preview-wrapper" v-show="imageUrl.length>1">
+                <img :src="imageUrl+'?imageView2/1/w/200/h/200'">
+                <div class="image-preview-action">
+                    <i @click="rmImage" class="el-icon-delete"></i>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+// 预览效果见付费文章
+import { getToken } from '@/api/qiniu'
+
+export default {
+  name: 'singleImageUpload',
+  props: {
+    value: String
+  },
+  computed: {
+    imageUrl() {
+      return this.value
+    }
+  },
+  data() {
+    return {
+      tempUrl: '',
+      dataObj: { token: '', key: '' }
+    }
+  },
+  methods: {
+    rmImage() {
+      this.emitInput('')
+    },
+    emitInput(val) {
+      this.$emit('input', val)
+    },
+    handleImageScucess() {
+      this.emitInput(this.tempUrl)
+    },
+    beforeUpload() {
+      const _self = this
+      return new Promise((resolve, reject) => {
+        getToken().then(response => {
+          const key = response.data.qiniu_key
+          const token = response.data.qiniu_token
+          _self._data.dataObj.token = token
+          _self._data.dataObj.key = key
+          this.tempUrl = response.data.qiniu_url
+          resolve(true)
+        }).catch(err => {
+          console.log(err)
+          reject(false)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+    @import "src/styles/mixin.scss";
+    .upload-container {
+        width: 100%;
+        position: relative;
+        @include clearfix;
+        .image-uploader {
+            width: 60%;
+            float: left;
+        }
+        .image-preview {
+            width: 200px;
+            height: 200px;
+            position: relative;
+            border: 1px dashed #d9d9d9;
+            float: left;
+            margin-left: 50px;
+            .image-preview-wrapper {
+                position: relative;
+                width: 100%;
+                height: 100%;
+                img {
+                    width: 100%;
+                    height: 100%;
+                }
+            }
+            .image-preview-action {
+                position: absolute;
+                width: 100%;
+                height: 100%;
+                left: 0;
+                top: 0;
+                cursor: default;
+                text-align: center;
+                color: #fff;
+                opacity: 0;
+                font-size: 20px;
+                background-color: rgba(0, 0, 0, .5);
+                transition: opacity .3s;
+                cursor: pointer;
+                text-align: center;
+                line-height: 200px;
+                .el-icon-delete {
+                    font-size: 36px;
+                }
+            }
+            &:hover {
+                .image-preview-action {
+                    opacity: 1;
+                }
+            }
+        }
+    }
+
+</style>

+ 118 - 0
dorm-service-admin/src/components/Upload/singleImage2.vue

@@ -0,0 +1,118 @@
+<template>
+	<div class="singleImageUpload2 upload-container">
+		<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
+		  :on-success="handleImageScucess">
+			<i class="el-icon-upload"></i>
+			<div class="el-upload__text">Drag或<em>点击上传</em></div>
+		</el-upload>
+		<div v-show="imageUrl.length>0" class="image-preview">
+			<div class="image-preview-wrapper" v-show="imageUrl.length>1">
+				<img :src="imageUrl">
+				<div class="image-preview-action">
+					<i @click="rmImage" class="el-icon-delete"></i>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import { getToken } from '@/api/qiniu'
+
+export default {
+  name: 'singleImageUpload2',
+  props: {
+    value: String
+  },
+  computed: {
+    imageUrl() {
+      return this.value
+    }
+  },
+  data() {
+    return {
+      tempUrl: '',
+      dataObj: { token: '', key: '' }
+    }
+  },
+  methods: {
+    rmImage() {
+      this.emitInput('')
+    },
+    emitInput(val) {
+      this.$emit('input', val)
+    },
+    handleImageScucess() {
+      this.emitInput(this.tempUrl)
+    },
+    beforeUpload() {
+      const _self = this
+      return new Promise((resolve, reject) => {
+        getToken().then(response => {
+          const key = response.data.qiniu_key
+          const token = response.data.qiniu_token
+          _self._data.dataObj.token = token
+          _self._data.dataObj.key = key
+          this.tempUrl = response.data.qiniu_url
+          resolve(true)
+        }).catch(() => {
+          reject(false)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.upload-container {
+	width: 100%;
+	height: 100%;
+	position: relative;
+	.image-uploader {
+		height: 100%;
+	}
+	.image-preview {
+		width: 100%;
+		height: 100%;
+		position: absolute;
+		left: 0px;
+		top: 0px;
+		border: 1px dashed #d9d9d9;
+		.image-preview-wrapper {
+			position: relative;
+			width: 100%;
+			height: 100%;
+			img {
+				width: 100%;
+				height: 100%;
+			}
+		}
+		.image-preview-action {
+			position: absolute;
+			width: 100%;
+			height: 100%;
+			left: 0;
+			top: 0;
+			cursor: default;
+			text-align: center;
+			color: #fff;
+			opacity: 0;
+			font-size: 20px;
+			background-color: rgba(0, 0, 0, .5);
+			transition: opacity .3s;
+			cursor: pointer;
+			text-align: center;
+			line-height: 200px;
+			.el-icon-delete {
+				font-size: 36px;
+			}
+		}
+		&:hover {
+			.image-preview-action {
+				opacity: 1;
+			}
+		}
+	}
+}
+</style>

+ 145 - 0
dorm-service-admin/src/components/Upload/singleImage3.vue

@@ -0,0 +1,145 @@
+<template>
+	<div class="upload-container">
+		<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
+		  :on-success="handleImageScucess">
+			<i class="el-icon-upload"></i>
+			<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+		</el-upload>
+		<div class="image-preview image-app-preview">
+			<div class="image-preview-wrapper" v-show="imageUrl.length>1">
+				<img :src="imageUrl">
+				<div class="image-preview-action">
+					<i @click="rmImage" class="el-icon-delete"></i>
+				</div>
+			</div>
+		</div>
+		<div class="image-preview">
+			<div class="image-preview-wrapper" v-show="imageUrl.length>1">
+				<img :src="imageUrl">
+				<div class="image-preview-action">
+					<i @click="rmImage" class="el-icon-delete"></i>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import { getToken } from '@/api/qiniu'
+
+export default {
+  name: 'singleImageUpload3',
+  props: {
+    value: String
+  },
+  computed: {
+    imageUrl() {
+      return this.value
+    }
+  },
+  data() {
+    return {
+      tempUrl: '',
+      dataObj: { token: '', key: '' }
+    }
+  },
+  methods: {
+    rmImage() {
+      this.emitInput('')
+    },
+    emitInput(val) {
+      this.$emit('input', val)
+    },
+    handleImageScucess(file) {
+      this.emitInput(file.files.file)
+    },
+    beforeUpload() {
+      const _self = this
+      return new Promise((resolve, reject) => {
+        getToken().then(response => {
+          const key = response.data.qiniu_key
+          const token = response.data.qiniu_token
+          _self._data.dataObj.token = token
+          _self._data.dataObj.key = key
+          this.tempUrl = response.data.qiniu_url
+          resolve(true)
+        }).catch(err => {
+          console.log(err)
+          reject(false)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import "src/styles/mixin.scss";
+.upload-container {
+	width: 100%;
+	position: relative;
+	@include clearfix;
+	.image-uploader {
+		width: 35%;
+		float: left;
+	}
+	.image-preview {
+		width: 200px;
+		height: 200px;
+		position: relative;
+		border: 1px dashed #d9d9d9;
+		float: left;
+		margin-left: 50px;
+		.image-preview-wrapper {
+			position: relative;
+			width: 100%;
+			height: 100%;
+			img {
+				width: 100%;
+				height: 100%;
+			}
+		}
+		.image-preview-action {
+			position: absolute;
+			width: 100%;
+			height: 100%;
+			left: 0;
+			top: 0;
+			cursor: default;
+			text-align: center;
+			color: #fff;
+			opacity: 0;
+			font-size: 20px;
+			background-color: rgba(0, 0, 0, .5);
+			transition: opacity .3s;
+			cursor: pointer;
+			text-align: center;
+			line-height: 200px;
+			.el-icon-delete {
+				font-size: 36px;
+			}
+		}
+		&:hover {
+			.image-preview-action {
+				opacity: 1;
+			}
+		}
+	}
+	.image-app-preview {
+		width: 320px;
+		height: 180px;
+		position: relative;
+		border: 1px dashed #d9d9d9;
+		float: left;
+		margin-left: 50px;
+		.app-fake-conver {
+			height: 44px;
+			position: absolute;
+			width: 100%; // background: rgba(0, 0, 0, .1);
+			text-align: center;
+			line-height: 64px;
+			color: #fff;
+		}
+	}
+}
+</style>

+ 91 - 0
dorm-service-admin/src/directive/sticky.js

@@ -0,0 +1,91 @@
+const vueSticky = {}
+let listenAction
+vueSticky.install = Vue => {
+  Vue.directive('sticky', {
+    inserted(el, binding) {
+      const params = binding.value || {}
+      const stickyTop = params.stickyTop || 0
+      const zIndex = params.zIndex || 1000
+      const elStyle = el.style
+
+      elStyle.position = '-webkit-sticky'
+      elStyle.position = 'sticky'
+      // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
+      // if (~elStyle.position.indexOf('sticky')) {
+      //     elStyle.top = `${stickyTop}px`;
+      //     elStyle.zIndex = zIndex;
+      //     return
+      // }
+      const elHeight = el.getBoundingClientRect().height
+      const elWidth = el.getBoundingClientRect().width
+      elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
+
+      const parentElm = el.parentNode || document.documentElement
+      const placeholder = document.createElement('div')
+      placeholder.style.display = 'none'
+      placeholder.style.width = `${elWidth}px`
+      placeholder.style.height = `${elHeight}px`
+      parentElm.insertBefore(placeholder, el)
+
+      let active = false
+
+      const getScroll = (target, top) => {
+        const prop = top ? 'pageYOffset' : 'pageXOffset'
+        const method = top ? 'scrollTop' : 'scrollLeft'
+        let ret = target[prop]
+        if (typeof ret !== 'number') {
+          ret = window.document.documentElement[method]
+        }
+        return ret
+      }
+
+      const sticky = () => {
+        if (active) {
+          return
+        }
+        if (!elStyle.height) {
+          elStyle.height = `${el.offsetHeight}px`
+        }
+
+        elStyle.position = 'fixed'
+        elStyle.width = `${elWidth}px`
+        placeholder.style.display = 'inline-block'
+        active = true
+      }
+
+      const reset = () => {
+        if (!active) {
+          return
+        }
+
+        elStyle.position = ''
+        placeholder.style.display = 'none'
+        active = false
+      }
+
+      const check = () => {
+        const scrollTop = getScroll(window, true)
+        const offsetTop = el.getBoundingClientRect().top
+        if (offsetTop < stickyTop) {
+          sticky()
+        } else {
+          if (scrollTop < elHeight + stickyTop) {
+            reset()
+          }
+        }
+      }
+      listenAction = () => {
+        check()
+      }
+
+      window.addEventListener('scroll', listenAction)
+    },
+
+    unbind() {
+      window.removeEventListener('scroll', listenAction)
+    }
+  })
+}
+
+export default vueSticky
+

+ 13 - 0
dorm-service-admin/src/directive/waves/index.js

@@ -0,0 +1,13 @@
+import waves from './waves'
+
+const install = function(Vue) {
+  Vue.directive('waves', waves)
+}
+
+if (window.Vue) {
+  window.waves = waves
+  Vue.use(install); // eslint-disable-line
+}
+
+waves.install = install
+export default waves

+ 26 - 0
dorm-service-admin/src/directive/waves/waves.css

@@ -0,0 +1,26 @@
+.waves-ripple {
+    position: absolute;
+    border-radius: 100%;
+    background-color: rgba(0, 0, 0, 0.15);
+    background-clip: padding-box;
+    pointer-events: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    -webkit-transform: scale(0);
+    -ms-transform: scale(0);
+    transform: scale(0);
+    opacity: 1;
+}
+
+.waves-ripple.z-active {
+    opacity: 0;
+    -webkit-transform: scale(2);
+    -ms-transform: scale(2);
+    transform: scale(2);
+    -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
+}

+ 42 - 0
dorm-service-admin/src/directive/waves/waves.js

@@ -0,0 +1,42 @@
+import './waves.css'
+
+export default{
+  bind(el, binding) {
+    el.addEventListener('click', e => {
+      const customOpts = Object.assign({}, binding.value)
+      const opts = Object.assign({
+        ele: el, // 波纹作用元素
+        type: 'hit', // hit点击位置扩散center中心点扩展
+        color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
+      }, customOpts)
+      const target = opts.ele
+      if (target) {
+        target.style.position = 'relative'
+        target.style.overflow = 'hidden'
+        const rect = target.getBoundingClientRect()
+        let ripple = target.querySelector('.waves-ripple')
+        if (!ripple) {
+          ripple = document.createElement('span')
+          ripple.className = 'waves-ripple'
+          ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
+          target.appendChild(ripple)
+        } else {
+          ripple.className = 'waves-ripple'
+        }
+        switch (opts.type) {
+          case 'center':
+            ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
+            ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
+            break
+          default:
+            ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
+            ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
+        }
+        ripple.style.backgroundColor = opts.color
+        ripple.className = 'waves-ripple z-active'
+        return false
+      }
+    }, false)
+  }
+}
+

+ 9 - 0
dorm-service-admin/src/icons/index.js

@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg组件
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+const req = require.context('./svg', false, /\.svg$/)
+requireAll(req)

File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/404.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/bug.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/chart.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/clipboard.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/component.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/dashboard.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/documentation.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/drag.svg


+ 43 - 0
dorm-service-admin/src/icons/svg/edit.svg

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 469.331 469.331" style="enable-background:new 0 0 469.331 469.331;" xml:space="preserve">
+<g>
+	<path d="M438.931,30.403c-40.4-40.5-106.1-40.5-146.5,0l-268.6,268.5c-2.1,2.1-3.4,4.8-3.8,7.7l-19.9,147.4
+		c-0.6,4.2,0.9,8.4,3.8,11.3c2.5,2.5,6,4,9.5,4c0.6,0,1.2,0,1.8-0.1l88.8-12c7.4-1,12.6-7.8,11.6-15.2c-1-7.4-7.8-12.6-15.2-11.6
+		l-71.2,9.6l13.9-102.8l108.2,108.2c2.5,2.5,6,4,9.5,4s7-1.4,9.5-4l268.6-268.5c19.6-19.6,30.4-45.6,30.4-73.3
+		S458.531,49.903,438.931,30.403z M297.631,63.403l45.1,45.1l-245.1,245.1l-45.1-45.1L297.631,63.403z M160.931,416.803l-44.1-44.1
+		l245.1-245.1l44.1,44.1L160.931,416.803z M424.831,152.403l-107.9-107.9c13.7-11.3,30.8-17.5,48.8-17.5c20.5,0,39.7,8,54.2,22.4
+		s22.4,33.7,22.4,54.2C442.331,121.703,436.131,138.703,424.831,152.403z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/email.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/example.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/excel.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/eye.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/form.svg


+ 72 - 0
dorm-service-admin/src/icons/svg/group.svg

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 487 487" style="enable-background:new 0 0 487 487;" xml:space="preserve">
+<g>
+	<g>
+		<path d="M171.1,260.8c2.9-11.2,8.8-21.5,17.3-30.6c-14.2-9.2-26.1-21.8-34.3-36.6h27.1c3.6,11.6,8.2,21.8,13.2,30.7
+			c3.5-3.2,7.3-6.1,11.3-8.6c1.9-1.3,3.8-2.5,5.7-3.6c-3.1-5.6-5.9-11.8-8.4-18.5h30.6v10.9c1.8-0.3,3.6-0.5,5.4-0.5
+			c2.1-0.2,4.2-0.3,6.2-0.3c3.1,0,6.1,0.2,9,0.6v-10.6h30.7c-2.3,6.5-5.1,12.5-8,17.9c0.6,0.3,1.1,0.6,1.7,0.9
+			c6.6,3.7,11.5,8,14.9,11.7c5-8.9,9.6-19.1,13.1-30.6h27.1c-8,14.4-19.3,26.6-33,35.7c2.7,2,5.3,4.4,7.7,7.4
+			c4.9,6.2,8.1,14,9.7,23.3c38.3-24.5,63.7-67.4,63.7-116.1C381.8,67.9,320,6,243.9,6C167.9,6,106,67.8,106,143.9
+			C106,193.1,132.1,236.5,171.1,260.8z M342.4,114.7c2.7,9.2,4.2,19,4.2,29.1s-1.5,19.9-4.2,29.1h-30.9c1.5-9.1,2.4-18.7,2.4-29.1
+			s-0.9-20.1-2.4-29.1C311.5,114.7,342.4,114.7,342.4,114.7z M333.8,94h-27.1c-5.6-18.1-13.7-32.9-22.1-44.6
+			C305.5,58.5,322.8,74.3,333.8,94z M254.2,45.6c10,10.1,22.4,26,30.6,48.5h-30.6V45.6z M254.2,114.7h36.2
+			c1.7,8.9,2.8,18.6,2.8,29.1s-1,20.2-2.7,29.1h-36.3V114.7z M233.6,173h-36.2c-1.7-8.9-2.8-18.6-2.8-29.1s1-20.2,2.7-29.1h36.3V173
+			z M233.6,94h-30.7c8.1-22.6,20.7-38.6,30.7-48.6V94z M203.2,49.5c-8.4,11.7-16.5,26.5-22.1,44.6H154
+			C165,74.3,182.3,58.5,203.2,49.5z M141.1,143.8c0-10.1,1.5-19.9,4.2-29.1h30.9c-1.5,9.1-2.4,18.7-2.4,29.1s0.9,20.1,2.4,29.1
+			h-30.9C142.6,163.7,141.1,153.9,141.1,143.8z"/>
+		<path d="M463.2,412c-23-8.8-36.7-17.7-36.7-17.7l-17.7,56l-2.4,7.6l-7.9-22.5c18.2-25.4-1.4-26.6-4.8-26.6l0,0c0,0,0,0-0.1,0
+			c0,0,0,0-0.1,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0l0,0c-3.4,0-23,1.2-4.8,26.6l-7.9,22.5l-2.4-7.6l-17.7-56c0,0-7.7,5-21.3,11.3
+			c-3.4-2.6-7.5-4.8-12.5-6.7c-27.3-10.4-43.7-21.1-43.7-21.1l-21.1,66.6l-2.9,9l-9.4-26.7c21.7-30.2-1.6-31.7-5.7-31.7l0,0
+			c0,0,0,0-0.1,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0l0,0c-4,0-27.4,1.5-5.7,31.7l-9.4,26.7l-2.9-9l-21.1-66.6
+			c0,0-16.4,10.7-43.7,21.1c-5,1.8-9.1,4-12.5,6.7c-13.6-6.2-21.3-11.3-21.3-11.3l-17.7,56l-2.4,7.6l-7.9-22.5
+			c18.2-25.4-1.4-26.6-4.8-26.6l0,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0s0,0-0.1,0l0,0c-3.4,0-23,1.2-4.8,26.6L81,457.9
+			l-2.4-7.6l-17.7-56c0,0-13.8,9-36.7,17.7C-1.1,421.2,0.5,442,0,481h89.1h4.8h37.8h56h50.1h5.8h55.6h56h33.2h4.8H487
+			C486.9,442,488.5,421.2,463.2,412z"/>
+		<path d="M381,266.7c-3.8,1.3-7.3,3.2-10.5,5.4c-3.9,2.5-7.5,5.5-10.8,8.9c-5.1,5.2-9.7,12-11.6,20.4c-1.7,6.3-1.3,12.9,0.1,19.9
+			l0,0c0.4,2.1,0.9,4.1,1.7,6.2c-3.9-0.4-8.4,1.9-4.1,17c3.1,11.1,6,14.2,8.2,14.3c2,13.2,12.2,29.9,28.8,35.7
+			c6.8,2.4,14.3,2.4,21.2,0c16.4-5.9,26.9-22.6,28.9-35.7c2.2-0.2,5.1-3.3,8.2-14.3c4.3-15.1-0.3-17.4-4.1-17
+			c0.7-2.1,1.3-4.2,1.7-6.2c6.5-39.2-12.8-40.5-12.8-40.5s-3.2-6.1-11.6-10.8c-5.6-3.3-13.5-5.9-23.9-5
+			C387.2,265,384,265.6,381,266.7L381,266.7z"/>
+		<path d="M54.8,358.8c2,13.2,12.2,29.9,28.8,35.7c6.8,2.4,14.3,2.4,21.2,0c16.4-5.9,26.9-22.6,28.9-35.7c2.2-0.2,5.1-3.3,8.2-14.3
+			c4.3-15.1-0.3-17.4-4.1-17c0.7-2.1,1.3-4.2,1.7-6.2c6.5-39.2-12.8-40.5-12.8-40.5s-3.2-6.1-11.6-10.8c-5.6-3.3-13.5-5.9-23.9-5
+			c-3.4,0.2-6.5,0.8-9.5,1.8l0,0c-3.8,1.3-7.3,3.2-10.4,5.4c-3.9,2.5-7.5,5.5-10.8,8.9c-5.1,5.2-9.7,12-11.6,20.4
+			c-1.7,6.3-1.3,12.9,0.1,19.9l0,0c0.4,2.1,0.9,4.1,1.7,6.2c-3.8-0.4-8.4,1.9-4.1,17C49.7,355.5,52.6,358.6,54.8,358.8z"/>
+		<path d="M187.1,318.4c3.7,13.2,7.2,16.8,9.8,17.1c2.4,15.7,14.5,35.6,34.3,42.5c8.1,2.9,17.1,2.9,25.2-0.1
+			c19.5-7,32-26.9,34.4-42.5c2.6-0.2,6.1-3.9,9.8-17.1c5.1-18-0.3-20.7-4.9-20.2c0.9-2.5,1.5-5,2-7.4c7.8-46.6-15.2-48.2-15.2-48.2
+			s-3.8-7.3-13.8-12.9c-6.7-4-16.1-7.1-28.4-6c-4,0.2-7.8,1-11.3,2.2l0,0c-4.5,1.5-8.7,3.8-12.4,6.4c-4.6,2.9-9,6.5-12.8,10.6
+			c-6.1,6.2-11.5,14.2-13.8,24.3c-2,7.5-1.5,15.3,0.1,23.7l0,0c0.4,2.5,1.1,4.9,2,7.4C187.4,297.8,182,300.4,187.1,318.4z"/>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/icon.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/international.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/language.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/lock.svg


+ 52 - 0
dorm-service-admin/src/icons/svg/magnifying-glass.svg

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 480.925 480.925" style="enable-background:new 0 0 480.925 480.925;" xml:space="preserve">
+<g>
+	<g>
+		<path d="M469.675,415.325l-100.2-100.2l-7.2,7.2l-11.1-11.1c56.9-76.3,50.8-184.8-18.5-254.1c-76.2-76.1-199.5-76.1-275.6,0
+			s-76.1,199.5,0,275.5c69.3,69.3,177.8,75.5,254.1,18.5l11.1,11.1l-7.2,7.2l100.2,100.2c15,15,39.4,15,54.4,0
+			C484.675,454.725,484.675,430.425,469.675,415.325z M290.275,290.325c-52.7,52.7-138.2,52.7-190.9,0s-52.7-138.2,0-190.9
+			s138.2-52.7,190.9,0S342.975,237.625,290.275,290.325z"/>
+		<path d="M155.675,186.225c2,12.9,12,29.4,28.4,35.2c6.7,2.4,14.1,2.4,20.8,0c16.1-5.8,26.4-22.2,28.4-35.1c2.2-0.2,5-3.2,8.1-14.1
+			c4.2-14.9-0.3-17.1-4-16.7c0.7-2.1,1.3-4.1,1.6-6.1c6.4-38.5-12.6-39.9-12.6-39.9s-3.1-6-11.4-10.6c-5.5-3.3-13.3-5.8-23.5-5
+			c-3.3,0.2-6.4,0.8-9.3,1.8l0,0c-3.7,1.3-7.2,3.1-10.3,5.3c-3.8,2.4-7.4,5.4-10.6,8.7c-5,5.1-9.5,11.8-11.4,20.1
+			c-1.6,6.2-1.3,12.6,0.1,19.6l0,0c0.4,2,0.9,4.1,1.6,6.1c-3.8-0.4-8.3,1.8-4,16.7C150.675,183.025,153.575,186.125,155.675,186.225
+			z"/>
+		<path d="M263.375,238.625c-22.6-8.6-36.1-17.5-36.1-17.5l-17.4,55l-2.4,7.5l-7.8-22.1c17.9-25-1.4-26.2-4.7-26.2l0,0
+			c0,0,0,0-0.1,0c0,0,0,0-0.1,0c0,0,0,0-0.1,0s0,0-0.1,0l0,0c-3.3,0-22.6,1.2-4.7,26.2l-7.8,22.1l-2.4-7.5l-17.4-55
+			c0,0-13.5,8.8-36.1,17.5c-12.2,4.4-18,11.6-20.9,22.2c3.2,4.4,6.8,8.6,10.8,12.5c43.4,43.4,113.7,43.4,157.1,0
+			c4-4,7.6-8.2,10.8-12.5C281.375,250.225,275.475,243.025,263.375,238.625z"/>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/message.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/money.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/password.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/people.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/peoples.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/qq.svg


+ 56 - 0
dorm-service-admin/src/icons/svg/raise-your-hand-to-ask.svg

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="912.1px" height="912.1px" viewBox="0 0 912.1 912.1" style="enable-background:new 0 0 912.1 912.1;" xml:space="preserve"
+	>
+<g>
+	<g>
+		<path d="M504.607,574.9c102.8,0,186.4-83.601,186.4-186.4s-83.601-186.4-186.4-186.4c-102.799,0-186.4,83.6-186.4,186.4
+			S401.808,574.9,504.607,574.9z"/>
+		<g>
+			<path d="M346.108,611.9c-71.8,0-130,58.199-130,130V887.1c0,13.801,11.2,25,25,25h527c13.8,0,25-11.199,25-25V745.5
+				c2.2-3.8,4.2-7.9,5.8-12.2l102-270c3.4-9,5.2-18.6,5.2-28.3V132c0-44.2-35.8-80-80-80s-80,35.8-80,80v288.4l-72.3,191.5H346.108z
+				"/>
+			<path d="M30.808,178.1h59c12.4,0,22.9-9,24.7-21.2c3.4-22.2,10.3-38.6,20.5-48.5c9.5-9.2,22.6-13.7,40.2-13.7
+				c18.2,0,32.1,5,42.7,15.4c10.6,10.4,15.5,22.9,15.5,39.5c0,7.8-1.8,15-5.5,22c-1.9,3.5-9.3,14.3-37.5,38.2
+				c-26.2,22.2-43.9,43.1-54.2,63.8c-10.5,21.1-15.6,51.8-15.6,93.6l0,0c0,13.8,11.2,25,25,25h53.3c13.8,0,25-11.2,25-25l0,0
+				c0-32.3,3.9-45.5,6.2-50.5c1.8-4,9.3-15.8,39-40.4c27.6-22.9,46.2-43.8,56.8-63.8c10.9-20.5,16.4-43,16.4-66.8
+				c0-42.5-16.101-78-48-105.6c-30.8-26.6-71-40.1-119.5-40.1c-46.2,0-85.3,13.8-116,40.9c-31,27.4-48.7,64.5-52.7,110.2l0,0
+				C4.708,165.5,16.208,178.1,30.808,178.1z"/>
+			<path d="M198.708,533.6c13.8,0,25-11.199,25-25V455.4c0-13.801-11.2-25-25-25h-53.2c-13.8,0-25,11.199-25,25V508.6
+				c0,13.801,11.2,25,25,25H198.708z"/>
+		</g>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/shoppingCard.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/star.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/tab.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/table.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/theme.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/user.svg


File diff ditekan karena terlalu besar
+ 1 - 0
dorm-service-admin/src/icons/svg/wechat.svg


+ 0 - 0
dorm-service-admin/src/icons/svg/zip.svg


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini