Browse Source

Signed-off-by: caner <5658514@qq.com>

caner 3 years ago
parent
commit
f323ad9b98
62 changed files with 1964 additions and 462 deletions
  1. 0 3
      .env.development
  2. 0 3
      .env.production
  3. 1 1
      .eslintignore
  4. 2 2
      .eslintrc.js
  5. 3 24
      .gitignore
  6. 8 0
      LICENSE
  7. 143 39
      README.md
  8. 2 2
      admin.html
  9. 14 11
      index.html
  10. 2 2
      login.html
  11. 17 18
      package.json
  12. 16 0
      pageB.html
  13. BIN
      public/favicon.ico
  14. 0 1
      public/vite.svg
  15. BIN
      src/assets/logo.png
  16. 0 1
      src/assets/vue.svg
  17. 8 0
      src/components/1.vue
  18. 20 24
      src/pages/admin/App.vue
  19. 0 3
      src/pages/admin/assets/js/interfacePublic.ts
  20. 0 9
      src/pages/admin/assets/js/nativeUiPluginPublic.ts
  21. 20 0
      src/pages/admin/main.js
  22. 0 13
      src/pages/admin/main.ts
  23. 0 0
      src/pages/admin/router/index.js
  24. 17 0
      src/pages/admin/store/index.js
  25. 0 12
      src/pages/admin/store/index.ts
  26. 27 4
      src/pages/admin/views/test.vue
  27. 15 7
      src/pages/index/App.vue
  28. 0 9
      src/pages/index/assets/js/nativeUiPluginPublic.ts
  29. 22 0
      src/pages/index/main.js
  30. 13 0
      src/pages/index/router/index.js
  31. 15 0
      src/pages/index/store/index.js
  32. 0 12
      src/pages/index/store/index.ts
  33. 9 0
      src/pages/index/store/user.js
  34. 250 8
      src/pages/index/views/test.vue
  35. 192 0
      src/pages/index/views/workOrder/components/add.vue
  36. 38 0
      src/pages/index/views/workOrder/components/details.vue
  37. 129 0
      src/pages/index/views/workOrder/index.vue
  38. 25 4
      src/pages/login/App.vue
  39. 5 7
      src/pages/login/main.js
  40. 0 5
      src/pages/login/main.ts
  41. 1 7
      src/pages/login/router/index.js
  42. 15 0
      src/pages/login/store/index.js
  43. 0 5
      src/pages/login/views/index.vue
  44. 30 0
      src/pages/login/views/test.vue
  45. 43 0
      src/utils/Excel2json.js
  46. 243 0
      src/utils/FormAnalyticalServer.js
  47. 33 0
      src/utils/GPS2KM.js
  48. 105 0
      src/utils/HTML2PNG.js
  49. 104 0
      src/utils/HtmlTbale2Excel.js
  50. 8 42
      src/utils/JsFn.js
  51. 99 0
      src/utils/MoveService.js
  52. 7 17
      src/utils/axios.js
  53. 0 57
      src/utils/exportExcel.js
  54. 99 0
      src/utils/openseadragon-svg-overlay.js
  55. 36 0
      src/utils/realDate.js
  56. 1 1
      src/utils/rem.js
  57. 34 31
      src/utils/userdata.js
  58. 13 0
      src/utils/weather.js
  59. 0 7
      src/vite-env.d.ts
  60. 0 17
      tsconfig.json
  61. 80 0
      vite.config.js
  62. 0 54
      vite.config.ts

+ 0 - 3
.env.development

@@ -1,3 +0,0 @@
-# api 参数
-VITE_APP_API_HOST=127.0.0.1
-VITE_APP_API_PORT=3000

+ 0 - 3
.env.production

@@ -1,3 +0,0 @@
-# api 参数
-VITE_APP_API_HOST=
-VITE_APP_API_PORT=

+ 1 - 1
.eslintignore

@@ -1,4 +1,4 @@
 # 排除eslint检查文件
 # 排除eslint检查文件
-/src/utils
+utils
 /dist
 /dist
 /public
 /public

+ 2 - 2
.eslintrc.js

@@ -6,7 +6,7 @@ module.exports = {
   },
   },
   parserOptions: {
   parserOptions: {
     ecmaVersion: 12,
     ecmaVersion: 12,
-    parser: '@typescript-eslint/parser'
+    sourceType: 'module'
   },
   },
   extends: [
   extends: [
     'plugin:vue/vue3-recommended',
     'plugin:vue/vue3-recommended',
@@ -47,4 +47,4 @@ module.exports = {
     'no-unused-vars': 1,
     'no-unused-vars': 1,
     'vue/no-reserved-component-names': 0
     'vue/no-reserved-component-names': 0
   }
   }
-}
+}

+ 3 - 24
.gitignore

@@ -1,28 +1,7 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
 node_modules
 node_modules
+.DS_Store
 dist
 dist
 dist-ssr
 dist-ssr
 *.local
 *.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
-yarn.lock
-dist
-package-lock.json
-dist-ssr
+GITHUB
+yarn.lock

+ 8 - 0
LICENSE

@@ -0,0 +1,8 @@
+MIT License
+Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 143 - 39
README.md

@@ -1,15 +1,127 @@
-# vue3+TS+Eslint 多入口模板
+# vue3多入口模板
 ```
 ```
