CzRger 1 year ago
parent
commit
0c16512c54

+ 41 - 0
src/api/index.ts

@@ -0,0 +1,41 @@
+import HttpService from "./request";
+
+export const handle = ({url, params, method,config,filName}: any) => {
+  const httpService = new HttpService()
+  // @ts-ignore
+  return httpService[method.toLowerCase()](url, params,config,filName)
+}
+
+// @ts-ignore
+const files = import.meta.glob("/src/api/modules/**/*.ts")
+const apiModule: any = {}
+const apiRepeatMap = new Map()
+let num1 = 0
+let num2 = 0
+
+for (const [key, value] of Object.entries(files)) {
+  num1++
+  // @ts-ignore
+  value().then(res => {
+    for (const [apiKey, apiValue] of Object.entries(res)) {
+      if (apiKey !== '__tla') { // 过滤掉内部属性,非业务
+        if (apiRepeatMap.has(apiKey)) {
+          apiRepeatMap.set(apiKey, [...apiRepeatMap.get(apiKey), key])
+        } else {
+          apiRepeatMap.set(apiKey, [key])
+        }
+      }
+    }
+    Object.assign(apiModule, res)
+    num2++
+    if (num1 === num2) {
+      apiRepeatMap.forEach((v, k) => {
+        if (v.length > 1) {
+          console.error(`检测到接口${k}重复定义,路径为:`, v)
+        }
+      })
+    }
+  })
+}
+
+export default apiModule

+ 100 - 0
src/api/interceptors.ts

@@ -0,0 +1,100 @@
+import axios from 'axios';
+import {notify} from '@/utils/notify'
+// import {toLogin} from "@/utils/permissions";
+export class Interceptors {
+  public instance: any
+
+  constructor() {
+    this.instance = axios.create({timeout: 1000 * 300})
+    this.initInterceptors()
+  }
+
+  public getInterceptors() {
+    return this.instance
+  }
+
+  public initInterceptors() {
+    // this.instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'
+    /**
+     * 请求拦截器
+     * 每次请求前,如果存在token则在请求头中携带token
+     */
+    this.instance.interceptors.request.use(
+      (config: any) => {
+        if (!config.headers.Authorization) {
+          const token = sessionStorage.getItem('ax_token');
+          if (token) {
+            config.headers.Authorization = token;
+          } else {
+            // @ts-ignore
+            delete config.headers.Authorization
+          }
+        }
+        return config;
+      },
+      (error: any) => {
+      }
+    );
+
+    // 响应拦截器
+    this.instance.interceptors.response.use(
+      // 请求成功
+      (res: any) => {
+        if (res.headers.authorization) {
+          sessionStorage.setItem('ax_token', res.headers.authorization);
+        } else {
+          if (res.data && res.data.code === 200 && res.data.token) {
+            sessionStorage.setItem('ax_token', res.data.token);
+          }
+        }
+        if (res.status === 200) {
+          if(res.data.code === 200){
+            return Promise.resolve(res.data);
+          } else if (res.data.code === 401) {
+            if(res.data.msg){
+              //@ts-ignore
+              notify.warning(res.data.msg);
+            }
+            // toLogin()
+          } else {
+            return Promise.resolve(res.data);
+          }
+        } else {
+          this.errorHandle(res);
+          return Promise.reject(res.data);
+        }
+      },
+      // 请求失败
+      (error: { response: any; }) => {
+        const { response } = error;
+        if (response) {
+          // 请求已发出,但是不在2xx的范围
+          this.errorHandle(response);
+          return Promise.reject(response.data);
+        } else {
+          //@ts-ignore
+          notify.warning('网络连接异常,请稍后再试!');
+          // 抛出报错信息,在页面里需要接收
+          return Promise.reject(error);
+        }
+      });
+  }
+
+  private errorHandle(res: any) {
+    console.error('错误接口:' + res.data.path)
+    // 状态码判断
+    switch (res.status) {
+      case 401:
+        break;
+      case 403:
+        break;
+      case 404:
+        //@ts-ignore
+        notify.warning('请求的资源不存在');
+        break;
+      default:
+        //@ts-ignore
+        notify.warning('连接错误');
+    }
+  }
+}

+ 8 - 0
src/api/modules/ais-test/index.ts

@@ -0,0 +1,8 @@
+import { handle } from '../../index'
+
+const suffix = 'ax-node-api'
+
+export const test = () => handle({
+  url: `/${suffix}/info`,
+  method: 'get',
+})

+ 236 - 0
src/api/request.ts

