rindy hace 2 años
padre
commit
2237188875

+ 4 - 0
.env

@@ -1,2 +1,6 @@
+# 静态资源地址
+VUE_APP_CDN_URL=https://4dkk.4dage.com/v4/www/
+# sdk文件地址
+VUE_APP_SDK_DIR=https://4dkk.4dage.com/v4-test/www/sdk/
 # 静态资源目录
 VUE_APP_STATIC_DIR=static

+ 31 - 0
public/smart-kankan.html

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="">
+    <head>
+        <meta charset="utf-8" />
+        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
+        <title></title>
+        <style>
+            html,
+            body {
+                width: 100%;
+                height: 100%;
+                margin: 0;
+                overflow: hidden;
+            }
+            #app {
+                width: 100%;
+                height: 100%;
+            }
+        </style>
+    </head>
+
+    <body>
+        <noscript>
+            <strong>We're sorry but doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+        </noscript>
+        <div id="app"></div>
+        <script src="<%= BASE_URL %><%= VUE_APP_SDK_DIR %>kankan-sdk-deps.js?v=<%= VUE_APP_VERSION %>"></script>
+        <script src="<%= BASE_URL %><%= VUE_APP_SDK_DIR %>kankan-sdk.js?v=<%= VUE_APP_VERSION %>"></script>
+    </body>
+</html>

+ 2 - 1
public/smart-viewer.html

@@ -5,8 +5,9 @@
         <meta charset="utf-8" />
         <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
         <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/iconfont/iconfont.css" />
-        <link rel="stylesheet" href="//at.alicdn.com/t/c/font_3693743_uzux8act1jo.css" />
+        <link rel="stylesheet" href="//at.alicdn.com/t/c/font_3693743_qnz6eozqyvk.css" />
         <script src="<%= VUE_APP_STATIC_DIR %>/lib/three.js/build/three.min.js"></script>
+        <script src="<%= VUE_APP_STATIC_DIR %>/lib/base64.min.js"></script>
     </head>
     <body>
         <noscript>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 0
public/static/lib/base64.min.js


+ 0 - 156
public/test-bim.html

@@ -1,156 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <!-- 本DEMO中将演示如何通过API设置自定义模型显示视角及工具条上的HOME视图 -->
-
-  <head>
-    <meta charset="utf-8" />
-    <title>自定义HOME视图</title>
-    <style type="text/css">
-      * {
-        margin: 0;
-        padding: 0;
-      }
-
-      html,
-      body {
-        height: 100%;
-      }
-
-      .buttons {
-        font-size: 0;
-      }
-
-      .button {
-        margin: 5px 0 5px 5px;
-        width: 100px;
-        height: 30px;
-        border-radius: 3px;
-        border: none;
-        background: #32d3a6;
-        color: #ffffff;
-      }
-
-      .main {
-        display: flex;
-        flex-direction: column;
-        overflow: hidden;
-        height: 100%;
-      }
-
-      #domId {
-        flex: 1;
-      }
-    </style>
-  </head>
-
-  <body>
-    <!-- 定义DOM元素,用于在该DOM元素中显示模型或图纸 -->
-    <div class="main">
-      <div class="buttons">
-        <button class="button" id="btnCustomView" onclick="customView()">
-          设置HOME视图
-        </button>
-      </div>
-      <!-- 定义DOM元素,用于在该DOM元素中显示模型或图纸 -->
-      <div id="domId"></div>
-    </div>
-    <!-- 引用BIMFACE的JavaScript显示组件库 -->
-    <script src="https://static.bimface.com/api/BimfaceSDKLoader/BimfaceSDKLoader@latest-release.js"></script>
-    <script>
-      let viewToken = "fe69c34c232047989b3619489027d9df";
-      // 声明Viewer及App
-      let viewer3D;
-      let app;
-      let viewAdded = false;
-      let cameraState = {
-        name: "persp",
-        position: {
-          x: -15290.504153609158,
-          y: -11705.98598911822,
-          z: 6547.152792941356,
-        },
-        target: {
-          x: 35869.08012166626,
-          y: 23950.30963410126,
-          z: -9486.25721153848,
-        },
-        up: {
-          x: 0,
-          y: -0.0000036732050934432307,
-          z: 0.9999999999932538,
-        },
-        fov: 45,
-      };
-      // 配置JSSDK加载项
-      window.onload = function () {
-        let loaderConfig = new BimfaceSDKLoaderConfig();
-        loaderConfig.viewToken = viewToken;
-        BimfaceSDKLoader.load(loaderConfig, successCallback, failureCallback);
-      };
-      // 加载成功回调函数
-      let worldPosition = new Array();
-      function successCallback(viewMetaData) {
-        let dom4Show = document.getElementById("domId");
-        // 设置WebApplication3D的配置项
-        let webAppConfig =
-          new Glodon.Bimface.Application.WebApplicationRfaConfig();
-        webAppConfig.domElement = dom4Show;
-        webAppConfig.EnableFamilyList = false;
-        // 设置模型爆炸配置项
-        webAppConfig.enableExplosion = true;
-        // 创建WebApplication3D,用以显示模型
-        app = new Glodon.Bimface.Application.WebApplicationRfa(webAppConfig);
-        app.addView(viewToken);
-        viewer3D = app.getViewer();
-        // 监听添加view完成的事件
-        viewer3D.addEventListener(
-          Glodon.Bimface.Viewer.Viewer3DEvent.ViewAdded,
-          function () {
-            setCameraStatus();
-            //自适应屏幕大小
-            window.onresize = function () {
-              viewer3D.resize(
-                document.documentElement.clientWidth,
-                document.documentElement.clientHeight - 40
-              );
-            };
-            viewAdded = true;
-            // 渲染3D模型
-            viewer3D.render();
-          }
-        );
-        
-        viewer3D.addEventListener(Glodon.Bimface.Viewer.Viewer3DEvent.MouseClicked,function (objectdata) {
-          // 调用viewerDrawing对象的Method,可以继续扩展功能
-          alert("objectId : " + JSON.stringify(objectdata.objectId) + "\n" + "worldPosition : " + JSON.stringify(objectdata.worldPosition));
-        });
-        
-        
-        
-      }
-
-      // 加载失败回调函数
-      function failureCallback(error) {
-        console.log(error);
-      }
-      function setCameraStatus() {
-        viewer3D.setCameraStatus(cameraState);
-      }
-
-      // ************************** 设置自定义HOME视图 **************************
-      let homeview;
-      function customView() {
-        if (!viewAdded) {
-          return;
-        } else {
-          homeview = viewer3D.getCameraStatus();
-          viewer3D.recordCustomHomeview(homeview);
-          window.alert(JSON.stringify(homeview));
-          viewer3D.render();
-        }
-      }
-      
-      
-    </script>
-  </body>
-</html>