-1. 默认安装:
-   1. aixos
-   2. js-md5
-   3. pinia
-   4. vue-router
-   5. less
-   6. naive-ui 
-2. 子页面全局interface文件/pages/*/assets/js/interfacePublic.ts
-3. 注意pinia 注册ID唯一性
+1. html自动对应各自入口文件(router,store)互不影响,即单独加载,共享数据,建议使用yarn安装依赖
+2. eslint自动校验修正,无需IDE修正
+3. eslint校准规则增加到 .eslintrc.js -> rules  中
+
 ```
 ```
+
+# 建议使用setup方式(Composition API),请注意书写格式!
+```
+import { onMounted, ref, computed} from 'vue'
+<script setup>
+    <!-- data 数据声明区 -->
+      exp:
+        const test=ref(1)
+        const test1:computed(()=>test)
+
+    <!-- function 调用区 -->
+      exp:
+       const test= ()=>{
+          console.log(123)
+        }
+
+    <!-- 单独生命周期监听区 -->
+      exp:
+        onMounted(() => {test()})
+</script>
+
+```
+
+# 鼓励使用option api 方式
+```
+export default {
+    props:{name:String},
+
+    <!-- 注意setup 和 data 使用其一即可 -->
+    setup(){
+      const test= ref(1)
+      return { test }
+    },
+
+    <!-- 注意setup 和 data 使用其一即可 -->
+    data() {
+        return {
+          greeting: 'Hello World!'
+        }
+    },
+
+    mounted(){
+      console.log(123)
+    }
+}
+</script>
+
+```
+
+## use
+```
+yarn
+
+yarn add ****
+
+yarn dev
+
+yarn build
+
+```
+
+## pinia 使用方法注意ID是唯一
+```
+<!-- 参考:https://blog.csdn.net/u012384510/article/details/122007683 -->
+
+
+<!-- vue3写法 -->
+import { ref, computed } from "vue"
+import { defineStore } from "pinia"
+const useCounterStore = defineStore('counter', function () {
+   const count = ref(0)
+   const double = computed(() => count.value * 2)
+   function increment() {
+     count.value++
+   }
+   return {
+    count, double, increment
+   }
+ })
+export default useCounterStore
+
+<!-- vue3  用法 -->
+import { useCounterStore } from '../stores/counter'
+const counter = useCounterStore()
+counter.count
+
+
+
+<!-- vuex 写法 -->
+import { defineStore } from 'pinia'
+const useStore = defineStore({
+  id: 'login', // id必填,且需要唯一
+  state: () => ({
+    loading: false
+  }),
+  getters: {
+
+  },
+  actions: {
+    setLoading(state) {
+      this.loading = state
+    }
+  }
+})
+export default useStore
+
+<!-- vue2 用法 -->
+import { mapActions, mapState } from 'pinia'
+import { useCounterStore } from '../model/counter'
+
+<!-- 计算属性 -->
+...mapState(useCounterStore, ['count', 'double']) 读取字段
+...mapActions(useCounterStore, ['increment']) 读取方法
+...mapWritableState(useStore, [ 'loading' ]) 读写字段
+
+```
+
 ## 目录结构
 ## 目录结构
 ```
 ```
 | - `src`
 | - `src`
@@ -19,53 +131,45 @@
 |           - `components`        子组件
 |           - `components`        子组件
 |           - `router`            子路由
 |           - `router`            子路由
 |           - `store`             子存储
 |           - `store`             子存储
-|           - `views`             子页面
 |           - `App.vue`           子模板
 |           - `App.vue`           子模板
-|           - `main.ts`           子入口文件
+|           - `main.js`           子入口文件
 |       - `admin`                 后台管理入口子目录
 |       - `admin`                 后台管理入口子目录
 |           - `assets`            子静态文件
 |           - `assets`            子静态文件
 |           - `components`        子组件
 |           - `components`        子组件
 |           - `router`            子路由
 |           - `router`            子路由
 |           - `store`             子存储
 |           - `store`             子存储
-|           - `views`             子页面
 |           - `App.vue`           子模板
 |           - `App.vue`           子模板
-|           - `main.ts`           子入口文件
+|           - `main.js`           子入口文件
 |       - `login`                 登录入口子目录
 |       - `login`                 登录入口子目录
 |           - `assets`            子静态文件
 |           - `assets`            子静态文件
 |           - `components`        子组件
 |           - `components`        子组件
 |           - `router`            子路由
 |           - `router`            子路由
 |           - `store`             子存储
 |           - `store`             子存储
-|           - `views`             子页面
 |           - `App.vue`           子模板
 |           - `App.vue`           子模板
-|           - `main.ts`           子入口文件
+|           - `main.js`           子入口文件
 |   - `components`                全局组件
 |   - `components`                全局组件
 |   - `utils`                     全局插件
 |   - `utils`                     全局插件
 |   - `assets`                    全局静态文件
 |   - `assets`                    全局静态文件
-```
-
-## vue3 使用setup方式,注意格式
-```
-import { onMounted, ref, computed} from 'vue'
-<script setup>
-    <!-- data 数据声明区 -->
-      exp:
-        const test=ref(1)
-        const test1:computed(()=>test)
 
 
-    <!-- function 调用区 -->
-      exp:
-       const test= ()=>{
-          console.log(123)
-        }
-
-    <!-- 单独生命周期监听区 -->
-      exp:
-        onMounted(() => {test()})
-</script>
+```    
 
 
+### 注意
 ```
 ```
 
 
-## use
-```
+1. 多页面路由模式不能使用 history 模式
+2. 模板采用 index.html
+3. 更多方法查看 utils/*.js
+4. vite 使用es6
+5. 默认安装:
+   1. aixos
+   2. js-md5
+   3. pinia
+   4. vue-router
+   5. less
+   6. echarts5.3.3
+   7. view-ui-plus   
+6. eslintignore 增加排除文件
+7. echarts 使用import * as echarts from 'echarts'
+8. 组件嵌套层级超过3层建议使用 provide/inject 方式
 
 
-```
+```

+ 2 - 2
admin.html

@@ -5,12 +5,12 @@
   <meta charset="UTF-8" />
   <meta charset="UTF-8" />
   <link rel="icon" href="/favicon.ico" />
   <link rel="icon" href="/favicon.ico" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-  <title>智慧隧道AI建造</title>
+  <title>Vite App</title>
 </head>
 </head>
 
 
 <body>
 <body>
   <div id="app"></div>
   <div id="app"></div>
-  <script type="module" src="/src/pages/admin/main.ts"></script>
+  <script type="module" src="./src/pages/admin/main.js"></script>
 </body>
 </body>
 
 
 </html>
 </html>

+ 14 - 11
index.html

@@ -1,13 +1,16 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html lang="en">
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>智慧隧道AI建造</title>
-  </head>
-  <body>
-    <div id="app"></div>
-    <script type="module" src="/src/pages/index/main.ts"></script>
-  </body>
-</html>
+
+<head>
+  <meta charset="UTF-8" />
+  <link rel="icon" href="/favicon.ico" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <title>Vite App</title>
+</head>
+
+<body>
+  <div id="app"></div>
+  <script type="module" src="./src/pages/index/main.js"></script>
+</body>
+
+</html>

+ 2 - 2
login.html

@@ -5,12 +5,12 @@
   <meta charset="UTF-8" />
   <meta charset="UTF-8" />
   <link rel="icon" href="/favicon.ico" />
   <link rel="icon" href="/favicon.ico" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-  <title>智慧隧道AI建造</title>
+  <title>Vite App</title>
 </head>
 </head>
 
 
 <body>
 <body>
   <div id="app"></div>
   <div id="app"></div>
-  <script type="module" src="/src/pages/login/main.ts"></script>
+  <script type="module" src="./src/pages/login/main.js"></script>
 </body>
 </body>
 
 
 </html>
 </html>

+ 17 - 18
package.json

@@ -1,32 +1,31 @@
 {
 {
   "name": "vite-project",
   "name": "vite-project",
-  "private": true,
   "version": "0.0.0",
   "version": "0.0.0",
   "scripts": {
   "scripts": {
-    "dev": "vite",
-    "build": "vue-tsc --noEmit && vite build",
+    "dev": "vite --host",
+    "build": "vite build",
     "preview": "vite preview"
     "preview": "vite preview"
   },
   },
   "dependencies": {
   "dependencies": {
-    "axios": "^0.27.2",
+    "axios": "^0.24.0",
+    "echarts": "^5.3.3",
     "js-md5": "^0.7.3",
     "js-md5": "^0.7.3",
-    "pinia": "^2.0.18",
-    "vue": "^3.2.37",
-    "vue-router": "^4.1.3",
-    "xlsx": "^0.18.5"
+    "pinia": "^2.0.14",
+    "view-ui-plus": "^1.2.0",
+    "vue": "^3.2.25",
+    "vue-router": "^4.0.13"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@types/node": "^18.7.1",
-    "@typescript-eslint/parser": "^5.33.0",
-    "@vitejs/plugin-vue": "^3.0.2",
-    "eslint": "^8.21.0",
+    "@vitejs/plugin-vue": "^2.3.3",
+    "eslint": "^8.15.0",
     "eslint-config-airbnb-base": "^15.0.0",
     "eslint-config-airbnb-base": "^15.0.0",
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-import": "^2.26.0",
-    "eslint-plugin-vue": "^9.3.0",
-    "less": "^4.1.3",
-    "typescript": "^4.6.4",
-    "vite": "^3.0.6",
-    "vite-plugin-eslint": "^1.8.0",
-    "vue-tsc": "^0.39.5"
+    "eslint-plugin-vue": "^9.1.0",
+    "glob": "^8.0.3",
+    "less": "^4.1.2",
+    "vite": "^2.9.9",
+    "vite-plugin-compression": "^0.5.1",
+    "vite-plugin-eslint": "^1.6.1",
+    "vue-template-compiler": "^2.6.14"
   }
   }
 }
 }

+ 16 - 0
pageB.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8" />
+  <link rel="icon" href="/favicon.ico" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <title>Vite App</title>
+</head>
+
+<body>
+  <div id="app"></div>
+  <script type="module" src="./src/pages/pageB/main.js"></script>
+</body>
+
+</html>

BIN
public/favicon.ico


+ 0 - 1
public/vite.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

BIN
src/assets/logo.png


+ 0 - 1
src/assets/vue.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 8 - 0
src/components/1.vue

@@ -0,0 +1,8 @@
+<template>
+  <div>
+    6666666666666
+    <Button type="primary">
+      Primary
+    </Button>
+  </div>
+</template>

+ 20 - 24
src/pages/admin/App.vue

@@ -1,37 +1,33 @@
 <template>
 <template>
-  <loading v-if="show" />
-  <router-view />
+  <div id="app">
+    <loading v-if="loading" />
+    <router-view />
+  </div>
 </template>
 </template>
-<script setup lang='ts'>
+<script>
 import loading from '@/components/loading.vue'
 import loading from '@/components/loading.vue'
+import { mapState } from 'pinia'
 import useStore from './store/index'
 import useStore from './store/index'
-import { computed } from 'vue'
-const store = useStore()
-const show = computed(() => store.loading)
+
+export default {
+  components: {
+    loading
+  },
+  computed: {
+    ...mapState(useStore, [ 'loading' ])
+  }
+}
 </script>
 </script>
-<style lang="less">
-html,
-body {
+<style>
+html,body{
   margin: 0;
   margin: 0;
   padding: 0;
   padding: 0;
 }
 }
 #app {
 #app {
-  background: #335391;
-  min-width: 1440px;
-  min-height: 800px;
-  user-select: none;
-  width: 19.2rem;
-  height: 10.8rem;
-  overflow: hidden;
-  font-family: "iconfont";
-  font-style: normal;
+  font-family: Avenir, Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
   -moz-osx-font-smoothing: grayscale;
-}
-
-/* 隐藏滚动条 */
-::-webkit-scrollbar {
-  width: 0 !important;
-  display: none;
+  text-align: center;
+  color: #2c3e50;
 }
 }
 </style>
 </style>

+ 0 - 3
src/pages/admin/assets/js/interfacePublic.ts

@@ -1,3 +0,0 @@
-export interface test{
-    a:string
-}

+ 0 - 9
src/pages/admin/assets/js/nativeUiPluginPublic.ts

@@ -1,9 +0,0 @@
-import {
-  create, NButton
-} from 'naive-ui'
-
-const naive = create({
-  components: [ NButton ]
-})
-
-export default naive

+ 20 - 0
src/pages/admin/main.js

@@ -0,0 +1,20 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+import { createPinia } from 'pinia'
+import '@/utils/rem.js'
+const store = createPinia()
+// 身份验证
+// router.beforeEach((to, from, next) => {
+//   const userdata = userData.getUserData()
+//   const datas = JSON.parse(userdata)
+//   if (to.name !== 'login' && !datas) {
+//     location.href = '/login.html#/'
+//   } else {
+//     next()
+//   }
+// })
+const app = createApp(App)
+app.use(router)
+  .use(store)
+  .mount('#app')

+ 0 - 13
src/pages/admin/main.ts

@@ -1,13 +0,0 @@
-import { createApp } from 'vue'
-import App from './App.vue'
-import { createPinia } from 'pinia'
-import naive from './assets/js/nativeUiPluginPublic'
-import router from './router'
-import '@/utils/rem'
-const store = createPinia()
-const app = createApp(App)
-
-app.use(store)
-  .use(router)
-  .use(naive)
-  .mount('#app')

+ 0 - 0
src/pages/admin/router/index.ts → src/pages/admin/router/index.js


+ 17 - 0
src/pages/admin/store/index.js

@@ -0,0 +1,17 @@
+import { defineStore } from 'pinia'
+// vuex 写法
+const useStore = defineStore({
+  id: 'admin', // id必填,且需要唯一
+  state: () => ({
+    loading: false
+  }),
+  getters: {
+
+  },
+  actions: {
+    setLoading(state) {
+      this.loading = state
+    }
+  }
+})
+export default useStore

+ 0 - 12
src/pages/admin/store/index.ts

@@ -1,12 +0,0 @@
-import { defineStore } from 'pinia'
-// id必填,且需要唯一
-import { ref } from 'vue'
-const useStore = defineStore('admin', () => {
-  const loading = ref(false)
-
-  const setLoading = (data: boolean) => {
-    loading.value = data
-  }
-  return { loading, setLoading }
-})
-export default useStore

+ 27 - 4
src/pages/admin/views/test.vue

@@ -1,7 +1,30 @@
 <template>
 <template>