@@ -0,0 +1,236 @@
+import { Interceptors } from './interceptors';
+import { ElMessage } from "element-plus";
+export class HttpRequest {
+  public axios: any
+  constructor() {
+    // 获取axios实例
+    this.axios = new Interceptors().getInterceptors();
+  }
+  public get(url: string, params: String, config: Object = {}) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      if (params) {
+        paramUrl += `?${params}`
+      }
+      this.axios.get(paramUrl, {
+        ...config
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        console.log(err)
+        reject(err.message);
+      })
+    })
+  }
+
+  public getjson(url: string, params: Object = {}, config: Object = {}) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      let paramStr = ''
+      for (const [key, value] of Object.entries(params)) {
+        if (value !== null && value !== undefined && value !== '') {
+          paramStr += `${key}=${value}&`
+        }
+      }
+      if (paramStr.length > 0) {
+        paramUrl += `?${paramStr.substring(0, paramStr.length - 1)}`
+      }
+      this.axios.get(paramUrl, {
+        ...config
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+   public getjsontab(url: string, params: Object = {}, config: Object = {}) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      let paramStr = ''
+      for (const [key, value] of Object.entries(params)) {
+          paramStr += `${key}=${value}&`
+      }
+      if (paramStr.length > 0) {
+        paramUrl += `?${paramStr.substring(0, paramStr.length - 1)}`
+      }
+      this.axios.get(paramUrl, {
+        ...config
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+  public getid(url: string, params: String, config: Object = {}) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      if (params) {
+        paramUrl += `${params}`
+      }
+      this.axios.get(paramUrl, {
+        ...config
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+  public post(url: string, params: Object, config: Object = {}) {
+    return new Promise((resolve, reject) => {
+      this.axios.post(url, params, {
+        ...config   //  导出添加的下载类型
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+  public put(url: string, params: Object, config: Object = {}) {
+    return new Promise((resolve, reject) => {
+      this.axios.put(url, params, {
+        ...config
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+  public delete(url: string, params: Array<any>) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url + params.toString()
+      this.axios.delete(paramUrl, {
+      }).then((res: any) => {
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+  /**
+   *
+   * @param url   请求路径
+   * @param params  { method  //  封装的请求类型(getId,post,get...) , params{ fileName // 文件名 } // 请求参数   }
+   * @returns
+   */
+
+  public exportfile(url: string, params: any) {
+    console.log(JSON.parse(JSON.stringify(params)))
+    return new Promise((resolve, reject) => {
+      // @ts-ignore
+      this[params.method](url,params.params,{responseType: "blob",}).then((res:any)=>{
+        console.log(JSON.parse(JSON.stringify(res)))
+        if(res.code == 500) return reject(res.message)
+          let blob = new Blob([res], { type: "application/x-xlsx" });
+          let url = URL.createObjectURL(blob);
+          console.log(params)
+          this.downloadFile(url, params.params.fileName);
+          resolve('下载成功!')
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+  public exprotfl(url: String, params: Object) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      if (params) {
+        paramUrl += `?${params}`
+      }
+      this.axios.get(paramUrl, {
+        responseType: "blob",
+      }).then((res: any) => {
+        let blob = new Blob([res], { type: "application/x-xlsx" });
+        let url = URL.createObjectURL(blob);
+        this.downloadFile(url, '船舶信息数据.xlsx');
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+  public examefl(url: String, params: Object,un:string,filName:string) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      if (params) {
+        paramUrl += `?${params}`
+      }
+      this.axios.get(paramUrl, {
+        responseType: "blob",
+      }).then((res: any) => {
+        let blob = new Blob([res], { type: "application/x-xlsx" });
+        let url = URL.createObjectURL(blob);
+        this.downloadFile(url, `${filName}.xlsx`);
+        this.resultHandle(res, resolve, reject, url);
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+  public downloadFile(url: string, filename: string) {
+    const a = document.createElement('a')
+    a.href = url
+    if (filename) a.download = filename
+    a.click()
+  }
+
+  public resultHandle(res: any, resolve: { (value: unknown): void; (value: unknown): void; (arg0: any): void; },reject: { (value: unknown): void; (value: unknown): void; (arg0: any): void; }, url: string) {
+    if (res) {
+      if (res.code === 200 || (res.size > 0 && res.type)) {   //  增加blob文件判断
+        resolve(res);
+      } else {
+        this.errorHandle(res, reject, url);
+      }
+    }
+  }
+
+  public errorHandle(res: any, reject: any, url: string) {
+    console.error('错误接口:' + url)
+    if (res.hasOwnProperty('message')) {
+      ElMessage.warning(res.message);  // 统一谈服务端提示,我们提示统一由服务端提供
+    } else if (res.hasOwnProperty('msg')) {
+      ElMessage.warning(res.msg);  // 统一谈服务端提示,我们提示统一由服务端提供
+    }
+    // 状态码判断
+    if (res) {
+      switch (res.code) {
+        case -102:
+          break;
+        case -152:
+          break;
+        default:
+          reject(res);
+      }
+    }
+  }
+
+  public trackpost(url: string, params: object,filName:string) {
+    return new Promise((resolve, reject) => {
+      let paramUrl = url
+      this.axios.post(paramUrl,params,{
+        headers: { Authorization: sessionStorage.getItem('ax_token') },
+        responseType: "blob",
+      }).then((res: Blob) => {
+        let blob = new Blob([res], { type: "application/x-xlsx" });
+        let url = URL.createObjectURL(blob);
+        this.downloadFile(url, `${filName}.xlsx`);
+        resolve('')
+      }).catch((err: { message: any; }) => {
+        reject(err.message);
+      })
+    })
+  }
+
+}
+
+export default HttpRequest

+ 14 - 0
src/browerPatch.ts

@@ -0,0 +1,14 @@
+// @ts-ignore
+;(function () {
+    if (typeof EventTarget !== 'undefined') {
+        const func = EventTarget.prototype.addEventListener
+        EventTarget.prototype.addEventListener = function (type, fn, capture) {
+            ;(this as any).func = func
+            if (typeof capture !== 'boolean') {
+                capture = capture || {}
+                capture.passive = false
+            }
+            ;(this as any).func(type, fn, capture)
+        }
+    }
+})()

+ 8 - 5
src/main.ts

@@ -5,15 +5,18 @@ import store from "./store"
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
 // @ts-ignore
-import initComponent from './initComponent'
 import './styles/index.scss'
-import * as easyMap from '@/utils/easyMap.ts'
-import * as util from '@/utils/util.ts'
+import './browerPatch'
+import initComponent from '@/plugins/initComponent'
+import initProperties from '@/plugins/initProperties'
+import repeatFileValid from '@/plugins/repeatFileValid'
+import initDirect from '@/plugins/initDirect'
+repeatFileValid()
 const app = createApp(App)
+await initProperties(app)
 initComponent(app)
+app.use(initDirect)
 app.use(router)
 app.use(store)
 app.use(ElementPlus)
-app.config.globalProperties.$util = util
-app.config.globalProperties.$easyMap = easyMap
 app.mount('#app')

src/initComponent.ts → src/plugins/initComponent.ts


+ 164 - 0
src/plugins/initDirect.ts

@@ -0,0 +1,164 @@
+import { App } from 'vue';
+import store from '@/store/index.js';
+
+// @ts-ignore
+interface type_OBj {
+	[key: string]: any
+}
+const screening_Brace = (el: HTMLElement) => {
+	return new Promise((s, e) => {
+		let sta = false, num = 1
+		if (el.className.indexOf('el-slider') != -1 || el.className.indexOf('label') != -1 || el.className.indexOf('title') != -1) {
+			num = 2
+			sta = true
+			return
+		} else if (num === 1) sta = false
+		s(sta)
+	})
+}
+export default {
+	install(Vue: App<Element>) {
+		Vue.directive('drag', {
+			mounted(el: HTMLElement, bind) {
+				el.onmousedown = async function (e: any) {
+					if (['INPUT', 'TEXTAREA', 'CANVAS'].includes(e.target.nodeName) || e.target.className.includes('el-slider')) {
+						return;
+					}
+					const sta = await screening_Brace(e.target)
+					if (sta) return
+					let elLeft = el.offsetLeft;
+					let elTop = el.offsetTop;
+					let x = e.clientX;
+					let y = e.clientY;
+					el.style.transition='unset'
+					document.onmousemove = (move: MouseEvent) => {
+						let left = elLeft - (x - move.clientX);
+						el.style.left = left + 'px'
+						el.style.right = 'unset'
+						let top = elTop - (y - move.clientY);
+						el.style.top = top + 'px'
+						el.style.bottom = 'unset'
+
+						if (window.getSelection()) {
+							// @ts-ignore
+							window.getSelection() ? window.getSelection().removeAllRanges() : null
+						}
+
+					}
+					document.onmouseup = (up: MouseEvent) => {
+						store.dispatch('app/LOAD_IS_DRAG')
+						document.onmousemove = null;
+						document.onmouseup = null;
+					}
+				}
+			},
+			unmounted(el, bind) {
+				el.onmousedown = null;
+			}
+		}),
+		Vue.directive('wheelScale', {
+			mounted(el: HTMLElement, bind) {
+				const setTransformCss = (el, cssVarName) => {
+					let transformCssString = el.style.transform
+					let regScaleGlobal = /scale\(.*?[ )]*[)]+[ ]*/g //匹配 Scale属性 全局
+					if (regScaleGlobal.test(transformCssString)) {
+						transformCssString = transformCssString.replace(
+							regScaleGlobal,
+							` scale(var(${cssVarName})) `
+						)
+					} else {
+						transformCssString += " " + `scale(var(${cssVarName}))`
+					}
+					el.style.transform = transformCssString
+				}
+				const setVarScale = (el, cssVarName, scale) => {
+					let cssText = el.style.cssText
+					let cssTextList = cssText.split(";")
+					let isExist = false
+					let isExistIndex = -1
+					for (let index = 0; index < cssTextList.length; index++) {
+						const element = cssTextList[index]
+						if (element.includes(cssVarName + ":")) {
+							isExist = true
+							isExistIndex = index
+							break
+						}
+					}
+					if (isExist) {
+						cssTextList[isExistIndex] = `--scale: ${scale}`
+					} else {
+						cssTextList.push(`--scale: ${scale}`)
+						//   el.setAttribute("style", `--scale: ${scale}`)
+					}
+					cssText = cssTextList.join(";")
+					el.style.cssText = cssText
+				}
+				const { maxScale = 5, minScale = 0.5, auto = false }: any = bind.value || {}
+				let oldScale: number = 1
+				const cssVarName = "--scale"
+				if (el) {
+					if (auto) {
+						setTimeout(() => {
+							if (el.parentElement) {
+								const l = (el.parentElement.clientWidth - el.clientWidth) / 2
+								const t = (el.parentElement.clientHeight - el.clientHeight) / 2
+								if (l) {
+									el.style.left = `${l}px`
+								}
+								if (t) {
+									el.style.top = `${t}px`
+								}
+								const eRatio = el.clientWidth / el.clientHeight
+								const eParRatio = el.parentElement.clientWidth / el.parentElement.clientHeight
+								if (eRatio > eParRatio) {
+									oldScale = el.parentElement.clientWidth / el.clientWidth
+								} else {
+									oldScale = el.parentElement.clientHeight / el.clientHeight
+								}
+								if (oldScale > maxScale) {
+									oldScale = maxScale
+								}
+								if (oldScale < minScale) {
+									oldScale = minScale
+								}
+								setVarScale(el, cssVarName, oldScale)
+								setTransformCss(el, cssVarName)
+							}
+						}, 300)
+					}
+					el.onwheel = (e: any) => {
+						let _scale: any = el.style.getPropertyValue(cssVarName) || 1
+						if (e.wheelDelta > 0) {
+							_scale = _scale * 1 + 0.1
+						} else {
+							_scale = _scale * 1 - 0.1
+						}
+						// 现在缩放范围
+						if (_scale > maxScale) {
+							_scale = maxScale
+						} else if (_scale < minScale) {
+							_scale = minScale
+						}
+						setVarScale(el, cssVarName, _scale)
+						setTransformCss(el, cssVarName)
+						// 缩放改变回调函数
+						const wheelScaleChange = bind.value || null
+
+						if (wheelScaleChange instanceof Function && _scale != oldScale) {
+							oldScale = _scale
+							wheelScaleChange({
+								cssVarName,
+								currentScale: _scale,
+								maxScale,
+								minScale,
+							})
+						}
+					}
+				}
+			},
+			unmounted(el, bind) {
+				el.onwheel = null
+			}
+		})
+	}
+}

+ 10 - 0
src/plugins/initProperties.ts

@@ -0,0 +1,10 @@
+import { App } from 'vue'
+import * as api from '@/api/index'
+import * as util from '@/utils/util'
+import * as easyMap from '@/utils/easyMap'
+
+export default async (app: App) => {
+    app.config.globalProperties.$api = await api.default
+    app.config.globalProperties.$util = util
+    app.config.globalProperties.$easyMap = easyMap
+}

+ 38 - 0
src/plugins/repeatFileValid.ts

@@ -0,0 +1,38 @@
+const SvgValid = () => {
+  // @ts-ignore
+  const svgs = import.meta.glob("/src/assets/svg/**/*.svg")
+  const svgModule: any = {}
+  const svgRepeatMap = new Map()
+  let num1 = 0
+  let num2 = 0
+  for (const [key, value] of Object.entries(svgs)) {
+    num1++
+    // @ts-ignore
+    value().then(res => {
+      const regex = /\/([^/]+)\.svg$/
+      for (const [svgKey, svgValue] of Object.entries(res)) {
+        // @ts-ignore
+        const result: any = svgValue.match(regex);
+        const text = result[1]; // 获取匹配到的文本
+        if (svgRepeatMap.has(text)) {
+          svgRepeatMap.set(text, [...svgRepeatMap.get(text), key])
+        } else {
+          svgRepeatMap.set(text, [key])
+        }
+      }
+      Object.assign(svgModule, res)
+      num2++
+      if (num1 === num2) {
+        svgRepeatMap.forEach((v, k) => {
+          if (v.length > 1) {
+            console.error(`检测到svg图标${k}重复定义,路径为:`, v)
+          }
+        })
+      }
+    })
+  }
+}
+
+export default (): void => {
+  SvgValid()
+}

+ 140 - 14
src/utils/easyMap.ts

@@ -6,11 +6,13 @@ import * as geom from 'ol/geom'
 import * as proj from 'ol/proj'
 import * as format from 'ol/format'
 import * as extent from 'ol/extent'
+import * as Coordinate from 'ol/coordinate'
+import * as turf from '@turf/turf'
 import store from '@/store/index'
 
 let hasPointClick = false
 let zIndex = 999
-let ctrlHideListGlobal = []
+let ctrlHideListGlobal: any = []
 const activeFeatureMap = new Map()
 const hoverFeatureMap = new Map()
 let moveFlag = false
@@ -18,7 +20,7 @@ let moveFlag = false
 export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick = false, clickHandle = (feature: any) => {}, layerZIndex}) => {
   const _layers = map.getLayers().getArray().filter(v => v.get('easyMapLayerName') === layerName)
   let realLayer = _layers.length > 0 ? _layers[0] : null
-  const features = []
+  const features: any = []
   const featuresMap = new Map()
   list.forEach((v, i) => {
     try {
@@ -101,10 +103,10 @@ export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick =
   } else {
     activeFeatureMap.set(layerName, null)
   }
-    if (realLayer) {
+  if (realLayer) {
     realLayer.setSource(vectorSource)
   } else {
-    realLayer = new layer.VectorImage({
+    realLayer = new layer.VectorImage(<any>{
       source: vectorSource,
       easyMapLayerName: layerName,
       layerType: 'easyMap',
@@ -181,7 +183,7 @@ export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick =
       hoverDialog = setOverlay(hoverEl)
       map.addOverlay(hoverDialog)
     }
-    let pointerMoveTime = null
+    let pointerMoveTime: any = null
     const mapPointerMove = e => {
       clearTimeout(pointerMoveTime)
       pointerMoveTime = setTimeout(() => {
@@ -244,7 +246,7 @@ export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick =
       }, 10)
     }
     map.on('pointermove', mapPointerMove)
-    let ctrlHideList = []
+    let ctrlHideList: any = []
     const mapContextmenu = e => {
       let isFeature = false
       let hoverLayer = {
@@ -262,6 +264,7 @@ export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick =
       }, {
         hitTolerance: 0,
       });
+      // @ts-ignore
       if (ctrlHideList.length > 0 && !window?.event?.ctrlKey && !window?.event.altKey) {
         if (ctrlHideListGlobal[ctrlHideListGlobal.length - 1] === ctrlHideList[ctrlHideList.length - 1]) {
           setTimeout(() => {
@@ -269,10 +272,12 @@ export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick =
             ctrlHideListGlobal.pop()
           }, 100)
         }
-      } else if (ctrlHideList.length > 0 && window?.event.altKey) {
-        switchVisible(ctrlHideList, true)
-        ctrlHideList = []
-        ctrlHideListGlobal = []
+      } else { // @ts-ignore
+        if (ctrlHideList.length > 0 && window?.event.altKey) {
+          switchVisible(ctrlHideList, true)
+          ctrlHideList = []
+          ctrlHideListGlobal = []
+        }
       }
       let pointFlag = true
       map.forEachFeatureAtPixel(e.pixel, (feature) => {
@@ -280,6 +285,7 @@ export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick =
           if (pointFlag) {
             if (feature.get('layerName') === hoverLayer.layerName) {
               pointFlag = false
+              // @ts-ignore
               if (window?.event?.ctrlKey) {
                 switchVisible([feature.get('easyMap').easyMapParams.id], false)
                 ctrlHideList.push(feature.get('easyMap').easyMapParams.id)
@@ -351,18 +357,67 @@ export const getShapeView = (map, position, L = 600) => {
   })
   const resolution = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) / (L / document.body.clientWidth * document.body.clientHeight)
   if (map) {
-    map.getView().animate({
-      center, resolution
-    })
+    if (position.length > 1) {
+      map.getView().animate({
+        center, resolution
+      })
+    } else {
+      map.getView().animate({
+        center, zoom: 12
+      })
+    }
   }
   return {
     center, resolution
   }
 }
 
+export const getShapeView2 = (map, source, L = 600) => {
+  const features = source.getFeatures();
+  const bounce = extent.boundingExtent(
+      features.map((feature) => feature.getGeometry().getExtent())
+  );
+  const center = extent.getCenter(bounce);
+
+  let x = 0;
+  let y = 0;
+  [[bounce[0], bounce[1]], [bounce[2], bounce[3]]].forEach((v) => {
+    if (Math.abs(v[0] - center[0]) > x) {
+      x = Math.abs(v[0] - center[0]);
+    }
+    if (Math.abs(v[1] - center[1]) > y) {
+      y = Math.abs(v[1] - center[1]);
+    }
+  })
+  const resolution =
+      Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) /
+      ((L / document.body.clientWidth) * document.body.clientHeight);
+
+
+  if (map) {
+    map.getView().animate({
+      center,
+      resolution,
+    });
+  }
+  return {
+    center,
+    resolution,
+  };
+};
+
+export const getShapeView3 = (map, source, L = 600) => {
+  map.getView().fit(source.getExtent(), {
+    size: map.getSize(),
+    padding: [50, 50, 50, 50],
+    duration: 1000,
+  });
+};
+
 export const formatPosition = {
   wptTwl: (arr) => {  // WKT POINT ARR TO WKT LINESTRING
-    const temp = arr.map(v => new format.WKT().readFeature(v).getGeometry().getCoordinates())
+    // @ts-ignore
+    const temp = arr.map(v => (new format.WKT().readFeature(v).getGeometry().getCoordinates()))
     return new format.WKT().writeGeometry(new geom.LineString(proj.fromLonLat(temp, 'EPSG:4326')), {
       dataProjection: 'EPSG:4326'
     })
@@ -371,9 +426,19 @@ export const formatPosition = {
     return `POINT(${cpt[0]} ${cpt[1]})`
   },
   wptTcpt: (wpt) => {  // WKT POINT TO coordinates POINT
+    // @ts-ignore
     return new format.WKT().readFeature(wpt).getGeometry().getCoordinates()
   },
+  wptTcptF: (wpt, digits = 0) => {  // WKT POINT TO coordinates format东经北纬 POINT
+    // @ts-ignore
+    const coor = new format.WKT().readFeature(wpt).getGeometry().getCoordinates()
+    const f = Coordinate.toStringHDMS(coor, digits).split(' ')
+    const formatLongitude = `${f[4]}${f[5]}${f[6]}${f[7]}`
+    const formatLatitude = `${f[0]}${f[1]}${f[2]}${f[3]}`
+    return [formatLongitude, formatLatitude]
+  },
   wpnTcpn: (wpn) => {  // WKT POLYGON TO coordinates POLYGON
+    // @ts-ignore
     return new format.WKT().readFeature(wpn).getGeometry().getCoordinates()
   },
   cpnTwpn: (cpn) => {  // coordinates POLYGON TO WKT POLYGON
@@ -383,9 +448,70 @@ export const formatPosition = {
     return `MULTIPOLYGON(${cmpt.map(v1 => `(${v1.map(v => '(' + v.map(c => `${c[0]} ${c[1]}`).join(',') + ')')})`)})`
   },
   wmpnTcmpn: (wmpn) => {  // WKT MULTIPOLYGON TO coordinates MULTIPOLYGON
+    // @ts-ignore
     return new format.WKT().readFeature(wmpn).getGeometry().getCoordinates()
   },
   wlTcl: (wl) => {  // WKT LINESTRING TO coordinates LINESTRING
+    // @ts-ignore
     return new format.WKT().readFeature(wl).getGeometry().getCoordinates()
+  },
+  clTwl: (cl) => {  // coordinates LINESTRING TO WKT LINESTRING
+    return `LINESTRING(${cl.map(c => `${c[0]} ${c[1]}`).join(',')})`
+  }
+}
+
+export const validWkt = {
+  //  点位WKT坐标校验
+  Point: (wkt) => {
+    try {
+      const feat: any = new format.WKT().readFeature(wkt)
+      if (feat.getGeometry().getType() === 'Point') {
+        return true
+      }
+      return false
+    } catch (e) {
+      return false
+    }
+  },
+  //  单线WKT坐标校验
+  LineString: (wkt) => {
+    try {
+      const feat: any = new format.WKT().readFeature(wkt)
+      if (feat.getGeometry().getType() === 'LineString') {
+        return true
+      }
+      return false
+    } catch (e) {
+      return false
+    }
+  },
+  //  单面WKT坐标校验
+  Polygon: (wkt) => {
+    try {
+      const feat: any = new format.WKT().readFeature(wkt)
+      if (feat.getGeometry().getType() === 'Polygon') {
+        return true
+      }
+      return false
+    } catch (e) {
+      return false
+    }
+  },
+  //  单面WKT坐标自相交校验
+  PolygonKinks: (wkt) => {
+    let flag = validWkt.Polygon(wkt)
+    if (flag) {
+      try {
+        // @ts-ignore
+        const poly = turf.polygon(new format.WKT().readFeature(wkt).getGeometry().getCoordinates())
+        const kinks = turf.kinks(poly)
+        if (kinks.features.length > 0) {
+          flag = false
+        }
+      } catch (e) {
+        flag = false
+      }
+    }
+    return flag
   }
 }

+ 23 - 0
src/utils/notify.ts

@@ -0,0 +1,23 @@
+
+/** 防止重复点击重复弹出notify弹框 */
+import { ElMessage } from "element-plus";
+let messageInstance: any = null
+export const notify = (options: any) => {
+  if (messageInstance) {
+    messageInstance.close()
+  }
+  messageInstance = ElMessage(options)
+}
+;["error", "success", "info", "warning"].forEach(type => {
+  // @ts-ignore
+  notify[type] = (options: any) => {
+    if (typeof options === "string") {
+      options = {
+        showClose: true,
+        message: options
+      }
+    }
+    options.type = type
+    return notify(options)
+  }
+})

+ 187 - 27
src/utils/util.ts

@@ -1,5 +1,5 @@
 export const isValue = (val: any) => {
-  if (val === null || val === undefined || val === '') {
+  if (val === null || val === undefined || (typeof val === 'string' && val.trim() === '') || (typeof val === 'object' && val?.length === 0)) {
     return false
   }
   return true
@@ -57,7 +57,7 @@ export const findInListData = (data: Array<any>, current:any, key = "id", childr
 
     if(!!item[children] && Array.isArray(item[children]) && item[children].length > 0){
 
-      const findChildData = findInListData(item[children], current, key, children)
+      const findChildData: any = findInListData(item[children], current, key, children)
 
       if(findChildData) return findChildData
 
@@ -68,7 +68,7 @@ export const findInListData = (data: Array<any>, current:any, key = "id", childr
   return null
 }
 
-export const formatGetParam = (params: Object) => {
+export const formatGetParam = (params: any) => {
   let paramUrl = ''
   Object.keys(params).forEach((v, i) => {
     paramUrl += i === 0 ? `${v}=${encodeURIComponent(params[v])}` : `&${v}=${encodeURIComponent(params[v])}`
@@ -76,7 +76,7 @@ export const formatGetParam = (params: Object) => {
   return paramUrl
 }
 
-export const formatTableHeadFilters = (arr, text = 'dictLabel', value = 'dictValue') => {
+export const formatTableHeadFilters = (arr: Array<any>, text = 'dictLabel', value = 'dictValue') => {
   return arr.map(v => {
     v.value = v[value]
     v.text = v[text]
@@ -84,60 +84,93 @@ export const formatTableHeadFilters = (arr, text = 'dictLabel', value = 'dictVal
   })
 }
 
-export const YMDHms = (date) => {
+export const YMDHms = (date: any) => {
   const _date = new Date(date)
   const Y = `${_date.getFullYear()}`;
   const M = `${_date.getMonth() + 1 < 10 ? `0${_date.getMonth() + 1}` : _date.getMonth() + 1}`;
-  const D = `${_date.getDate() + 1 < 10 ? `0${_date.getDate()}` : _date.getDate()}`;
+  const D = `${_date.getDate() < 10 ? `0${_date.getDate()}` : _date.getDate()}`;
   const H = `${_date.getHours() < 10 ? `0${_date.getHours()}` : _date.getHours()}`;
   const m = `${_date.getMinutes() < 10 ? `0${_date.getMinutes()}` : _date.getMinutes()}`;
   const s = _date.getSeconds() < 10 ? `0${_date.getSeconds()}` : _date.getSeconds();
   return `${Y}-${M}-${D} ${H}:${m}:${s}`;
 }
 
-export const YMD = (date) => {
+export const YMD = (date: any, format = false) => {
   const _date = new Date(date)
   const Y = `${_date.getFullYear()}`;
   const M = `${_date.getMonth() + 1 < 10 ? `0${_date.getMonth() + 1}` : _date.getMonth() + 1}`;
-  const D = `${_date.getDate() + 1 < 10 ? `0${_date.getDate()}` : _date.getDate()}`;
-  return `${Y}-${M}-${D}`;
+  const D = `${_date.getDate() < 10 ? `0${_date.getDate()}` : _date.getDate()}`;
+  return format ? `${Y}年${M}月${D}日` : `${Y}-${M}-${D}`;
+}
+
+export const Hms = (date: any, format = false) => {
+  const _date = new Date(date)
+  const H = `${_date.getHours() < 10 ? `0${_date.getHours()}` : _date.getHours()}`;
+  const m = `${_date.getMinutes() < 10 ? `0${_date.getMinutes()}` : _date.getMinutes()}`;
+  const s = _date.getSeconds() < 10 ? `0${_date.getSeconds()}` : _date.getSeconds();
+  return format ? `${H}时${m}分${s}秒` : `${H}:${m}:${s}`;
 }
 
 //防抖
-export const debounce = function (cb, ms = 0) {
-  let timer = null
+export const debounce = function (cb: any, ms = 0) {
+  let timer: any = null
   return function () {
     if (timer) clearTimeout(timer)
     timer = setTimeout(() => {
+      //  @ts-ignore
       cb.apply(this, arguments)
       timer = null
     }, ms)
   }
 }
 
-export const comTime = (time) => {
+export const comTime = (time: any, format = false) => {
   const sAll = time
   const d = Math.floor(sAll / (1000 * 60 * 60 * 24))
   const h = Math.floor((sAll - d * (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
   const m = Math.floor((sAll - d * (1000 * 60 * 60 * 24) - h * (1000 * 60 * 60)) / (1000 * 60))
   const s = Math.floor((sAll - d * (1000 * 60 * 60 * 24) - h * (1000 * 60 * 60) - m * (1000 * 60)) / 1000)
-  return{
-    d, h, m ,s
+  let result: any = {d, h, m ,s}
+  if (format) {
+    result = ''
+    if (d > 0) {
+      result += d + '天'
+    }
+    if (d > 0 || h > 0) {
+      result += h + '时'
+    }
+    if (d > 0 || h > 0 || m > 0) {
+      result += m + '分'
+    }
+    result += s + '秒'
   }
+  return result
 }
 
-export const comTimeByArea = (start, end) => {
+export const comTimeByArea = (start: any, end: any, format = false) => {
   const sAll = new Date(end).getTime() - new Date(start).getTime()
   const d = Math.floor(sAll / (1000 * 60 * 60 * 24))
   const h = Math.floor((sAll - d * (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
   const m = Math.floor((sAll - d * (1000 * 60 * 60 * 24) - h * (1000 * 60 * 60)) / (1000 * 60))
   const s = Math.floor((sAll - d * (1000 * 60 * 60 * 24) - h * (1000 * 60 * 60) - m * (1000 * 60)) / 1000)
-  return{
-    d, h, m ,s
+  let result: any = {d, h, m ,s}
+  if (format) {
+    result = ''
+    if (d > 0) {
+      result += d + '天'
+    }
+    if (d > 0 || h > 0) {
+      result += h + '时'
+    }
+    if (d > 0 || h > 0 || m > 0) {
+      result += m + '分'
+    }
+    result += s + '秒'
   }
+  return result
 }
 
-export const deepAssign = (...obj) => {
+export const deepAssign = (...obj: any) => {
   const result = Object.assign({}, ...obj)
   for (let item of obj) {
     for (let [idx, val] of Object.entries(item)) {
@@ -151,7 +184,7 @@ export const deepAssign = (...obj) => {
   return result
 }
 
-export const copy = (value) => {
+export const copy = (value: any) => {
   const str = document.createElement('input')
   str.setAttribute('value', value)
   document.body.appendChild(str)
@@ -179,9 +212,9 @@ export const copy = (value) => {
  *    [20.7, '#eeeeee']
  * ])
  */
-export const getGradientColorArray = (precision, colorArr) => {
+export const getGradientColorArray = (precision: any, colorArr: any) => {
   // 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
-  const colorRgb = (sColor) => {
+  const colorRgb = (sColor: any) => {
     const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
     let _sColor = sColor.toLowerCase();
     if (_sColor && reg.test(_sColor)) {
@@ -195,6 +228,7 @@ export const getGradientColorArray = (precision, colorArr) => {
       //处理六位的颜色值
       const sColorChange = [];
       for (let i = 1; i < 7; i += 2) {
+        // @ts-ignore
         sColorChange.push(parseInt("0x" + _sColor.slice(i, i + 2)));
       }
       return sColorChange;
@@ -203,7 +237,7 @@ export const getGradientColorArray = (precision, colorArr) => {
     }
   };
   // 将rgb表示方式转换为hex表示方式
-  const colorHex = (rgb) => {
+  const colorHex = (rgb: any) => {
     const _this = rgb;
     const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
     if (/^(rgb|RGB)/.test(_this)) {
@@ -211,7 +245,7 @@ export const getGradientColorArray = (precision, colorArr) => {
       let strHex = "#";
       for (let i = 0; i < aColor.length; i++) {
         let hex = Number(aColor[i]).toString(16);
-        hex = hex < 10 ? 0 + '' + hex : hex;// 保证每个rgb的值为2位
+        hex = Number(hex) < 10 ? 0 + '' + hex : hex;// 保证每个rgb的值为2位
         if (hex === "0") {
           hex += hex;
         }
@@ -236,17 +270,17 @@ export const getGradientColorArray = (precision, colorArr) => {
       return _this;
     }
   }
-  const rgb2hex = (sRGB) => {
+  const rgb2hex = (sRGB: any) => {
     const reg = /^(RGB|rgb)\((\d+),\s*(\d+),\s*(\d+)\)$/
     if (!reg.test(sRGB)) return sRGB
     const rgbArr = sRGB.match(/\d+/g)
-    const resultRgbArr = rgbArr.map(v => {
+    const resultRgbArr = rgbArr.map((v: any) => {
       if (+v > 16) return (+v).toString(16)
       return '0' + (+v).toString(16)
     })
     return '#' + resultRgbArr.join('')
   }
-  const gradientColor = (startColor, endColor, step) => {
+  const gradientColor = (startColor: any, endColor: any, step: any) => {
     const startRGB = colorRgb(startColor);//转换为rgb数组模式
     const startR = startRGB[0];
     const startG = startRGB[1];
@@ -262,12 +296,13 @@ export const getGradientColorArray = (precision, colorArr) => {
     for (let i = 0; i <= step; i++) {
       //计算每一步的hex值
       const hex = colorHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')');
+      // @ts-ignore
       colorArr.push(rgb2hex(hex));
     }
     return colorArr;
   }
   const colorMap = new Map()
-  colorArr.forEach((v, i) => {
+  colorArr.forEach((v: any, i: number) => {
     if (i < colorArr.length - 1) {
       const _arr = gradientColor(v[1], colorArr[i + 1][1], (Number(colorArr[i + 1][0]) - Number(v[0])) / precision)
       _arr.forEach((cV, cI) => {
@@ -279,3 +314,128 @@ export const getGradientColorArray = (precision, colorArr) => {
   })
   return colorMap
 }
+// 根据部门名称 寻找上级所有父节点名称
+//data:要遍历的数据, target:查找目标, result用于装查找结果的数组
+export const findParent = (data: any, target: any, result: any) => {
+  for (let item of data) {
+    if (item.deptName === target) {
+      //将查找到的目标数据加入结果数组中
+      //可根据需求unshift(item.id)或unshift(item)
+      result.unshift(item.deptName);
+      return true;
+    }
+    if (item.children && item.children.length > 0) {
+      let isFind = findParent(item.children, target, result);
+      if (isFind) {
+        result.unshift(item.deptName);
+        return true;
+      }
+    }
+  }
+  return false;
+};
+
+// 涉及到跨域问题,需要配nginx代理的url地址处理
+export const proxyNginxUrl = (url: string) => {
+  if (url) {
+    //  @ts-ignore
+    const apiMapper = window.cusConfig?.nginxApiMapper || new Map()
+    let newUrl = url
+    apiMapper.forEach((v: any, k: any) => {
+      if (url.includes(k)) {
+        newUrl =  v + url.substring(url.indexOf(k) + k.length, url.length)
+      }
+    })
+    return newUrl
+  }
+  return url
+};
+
+//  后端接口拦截 <  > 内的文本,正反向格式化为  /《/   /》/    res = true 为接收返回值进行格式化
+export const formatInputHtmlInterceptor = (html: string, res = true) => {
+  if (html) {
+    const map = new Map()
+    map.set('<', '_《_')
+    map.set('>', '_》_')
+    let nHtml = html.toString()
+    map.forEach((v, k) => {
+      if (res) {
+        nHtml = nHtml.replace(eval(`/${v}/g`), k)
+      } else {
+        nHtml = nHtml.replace(eval(`/${k}/g`), v)
+      }
+    })
+    return nHtml
+  }
+  return html
+}
+
+
+
+//生成从minNum到maxNum的随机数
+// export  const randomNum = (minNum: number,maxNum: number) => {
+//   return parseInt(String(Math.random() * (maxNum - minNum + 1) + minNum),10);
+// }
+
+export const randomNum = (min = 0, max = 0, decimal=0) => {
+  // 获取数值的小数部分
+  const getDecimalNum = (data: number) => {
+    return Number(data.toString().split('.')[1]);
+  }
+  let min_z = Math.trunc(min); // 最小值的整数部分
+  let max_z = Math.trunc(max); // 最大值的整数部分
+  // 判断是否存在小数部分,不存在的话为0
+  let min_x = isNaN(getDecimalNum(min)) ? 0 : getDecimalNum(min);  // 最小值的小数部分
+  let max_x = isNaN(getDecimalNum(max)) ? 0 : getDecimalNum(max);  // 最大值的小数部分
+
+  // 区分有小数和没小数的情况
+  if (min_x > 0 || max_x > 0 || decimal > 0) {
+    // 整数部分随机数
+    let z = parseInt(String(Math.random() * (max_z - min_z + 1) + min_z), 10);
+    // 小数部分随机数
+    let x = 0;
+    // 小数部分随机数最大位数
+    let max_decimal = min_x.toString().length > max_x.toString().length ? min_x.toString().length : max_x.toString().length;
+    max_decimal = decimal > max_decimal ? decimal : max_decimal;
+    // 判断随机出的整数部分,是否等于最小值或者最大值
+    if(z == min_z || z == max_z){
+      if(z == min_z){
+        // 整数部分随机数等于最小值,那么应该从最小值的小数部分开始,到小数位数的最大值随机就可以
+        x = parseInt(String(Math.random() * (Math.pow(10, max_decimal) - min_x) + min_x), 10);
+      }else{
+        // 整数部分随机数等于最大值,那么应该从0开始,到最大值小数部分
+        x = parseInt(String(Math.random() * (max_x + 1)), 10);
+      }
+    }else{
+      // 整数部分在最大最小值区间的,就从0到小数位数的最大值随机就可以
+      x = parseInt(String(Math.random() * (Math.pow(10, max_decimal))), 10);
+    }
+    return Number(`${z}.${x}`);
+  } else {
+    return parseInt(String(Math.random() * (max_z - min_z + 1) + min_z), 10);
+  }
+}
+
+/**
+ *
+ * @param val 处理的数值
+ * @param unit  单位,默认空字符
+ * @param digits  小数,默认1
+ */
+export const formatNumberUnit = (val, unit = '', digits = 1) => {
+  let num = ''
+  let str = ''
+  if (String(val).length < 5) {
+    num = val
+    str = unit
+  } else if (String(val).length < 9) {
+    num = Number((Number(val) / 10000).toFixed(digits)) / 1 + ''
+    str = '万' + unit
+  } else if (String(val).length < 13) {
+    num = Number((Number(val) / 10000 / 10000).toFixed(digits)) / 1 + ''
+    str = '亿' + unit
+  }
+  return {
+    num: num, unit: str
+  }
+}

+ 64 - 0
src/views/ais-test/index.vue

@@ -0,0 +1,64 @@
+<template>
+  <div class="main">
+    <EasyMapComponent
+        class="map"
+        layout="info"
+        @easyMapLoad="mapLoad"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import {
+  defineComponent,
+  computed,
+  onMounted,
+  ref,
+  reactive,
+  watch,
+  getCurrentInstance,
+  ComponentInternalInstance,
+  toRefs,
+  nextTick
+} from 'vue'
+import {useStore} from 'vuex'
+import {useRouter, useRoute} from 'vue-router'
+import {ElMessage, ElMessageBox} from "element-plus";
+import axios from "axios";
+import * as style from 'ol/style'
+
+export default defineComponent({
+  name: '',
+  components: {
+  },
+  props: {},
+  setup(props, {emit}) {
+    const store = useStore();
+    const router = useRouter();
+    const route = useRoute();
+    const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
+    const state = reactive({
+      map: <any>null,
+      mapFunc: <any>null,
+    })
+    const mapLoad = (map, func) => {
+      state.map = map
+      state.mapFunc = func
+    }
+    onMounted(() => {
+      that.$api.test()
+    })
+    return {
+      ...toRefs(state),
+      mapLoad
+    }
+  },
+})
+</script>
+
+<style scoped lang="scss">
+.main {
+  width: 100%;
+  height: 100vh;
+}
+</style>

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

@@ -1 +0,0 @@
-/// <reference types="vite/client" />

+ 7 - 0
vite.config.ts

@@ -49,6 +49,13 @@ export default defineConfig({
           return path.replace(/^\/api/, '')
         }
       },
+      '/ax-node-api': {
+        target: 'http://localhost:3000/',
+        changeOrigin: true,
+        rewrite: path => {
+          return path.replace(/^\/ax-node-api/, '')
+        }
+      },
       '/EzServer6-api': {
         target: 'http://74.10.28.116:8090/',
         changeOrigin: true,