Pārlūkot izejas kodu

Merge remote-tracking branch 'origin/master'

lrf 10 mēneši atpakaļ
vecāks
revīzija
5705b39a9b

+ 7 - 0
index.html

@@ -12,6 +12,13 @@
   </body>
 </html>
 <style>
+  body {
+    margin: 0;
+  }
+  #app {
+    height: 100vh;
+    width: 100vw;
+  }
 </style>
 </body>
 </html>

src/assets/images/401.gif → public/images/401.gif


src/assets/images/404.png → public/images/404.png


src/assets/images/404_cloud.png → public/images/404_cloud.png


src/assets/images/login-bg.jpg → public/images/login-bg.jpg


src/assets/logo.png → public/images/logo.png


BIN
public/images/video.mp4


+ 5 - 4
src/App.vue

@@ -11,11 +11,12 @@ const appStore = useAppStore()
 </template>
 
 <style lang="scss">
-body {
-  margin: 0;
-}
 .w_1200 {
-  width: 1200px;
+  // width: 1200px;
   margin: 0 auto;
 }
+#index {
+  width: 100%;
+  height: 100%;
+}
 </style>

+ 1 - 1
src/layout/index.vue

@@ -33,7 +33,7 @@ import cHeader from './parts/Header.vue'
 import cAside from './parts/Sidebar.vue'
 import tagsBar from './parts/Tagsbar.vue'
 const viewStyle = ref({
-  height: '85vh',
+  height: '81.5vh',
   background: '#ffffff',
   'overflow-x': 'hidden',
   'overflow-y': 'auto',

+ 0 - 1
src/main.js

@@ -3,7 +3,6 @@ import { setupStore } from '@/store'
 
 import App from './App.vue'
 import router from './router'
-
 import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 
 // 本地SVG图标

+ 84 - 34
src/router/guard.js

@@ -1,6 +1,6 @@
 import { AxiosWrapper } from '@/utils/axios-wrapper'
 import { UserStore } from '@/store/user'
-import { cloneDeep, isArray, omit } from 'lodash-es'
+import { cloneDeep, get, isArray, omit } from 'lodash-es'
 import NProgress from 'nprogress'
 import 'nprogress/nprogress.css'
 import { ElMessageBox } from 'element-plus'
@@ -73,7 +73,7 @@ const routesRegister = (menus, defaultRoutes, router) => {
   for (const route of menus) {
     const { type, route_name, path, component, parent_id } = route
     if (!path) {
-      console.log(route)
+      // console.log(route)
     }
     // 检查路由是否已存在,存在跳过
     const hasRoute = defaultRoutes.find((f) => f.path === path)
@@ -127,6 +127,8 @@ const resetMenus = (menus) => {
   return result
 }
 
+const dontRedirectList = ['/login', '/', '/401', '/404']
+
 // 注册前置守卫
 export const registerBeforeRouter = async (router) => {
   router.beforeEach(async (to, from, next) => {
@@ -141,43 +143,91 @@ export const registerBeforeRouter = async (router) => {
       NProgress.inc()
       if (to.path === '/login') next()
       NProgress.inc()
-      const { menus, errcode, errmsg } = await getUserMeta(token)
-      // 登录信息有问题
-      if (errcode !== 0) {
-        if (errcode.includes('FRAMEERROR_401')) {
-          await ElMessageBox.alert(errmsg, i18n.global.t('common.user_confirm'), {
-            confirmButtonText: i18n.global.t('common.re_login'),
-            type: 'error',
-          })
-          next('/login')
+      try {
+        const { menus, errcode, errmsg } = await getUserMeta(token)
+        // 登录信息有问题
+        if (errcode !== 0) {
+          if (errcode.includes('FRAMEERROR_401')) {
+            await ElMessageBox.alert(errmsg, i18n.global.t('common.user_confirm'), {
+              confirmButtonText: i18n.global.t('common.re_login'),
+              type: 'error'
+            })
+            const fp = from.path
+            const noneed = dontRedirectList.includes(fp)
+            if (noneed) next('/login')
+            else next(`/login?redirect=${from.fullPath}`)
+            return
+          } else {
+            await ElMessageBox.alert(errmsg, i18n.global.t('common.user_confirm'), {
+              confirmButtonText: i18n.global.t('common.re_login'),
+              type: 'error'
+            })
+            // location.reload()
+            const fp = from.path
+            const noneed = dontRedirectList.includes(fp)
+            if (noneed) next('/login')
+            else next(`/login?redirect=${from.fullPath}`)
+          }
+        }
+        // 菜单格式不正确
+        if (!menus) {
+          next('/401')
           return
-        } else {
-          await ElMessageBox.alert(errmsg, i18n.global.t('common.user_confirm'), {
-            confirmButtonText: i18n.global.t('common.re_login'),
-            type: 'error'
-          })
-          location.reload()
         }
-      }
-      // 菜单格式不正确
-      if (!menus) {
-        next('/401')
-        return
-      }
-      // 检查目的地路由是否注册
-      const hasRoute = hasNecessaryRoute(to, router)
-      NProgress.inc()
-      if (hasRoute || to.meta.hidden) {
-        // 注册了直接进入
-        next()
-      } else {
-        // 没注册就先注册再重定向进入直到进入为止
-        await addUserRoutes(menus, router)
+        // 检查目的地路由是否注册
+        const hasRoute = hasNecessaryRoute(to, router)
         NProgress.inc()
-        next({ ...to, replace: true })
+        // console.log(`hasRoute`)
+        // console.log(hasRoute)
+        // const t = router.getRoutes()
+        // console.log(`t`)
+        // console.log(JSON.parse(JSON.stringify(t)))
+        if (hasRoute || to.meta.hidden) {
+          // 注册了直接进入
+          // console.log(`if: to.path`)
+          if (get(from, 'query.redirect')) {
+            const redirect = get(from, 'query.redirect')
+            from.query = {}
+            next(redirect)
+            return
+          } else {
+            next()
+            return
+          }
+        } else {
+          // 没注册就先注册再重定向进入直到进入为止
+          await addUserRoutes(menus, router)
+          NProgress.inc()
+          // const t2 = router.getRoutes()
+          // console.log(`t2`)
+          // console.log(JSON.parse(JSON.stringify(t2)))
+          // const t3 = hasNecessaryRoute(to, router)
+          // console.log('t3')
+          // console.log(JSON.parse(JSON.stringify(t3)))
+          // console.log('to')
+          // console.log(JSON.parse(JSON.stringify(to)))
+          // console.log(`else: to.path`)
+          if (get(from, 'query.redirect')) {
+            const redirect = get(from, 'query.redirect')
+            from.query = {}
+            next(redirect)
+          } else {
+            await next(to)
+          }
+
+          // next({ ...to, replace: true })
+        }
+      } catch (error) {
+        const fp = from.path
+        const noneed = dontRedirectList.includes(fp)
+        if (noneed) next('/login')
+        else next(`/login?redirect=${from.fullPath}`)
       }
     } else {
-      next('/login')
+      const fp = from.path
+      const noneed = dontRedirectList.includes(fp)
+      if (noneed) next('/login')
+      else next(`/login?redirect=${from.fullPath}`)
     }
   })
 }

+ 6 - 0
src/router/index.js

@@ -28,6 +28,12 @@ export const constantRoutes = [
     meta: { title: '孵化大脑' },
     component: () => import('@/views/hatch/index.vue')
   },
+  {
+    path: '/video',
+    name: 'Video',
+    meta: { title: '视频播放' },
+    component: () => import('@/views/video/index.vue')
+  },
   {
     path: '/',
     name: 'Layout',

+ 1 - 1
src/views/error-page/401.vue

@@ -9,7 +9,7 @@ defineComponent({
 })
 
 const state = reactive({
-  errGif: new URL(`../../assets/images/401.gif`, import.meta.url).href,
+  errGif: new URL(`/images/401.gif`, import.meta.url).href,
 
   ewizardClap: 'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
   dialogVisible: false

+ 4 - 4
src/views/error-page/404.vue

@@ -15,10 +15,10 @@ function message() {
   <div class="wscn-http404-container">
     <div class="wscn-http404">
       <div class="pic-404">
-        <img class="pic-404__parent" src="@/assets/images/404.png" alt="404" />
-        <img class="pic-404__child left" src="@/assets/images/404_cloud.png" alt="404" />
-        <img class="pic-404__child mid" src="@/assets/images/404_cloud.png" alt="404" />
-        <img class="pic-404__child right" src="@/assets/images/404_cloud.png" alt="404" />
+        <img class="pic-404__parent" src="/images/404.png" alt="404" />
+        <img class="pic-404__child left" src="/images/404_cloud.png" alt="404" />
+        <img class="pic-404__child mid" src="/images/404_cloud.png" alt="404" />
+        <img class="pic-404__child right" src="/images/404_cloud.png" alt="404" />
       </div>
       <div class="bullshit">
         <div class="bullshit__oops">OOPS!</div>

+ 85 - 0
src/views/hatch/dataV/mixin/autoResize.js

@@ -0,0 +1,85 @@
+import { debounce, observerDomResize } from '../util/index'
+
+export default {
+  data () {
+    return {
+      dom: '',
+
+      width: 0,
+      height: 0,
+
+      debounceInitWHFun: '',
+
+      domObserver: ''
+    }
+  },
+  methods: {
+    async autoResizeMixinInit () {
+      const { initWH, getDebounceInitWHFun, bindDomResizeCallback, afterAutoResizeMixinInit } = this
+
+      await initWH(false)
+
+      getDebounceInitWHFun()
+
+      bindDomResizeCallback()
+
+      if (typeof afterAutoResizeMixinInit === 'function') afterAutoResizeMixinInit()
+    },
+    initWH (resize = true) {
+      const { $nextTick, $refs, ref, onResize } = this
+
+      return new Promise(resolve => {
+        $nextTick((_) => {
+          const dom = (this.dom = $refs[ref])
+          // this.width = dom ? dom.clientWidth : 0
+          // this.height = dom ? dom.clientHeight : 0
+          this.width = window.innerWidth
+          this.height = window.innerHeight
+
+          if (!dom) {
+            console.warn('DataV: Failed to get dom node, component rendering may be abnormal!')
+          } else if (!this.width || !this.height) {
+            console.warn('DataV: Component width or height is 0px, rendering abnormality may occur!')
+          }
+
+          if (typeof onResize === 'function' && resize) onResize()
+
+          resolve()
+        })
+      })
+    },
+    getDebounceInitWHFun () {
+      const { initWH } = this
+
+      this.debounceInitWHFun = debounce(100, initWH)
+    },
+    bindDomResizeCallback () {
+      const { dom, debounceInitWHFun } = this
+
+      this.domObserver = observerDomResize(dom, debounceInitWHFun)
+
+      window.addEventListener('resize', debounceInitWHFun)
+    },
+    unbindDomResizeCallback () {
+      let { domObserver, debounceInitWHFun } = this
+
+      if (!domObserver) return
+
+      domObserver.disconnect()
+      domObserver.takeRecords()
+      domObserver = null
+
+      window.removeEventListener('resize', debounceInitWHFun)
+    }
+  },
+  mounted () {
+    const { autoResizeMixinInit } = this
+
+    autoResizeMixinInit()
+  },
+  beforeDestroy () {
+    const { unbindDomResizeCallback } = this
+
+    unbindDomResizeCallback()
+  }
+}

+ 60 - 0
src/views/hatch/dataV/myMain.vue

@@ -0,0 +1,60 @@
+<template>
+  <div id="dv-full-screen-container" :ref="ref">
+    <template v-if="ready">
+      <slot></slot>
+    </template>
+  </div>
+</template>
+
+<script>
+import autoResize from './mixin/autoResize.js'
+
+export default {
+  name: 'DvFullScreenContainer',
+  mixins: [autoResize],
+  data() {
+    return {
+      ref: 'full-screen-container',
+      allWidth: 0,
+      allHeight: 0,
+      scale: 0,
+      datavRoot: '',
+      ready: false
+    }
+  },
+  methods: {
+    afterAutoResizeMixinInit() {
+      const { initConfig, setAppScale } = this
+
+      initConfig()
+
+      setAppScale()
+
+      this.ready = true
+    },
+    initConfig() {
+      const { dom } = this
+      // const { width } = screen
+      let width = window.innerWidth
+      let height = window.innerHeight
+      this.allWidth = width
+      this.allHeight = height
+
+      dom.style.width = `${width}px`
+      dom.style.height = `${height}px`
+    },
+    setAppScale() {
+      const { allWidth, allHeight, dom } = this
+      const currentWidth = window.outerWidth
+      const currentHeight = window.innerHeight
+      // dom.style.transform = `scale(${currentWidth / allWidth})`
+      dom.style.transform = `scaleY(${currentHeight / allHeight}) scaleX(${currentWidth / allWidth})`
+    },
+    onResize() {
+      const { setAppScale } = this
+
+      setAppScale()
+    }
+  }
+}
+</script>

+ 47 - 0
src/views/hatch/dataV/util/index.js

@@ -0,0 +1,47 @@
+export function randomExtend(minNum, maxNum) {
+  if (arguments.length === 1) {
+    return parseInt(Math.random() * minNum + 1, 10)
+  } else {
+    return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10)
+  }
+}
+
+export function debounce(delay, callback) {
+  let lastTime
+
+  return function () {
+    clearTimeout(lastTime)
+
+    const [that, args] = [this, arguments]
+
+    lastTime = setTimeout(() => {
+      callback.apply(that, args)
+    }, delay)
+  }
+}
+
+export function observerDomResize(dom, callback) {
+  const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
+
+  const observer = new MutationObserver(callback)
+
+  observer.observe(dom, { attributes: true, attributeFilter: ['style'], attributeOldValue: true })
+
+  return observer
+}
+
+export function getPointDistance(pointOne, pointTwo) {
+  const minusX = Math.abs(pointOne[0] - pointTwo[0])
+
+  const minusY = Math.abs(pointOne[1] - pointTwo[1])
+
+  return Math.sqrt(minusX * minusX + minusY * minusY)
+}
+
+export function uuid(hasHyphen) {
+  return (hasHyphen ? 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' : 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx').replace(/[xy]/g, function (c) {
+    const r = (Math.random() * 16) | 0
+    const v = c == 'x' ? r : (r & 0x3) | 0x8
+    return v.toString(16)
+  })
+}

+ 44 - 28
src/views/hatch/index.vue

@@ -1,34 +1,51 @@
 <template>
-  <div id="index">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <div class="head">
-          <h1 class="head_1">大数据可视化系统数据分析通用模版</h1>
-          <div class="head_2" id="showTime">{{ formattedTime }}</div>
-        </div>
-        <div class="center">
-          <ul class="clearfix">
-            <li>
-              <div class="boxall" style="height: calc(40% - 0.15rem)">
-                <div class="titleall">模块标题</div>
-                <div class="list">
-                  <div class="list_1" v-for="i in listOne" :key="i.value">
-                    <h2>{{ i.value }}</h2>
-                    <span>{{ i.label }}</span>
+  <myMain>
+    <div id="index" class="main">
+      <el-row>
+        <el-col :span="24" class="animate__animated animate__backInRight" v-loading="loading">
+          <div class="head">
+            <h1 class="head_1">大数据可视化系统数据分析通用模版</h1>
+            <div class="head_2" id="showTime">{{ formattedTime }}</div>
+          </div>
+          <div class="center">
+            <ul class="clearfix">
+              <li>
+                <div class="boxall" style="height: calc(40% - 0.15rem)">
+                  <div class="titleall">模块标题</div>
+                  <div class="list">
+                    <div class="list_1" v-for="i in listOne" :key="i.value">
+                      <h2>{{ i.value }}</h2>
+                      <span>{{ i.label }}</span>
+                    </div>
                   </div>
+                  <div class="boxfoot"></div>
                 </div>
-                <div class="boxfoot"></div>
-              </div>
-            </li>
-          </ul>
-        </div>
-        <div class="bottom">下</div>
-      </el-col>
-    </el-row>
-  </div>
+              </li>
+              <li>
+                <div class="boxall" style="height: calc(40% - 0.15rem)">
+                  <div class="titleall">模块标题</div>
+                  <div class="list">
+                    <div class="list_1" v-for="i in listOne" :key="i.value">
+                      <h2>{{ i.value }}</h2>
+                      <span>{{ i.label }}</span>
+                    </div>
+                  </div>
+                  <div class="boxfoot"></div>
+                </div>
+              </li>
+            </ul>
+            <!-- <Decoration5 style="width: 300px; height: 40px" />" -->
+          </div>
+          <div class="bottom">下</div>
+        </el-col>
+      </el-row>
+    </div>
+  </myMain>
 </template>
 
 <script setup>
+// import { Decoration5 } from '@dataview/datav-vue3'
+import myMain from './dataV/myMain.vue'
 // 加载中
 const loading = ref(false)
 // 时间
@@ -72,8 +89,7 @@ onBeforeUnmount(() => {
 </script>
 <style scoped lang="scss">
 .main {
-  height: 100vh;
-  background: url('./images/bg.jpg') no-repeat center center;
+  background: url('/images/bg.jpg');
   background-size: 100% 100%;
   padding: 0px;
   margin: 0px;
@@ -90,7 +106,7 @@ onBeforeUnmount(() => {
   .head {
     position: relative;
     height: 4.5rem;
-    background: url('./images/head_bg.png') no-repeat center center;
+    background: url('/images/head_bg.png') no-repeat center center;
     background-size: 100% 100%;
     .head_1 {
       color: #fff;

+ 1 - 1
src/views/login/index.vue

@@ -82,7 +82,7 @@ function handleLogin() {
   display: flex;
   align-items: center;
   justify-content: center;
-  background: url('@/assets/images/login-bg.jpg') no-repeat center right;
+  background: url('/images/login-bg.jpg') no-repeat center right;
   .lang {
     display: flex;
     align-items: center;

+ 45 - 0
src/views/video/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <video ref="videoElement" width="100%" height="630px" controls @timeupdate="onTimeUpdate">
+            <source :src="video" type="video/mp4" />
+            Your browser does not support the video tag.
+          </video>
+          <p>观看时长: {{ watchedDuration }} 秒</p>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 图片引入
+import video from '/images/video.mp4'
+// 加载中
+const loading = ref(false)
+const videoElement = ref(null)
+const watchedDuration = ref(0)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  // 监听播放结束事件,如果需要的话
+  videoElement.value.addEventListener('ended', () => {
+    console.log('视频播放结束')
+  })
+  loading.value = false
+})
+const onTimeUpdate = () => {
+  // 获取当前视频的播放时间(以秒为单位)
+  const currentTime = videoElement.value.currentTime
+  // 更新观看时长
+  watchedDuration.value = currentTime
+}
+
+onUnmounted(() => {
+  // 组件卸载时移除事件监听器
+  videoElement.value.removeEventListener('ended', onTimeUpdate)
+})
+</script>
+<style scoped lang="scss"></style>