-  <div>
-    <n-button type="primary">
-      Primary
-    </n-button>
+  <div class="test">
+    {{ test }}
   </div>
   </div>
 </template>
 </template>
+<script>
+import { mapWritableState } from 'pinia'
+import useStore from '../store/index'
+import { sleep } from '@/utils/JsFn.js'
+export default {
+  data() {
+    return {
+      test: '55555555555'
+    }
+  },
+  computed: {
+    ...mapWritableState(useStore, [ 'loading' ])
+  },
+  async mounted() {
+    await sleep(3000)
+    this.loading = true
+  }
+}
+</script>
+<style lang="less" scoped>
+.test {
+  background: red;
+  border: solid 1px black;
+}
+</style>

+ 15 - 7
src/pages/index/App.vue

@@ -1,17 +1,25 @@
 <template>
 <template>
-  <loading v-if="show" />
-  <router-view />
+  <div id="app">
+    <loading v-if="loading" />
+    <router-view />
+  </div>
 </template>
 </template>
-<script setup lang='ts'>
+<script>
 import loading from '@/components/loading.vue'
 import loading from '@/components/loading.vue'
+import { mapState } from 'pinia'
 import useStore from './store/index'
 import useStore from './store/index'
-import { computed } from 'vue'
-const store = useStore()
-const show = computed(() => store.loading)
+export default {
+  components: {
+    loading
+  },
+  computed: {
+    ...mapState(useStore, [ 'loading' ])
+  }
+}
 </script>
 </script>
 <style>
 <style>
 html,body{
 html,body{
   margin: 0;
   margin: 0;
   padding: 0;
   padding: 0;
 }
 }
-</style>
+</style>

+ 0 - 9
src/pages/index/assets/js/nativeUiPluginPublic.ts

@@ -1,9 +0,0 @@
-import {
-  create, NButton
-} from 'naive-ui'
-
-const naive = create({
-  components: [ NButton ]
-})
-
-export default naive

+ 22 - 0
src/pages/index/main.js

@@ -0,0 +1,22 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+import { createPinia } from 'pinia'
+import 'view-ui-plus/dist/styles/viewuiplus.css'
+
+import '@/utils/rem.js'
+const store = createPinia()
+// 身份验证
+// router.beforeEach((to, from, next) => {
+//   const userdata = userData.getUserData()
+//   const datas = JSON.parse(userdata)
+//   if (to.name !== 'login' && !datas) {
+//     location.href = '/login.html#/'
+//   } else {
+//     next()
+//   }
+// })
+const app = createApp(App)
+app.use(router)
+  .use(store)
+  .mount('#app')

+ 13 - 0
src/pages/index/router/index.js

@@ -0,0 +1,13 @@
+import { createRouter, createWebHashHistory } from 'vue-router'
+
+const routes = [
+  {
+    path: '/',
+    component: () => import('../views/workOrder/index.vue')
+  }
+]
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes
+})
+export default router

+ 15 - 0
src/pages/index/store/index.js

@@ -0,0 +1,15 @@
+import { defineStore } from 'pinia'
+// vuex 写法
+const useStore = defineStore({
+  id: 'main', // id必填,且需要唯一
+  state: () => ({
+    loading: false
+  }),
+  getters: {
+
+  },
+  actions: {
+
+  }
+})
+export default useStore

+ 0 - 12
src/pages/index/store/index.ts

@@ -1,12 +0,0 @@
-import { defineStore } from 'pinia'
-// id必填,且需要唯一
-import { ref } from 'vue'
-const useStore = defineStore('index', () => {
-  const loading = ref(false)
-
-  const setLoading = (data:boolean) => {
-    loading.value = data
-  }
-  return { loading, setLoading }
-})
-export default useStore

+ 9 - 0
src/pages/index/store/user.js

@@ -0,0 +1,9 @@
+import { defineStore } from 'pinia'
+
+const useUserStore = defineStore({
+  id: 'user', // id必填,且需要唯一
+  state: () => ({
+    name: '张三'
+  })
+})
+export default useUserStore

+ 250 - 8
src/pages/index/views/test.vue

@@ -1,12 +1,254 @@
 <template>
 <template>
-  <div>
-    <n-button type="primary">
-      我不是全局组件
-    </n-button>
+  <div class="work-order">
+    <Button
+      type="primary"
+      class="btn"
+      @click="modalShow = true"
+    >
+      新增工单
+    </Button>
+    <Table
+      :columns="columns"
+      :data="data"
+    >
+      <template #operation="{}">
+        <!-- <Button>查看详情</Button> -->
+        <div class="text">
+          详情
+        </div>
+      </template>
+    </Table>
+    <Modal
+      v-model="modalShow"
+      title="新增工单"
+      @on-ok="ok"
+      @on-cancel="cancel"
+    >
+      <Form
+        ref="form"
+        :model="form"
+      >
+        <FormItem label="工单名称:">
+          <Input
+            v-model="form.name"
+            placeholder="请输入工单名称"
+          />
+        </FormItem>
+        <FormItem label="具体问题:">
+          <Input
+            v-model="form.question"
+            type="textarea"
+            placeholder="请输入具体问题"
+          />
+        </FormItem>
+        <FormItem label="图片上传:">
+          <div class="img">
+            <div
+              v-for="item in uploadList"
+              :key="item"
+              class="demo-upload-list"
+            >
+              <template v-if="item.status === 'finished'">
+                <img :src="item.url">
+                <div class="demo-upload-list-cover">
+                  <Icon
+                    type="ios-eye-outline"
+                    @click="handleView(item.url)"
+                  />
+                  <Icon
+                    type="ios-trash-outline"
+                    @click="handleRemove(item)"
+                  />
+                </div>
+              </template>
+              <template v-else>
+                <Progress
+                  v-if="item.showProgress"
+                  :percent="item.percentage"
+                  hide-info
+                />
+              </template>
+            </div>
+            <Upload
+              ref="upload"
+              :show-upload-list="false"
+              :default-file-list="defaultList"
+              :on-success="handleSuccess"
+              :format="['jpg', 'jpeg', 'png']"
+              :max-size="2048"
+              :on-format-error="handleFormatError"
+              :on-exceeded-size="handleMaxSize"
+              :before-upload="handleBeforeUpload"
+              multiple
+              type="drag"
+              action="//jsonplaceholder.typicode.com/posts/"
+              style="display: inline-block; width: 0.58rem"
+            >
+              <div
+                style="width: 0.58rem; height: 0.58rem; line-height: 0.58rem"
+              >
+                <Icon
+                  type="ios-camera"
+                  size="20"
+                />
+              </div>
+            </Upload>
+            <Modal
+              v-model="visible"
+              title="图片"
+            >
+              <img
+                v-if="visible"
+                :src="imgName"
+                style="width: 100%"
+              >
+            </Modal>
+          </div>
+        </FormItem>
+      </Form>
+    </Modal>
   </div>
   </div>
 </template>
 </template>
-<script setup lang="ts">
-import { reactive, ref } from 'vue'
-const t = ref(0)
-const a = reactive({ test: 1 })
+<script>
+export default {
+  data() {
+    return {
+      // modal显示隐藏
+      modalShow: false,
+
+      columns: [ {
+        title: '工单名称',
+        key: 'name',
+        align: 'center'
+      },
+      {
+        title: '创建时间',
+        key: 'time',
+        align: 'center'
+      },
+      {
+        title: '创建人',
+        key: 'people',
+        align: 'center'
+      }, {
+        title: '是否完成',
+        key: 'complete',
+        align: 'center'
+      }, {
+        title: '操作',
+        slot: 'operation',
+        align: 'center'
+      }
+      ],
+      data: [ {
+        name: '问题1',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      },
+      {
+        name: '问题2',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      },
+      {
+        name: '问题3',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      },
+      {
+        name: '问题4',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      }
+      ],
+      //   图片
+
+      defaultList: [
+        {
+          name: 'a42bdcc1178e62b4694c830f028db5c0',
+          url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F113020142315%2F201130142315-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657965995&t=bc5851d837f31836a234ba8d5c0b0144'
+        },
+        {
+          name: 'bc7521e033abdd1e92222d733590f104',
+          url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F063021120F9%2F210630120F9-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657966092&t=abd300eae0fcc7d00058060b27cd68dd'
+        }
+      ],
+      imgName: '',
+      visible: false,
+      uploadList: []
+    }
+  },
+  methods: {
+    ok() {
+      this.$Message.info('Clicked ok')
+    },
+    cancel() {
+      this.$Message.info('Clicked cancel')
+    },
+    handleView(name) {
+      this.imgName = name
+      this.visible = true
+    },
+    handleRemove(file) {
+      const { fileList } = this.$refs.upload
+      this.$refs.upload.fileList.splice(fileList.indexOf(file), 1)
+    },
+    handleSuccess(res, file) {
+      file.url = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F113020142315%2F201130142315-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657965995&t=bc5851d837f31836a234ba8d5c0b0144'
+      file.name = '7eb99afb9d5f317c912f08b5212fd69a'
+    },
+    handleFormatError(file) {
+      this.$Notice.warning({
+        title: 'The file format is incorrect',
+        desc: `File format of ${file.name} is incorrect, please select jpg or png.`
+      })
+    },
+    handleMaxSize(file) {
+      this.$Notice.warning({
+        title: 'Exceeding file size limit',
+        desc: `File  ${file.name} is too large, no more than 2M.`
+      })
+    },
+    handleBeforeUpload() {
+      const check = this.uploadList.length < 5
+      if (!check) {
+        this.$Notice.warning({
+          title: 'Up to five pictures can be uploaded.'
+        })
+      }
+      return check
+    }
+  },
+  mounted() {
+    this.uploadList = this.$refs.upload.fileList
+    console.log('====================================')
+    console.log(this.$refs.upload.fileList)
+    console.log('====================================')
+  }
+}
+
 </script>
 </script>
