Quellcode durchsuchen

Merge branch 'dev' of http://192.168.0.115:3000/4dkankan/4dkankan_bim into dev

xzw vor 2 Jahren
Ursprung
Commit
57bf332518

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
   "dependencies": {
     "axios": "^0.21.1",
     "core-js": "^3.6.5",
+    "vant": "^3.6.4",
     "vue": "^3.2.26",
     "vue-i18n": "9",
     "vue-router": "4.0.12",

+ 19 - 0
public/smart-sviewer.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <title></title>
+        <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_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>
+            <strong>We're sorry but doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+        </noscript>
+        <div id="app"></div>
+    </body>
+ 
+</html>

+ 1 - 1
public/smart-viewer.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
     <head>
-        <title>BIM</title>
+        <title></title>
         <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" />

+ 103 - 0
src/components/calendar/mobile.vue

@@ -0,0 +1,103 @@
+<template>
+    <div class="calendar" v-show="!showCalendar">
+        <span class="prev" @click="emits('prev')"><i class="iconfont icon-arrows_left"></i></span>
+        <span class="cale" @click="onPickDate()">{{ date }}<i class="iconfont icon-date"></i></span>
+        <span class="next" @click="emits('next')"><i class="iconfont icon-arrows_right"></i></span>
+    </div>
+    <div class="calendar-list" v-if="showCalendar" @click="showCalendar = false">
+        <div @click.stop>
+            <van-datetime-picker v-model="props.value" type="date" title="选择时间" confirm-button-text="确定" />
+        </div>
+    </div>
+</template>
+<script setup>
+import { ref, defineProps, computed } from 'vue'
+const props = defineProps({
+    value: Date,
+    highlighted: Object,
+})
+const emits = defineEmits(['prev', 'selected', 'next', 'pick'])
+const date = computed(() => {
+    if (!props.value) {
+        return ''
+    }
+    return props.value.format('YYYY-mm-dd')
+})
+const showCalendar = ref(false)
+
+const onPickDate = () => {
+    showCalendar.value = !showCalendar.value
+    if (showCalendar.value) {
+        emits('pick')
+    }
+}
+const onSelected = payload => {
+    emits('selected', { payload })
+    showCalendar.value = false
+}
+</script>
+<style lang="scss" scoped>
+.calendar {
+    height: 50px;
+    background: rgba(27, 27, 28, 0.8);
+    box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+    border-radius: 47px 47px 47px 47px;
+    border: 1px solid #000000;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-left: 10px;
+    margin-right: 10px;
+    font-size: 16px;
+    padding: 0 16px;
+    span {
+        cursor: pointer;
+    }
+    .cale {
+        i {
+            margin-left: 4px;
+            font-size: 15px;
+        }
+    }
+    .prev {
+        margin-right: 10px;
+    }
+    .next {
+        margin-left: 10px;
+    }
+}
+.calendar-list {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    height: 100vh;
+    z-index: 1000;
+    display: flex;
+    align-items: flex-end;
+    justify-content: center;
+    > div {
+        width: 100%;
+    }
+}
+</style>
+<style lang="scss">
+:root {
+    --van-gray-8: rgba(255, 255, 255, 0.3);
+    --van-picker-background-color: rgba(0, 0, 0, 0.8);
+}
+.van-picker__mask {
+    display: none;
+}
+.van-picker__toolbar {
+    button {
+        font-size: 16px !important;
+        &.van-picker__confirm {
+            color: #0076f6;
+        }
+    }
+}
+.van-picker-column__item--selected {
+    color: #fff;
+}
+</style>

+ 21 - 13
src/components/header/index.vue

@@ -39,7 +39,7 @@
     </footer>
 </template>
 <script setup>
-import { ref, defineProps, onMounted } from 'vue'
+import { ref, defineProps, onMounted, watchEffect } from 'vue'
 import { http } from '@/utils/request'
 import browser from '@/utils/browser'
 import Login from './Login'
@@ -55,29 +55,28 @@ const user = ref(null)
 const points = ref({ p1: null, p2: null })
 const showLogin = ref(false)
 
-const getCurPosInfo = ()=>{
+const getCurPosInfo = () => {
     let app = sync.sourceInst
-    let id  
-    if(app.sceneType == 'laser'){
-        id = app.viewer.images360.currentPano.id 
-    }else{
-        id = app.app.core.get('Player').currentPano.id 
+    let id
+    if (app.sceneType == 'laser') {
+        id = app.viewer.images360.currentPano.id
+    } else {
+        id = app.app.core.get('Player').currentPano.id
     }
     let info = sync.targetInst.viewer.getCameraStatus()
     let position = info.position
-    return {id, position}
+    return { id, position }
 }
 
-const onSetP1 = () => { 
+const onSetP1 = () => {
     points.value.p1 = getCurPosInfo()
     console.log(points.value.p1)
-    emits('update','p1')
-
+    emits('update', 'p1')
 }
 const onSetP2 = () => {
     points.value.p2 = getCurPosInfo()
     console.log(points.value.p2)
-    emits('update','p2')
+    emits('update', 'p2')
 }
 
 const getUserInfo = () => {
@@ -121,13 +120,22 @@ const onSubmit = () => {
         .then(response => {
             if (response.success) {
                 window.location.href = window.location.href.replace('&adjust', '&split')
-            }else {
+            } else {
                 alert(response.message)
             }
         })
         .catch(() => {})
 }
 
+watchEffect(() => {
+    if (props.showAdjust) {
+        if (props.project && props.project.panos) {
+            points.value.p1 = props.project.panos.p1
+            points.value.p2 = props.project.panos.p2
+        }
+    }
+})
+
 onMounted(() => {
     if (localStorage.getItem('token')) {
         getUserInfo()

+ 329 - 0
src/pages/SViewer.vue

@@ -0,0 +1,329 @@
+<template>
+    <main>
+        <iframe v-if="source" :src="sourceURL" frameborder="0"></iframe>
+        <div class="tools" v-show="!bimChecked">
+            <div class="item-date">
+                <Calendar :value="sourceDate" />
+            </div>
+            <!-- <div class="item-mode" v-if="source.type == 2">
+                <div class="iconfont icon-show_roaming" :class="{ active: mode == 0 }" @click="onModeChange(0)"></div>
+                <div class="iconfont icon-show_plane" :class="{ active: mode == 1 }" @click="onModeChange(1)"></div>
+            </div> -->
+        </div>
+        <!-- <van-datetime-picker v-model="sourceDate" :filter="onFilter" :formatter="onFormatter" type="date" title="选择时间" confirm-button-text="确定" /> -->
+    </main>
+</template>
+
+<script setup>
+import { ref, onMounted, computed, nextTick } from 'vue'
+import { http } from '@/utils/request'
+import browser from '@/utils/browser'
+import Calendar from '@/components/calendar/mobile.vue'
+import sync, { loadSourceScene, loadTargetScene } from '@/utils/sync'
+
+const bimChecked = ref(null)
+
+const datepickName = ref(null)
+
+const sourceFrame = ref(null)
+const targetFrame = ref(null)
+
+const mode = ref(0)
+const source = ref(null)
+const target = ref(null)
+const project = ref(null)
+const points = ref({ p1: false, p2: false })
+
+const scenes = computed(() => {
+    if (!project.value) {
+        return []
+    }
+    return project.value.sceneList.map(item => {
+        return {
+            num: item.num,
+            type: item.type,
+            createTime: item.createTime,
+        }
+    })
+})
+const sourceURL = computed(() => {
+    if (bimChecked.value) {
+        return `smart-bim.html?m=${source.value.num}`
+    }
+
+    if (source.value.type < 2) {
+        // 看看、看见场景
+        return `smart-kankan.html?m=${source.value.num}&dev`
+    } else {
+        // 深时场景
+        return `smart-laser.html?m=${source.value.num}&dev`
+    }
+})
+
+const sourceDate = computed(() => {
+    if (source.value) {
+        return source.value.createTime.toDate()
+    }
+})
+
+const sourceDays = computed(() => {
+    let dates = []
+    if (datepickName.value == 'source') {
+        if (dbsChecked.value) {
+            // 分屏模式
+            if (bimChecked.value) {
+                // BIM模式
+                dates = scenes.value.map(item => item.createTime.toDate())
+            } else {
+                // 非BIM模式
+                dates = scenes.value.filter(item => item.createTime != target.value.createTime).map(item => item.createTime.toDate())
+            }
+        } else {
+            // 非分屏模式
+            dates = scenes.value.map(item => item.createTime.toDate())
+        }
+    }
+    return {
+        dates: dates,
+    }
+})
+
+const onFilter = (type, options) => {
+    console.log(type, options)
+    return options
+}
+const onFormatter = (type, val) => {
+    if (type === 'year') {
+        return `${val}年`
+    }
+    if (type === 'month') {
+        return `${val}月`
+    }
+    if (type === 'day') {
+        return `${val}日`
+    }
+    return val
+}
+
+const onLoadSource = () => {
+    if (bimChecked.value && !dbsChecked.value) {
+        // BIM单屏模式
+        return
+    }
+
+    loadSourceScene(sourceFrame, source.value.type < 2 ? 'kankan' : 'laser')
+}
+
+const onModeChange = targetMode => {
+    if (sync.sourceInst) {
+        sync.sourceInst.loaded.then(sdk => sdk.scene.changeMode(targetMode))
+        mode.value = targetMode
+    }
+}
+const onPickDate = name => {
+    datepickName.value = name
+}
+
+const onSelected = data => {
+    if (!data.payload) {
+        return
+    }
+    let { name, payload } = data
+    let date = payload.format('YYYY-mm-dd')
+    let dates = (name == 'source' ? sourceDays : targetDays).value.dates.map(item => item.format('YYYY-mm-dd'))
+
+    if (dates.indexOf(date) != -1) {
+        let time = payload.format('YYYY-mm-dd HH:MM')
+        let find = scenes.value.find(c => c.createTime.indexOf(time) != -1)
+        if (find) {
+            if (name == 'source') {
+                if (find.num != source.value.num) {
+                    source.value = find
+                }
+            } else {
+                if (find.num != target.value.num) {
+                    target.value = find
+                }
+            }
+        }
+    }
+
+    datepickName.value = null
+}
+
+const onPrevDate = name => {
+    let scene = null
+    if (name == 'source') {
+        scene = source
+    } else {
+        scene = target
+    }
+    let index = scenes.value.findIndex(item => item.num == scene.value.num)
+    if (index == -1) {
+        return
+    }
+    if (--index == -1) {
+        index = scenes.value.length - 1
+    }
+
+    if (target.value) {
+        // 分屏模式判断
+        if (name == 'source') {
+            if (scenes.value[index].createTime == target.value.createTime) {
+                index--
+            }
+        } else {
+            if (scenes.value[index].createTime == source.value.createTime) {
+                index--
+            }
+        }
+        if (index == -1) {
+            index = scenes.value.length - 1
+        }
+    }
+
+    scene.value = scenes.value[index]
+}
+const onNextDate = name => {
+    let scene = null
+    if (name == 'source') {
+        scene = source
+    } else {
+        scene = target
+    }
+    let index = scenes.value.findIndex(item => item.num == scene.value.num)
+    if (index == -1) {
+        return
+    }
+    if (++index > scenes.value.length - 1) {
+        index = 0
+    }
+
+    if (target.value) {
+        // 分屏模式判断
+        if (name == 'source') {
+            if (scenes.value[index].createTime == target.value.createTime) {
+                index++
+            }
+        } else {
+            if (scenes.value[index].createTime == source.value.createTime) {
+                index++
+            }
+        }
+
+        if (index > scenes.value.length - 1) {
+            index = 0
+        }
+    }
+
+    scene.value = scenes.value[index]
+}
+
+// bim点击
+const onBimChecked = () => {
+    if (bimChecked.value) {
+        bimChecked.value = false
+    } else {
+        bimChecked.value = true
+    }
+}
+
+onMounted(() => {
+    const projectId = browser.valueFromUrl('projectId') || 1
+    http.get(`smart-site/project/info?projectId=${projectId}`)
+        .then(response => {
+            if (response.success) {
+                project.value = response.data
+                if (project.value.sceneList.length) {
+                    source.value = project.value.sceneList[0]
+                }
+            } else {
+                alert('获取数据失败')
+            }
+        })
+        .catch(err => {
+            alert('服务器连接失败')
+        })
+})
+</script>
+
+<style lang="scss" scoped>
+main {
+    width: 100%;
+    height: 100%;
+    iframe {
+        width: 100%;
+        height: 100%;
+    }
+    .tools {
+        position: absolute;
+        width: 100%;
+        bottom: 40px;
+        z-index: 2000;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        color: #fff;
+        pointer-events: none;
+        > div {
+            pointer-events: all;
+        }
+
+        .item-mode {
+            height: 50px;
+            background: rgba(27, 27, 28, 0.8);
+            box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+            border-radius: 47px 47px 47px 47px;
+            border: 1px solid #000000;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            margin-left: 10px;
+            margin-right: 10px;
+            font-size: 16px;
+            padding: 0 16px;
+            div {
+                cursor: pointer;
+                font-size: 18px;
+            }
+            div:last-child {
+                margin-left: 20px;
+            }
+            div.active {
+                color: #0076f6;
+            }
+        }
+    }
+}
+</style>
+<style lang="scss">
+#app {
+    background-color: rgba(0, 0, 0, 0.8);
+    display: flex;
+    flex-direction: column;
+}
+:root {
+    --van-gray-8: rgba(255, 255, 255, 0.3);
+    --van-picker-background-color: rgba(0, 0, 0, 0.5);
+}
+// .van-picker {
+//     position: absolute;
+//     left: 0;
+//     right: 0;
+//     bottom: 0;
+// }
+.van-picker__mask {
+    display: none;
+}
+.van-picker__toolbar {
+    button {
+        font-size: 16px !important;
+        &.van-picker__confirm {
+            color: #0076f6;
+        }
+    }
+}
+.van-picker-column__item--selected {
+    color: #fff;
+}
+</style>

+ 32 - 17
src/pages/Viewer.vue

@@ -14,12 +14,12 @@
                     </div>
                 </div>
                 <div class="points" v-if="showAdjust">
-                    <div :class="{active:points.p1}">
-                        <i class="iconfont" :class="[points.p1?'icon-positioning01':'icon-positioning02']"></i>
+                    <div :class="{ active: points.p1 }">
+                        <i class="iconfont" :class="[points.p1 ? 'icon-positioning01' : 'icon-positioning02']"></i>
                         <span>P1</span>
                     </div>
-                    <div :class="{active:points.p2}">
-                        <i class="iconfont" :class="[points.p2?'icon-positioning01':'icon-positioning02']"></i>
+                    <div :class="{ active: points.p2 }">
+                        <i class="iconfont" :class="[points.p2 ? 'icon-positioning01' : 'icon-positioning02']"></i>
                         <span>P2</span>
                     </div>
                 </div>
@@ -32,12 +32,12 @@
                     </div>
                 </div>
                 <div class="points" v-if="showAdjust">
-                    <div :class="{active:points.p1}">
-                        <i class="iconfont" :class="[points.p1?'icon-positioning01':'icon-positioning02']"></i>
+                    <div :class="{ active: points.p1 }">
+                        <i class="iconfont" :class="[points.p1 ? 'icon-positioning01' : 'icon-positioning02']"></i>
                         <span>P1</span>
                     </div>
-                    <div :class="{active:points.p2}">
-                        <i class="iconfont" :class="[points.p2?'icon-positioning01':'icon-positioning02']"></i>
+                    <div :class="{ active: points.p2 }">
+                        <i class="iconfont" :class="[points.p2 ? 'icon-positioning01' : 'icon-positioning02']"></i>
                         <span>P2</span>
                     </div>
                 </div>
@@ -87,7 +87,7 @@ const mode = ref(0)
 const source = ref(null)
 const target = ref(null)
 const project = ref(null)
-const points = ref({p1:false,p2:false})
+const points = ref({ p1: false, p2: false })
 
 const scenes = computed(() => {
     if (!project.value) {
@@ -369,21 +369,36 @@ const onFscChecked = () => {
     }
 }
 
-const onPointsUpdate = type =>{
+const onPointsUpdate = type => {
     points.value[type] = true
 }
 
 onMounted(() => {
+    const num = browser.valueFromUrl('m') || ''
     const projectId = browser.valueFromUrl('projectId') || 1
     http.get(`smart-site/project/info?projectId=${projectId}`)
         .then(response => {
             if (response.success) {
-                project.value = response.data
-                if (project.value.sceneList.length) {
-                    source.value = project.value.sceneList[0]
-                    if (showAdjust.value || showSplit.value) {
-                        onBimChecked()
-                        nextTick(() => onDbsChecked())
+                if (response.data) {
+                    if (response.data.panos) {
+                        try {
+                            response.data.panos = JSON.parse(response.data.panos)
+                            points.value.p1 = true
+                            points.value.p2 = true
+                        } catch (error) {}
+                    }
+                    project.value = response.data
+                    if (project.value.sceneList.length) {
+                        if (num) {
+                            source.value = project.value.sceneList.find(c => c.num == num)
+                        }
+                        if (!source.value) {
+                            source.value = project.value.sceneList[0]
+                        }
+                        if (showAdjust.value || showSplit.value) {
+                            onBimChecked()
+                            nextTick(() => onDbsChecked())
+                        }
                     }
                 }
             } else {
@@ -477,7 +492,7 @@ main {
                 flex-direction: column;
                 align-items: center;
                 justify-content: center;
-                &.active{
+                &.active {
                     color: #0076f6;
                 }
                 i {

+ 41 - 0
src/pages/sviewer.js

@@ -0,0 +1,41 @@
+import '../assets/index.scss'
+import 'vant/lib/index.css';
+import { createApp } from 'vue'
+import { DatetimePicker } from 'vant';
+import { setup } from '../utils/request'
+import App from './SViewer.vue'
+
+Date.prototype.format = function(fmt = 'YYYY-mm-dd HH:MM:SS') {
+    var res = ''
+    try {
+        var date = this
+        var opt = {
+            'Y+': date.getFullYear().toString(), // 年
+            'm+': (date.getMonth() + 1).toString(), // 月
+            'd+': date.getDate().toString(), // 日
+            'H+': date.getHours().toString(), // 时
+            'M+': date.getMinutes().toString(), // 分
+            'S+': date.getSeconds().toString() // 秒
+        }
+        for (var k in opt) {
+            var ret = new RegExp('(' + k + ')').exec(fmt)
+            if (ret) {
+                fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'))
+            }
+        }
+        res = fmt
+    } catch (error) {
+        logger.warn('ERROR formatDate', error)
+    }
+    return res
+}
+
+String.prototype.toDate = function() {
+    if (!this) {
+        return null
+    }
+    return new Date(this.replace(/\//g, '-').replace(' ', 'T'))
+}
+
+setup()
+createApp(App).use(DatetimePicker).mount('#app')

+ 1 - 0
vue.config.js

@@ -36,6 +36,7 @@ const config = {
         'smart-kankan': 'src/pages/kankan.js',
         'smart-laser': 'src/pages/laser.js',
         'smart-viewer': 'src/pages/viewer.js',
+        'smart-sviewer': 'src/pages/sviewer.js',
     },
     css: {
         extract: false,

+ 28 - 41
yarn.lock

@@ -1284,6 +1284,21 @@
     anymatch "^3.0.0"
     source-map "^0.6.0"
 
+"@vant/icons@^1.8.0":
+  version "1.8.0"
+  resolved "https://registry.npmmirror.com/@vant/icons/-/icons-1.8.0.tgz#36b13f2e628b533f6523a93a168cf02f07056674"
+  integrity sha512-sKfEUo2/CkQFuERxvkuF6mGQZDKu3IQdj5rV9Fm0weJXtchDSSQ+zt8qPCNUEhh9Y8shy5PzxbvAfOOkCwlCXg==
+
+"@vant/popperjs@^1.2.1":
+  version "1.3.0"
+  resolved "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz#e0eff017124b5b2352ef3b36a6df06277f4400f2"
+  integrity sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==
+
+"@vant/use@^1.4.2":
+  version "1.4.3"
+  resolved "https://registry.npmmirror.com/@vant/use/-/use-1.4.3.tgz#0c542fe01a1439878e4aa8779d1791e189610d30"
+  integrity sha512-rSnETN7P9qT1WbItMpQxBqe3cHeK2ZFYp1sCxWUXaTeI71TqA8sOdzC36ledZ36NQgFNTch9fsRPYOkrCgZfQA==
+
 "@vue/babel-helper-vue-jsx-merge-props@^1.4.0":
   version "1.4.0"
   resolved "https://registry.npmmirror.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz#8d53a1e21347db8edbe54d339902583176de09f2"
@@ -6105,7 +6120,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
   resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
-pify@^2.0.0, pify@^2.3.0:
+pify@^2.0.0:
   version "2.3.0"
   resolved "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
   integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
@@ -6223,15 +6238,6 @@ postcss-discard-overridden@^4.0.1:
   dependencies:
     postcss "^7.0.0"
 
-postcss-import@^15.0.0:
-  version "15.0.0"
-  resolved "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.0.0.tgz#0b66c25fdd9c0d19576e63c803cf39e4bad08822"
-  integrity sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==
-  dependencies:
-    postcss-value-parser "^4.0.0"
-    read-cache "^1.0.0"
-    resolve "^1.1.7"
-
 postcss-load-config@^2.0.0:
   version "2.1.2"
   resolved "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a"
@@ -6345,13 +6351,6 @@ postcss-modules-values@^3.0.0:
     icss-utils "^4.0.0"
     postcss "^7.0.6"
 
-postcss-nested@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735"
-  integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==
-  dependencies:
-    postcss-selector-parser "^6.0.10"
-
 postcss-normalize-charset@^4.0.1:
   version "4.0.1"
   resolved "https://registry.npmmirror.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4"
@@ -6471,7 +6470,7 @@ postcss-selector-parser@^3.0.0:
     indexes-of "^1.0.1"
     uniq "^1.0.1"
 
-postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2:
+postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
   version "6.0.10"
   resolved "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
   integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
@@ -6479,11 +6478,6 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selecto
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
 
-postcss-simple-vars@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.npmmirror.com/postcss-simple-vars/-/postcss-simple-vars-7.0.0.tgz#f1d10a979762aa4e7e3450a35a32885112893d1b"
-  integrity sha512-SPSkKQK7mKjD/tqcTbZkDi3KP+C/cTGXnKQmSt3AisJtnZE6ZxHEUoOGRfpV0B5dW1Y36EETfRHx10WLHpXThA==
-
 postcss-svgo@^4.0.3:
   version "4.0.3"
   resolved "https://registry.npmmirror.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e"
@@ -6507,7 +6501,7 @@ postcss-value-parser@^3.0.0:
   resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
   integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
 
-postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
   version "4.2.0"
   resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
   integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@@ -6529,15 +6523,6 @@ postcss@^8.1.10:
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
-postcss@^8.4.17:
-  version "8.4.17"
-  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.17.tgz#f87863ec7cd353f81f7ab2dec5d67d861bbb1be5"
-  integrity sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==
-  dependencies:
-    nanoid "^3.3.4"
-    picocolors "^1.0.0"
-    source-map-js "^1.0.2"
-
 prepend-http@^1.0.0:
   version "1.0.4"
   resolved "https://registry.npmmirror.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -6721,13 +6706,6 @@ raw-body@2.5.1:
     iconv-lite "0.4.24"
     unpipe "1.0.0"
 
-read-cache@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
-  integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
-  dependencies:
-    pify "^2.3.0"
-
 read-pkg@^5.1.1:
   version "5.2.0"
   resolved "https://registry.npmmirror.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
@@ -6930,7 +6908,7 @@ resolve-url@^0.2.1:
   resolved "https://registry.npmmirror.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
 
-resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2:
+resolve@^1.10.0, resolve@^1.14.2:
   version "1.22.1"
   resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
   integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -8041,6 +8019,15 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
+vant@^3.6.4:
+  version "3.6.4"
+  resolved "https://registry.npmmirror.com/vant/-/vant-3.6.4.tgz#939a0101a2938479ef77c121b21ba98ac31285a2"
+  integrity sha512-IgPzekX7YGoqf7h/jx75F087lsBEWA/cQfRqPVgiR6cyqrmi8+dfpfFTz2OcPZ755avTzKk3L0WaclXIbHnVeQ==
+  dependencies:
+    "@vant/icons" "^1.8.0"
+    "@vant/popperjs" "^1.2.1"
+    "@vant/use" "^1.4.2"
+
 vary@~1.1.2:
   version "1.1.2"
   resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"