+ 288 - 0
src/components/header/Login.vue

@@ -0,0 +1,288 @@
+<template>
+    <Teleport to="body">
+        <div class="login-layer">
+            <div class="login-box">
+                <span class="close" @click="emits('close')"><i class="iconfont icon-close"></i></span>
+                <div class="area">
+                    <h4>用户登录</h4>
+                    <div class="input">
+                        <span class="icon">
+                            <i class="iconfont icon-user"></i>
+                        </span>
+                        <input type="text" v-model.trim="username" />
+                        <div class="tips" v-show="errors.username">{{ errors.username }}</div>
+                    </div>
+                    <div class="input">
+                        <span class="icon">
+                            <i class="iconfont icon-password"></i>
+                        </span>
+                        <input :type="showpass ? 'text' : 'password'" v-model.trim="password" />
+                        <div class="tips" v-show="errors.password">{{ errors.password }}</div>
+                        <span class="showpass" @click="showpass = !showpass">
+                            <i class="iconfont" :class="[showpass ? 'icon-log_eye_selected' : 'icon-log_eye_normal']"></i>
+                        </span>
+                    </div>
+                    <div class="remember">
+                        <div @click="remember = !remember">
+                            <div class="checkbox" :class="{ checked: remember }"></div>
+                            <div class="checkbox-label">记住密码</div>
+                        </div>
+                    </div>
+                    <div class="button">
+                        <button type="submit" @click="onLogin">登录</button>
+                        <div class="tips" v-show="errors.message">{{ errors.message }}</div>
+                    </div>
+                    <div class="links">
+                        <a href="http://test.4dkankan.com/#/login/forget?from=%2F">忘记密码</a>
+                        <a href="http://test.4dkankan.com/#/login/register?from=%2F">官网注册</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </Teleport>
+</template>
+<script setup>
+import { ref, onMounted } from 'vue'
+import { http } from '@/utils/request'
+import common from '@/utils/common'
+const emits = defineEmits(['close','user'])
+const showpass = ref(false)
+const remember = ref(false)
+const username = ref('')
+const password = ref('')
+const errors = ref({})
+const onLogin = () => {
+    errors.value = {}
+    if (!username.value) {
+        errors.value.username = '手机号码不能为空'
+        return
+    }
+    if (!/^1[3-9]\d{9}$/.test(username.value)) {
+        errors.value.username = '请输入正确手机号'
+        return
+    }
+    if (!password.value) {
+        errors.value.password = '密码不能为空'
+        return
+    }
+
+    http.post(`smart-site/fdLogin`, {
+        password: common.encodeStr(Base64.encode(password.value)),
+        phoneNum: username.value,
+        rememberMe: remember.value,
+        randomcode: '1234',
+    })
+        .then(response => {
+            if (response.success) {
+                if (remember.value) {
+                    localStorage.setItem('remember', true)
+                    localStorage.setItem('username', username.value)
+                    localStorage.setItem('password', password.value)
+                } else {
+                    localStorage.removeItem('remember')
+                    localStorage.removeItem('username')
+                    localStorage.removeItem('password')
+                }
+                localStorage.setItem('token',response.data.token)
+                emits('user',response.data.user)
+            } else {
+                errors.value.message = response.message
+            }
+        })
+        .catch(() => {
+            alert('服务器连接失败')
+        })
+}
+onMounted(() => {
+    if (localStorage.getItem('remember')) {
+        remember.value = true
+        username.value = localStorage.getItem('username') || ''
+        password.value = localStorage.getItem('password') || ''
+    }
+})
+</script>
+<style lang="scss" scoped>
+.login-layer {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    z-index: 9999;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.login-box {
+    padding: 0 40px;
+    position: absolute;
+    width: 440px;
+    height: 482px;
+    background: rgba(27, 27, 28, 0.8);
+    box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+    border-radius: 4px 4px 4px 4px;
+    opacity: 1;
+    border: 1px solid #000000;
+    backdrop-filter: blur(4px);
+    color: #fff;
+
+    h4 {
+        font-size: 24px;
+        color: #999999;
+        font-weight: 400;
+        padding-bottom: 20px;
+        border-bottom: solid 1px rgba(255, 255, 255, 0.16);
+        margin-top: 60px;
+        margin-bottom: 0px;
+    }
+
+    .close {
+        cursor: pointer;
+        position: absolute;
+        top: 20px;
+        right: 20px;
+        color: rgba(255, 255, 255, 0.8);
+        i {
+            font-size: 14px;
+        }
+    }
+
+    .tips {
+        position: absolute;
+        left: 0;
+        top: 38px;
+        font-size: 12px;
+        color: rgba(250, 85, 85, 1);
+    }
+
+    .input {
+        position: relative;
+        height: 34px;
+        margin-top: 30px;
+        background: rgba(255, 255, 255, 0.1);
+        border-radius: 4px 4px 4px 4px;
+        border: 1px solid rgba(255, 255, 255, 0.2);
+        display: flex;
+        .icon {
+            position: relative;
+            width: 36px;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            &::after {
+                content: '';
+                position: absolute;
+                right: 0;
+                top: 50%;
+                width: 1px;
+                height: 20px;
+                margin-top: -10px;
+                background-color: rgba(255, 255, 255, 0.2);
+            }
+        }
+
+        .showpass {
+            cursor: pointer;
+            position: absolute;
+            top: 50%;
+            right: 10px;
+            transform: translateY(-50%);
+        }
+        input {
+            flex: 1;
+            width: 100%;
+            height: 100%;
+            border: none;
+            background: transparent;
+            outline: none;
+            padding: 0 10px;
+            color: #fff;
+        }
+    }
+
+    .remember {
+        margin-top: 30px;
+
+        > div {
+            cursor: pointer;
+            display: inline-block;
+            position: relative;
+            white-space: nowrap;
+        }
+    }
+
+    .checkbox {
+        display: inline-block;
+        position: relative;
+        width: 16px;
+        height: 16px;
+        margin-right: 5px;
+        &::before {
+            content: '';
+            border: 1px solid #0076f6;
+            border-radius: 2px;
+            width: 16px;
+            height: 16px;
+            position: absolute;
+            left: 0px;
+            top: 0;
+            display: inline-block;
+        }
+        &.checked {
+            &::after {
+                left: 4px;
+                top: 7px;
+                position: absolute;
+                display: table;
+                border: 2px solid #0076f6;
+                border-top: 0;
+                border-left: 0;
+                transform: rotate(45deg) translate(-50%, -50%);
+                opacity: 1;
+                transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
+                width: 6px;
+                height: 8px;
+                content: ' ';
+            }
+        }
+    }
+
+    .checkbox-label {
+        display: inline-block;
+        vertical-align: 3px;
+    }
+
+    .button {
+        position: relative;
+        margin-top: 40px;
+        button {
+            cursor: pointer;
+            color: #fff;
+            width: 100%;
+            height: 34px;
+            background: #0076f6;
+            border-radius: 2px;
+            border: none;
+            outline: none;
+        }
+        .tips {
+            text-align: center;
+            top: 40px;
+            width: 100%;
+        }
+    }
+    .links {
+        margin-top: 40px;
+        display: flex;
+        justify-content: space-between;
+        a {
+            color: #0076f6;
+            text-decoration: none;
+            &:hover {
+                text-decoration: underline;
+            }
+        }
+    }
+}
+</style>

+ 85 - 0
src/components/header/index.vue

@@ -0,0 +1,85 @@
+<template>
+    <header>
+        <div v-if="project">{{ project.projectName }}</div>
+        <div class="user">
+            <ul>
+                <li>
+                    <i class="iconfont icon-share"></i>
+                </li>
+                <li><em></em></li>
+                <li class="login" @click="showLogin = true"><span>登录</span></li>
+            </ul>
+        </div>
+        <Login v-if="showLogin" @close="showLogin = false" />
+    </header>
+</template>
+<script setup>
+import { ref,defineProps, onMounted } from 'vue'
+import { http } from '@/utils/request'
+import Login from './Login'
+const props = defineProps({
+    project: Object,
+})
+const showLogin = ref(false)
+const getUserInfo = () => {
+    http.post(`smart-site/getUserInfo`)
+        .then(response => {
+            if (response.success) {
+            } else {
+                if (response.code == 4008) {
+                    // 未登录
+                }
+            }
+        })
+        .catch(() => {})
+}
+onMounted(() => {})
+</script>
+<style lang="scss" scoped>
+ul,
+li {
+    margin: 0;
+    padding: 0;
+    list-style: none;
+}
+header {
+    position: relative;
+    height: 60px;
+    background-color: #1a1b1d;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 16px;
+}
+.user {
+    position: absolute;
+    top: 0;
+    right: 20px;
+    bottom: 0;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+    ul {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+    }
+    i {
+        font-size: 18px;
+    }
+    em {
+        margin: 0 20px;
+        display: inline-block;
+        width: 1px;
+        height: 16px;
+        vertical-align: -2px;
+        background-color: rgba(255, 255, 255, 0.16);
+    }
+
+    .login{
+        cursor: pointer;
+        color:rgba(0, 118, 246, 1) ;
+    }
+}
+</style>

+ 2 - 11
src/pages/Viewer.vue

@@ -1,7 +1,5 @@
 <template>
-    <header v-show="!fscChecked">
-        <div v-if="project">{{ project.projectName }}</div>
-    </header>
+    <AppHeader v-show="!fscChecked" :project="project" />
     <article>
         <main>
             <div class="split" v-if="source">
@@ -48,6 +46,7 @@
 import { ref, onMounted, computed } from 'vue'
 import { http } from '@/utils/request'
 import browser from '@/utils/browser'
+import AppHeader from '@/components/header'
 import Calendar from '@/components/calendar'
 import ConvertViews from '@/utils/ConvertViews'
 
@@ -423,14 +422,6 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
-header {
-    height: 60px;
-    background-color: #1a1b1d;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 16px;
-}
 article {
     display: flex;
     width: 100%;

+ 7 - 0
src/pages/kankan.js

@@ -0,0 +1,7 @@
+import browser from '../utils/browser'
+
+window.app = new KanKan({
+    dom: '#app',
+    num: browser.valueFromUrl('m')
+})
+app.render()

+ 52 - 53
src/utils/common.js

@@ -1,4 +1,3 @@
-import { getApp } from '@/app'
 export default {
     deepExtend: function e(t) {
         t = t || {}
@@ -8,17 +7,6 @@ export default {
         }
         return t
     },
-    changeUrl(name) {
-        if (name.indexOf('http') != -1) {
-            return name
-        } else {
-            if ((typeof name === 'string' && name.substring(0, 4) == 'blob') || (typeof name === 'string' && name.substring(0, 10) == 'data:image')) {
-                return name
-            } else {
-                return getApp().resource.getUserResourceURL(name)
-            }
-        }
-    },
     getRandomSid() {
         //5-7位随机字符串 + 6位时间    为热点准备
         var pre = this.randomWord(true, 5, 7)
@@ -93,7 +81,7 @@ export default {
                 'W',
                 'X',
                 'Y',
-                'Z'
+                'Z',
             ]
 
         if (randomFlag) {
@@ -106,56 +94,67 @@ export default {
         }
         return str
     },
-    
-    
-    
-    ifSame : function(object1, object2){
-        if(object1 == object2  )return true // 0 != undefined  , 0 == ''
-        else if(!object1 || !object2) return false
-        else if(object1.constructor != object2.constructor){
+
+    ifSame: function (object1, object2) {
+        if (object1 == object2) return true // 0 != undefined  , 0 == ''
+        else if (!object1 || !object2) return false
+        else if (object1.constructor != object2.constructor) {
             return false
-        }else if(object1 instanceof Array ) {
-            if(object1.length != object2.length)return false;
-            var _object2 = object2.slice(0);
-            
-            for(let i=0;i<object1.length;i++){ 
-                var u = _object2.find(e=>ifSame(object1[i], e));
-                if(u == void 0 && !_object2.includes(u) && !object1.includes(u))return false;
-                else{
-                    let index = _object2.indexOf(u);
-                    _object2.splice(index,1);
+        } else if (object1 instanceof Array) {
+            if (object1.length != object2.length) return false
+            var _object2 = object2.slice(0)
+
+            for (let i = 0; i < object1.length; i++) {
+                var u = _object2.find(e => ifSame(object1[i], e))
+                if (u == void 0 && !_object2.includes(u) && !object1.includes(u)) return false
+                else {
+                    let index = _object2.indexOf(u)
+                    _object2.splice(index, 1)
                 }
             }
-            
+
             return true
-        }else if(object1.equals instanceof Function ){//复杂数据仅支持这种,其他的可能卡住?
-            
+        } else if (object1.equals instanceof Function) {
+            //复杂数据仅支持这种,其他的可能卡住?
+
             return object1.equals(object2)
-              
-        }else if(typeof object1 == 'number' ||  typeof object1 == 'string'){
-            if(isNaN(object1) && isNaN(object2))return true
+        } else if (typeof object1 == 'number' || typeof object1 == 'string') {
+            if (isNaN(object1) && isNaN(object2)) return true
             else return object1 == object2
-            
-        }else if(typeof object1 == "object"){
+        } else if (typeof object1 == 'object') {
             var keys1 = Object.keys(object1)
             var keys2 = Object.keys(object2)
-            if(!ifSame(keys1,keys2))return false;
-            
-            for(let i in object1){
-                var same = ifSame(object1[i], object2[i]);
-                if(!same)return false
+            if (!ifSame(keys1, keys2)) return false
+
+            for (let i in object1) {
+                var same = ifSame(object1[i], object2[i])
+                if (!same) return false
             }
             return true
-        }else{
+        } else {
             console.log('isSame出现例外')
-        } 
-        
-    }
-    ,
-    replaceAll : function (str, f, e) {
+        }
+    },
+    replaceAll: function (str, f, e) {
         //f全部替换成e
-        var reg = new RegExp(f, "g"); //创建正则RegExp对象  
-        return str.replace(reg, e);
-    } 
-    ,
+        var reg = new RegExp(f, 'g') //创建正则RegExp对象
+        return str.replace(reg, e)
+    },
+    encodeStr(str, strv = '') {
+        const NUM = 2
+        const front = this.randomWord(false, 8)
+        const middle = this.randomWord(false, 8)
+        const end = this.randomWord(false, 8)
+
+        let str1 = str.substring(0, NUM)
+        let str2 = str.substring(NUM)
+
+        if (strv) {
+            let strv1 = strv.substring(0, NUM)
+            let strv2 = strv.substring(NUM)
+            return [front + str2 + middle + str1 + end, front + strv2 + middle + strv1 + end]
+        }
+
+        return front + str2 + middle + str1 + end
+    },
 }

+ 5 - 0
vue.config.js

@@ -15,6 +15,10 @@ const devServer = {
         'Cache-Control': 'no-store'
     },
     proxy: {
+        '/service': {
+            target: 'https://test.4dkankan.com/',
+            changeOrigin: true
+        },
         '/smart-site': {
             target: 'http://192.168.0.38:8011/',
             changeOrigin: true
@@ -29,6 +33,7 @@ const config = {
     productionSourceMap: isDev,
     pages: {
         'smart-bim': 'src/pages/bim.js',
+        'smart-kankan': 'src/pages/kankan.js',
         'smart-laser': 'src/pages/laser.js',
         'smart-viewer': 'src/pages/viewer.js',
     },