+<style lang="less" scoped>
+.work-order {
+  .btn {
+    margin: 0.3rem 0.2rem;
+  }
+  .text {
+    cursor: pointer;
+    &:hover {
+      color: skyblue;
+    }
+  }
+}
+:deep(.ivu-input-wrapper) {
+    width: 80%;
+}
+img {
+  width: 0.58rem;
+  height: 0.58rem;
+}
+</style>

+ 192 - 0
src/pages/index/views/workOrder/components/add.vue

@@ -0,0 +1,192 @@
+<template>
+  <Modal
+    v-model="modalShow"
+    title="新增工单"
+    class="add-modal"
+    @on-ok="ok"
+    @on-cancel="cancel"
+  >
+    <Form
+      ref="form"
+      :model="form"
+    >
+      <FormItem label="工单名称:">
+        <Input
+          v-model="form.name"
+          placeholder="请输入工单名称"
+        />
+      </FormItem>
+      <FormItem label="具体问题:">
+        <Input
+          v-model="form.question"
+          type="textarea"
+          placeholder="请输入具体问题"
+        />
+      </FormItem>
+      <FormItem label="图片上传:">
+        <div class="img-list">
+          <div
+            v-for="item in uploadList"
+            :key="item"
+            class="demo-upload-list"
+          >
+            <template v-if="item.status === 'finished'">
+              <img :src="item.url">
+              <div class="demo-upload-list-cover">
+                <Icon
+                  type="ios-eye-outline"
+                  @click="handleView(item.url)"
+                />
+                <Icon
+                  type="ios-trash-outline"
+                  @click="handleRemove(item)"
+                />
+              </div>
+            </template>
+            <template v-else>
+              <Progress
+                v-if="item.showProgress"
+                :percent="item.percentage"
+                hide-info
+              />
+            </template>
+          </div>
+          <Upload
+            ref="upload"
+            :show-upload-list="false"
+            :default-file-list="defaultList"
+            :on-success="handleSuccess"
+            :format="['jpg', 'jpeg', 'png']"
+            :max-size="2048"
+            :on-format-error="handleFormatError"
+            :on-exceeded-size="handleMaxSize"
+            multiple
+            type="drag"
+            action="//jsonplaceholder.typicode.com/posts/"
+            style="display: inline-block; width: 0.58rem"
+          >
+            <div style="width: 0.58rem; height: 0.58rem; line-height: 0.58rem">
+              <Icon
+                type="ios-camera"
+                size="20"
+              />
+            </div>
+          </Upload>
+          <Modal
+            v-model="visible"
+            title="图片"
+          >
+            <img
+              v-if="visible"
+              :src="imgName"
+              style="width: 100%"
+            >
+          </Modal>
+        </div>
+      </FormItem>
+    </Form>
+  </Modal>
+</template>
+<script>
+import {
+  Modal, Form, FormItem, Icon, Upload, Input
+} from 'view-ui-plus'
+export default {
+  components: {
+    Modal, FormItem, Form, Icon, Upload, Input
+  },
+  data() {
+    return {
+      //   表单
+      form: {
+
+      },
+      // modal显示隐藏
+      modalShow: false,
+      //   图片默认
+      defaultList: [
+        {
+          name: 'a42bdcc1178e62b4694c830f028db5c0',
+          url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F113020142315%2F201130142315-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657965995&t=bc5851d837f31836a234ba8d5c0b0144'
+        },
+        {
+          name: 'bc7521e033abdd1e92222d733590f104',
+          url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F063021120F9%2F210630120F9-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657966092&t=abd300eae0fcc7d00058060b27cd68dd'
+        }
+      ],
+      imgName: '',
+      visible: false,
+      //   已上传图片的列表
+      uploadList: []
+    }
+  },
+  methods: {
+    // 点击确定
+    ok() {
+      this.$Message.info('Clicked ok')
+    },
+    // 点击取消
+    cancel() {
+      this.$Message.info('取消新增')
+    },
+    handleView(name) {
+      this.imgName = name
+      this.visible = true
+    },
+    handleRemove(file) {
+      const { fileList } = this.$refs.upload
+      this.$refs.upload.fileList.splice(fileList.indexOf(file), 1)
+    },
+    // 上传成功的钩子函数
+    handleSuccess(res, file) {
+      file.url = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F113020142315%2F201130142315-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1657965995&t=bc5851d837f31836a234ba8d5c0b0144'
+      file.name = '7eb99afb9d5f317c912f08b5212fd69a'
+    },
+    // 文件格式校验失败的钩子
+    handleFormatError(file) {
+      this.$Notice.warning({
+        title: 'The file format is incorrect',
+        desc: `File format of ${file.name} is incorrect, please select jpg or png.`
+      })
+    },
+    // 文件超出时候的钩子函数
+    handleMaxSize(file) {
+      this.$Notice.warning({
+        title: '提示',
+        desc: `文件  ${file.name} 超过 2M大小,无法上传.`
+      })
+    }
+  },
+  mounted() {
+    // 默认图片设置
+    this.uploadList = this.$refs.upload.fileList
+  }
+}
+
+</script>
+<style lang="less" scoped>
+.add-modal {
+  .ivu-input-wrapper {
+    width: 80%;
+  }
+  img {
+    width: 0.58rem;
+    height: 0.58rem;
+  }
+  .img-list {
+    display: flex;
+    flex-wrap: wrap;
+    .demo-upload-list {
+        // margin: 0 .1rem;
+        margin-right: .2rem;
+      .demo-upload-list-cover {
+        display: flex;
+        justify-content: space-around;
+        i {
+          cursor: pointer;
+        }
+      }
+    }
+  }
+}
+</style>

+ 38 - 0
src/pages/index/views/workOrder/components/details.vue

@@ -0,0 +1,38 @@
+<template>
+  <Modal
+    v-model="modalShow"
+    title="详情"
+    class="details"
+  >
+    <div>
+      工单名称:{{ dtData.name }}
+    </div>
+    <div>
+      创建时间:{{ dtData.time }}
+    </div>
+  </Modal>
+</template>
+<script>
+import { Modal } from 'view-ui-plus'
+export default {
+  components: {
+    Modal
+  },
+  data() {
+    return {
+      modalShow: false,
+      dtData: {}// 详情data
+    }
+  },
+  methods: {
+    setData(data) {
+      this.modalShow = true
+      this.dtData = data
+      console.log(data)
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+
+</style>

+ 129 - 0
src/pages/index/views/workOrder/index.vue

@@ -0,0 +1,129 @@
+<template>
+  <div class="work-order">
+    <Button
+      type="primary"
+      class="btn"
+      @click="addShow"
+    >
+      新增工单
+    </Button>
+    <!-- 表单 -->
+    <Table
+      :columns="columns"
+      :data="data"
+    >
+      <template #operation="{ row }">
+        <!-- <Button>查看详情</Button> -->
+        <div
+          class="text"
+          @click="detalis(row)"
+        >
+          详情
+        </div>
+      </template>
+    </Table>
+    <!-- 新增弹框 -->
+    <add-modal ref="add" />
+    <details-modal ref="details" />
+  </div>
+</template>
+<script>
+import addModal from './components/add.vue'
+import detailsModal from './components/details.vue'
+import { Button, Table } from 'view-ui-plus'
+export default {
+  components: {
+    addModal, detailsModal, Button, Table
+  },
+  data() {
+    return {
+      // modal显示隐藏
+      modalShow: true,
+      //   表单
+      form: {
+
+      },
+      columns: [ {
+        title: '工单名称',
+        key: 'name',
+        align: 'center'
+      },
+      {
+        title: '创建时间',
+        key: 'time',
+        align: 'center'
+      },
+      {
+        title: '创建人',
+        key: 'people',
+        align: 'center'
+      }, {
+        title: '是否完成',
+        key: 'complete',
+        align: 'center'
+      }, {
+        title: '操作',
+        slot: 'operation',
+        align: 'center'
+      }
+      ],
+      data: [ {
+        name: '问题1',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      },
+      {
+        name: '问题2',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      },
+      {
+        name: '问题3',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      },
+      {
+        name: '问题4',
+        people: '王二麻子',
+        complete: '是',
+        time: '2016-10-03'
+      }
+      ]
+    }
+  },
+  methods: {
+    // 新增弹框
+    addShow() {
+      this.$refs.add.modalShow = true
+    },
+    // 详情弹框
+    detalis(data) {
+      this.$refs.details.setData(data)
+    }
+  }
+}
+
+</script>
+<style lang="less" scoped>
+.work-order {
+  .btn {
+    margin: 0.3rem 0.2rem;
+  }
+  .text {
+    cursor: pointer;
+    &:hover {
+      color: skyblue;
+    }
+  }
+}
+:deep(.ivu-input-wrapper) {
+  width: 80%;
+}
+img {
+  width: 0.58rem;
+  height: 0.58rem;
+}
+</style>

+ 25 - 4
src/pages/login/App.vue

@@ -1,12 +1,33 @@
 <template>
 <template>
-  <test />
+  <div id="app">
+    <loading v-if="loading" />
+    <router-view />
+  </div>
 </template>
 </template>
-<script setup lang='ts'>
-import test from './views/index.vue'
+<script>
+import loading from '@/components/loading.vue'
+import { mapState } from 'pinia'
+import useStore from './store/index'
+
+export default {
+  components: {
+    loading
+  },
+  computed: {
+    ...mapState(useStore, [ 'loading' ])
+  }
+}
 </script>
 </script>
 <style>
 <style>
 html,body{
 html,body{
   margin: 0;
   margin: 0;
   padding: 0;
   padding: 0;
 }
 }
-</style>
+#app {
+  font-family: Avenir, Helvetica, Arial, sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-align: center;
+  color: #2c3e50;
+}
+</style>

+ 5 - 7
src/pages/index/main.ts → src/pages/login/main.js

@@ -1,12 +1,10 @@
 import { createApp } from 'vue'
 import { createApp } from 'vue'
 import App from './App.vue'
 import App from './App.vue'
-import { createPinia } from 'pinia'
 import router from './router'
 import router from './router'
-import naive from './assets/js/nativeUiPluginPublic'
+import { createPinia } from 'pinia'
+import '@/utils/rem.js'
 const store = createPinia()
 const store = createPinia()
 const app = createApp(App)
 const app = createApp(App)
-
-app.use(store)
-  .use(naive)
-  .use(router)
-  .mount('#app')
+app.use(router)
+  .use(store)
+  .mount('#app')

+ 0 - 5
src/pages/login/main.ts

@@ -1,5 +0,0 @@
-import { createApp } from 'vue'
-import App from './App.vue'
-import '@/utils/rem.js'
-const app = createApp(App)
-app.mount('#app')

+ 1 - 7
src/pages/index/router/index.ts → src/pages/login/router/index.js

@@ -4,16 +4,10 @@ const routes = [
   {
   {
     path: '/',
     path: '/',
     component: () => import('../views/test.vue')
     component: () => import('../views/test.vue')
-
-  },
-  // 重定向
-  {
-    path: '/:pathMatch(.*)*',
-    redirect: '/'
   }
   }
 ]
 ]
 const router = createRouter({
 const router = createRouter({
   history: createWebHashHistory(),
   history: createWebHashHistory(),
   routes
   routes
 })
 })
-export default router
+export default router

+ 15 - 0
src/pages/login/store/index.js

@@ -0,0 +1,15 @@
+import { defineStore } from 'pinia'
+// vuex 写法
+const useStore = defineStore({
+  id: 'login', // id必填,且需要唯一
+  state: () => ({
+    loading: false
+  }),
+  getters: {
+
+  },
+  actions: {
+
+  }
+})
+export default useStore

+ 0 - 5
src/pages/login/views/index.vue

@@ -1,5 +0,0 @@
-<template>
-  <div>
-    321
-  </div>
-</template>

+ 30 - 0
src/pages/login/views/test.vue

@@ -0,0 +1,30 @@
+<template>
+  <div class="test">
+    {{ test }}
+  </div>
+</template>
+<script>
+import { mapWritableState } from 'pinia'
+import useStore from '../store/index'
+import { sleep } from '@/utils/JsFn.js'
+export default {
+  data() {
+    return {
+      test: '55555555555'
+    }
+  },
+  computed: {
+    ...mapWritableState(useStore, [ 'loading' ])
+  },
+  async mounted() {
+    await sleep(3000)
+    this.loading = true
+  }
+}
+</script>
+<style lang="less" scoped>
+.test {
+  background: red;
+  border: solid 1px black;
+}
+</style>

+ 43 - 0
src/utils/Excel2json.js

@@ -0,0 +1,43 @@
+/* eslint-disable no-return-await */
+/* eslint-disable camelcase */
+import XLSX from 'xlsx'
+/**
+ * excel文件转json数据
+ */
+class Excel2JsonService {
+  /**
+     * 解析excel表格
+     * @param {File} file 文件
+     */
+  async export2excel(file) {
+    return await new Promise((resolve, reject) => {
+      try {
+        const reader = new FileReader()
+        reader.onload = (e) => {
+          const wb = XLSX.read(e.target.result, {
+            type: 'binary'
+          }) // 读取完成的数据
+          // 转成json header解析第一行标题
+          const data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { header: 1 })
+          resolve(data)
+        }
+        reader.readAsBinaryString(file)
+      } catch (error) {
+        console.log('解析错误')
+        reject(error)
+      }
+    })
+  }
+
+  /**
+     * 解析后的浮点数转时间戳
+     * @param num 时间浮点
+     */
+  number2times(num) {
+    const utc_value = (num - 25569) * 86400
+    const date_info = new Date(utc_value * 1000).getTime()
+    const newtime = (date_info - 8 * 3600 * 1000)
+    return newtime
+  }
+}
+export default new Excel2JsonService()

+ 243 - 0
src/utils/FormAnalyticalServer.js

@@ -0,0 +1,243 @@
+import X2js from 'x2js'
+import XLSX from 'xlsx'
+import axios from 'axios'
+/**
+ * 围岩表格解析服务
+ * 来源以模板为准
+ */
+class FormAnalyticalServer {
+  constructor() {
+    console.warn('该服务需要特定数据模板')
+    this.XLSX = XLSX
+    this.X2js = new X2js()
+    this.Axios = axios
+  }
+
+  /**
+   *  钻进参数xml解析
+   *  @param {File} file file
+   *  @return srcData
+   */
+  async CountdrillingParameterObj(file) {
+    const url = window.URL.createObjectURL(file)
+    const res = await this.Axios.get(url)
+    const jsonObj = this.X2js.xml2js(res)
+    const xmlData = jsonObj.Workbook.Worksheet.Table.Row
+    const srcData = []
+    for (const i in xmlData) {
+      const rowData = xmlData[i].Cell
+      const arr = []
+      for (const j in rowData) {
+        if (rowData[j].Data && rowData[j].Data.__text) {
+          arr.push(rowData[j].Data.__text)
+        }
+      }
+      srcData.push(arr)
+    }
+    return srcData
+  }
+
+  /**
+   * 地质素描EXCEL解析
+   * @param {File} file file
+   * @return geologicalSketchObj
+   */
+  async CountGeologicalSketchObj(file) {
+    const data = await this.XLSX2JSON(file)
+    const mileageTime = new Date(data[0].__EMPTY_9).getTime() / 1000
+    const date = new Date(data[23].__EMPTY_5).getTime() / 1000
+    const geologicalSketchObj = {
+      tunnelName: data[0].__EMPTY, // 隧道
+      workArea: data[0].__EMPTY_2, // 工区
+      workFace: data[0].__EMPTY_4, // 工作面
+      mileage: data[0].__EMPTY_6, // 断面里程
+      mileageTime: mileageTime || '', // 时间
+      tunnelNumber: data[1].__EMPTY, // 项目编号
+      faceSize: {
+        width: data[2].__EMPTY_2, // 开挖宽度
+        height: data[2].__EMPTY_4, // 开挖高度
+        faceNum: data[2].__EMPTY_6, // 开挖面积
+        methods: data[2].__EMPTY_8, // 开挖方法
+        support: data[2].__EMPTY_10 // 超前支护类型
+      },
+      lithology: data[3].__EMPTY_1, // 地层岩性
+      choose1: data[4].__EMPTY_1, // 风化程度
+      choose2: data[5].__EMPTY_1, // 岩石强度(MPa)
+      choose12: data[6].__EMPTY_1, // 岩体结构类型
+      choose3: data[7].__EMPTY_1, // 主要结构面组数
+      choose4: data[8].__EMPTY_1, // 结构面平均间距(m)
+      choose5: data[9].__EMPTY_1, // 结构面发育程度
+      choose6: data[10].__EMPTY_1, // 裂隙宽度(mm)
+      choose7: data[11].__EMPTY_1, // 裂隙充填物
+      choose13: data[12].__EMPTY_1, // 结构面粗糙程度
+      choose8: data[13].__EMPTY_1, // 结合程度
+      choose9: data[14].__EMPTY_1, // 完整程度
+      choose10: data[15].__EMPTY_1, // 地下水状态
+      choose11: data[17].__EMPTY_1, // 地应力状态
+      mainStructural: {
+        text1: data[16].__EMPTY_2, // 主要结构面走向
+        text2: data[16].__EMPTY_4, // 主要结构面倾角
+        text3: data[16].__EMPTY_6, // 与洞轴线夹角
+        text4: data[16].__EMPTY_8 // 备注
+      }, // 主要结构面产状及与洞轴线夹角
+      grade: data[18].__EMPTY_1, // 围岩亚级划分
+      stability: data[19].__EMPTY_1, // 掌子面稳定性划分
+      describeText: data[20].__EMPTY_1, // 描述
+      personCompany: {
+        tabulation: data[22].__EMPTY_1, // 制表
+        review: data[22].__EMPTY_5, // 复核
+        supervisor: data[22].__EMPTY_9, // 监理工程师
+        company: data[23].__EMPTY_1, // 施工单位
+        date: date || '' // 日期
+      }
+    }
+    return geologicalSketchObj
+  }
+
+  /**
+   * 围岩设计等级excel解析
+   * @param {File} file file
+   * @return DesignDb
+   */
+  async CountDesign(file) {
+    const data = await this.XLSX2JSON(file)
+    const DesignDb = []
+    for (let j = 0; j < data.length; j++) {
+      const el = data[j]
+      DesignDb.push({
+        workFace: el['工作面'],
+        workArea: el['工区'],
+        startMileage: el['开始里程'],
+        endMileage: el['结束里程'],
+        supportingDesign: el['洞身支护设计级别'],
+        type: el['类型'],
+        designRock: el['设计围岩级别'],
+        forepolingDesign: el['超前支护设计级别'],
+        tunnel: el['隧道']
+      })
+    }
+    return DesignDb
+  }
+
+  /**
+   * EXCEL2JSON
+   * @param {FILE} FILE
+   * @return JSON
+   */
+  async XLSX2JSON(FILE) {
+    const reader = new FileReader()
+    reader.readAsBinaryString(FILE)
+    const JSON = await new Promise((resolve, reject) => {
+      reader.onload = (e) => {
+        const wb = this.XLSX.read(e.target.result, {
+          type: 'binary'
+        }) // 读取完成的数据
+        // 转成json header解析第一行标题,只解析最后一个标签
+        const lastexcel = wb.SheetNames[wb.SheetNames.length - 1]
+        const data = this.XLSX.utils.sheet_to_json(wb.Sheets[lastexcel], { dateNF: 'yyyy/mm/dd', raw: false })
+        resolve(data)
+      }
+    })
+    return JSON
+  }
+
+  /**
+   * 导出excel
+   * @param fileName 保存文件名
+   * @param table table表格DOM
+   */
+  outfile(fileName, table) {
+    try {
+      const sheet1 = XLSX.utils.table_to_sheet(table, { raw: true })
+      const blob2 = this.sheets2book2blob([ sheet1 ])
+      this.openDownloadDialog(blob2, `${fileName}.xlsx`)
+    } catch (error) {
+      console.error('导出错误')
+    }
+  }
+
+  /**
+   * sheet转blob
+   * @param params sheet参数arr|obj
+   * @returns
+   */
+  sheets2book2blob(params) {
+    let blob = null
+    if (params && params.length > 0) {
+      const workbook = {
+        SheetNames: [],
+        Sheets: {}
+      }
+      // 参数两种模式纯arr || arrobj
+      for (let k = 0; k < params.length; k++) {
+        const el = params[k]
+        if (el.db && el.name) {
+          workbook.SheetNames.push(el.name)
+          workbook.Sheets[el.name] = el.db
+        } else {
+          workbook.SheetNames.push(`sheet${k}`)
+          workbook.Sheets[`sheet${k}`] = el
+        }
+      }
+      // 生成excel的配置项
+      const wopts = {
+        bookType: 'xlsx', // 要生成的文件类型
+        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
+        type: 'binary'
+      }
+      const wbout = XLSX.write(workbook, wopts)
+      blob = new Blob([ this.s2ab(wbout) ], { type: 'application/octet-stream' })
+    }
+    return blob
+  }
+
+  /**
+   * 字符串转ArrayBuffer
+   * @param s 字符串
+   */
+  s2ab(s) {
+    const buf = new ArrayBuffer(s.length)
+    const view = new Uint8Array(buf)
+    for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
+    return buf
+  }
+
+  /**
+   * 下载
+   * @param url 文件blob
+   * @param fileName 文件名
+   */
+  openDownloadDialog(url, fileName) {
+    if (typeof url === 'object' && url instanceof Blob) {
+      url = URL.createObjectURL(url) // 创建blob地址
+    }
+    const aLink = document.createElement('a')
+    aLink.href = url
+    aLink.download = fileName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
+    let event
+    if (window.MouseEvent) event = new MouseEvent('click')
+    else {
+      event = document.createEvent('MouseEvents')
+      event.initMouseEvent(
+        'click',
+        true,
+        false,
+        window,
+        0,
+        0,
+        0,
+        0,
+        0,
+        false,
+        false,
+        false,
+        false,
+        0,
+        null
+      )
+    }
+    aLink.dispatchEvent(event)
+  }
+}
+
+export default new FormAnalyticalServer()

+ 33 - 0
src/utils/GPS2KM.js

@@ -0,0 +1,33 @@
+/**
+ * 计算经纬度之间的距离m
+ */
+class Lat2kmService {
+  constructor() {
+    this.EARTH_RADIUS = 6378.137
+  }
+
+  rad(d) {
+    return d * Math.PI / 180.0
+  }
+
+  /**
+     * 通过经纬度获取距离(单位:米)
+     * @param lat1
+     * @param lng1
+     * @param lat2
+     * @param lng2
+     * @return
+     */
+  getDistance(lat1, lng1, lat2, lng2) {
+    const radLat1 = this.rad(lat1)
+    const radLat2 = this.rad(lat2)
+    const a = radLat1 - radLat2
+    const b = this.rad(lng1) - this.rad(lng2)
+    let s = 2 * Math.asin(Math.sqrt(Math.sin(a / 2) ** 2 + Math.cos(radLat1) * Math.cos(radLat2) * Math.sin(b / 2) ** 2))
+    s *= this.EARTH_RADIUS
+    s = Math.round(s * 10000) / 10000
+    s *= 1000
+    return s
+  }
+}
+export default new Lat2kmService()

+ 105 - 0
src/utils/HTML2PNG.js

@@ -0,0 +1,105 @@
+import html2canvas from 'html2canvas'
+/**
+ * html转图片
+ * dom 节点ID
+ * name 文件名
+ */
+export default class Html2PngService {
+  /**
+   *  初始化
+   * @param {string} domID 节点ID
+   * @param {string} name 文件名
+   * @param {string} bkcolor 背景色
+   */
+  constructor(domID, name, bkcolor) {
+    try {
+      this.init(domID, name, bkcolor)
+    } catch (error) {
+      console.error(error)
+    }
+  }
+
+  /**
+   * 初始化
+   */
+  async init(domID, name, bkcolor) {
+    window.scroll(0, 0) // 首先先顶部
+    const design = document.getElementById(domID)
+    const imgHeight = design.offsetHeight // 获取DOM高度
+    const imgWidth = design.offsetWidth // 获取DOM宽度
+    const scale = window.devicePixelRatio <= 3 ? 3 : window.devicePixelRatio // 获取设备像素比
+    const canvas = await html2canvas(design, {
+      backgroundColor: bkcolor, // 设置背景颜色
+      borderRadius: '10px',
+      useCORS: true, // 允许图片跨域
+      scale, // 缩放3倍,使得图片更加清晰=>越清晰图片越大
+      width: imgWidth,
+      height: imgHeight,
+      imageTimeout: 5000 // 设置图片的超时,设置0为禁用
+    })
+    const imgURL = canvas.toDataURL('image/png')
+    this.openDownloadDialog(imgURL, `${name || 123}.png`)
+  }
+
+  /**
+   * url+blob下载
+   * @param url 地址
+   * @param saveName 文件名
+   */
+  openDownloadDialog(url, saveName) {
+    // 两种下载方式url + blob
+    if (typeof url === 'object' && url instanceof Blob) {
+      url = URL.createObjectURL(url) // 创建blob地址
+      this.download(url, saveName)
+    } else {
+      // url  +  请求得到blob
+      const that = this
+      const htmlrq = new XMLHttpRequest()
+      htmlrq.open('GET', url, true)
+      htmlrq.responseType = 'blob'
+      htmlrq.onload = function (e) {
+        if (e.target.status === 200) {
+          url = URL.createObjectURL(e.target.response) // 创建blob地址
+          that.download(url, saveName)
+        } else {
+          console.error('下载错误')
+        }
+      }
+      htmlrq.send()
+    }
+  }
+
+  /**
+   * A标签点击下载
+   * @param url 连接
+   * @param saveName 文件名
+   */
+  download(url, saveName) {
+    const aLink = document.createElement('a')
+    aLink.href = url
+    aLink.download = saveName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
+    let event
+    if (window.MouseEvent) event = new MouseEvent('click')
+    else {
+      event = document.createEvent('MouseEvents')
+      event.initMouseEvent(
+        'click',
+        true,
+        false,
+        window,
+        0,
+        0,
+        0,
+        0,
+        0,
+        false,
+        false,
+        false,
+        false,
+        0,
+        null
+      )
+    }
+    aLink.dispatchEvent(event)
+  }
+}

+ 104 - 0
src/utils/HtmlTbale2Excel.js

@@ -0,0 +1,104 @@
+import XLSX from 'xlsx'
+/**
+ * HTMLtabl转excel文件
+ */
+class HtmlTbale2ExcelService {
+  /**
+     * 导出excel
+     * @param {string} fileName 保存文件名
+     * @param {HTMLElement} table table表格DOM
+     */
+  outfile(fileName, table) {
+    try {
+      const sheet1 = XLSX.utils.table_to_sheet(table, { raw: true })
+      const blob2 = this.sheets2book2blob([ sheet1 ])
+      this.openDownloadDialog(blob2, `${fileName}.xlsx`)
+    } catch (error) {
+      console.error('导出错误')
+    }
+  }
+
+  /**
+     * sheet转blob
+     * @param {Array<any>} params sheet参数arr|obj
+     */
+  sheets2book2blob(params) {
+    if (params && params.length > 0) {
+      const workbook = {
+        SheetNames: [],
+        Sheets: {}
+      }
+      // 参数两种模式纯arr || arrobj
+      for (let k = 0; k < params.length; k++) {
+        const el = params[k]
+        if (el.db && el.name) {
+          workbook.SheetNames.push(el.name)
+          workbook.Sheets[el.name] = el.db
+        } else {
+          workbook.SheetNames.push(`sheet${k}`)
+          workbook.Sheets[`sheet${k}`] = el
+        }
+      }
+      // 生成excel的配置项
+      const wopts = {
+        bookType: 'xlsx', // 要生成的文件类型
+        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
+        type: 'binary'
+      }
+      const wbout = XLSX.write(workbook, wopts)
+      const blob = new Blob([ this.s2ab(wbout) ], { type: 'application/octet-stream' })
+
+      return blob
+    }
+    console.error('参数错误(need arr and arr obj)')
+  }
+
+  /**
+     * 字符串转ArrayBuffer
+     * @param {string} s 字符串
+     */
+  s2ab(s) {
+    const buf = new ArrayBuffer(s.length)
+    const view = new Uint8Array(buf)
+    for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
+    return buf
+  }
+
+  /**
+     * 下载
+     * @param {any} url 文件blob
+     * @param {string} fileName 文件名
+     */
+  openDownloadDialog(url, fileName) {
+    if (typeof url === 'object' && url instanceof Blob) {
+      url = URL.createObjectURL(url) // 创建blob地址
+    }
+    const aLink = document.createElement('a')
+    aLink.href = url
+    aLink.download = fileName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
+    let event
+    if (window.MouseEvent) event = new MouseEvent('click')
+    else {
+      event = document.createEvent('MouseEvents')
+      event.initMouseEvent(
+        'click',
+        true,
+        false,
+        window,
+        0,
+        0,
+        0,
+        0,
+        0,
+        false,
+        false,
+        false,
+        false,
+        0,
+        null
+      )
+    }
+    aLink.dispatchEvent(event)
+  }
+}
+export default new HtmlTbale2ExcelService()

+ 8 - 42
src/utils/JsFn.js

@@ -4,7 +4,7 @@
  * @param key 关键字
  * @param key 关键字
  * @returns 去重后
  * @returns 去重后
  */
  */
-function unique(arr, key) {
+ function unique(arr, key) {
   const res = []
   const res = []
   const obj = {}
   const obj = {}
   for (let i = 0; i < arr.length; i++) {
   for (let i = 0; i < arr.length; i++) {
@@ -68,48 +68,14 @@ function search(data, key) {
 }
 }
 
 
 /**
 /**
- * admin时间格式化
- * @param {date} date 
+ * vite 特有图片引用方法
+ * @param {string} url 图片路径
+ * @param {string} name 图片名称
  * @returns
  * @returns
  */
  */
-function adminFormatTime(date) {
-  const h = date.getHours()
-  const m = date.getMinutes()
-  const mon = date.getMonth() + 1
-  const day = date.getDate()
-  const wk = date.getDay()
-  let txt = ''
-  switch (wk) {
-    case 1:
-      txt = '一'
-      break
-    case 2:
-      txt = '二'
-      break
-    case 3:
-      txt = '三'
-      break
-    case 4:
-      txt = '四'
-      break
-    case 5:
-      txt = '五'
-      break
-    case 6:
-      txt = '六'
-      break
-    case 7:
-      txt = '天'
-      break
-    default:
-      break
-  }
-  const obj = {
-    time: `${h < 10 ? `0${h}` : h}:${m < 10 ? `0${m}` : m}`,
-    day: `${mon < 10 ? `0${mon}` : mon}月${day < 10 ? `0${day}` : day}日 星期${txt}`
-  }
-  return obj
+function getImageUrl(url, name) {
+  const src = url + name
+  return new URL(src, import.meta.url).href
 }
 }
 
 
-
-export { unique, sleep, flatten, randomNum, search, adminFormatTime }
+export { unique, sleep, flatten, randomNum, search, getImageUrl }

+ 99 - 0
src/utils/MoveService.js

@@ -0,0 +1,99 @@
+export default class MoveService {
+  constructor(DOM) {
+    if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
+      this.DviceType = true
+    } else {
+      this.DviceType = false
+    }
+    this.movedom = null
+    this.w = document.body.clientWidth
+    this.h = document.body.clientHeight
+    this.PX = 0
+    this.PY = 0
+    this.domw = 0
+    this.domh = 0
+    this.on(DOM)
+  }
+
+  /**
+       * 移动
+       */
+  mousemove(event) {
+    const e = event || window.event
+    const x = this.DviceType ? e.touches[0].clientX : e.clientX
+    const y = this.DviceType ? e.touches[0].clientY : e.clientY
+    const mx = x - this.PX
+    const my = y - this.PY
+    const outx = this.w - this.domw
+    const outy = this.h - this.domh
+    this.movedom.style.left = `${mx}px`
+    this.movedom.style.top = `${my}px`
+    if (mx >= outx) {
+      this.movedom.style.left = `${outx}px`
+    }
+    if (my >= outy) {
+      this.movedom.style.top = `${outy}px`
+    }
+    if (mx <= 0) {
+      this.movedom.style.left = '0px'
+    }
+    if (my <= 0) {
+      this.movedom.style.top = '0px'
+    }
+  }
+
+  /**
+       * 鼠标按下
+       */
+  mousedown(event) {
+    // 获取点击DOM
+    const e = event || window.event
+    if (this.DviceType) {
+      this.PX = e.touches[0].clientX - this.movedom.offsetLeft
+      this.PY = e.touches[0].clientY - this.movedom.offsetTop
+      this.movedom.ontouchmove = this.mousemove.bind(this)
+      this.movedom.ontouchend = this.mouseup.bind(this)
+    } else {
+      this.PX = e.clientX - this.movedom.offsetLeft
+      this.PY = e.clientY - this.movedom.offsetTop
+      this.movedom.onmousemove = this.mousemove.bind(this)
+      this.movedom.onmouseup = this.mouseup.bind(this)
+    }
+  }
+
+  /**
+       * 鼠标松开
+       */
+  mouseup() {
+    this.off()
+  }
+
+  /**
+       * 监听鼠标
+       * @param dom dom元素
+       */
+  on(dom) {
+    this.movedom = dom
+    try {
+      if (this.DviceType) {
+        this.movedom.ontouchstart = this.mousedown.bind(this)
+      } else {
+        this.movedom.onmousedown = this.mousedown.bind(this)
+      }
+      this.domw = parseInt(window.getComputedStyle(this.movedom).width)
+      this.domh = parseInt(window.getComputedStyle(this.movedom).height)
+    } catch (error) {
+      console.warn('dom 获取失败')
+    }
+  }
+
+  /**
+       * 移除监听
+       */
+  off() {
+    this.movedom.onmousemove = null
+    this.movedom.onmouseup = null
+    this.movedom.ontouchmove = null
+    this.movedom.ontouchend = null
+  }
+}

+ 7 - 17
src/utils/axios.js

@@ -1,30 +1,20 @@
 import axios from 'axios'
 import axios from 'axios'
-import userData from '@/utils/userdata'
-const userinfo = userData.getUserData() || ''
-
 // http request 拦截
 // http request 拦截
 axios.interceptors.request.use(
 axios.interceptors.request.use(
   (config) => {
   (config) => {
     config.baseURL = process.env.SERVERURL
     config.baseURL = process.env.SERVERURL
-    config.headers['Authorization'] = 'Bearer ' + userinfo.token
+    config.headers['Authorization'] = 'Bearer '
     return config
     return config
   },
   },
-  (err) => { throw err }
+  err => {
+    throw err
+  }
 )
 )
-
 // http response 拦截
 // http response 拦截
 axios.interceptors.response.use(
 axios.interceptors.response.use(
-  (response) => {
-    const data = response.data
-    if (data.code !== 200) {
-      if (data.code === 2002) {
-        // token 错误
-        userData.clear()
-        window.location.href = '/login.html'
-      }
+  (response) => response.data,
+  err => {
+      throw err
     }
     }
-    return data
-  },
-  (error) => { throw error }
 )
 )
 export default axios
 export default axios

+ 0 - 57
src/utils/exportExcel.js

@@ -1,57 +0,0 @@
-import * as XLSX from 'xlsx'
-function openDownloadDialog(url, saveName) {
-    if (typeof url == 'object' && url instanceof Blob) {
-        url = URL.createObjectURL(url); // 创建blob地址
-    }
-    let aLink = document.createElement('a');
-    aLink.href = url;
-    aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
-    let event;
-    if (window.MouseEvent) event = new MouseEvent('click');
-    else {
-        event = document.createEvent('MouseEvents');
-        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-    }
-    aLink.dispatchEvent(event);
-}
-
-// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
-function sheet2blob(sheet, sheetName) {
-    sheetName = sheetName || 'sheet1';
-    let workbook = {
-        SheetNames: [sheetName],
-        Sheets: {}
-    };
-    workbook.Sheets[sheetName] = sheet;
-    // 生成excel的配置项
-    let wopts = {
-        bookType: 'xlsx', // 要生成的文件类型
-        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
-        type: 'binary'
-    };
-    let wbout = XLSX.write(workbook, wopts);
-    let blob = new Blob([s2ab(wbout)], {type: "application/octet-stream"});
-    // 字符串转ArrayBuffer
-    function s2ab(s) {
-        let buf = new ArrayBuffer(s.length);
-        let view = new Uint8Array(buf);
-        for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
-        return buf;
-    }
-    return blob;
-}
- /**
-  * @description: 导出excel
-  * @param {*} arr 数据是数组包含的对象
-  * @param {*} name 名字
-  * @return {*}
-  */
- function exp(arr,name="导出") {
-    var sheet = XLSX.utils.json_to_sheet(arr);
-    // excel宽高设置
-    sheet["!cols"]= arr.map(item=>{
-        return {wch:30}
-    })
-    openDownloadDialog(sheet2blob(sheet), name+'.xlsx')
-}
-export default exp;

+ 99 - 0
src/utils/openseadragon-svg-overlay.js

@@ -0,0 +1,99 @@
+// OpenSeadragon SVG Overlay plugin 0.0.4
+
+export const svgOverlay = function (OpenSeadragon) {
+  if (!OpenSeadragon) {
+    console.error('[openseadragon-svg-overlay] requires OpenSeadragon')
+    return
+  }
+
+  const svgNS = 'http://www.w3.org/2000/svg'
+
+  // ----------
+  OpenSeadragon.Viewer.prototype.svgOverlay = function () {
+    if (this._svgOverlayInfo) {
+      return this._svgOverlayInfo
+    }
+
+    this._svgOverlayInfo = new Overlay(this)
+    return this._svgOverlayInfo
+  }
+
+  // ----------
+  var Overlay = function (viewer) {
+    const self = this
+
+    this._viewer = viewer
+    this._containerWidth = 0
+    this._containerHeight = 0
+
+    this._svg = document.createElementNS(svgNS, 'svg')
+    this._svg.style.position = 'absolute'
+    this._svg.style.left = 0
+    this._svg.style.top = 0
+    this._svg.style.width = '100%'
+    this._svg.style.height = '100%'
+    this._viewer.canvas.appendChild(this._svg)
+
+    this._node = document.createElementNS(svgNS, 'g')
+    this._svg.appendChild(this._node)
+
+    this._viewer.addHandler('animation', () => {
+      self.resize()
+    })
+
+    this._viewer.addHandler('open', () => {
+      self.resize()
+    })
+
+    this._viewer.addHandler('rotate', (evt) => {
+      self.resize()
+    })
+
+    this._viewer.addHandler('resize', () => {
+      self.resize()
+    })
+
+    this.resize()
+  }
+
+  // ----------
+  Overlay.prototype = {
+    // ----------
+    node() {
+      return this._node
+    },
+
+    // ----------
+    resize() {
+      if (this._containerWidth !== this._viewer.container.clientWidth) {
+        this._containerWidth = this._viewer.container.clientWidth
+        this._svg.setAttribute('width', this._containerWidth)
+      }
+
+      if (this._containerHeight !== this._viewer.container.clientHeight) {
+        this._containerHeight = this._viewer.container.clientHeight
+        this._svg.setAttribute('height', this._containerHeight)
+      }
+
+      const p = this._viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(0, 0), true)
+      const zoom = this._viewer.viewport.getZoom(true)
+      const rotation = this._viewer.viewport.getRotation()
+      // TODO: Expose an accessor for _containerInnerSize in the OSD API so we don't have to use the private variable.
+      const scale = this._viewer.viewport._containerInnerSize.x * zoom
+      this._node.setAttribute(
+        'transform',
+        `translate(${p.x},${p.y}) scale(${scale}) rotate(${rotation})`
+      )
+    },
+
+    // ----------
+    onClick(node, handler) {
+      // TODO: Fast click for mobile browsers
+
+      new OpenSeadragon.MouseTracker({
+        element: node,
+        clickHandler: handler
+      }).setTracking(true)
+    }
+  }
+}

+ 36 - 0
src/utils/realDate.js

@@ -0,0 +1,36 @@
+import axios from 'axios'
+import store from 'vuex'
+class RealDataService {
+  constructor() {
+    this.timer = 0
+    this.axios = axios
+    this.RealData()
+  }
+
+  /**
+   * 实时数据
+   */
+  async RealData() {
+    const db = await this.axios.get('/api/v1/getRealData')
+    if (db.status === 200 && db.data.success) {
+      store.commit('setRealDB', db.data.data)
+    }
+  }
+  /**
+   * 定时器
+   * @param time 请求时间
+   */
+  async startTimerGet(time = 5000) {
+    this.timer = setInterval(async () => {
+      await this.RealData()
+    }, time)
+  }
+
+  /**
+   * 清除定时器
+   */
+  stopTimerGet() {
+    clearInterval(this.timer)
+  }
+}
+export default new RealDataService()

+ 1 - 1
src/utils/rem.js

@@ -28,5 +28,5 @@
   recalc()
   recalc()
   if (!doc.addEventListener) { return }
   if (!doc.addEventListener) { return }
   win.addEventListener(resizeEvt, recalc, false)
   win.addEventListener(resizeEvt, recalc, false)
-  console.log('rem自适应')
+  console.log('自适应')
 }(document, window))
 }(document, window))

+ 34 - 31
src/utils/userdata.js

@@ -3,61 +3,64 @@ import MD5 from 'js-md5'
  * 用户加密操作
  * 用户加密操作
  */
  */
 class Userservice {
 class Userservice {
-  constructor() { }
+  constructor() {
+    this.setTime()
+  }
+
   /**
   /**
-   * 加密
-   * @param {string} txt 密码
-   */
+     * 加密
+     * @param {string} txt 密码
+     */
   encryPassword(txt) {
   encryPassword(txt) {
-    const password = MD5(txt)
+    const md5 = MD5(txt)
+    const password = MD5(`${md5}Homey`)
     return password
     return password
   }
   }
+
   /**
   /**
-   * 存储
-   * @param {object} params 参数
-   */
-  saveUserData(params) {
+     * 存储
+     * @param {string} phone 手机号
+     * @param {string} password 密码
+     */
+  saveUserData(phone, password) {
+    const psd = this.encryPassword(password)
     const lastLogin = Date.now()
     const lastLogin = Date.now()
     const uses = {
     const uses = {
-      ...params,
-      lastLogin,
-      token: params.loginInfo.token || ''
+      phone,
+      psd,
+      lastLogin
     }
     }
     const USERS = JSON.stringify(uses)
     const USERS = JSON.stringify(uses)
     localStorage.setItem('userDATA', USERS)
     localStorage.setItem('userDATA', USERS)
     return uses
     return uses
   }
   }
+
   /**
   /**
-   * 获取
-   */
+     * 获取
+     */
   getUserData() {
   getUserData() {
-    const uses = JSON.parse(localStorage.getItem('userDATA')) || null
+    const uses = localStorage.getItem('userDATA')
     return uses
     return uses
   }
   }
+
   /**
   /**
-   * 时间限制24小时
-   */
+     * 时间限制24小时
+     */
   async setTime() {
   async setTime() {
     const nowtime = Date.now()
     const nowtime = Date.now()
-    const data = this.getUserData()
-    if (data && data.lastLogin) {
-      if ((nowtime - data.lastLogin) > (1000 * 60 * 60 * 24)) {
+    const UserData = this.getUserData()
+    const lasttime = await JSON.parse(UserData)
+    if (lasttime && lasttime.lastLogin) {
+      if ((nowtime - lasttime.lastLogin) > (1000 * 60 * 60 * 24)) {
+        console.log('需要重新登录', lasttime)
         localStorage.clear()
         localStorage.clear()
         return false
         return false
-      } else {
-        return true
       }
       }
-    } else {
-      localStorage.clear()
-      return false
+      console.log('不需要重新登录', lasttime)
+      return true
     }
     }
-  }
-
-  /** 
-   * 清楚数据
-   */
-  clear() {
     localStorage.clear()
     localStorage.clear()
+    return false
   }
   }
 }
 }
 export default new Userservice()
 export default new Userservice()

File diff suppressed because it is too large
+ 13 - 0
src/utils/weather.js


+ 0 - 7
src/vite-env.d.ts

@@ -1,7 +0,0 @@
-/// <reference types="vite/client" />
-
-declare module '*.vue' {
-  import type { DefineComponent } from 'vue'
-  const component: DefineComponent<{}, {}, any>
-  export default component
-}

+ 0 - 17
tsconfig.json

@@ -1,17 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "ESNext",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "moduleResolution": "Node",
-    "strict": true,
-    "jsx": "preserve",
-    "sourceMap": true,
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "esModuleInterop": true,
-    "lib": ["ESNext", "DOM"],
-    "skipLibCheck": true
-  },
-  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/utils/*.js"]
-}

+ 80 - 0
vite.config.js

@@ -0,0 +1,80 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import viteCompression from 'vite-plugin-compression'
+import eslint from 'vite-plugin-eslint'
+import path from 'path'
+import glob from 'glob'
+import fs from 'fs'
+// 多页面入口配置
+const entryConfig = function () {
+  const viteconfig = {}
+  // 含有.js的文件
+  const entryFiles = glob.sync('./src/pages/*/*.js')
+  // 获取模板
+  const temp = fs.readFileSync('./index.html')
+  // 模板增加ts入口
+  entryFiles.forEach((entry) => {
+    const projectName = entry.split('/')[3]
+    try {
+      fs.accessSync(`./${projectName}.html`)
+    } catch (error) {
+      // 重构模板
+      const html = temp.toString().replace(/\.\/src\/[^\s]*/g, `${entry}"></script>`)
+      fs.writeFile(`./${projectName}.html`, html, (err) => {
+        if (err) console.error(err)
+      })
+    }
+    viteconfig[projectName] = path.resolve(__dirname, `./${projectName}.html`)
+  })
+  return viteconfig
+}
+
+export default ({ mode }) => defineConfig({
+  base: './',
+  resolve: {
+    alias: {
+      /*
+        路径别名
+        若为文件系统路径必须是绝对路径的形式,否则将以别名原样呈现,不会解析为文件系统路径路径
+      */
+      '@': path.resolve(__dirname, './src')
+    }
+  },
+  plugins: [ vue(), viteCompression({ disable: true }), eslint({ fix: true }) ],
+  server: {
+    host: 'localhost',
+    port: 6547,
+    open: true,
+    strictPort: false,
+    https: false
+    // 反向代理
+    // proxy: {
+    //   '/': {
+    //     target: 'http://172.16.1.215:5000',
+    //     changeOrigin: true,
+    //     rewrite: (path) => path.replace(/^\//, '')
+    //   },
+    // }
+  },
+  build: {
+    rollupOptions: {
+      input: entryConfig(),
+      output: { // 静态资源分类打包
+        chunkFileNames: 'js/[name]-[hash].js',
+        entryFileNames: 'js/[name]-[hash].js',
+        assetFileNames: 'assets/[name]-[hash].[ext]'
+      }
+    },
+    terserOptions: { // 去掉打印
+      compress: {
+        drop_console: true,
+        drop_debugger: true
+      }
+    }
+  },
+  define: { // 环境变量配置
+    'process.env': {
+      SERVERURL: mode === 'development' ? 'http://127.0.0.1:5000' : 'http://127.0.0.1:5000'
+    }
+  }
+})

+ 0 - 54
vite.config.ts

@@ -1,54 +0,0 @@
-import { defineConfig } from 'vite'
-import vue from '@vitejs/plugin-vue'
-import eslint from 'vite-plugin-eslint'
-import path from 'path'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  base: './',
-  resolve: {
-    alias: {
-      /*
-        路径别名
-        若为文件系统路径必须是绝对路径的形式,否则将以别名原样呈现,不会解析为文件系统路径路径
-      */
-      '@': path.resolve(__dirname, './src')
-    }
-  },
-  plugins: [vue(), eslint({ fix: true })],
-  server: {
-    host: 'localhost',
-    port: 6547,
-    open: true,
-    strictPort: false,
-    https: false
-    // 反向代理
-    // proxy: {
-    //   '/': {
-    //     target: 'http://172.16.1.215:5000',
-    //     changeOrigin: true,
-    //     rewrite: (path) => path.replace(/^\//, '')
-    //   },
-    // }
-  },
-  build: {
-    rollupOptions: {
-      input: {
-        admin: path.resolve(__dirname, 'admin.html'),
-        index: path.resolve(__dirname, 'index.html'),
-        login: path.resolve(__dirname, 'login.html')
-      },
-      output: { // 静态资源分类打包
-        chunkFileNames: 'js/[name]-[hash].js',
-        entryFileNames: 'js/[name]-[hash].js',
-        assetFileNames: 'assets/[name]-[hash].[ext]'
-      }
-    },
-    terserOptions: { // 去掉打印
-      compress: {
-        drop_console: true,
-        drop_debugger: true
-      }
-    }
-  },
-})

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