Atticus6 2 роки тому
батько
коміт
d68aaf717e

+ 74 - 0
package-lock.json

@@ -8,6 +8,7 @@
       "name": "smart-school-map",
       "version": "0.0.0",
       "dependencies": {
+        "@vueuse/core": "^10.7.0",
         "ant-design-vue": "^4.0.7",
         "lucide-vue-next": "^0.294.0",
         "pinia": "^2.1.7",
@@ -734,6 +735,11 @@
       "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
       "dev": true
     },
+    "node_modules/@types/web-bluetooth": {
+      "version": "0.0.20",
+      "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
+      "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
+    },
     "node_modules/@vitejs/plugin-vue": {
       "version": "4.5.2",
       "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.5.2.tgz",
@@ -907,6 +913,74 @@
       "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.10.tgz",
       "integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw=="
     },
+    "node_modules/@vueuse/core": {
+      "version": "10.7.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-10.7.0.tgz",
+      "integrity": "sha512-4EUDESCHtwu44ZWK3Gc/hZUVhVo/ysvdtwocB5vcauSV4B7NiGY5972WnsojB3vRNdxvAt7kzJWE2h9h7C9d5w==",
+      "dependencies": {
+        "@types/web-bluetooth": "^0.0.20",
+        "@vueuse/metadata": "10.7.0",
+        "@vueuse/shared": "10.7.0",
+        "vue-demi": ">=0.14.6"
+      }
+    },
+    "node_modules/@vueuse/core/node_modules/vue-demi": {
+      "version": "0.14.6",
+      "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
+      "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vueuse/metadata": {
+      "version": "10.7.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-10.7.0.tgz",
+      "integrity": "sha512-GlaH7tKP2iBCZ3bHNZ6b0cl9g0CJK8lttkBNUX156gWvNYhTKEtbweWLm9rxCPIiwzYcr/5xML6T8ZUEt+DkvA=="
+    },
+    "node_modules/@vueuse/shared": {
+      "version": "10.7.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-10.7.0.tgz",
+      "integrity": "sha512-kc00uV6CiaTdc3i1CDC4a3lBxzaBE9AgYNtFN87B5OOscqeWElj/uza8qVDmk7/U8JbqoONLbtqiLJ5LGRuqlw==",
+      "dependencies": {
+        "vue-demi": ">=0.14.6"
+      }
+    },
+    "node_modules/@vueuse/shared/node_modules/vue-demi": {
+      "version": "0.14.6",
+      "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
+      "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/acorn": {
       "version": "8.11.2",
       "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.11.2.tgz",

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@vueuse/core": "^10.7.0",
     "ant-design-vue": "^4.0.7",
     "lucide-vue-next": "^0.294.0",
     "pinia": "^2.1.7",

+ 71 - 0
src/components/Init.vue

@@ -0,0 +1,71 @@
+<script setup lang="ts">
+import { Steps, Card, Button } from "ant-design-vue";
+
+const localStore = useLocalStore();
+const current = ref(0);
+const container = ref<HTMLDivElement>(null);
+
+const items = [
+  ...localStore.locals.map((local) => ({ title: local.name })),
+  { title: "完成" },
+];
+
+const tempLocals: Local[] = reactive([]);
+const finish = computed(() => {
+  return tempLocals.length === localStore.locals.length;
+});
+const handleClick = (event: MouseEvent) => {
+  if (finish.value) {
+    return;
+  }
+  const x = event.clientX; // 获取鼠标点击位置的X坐标
+  const y = event.clientY; // 获取鼠标点击位置的Y坐标
+  const temp: Local = {
+    name: localStore.locals[current.value].name,
+    x: x,
+    y: y,
+  };
+  tempLocals.push(temp);
+
+  current.value++;
+
+  console.log(temp);
+};
+
+const reset = () => {
+  tempLocals.splice(0, tempLocals.length);
+  current.value = 0;
+};
+const set = () => {
+  tempLocals.forEach((local) => {
+    localStore.setLocal(local);
+  });
+};
+</script>
+<template>
+  <div class="w-full h-screen relative" ref="container">
+    <Card class="w-4/5 sm:w-3/4 md:w-1/2 mx-auto mt-4 select-none">
+      <div class="flex justify-between mb-2 text-2xl h-14">
+        <div v-if="current !== 4">
+          请选择
+          <span class="text-blue-500">{{ items[current].title }}</span>
+          的位置 {{ current }}
+        </div>
+        <div v-else class="flex justify-between w-full">
+          <Button type="primary" size="large" @click="reset">重新选择</Button>
+          <Button type="primary" size="large" @click="set">确定</Button>
+        </div>
+      </div>
+      <Steps :items="items" :current="current" />
+    </Card>
+
+    <!-- 全屏的点击区域 -->
+    <div
+      v-show="!finish"
+      class="absolute w-full h-full top-0 left-0"
+      @click="handleClick"
+    ></div>
+
+    <ShowPoint v-for="(item, i) in tempLocals" :key="i" :local="item" />
+  </div>
+</template>

+ 15 - 0
src/components/ShowPoint.vue

@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { Tooltip } from "ant-design-vue";
+
+defineProps<{ local: Local }>();
+</script>
+<template>
+  <div
+    class="absolute p-3"
+    :style="{ top: local.y + 'px', left: local.x + 'px' }"
+  >
+    <Tooltip :title="local.name" :open="true" />
+  </div>
+</template>
+
+<style scoped></style>

+ 2 - 0
src/components/auto-components.d.ts

@@ -9,8 +9,10 @@ declare module 'vue' {
   export interface GlobalComponents {
     BackButton: typeof import('./BackButton.vue')['default']
     HomeItem: typeof import('./HomeItem.vue')['default']
+    Init: typeof import('./Init.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     SearchCard: typeof import('./SearchCard.vue')['default']
+    ShowPoint: typeof import('./ShowPoint.vue')['default']
   }
 }

+ 1 - 0
src/main.ts

@@ -8,6 +8,7 @@ import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
 const app = createApp(App);
 const pinia = createPinia();
 pinia.use(piniaPluginPersistedstate);
+
 app.use(router);
 app.use(pinia);
 app.mount("#app");

+ 2 - 2
src/model/local.ts

@@ -1,5 +1,5 @@
 interface Local {
   name: string;
-  x?: number;
-  y?: number;
+  x: number;
+  y: number;
 }

+ 50 - 29
src/pages/find/index.vue

@@ -1,46 +1,67 @@
 <script setup lang="ts">
-import { Input, Button } from "ant-design-vue";
+import { Input } from "ant-design-vue";
 const router = useRouter();
 const inputValue = ref("");
+const localStore = useLocalStore();
+onMounted(() => {
+  console.log(localStore.initialized);
+  console.log(localStore.locals);
+});
 </script>
 <template>
   <div
-    class="h-screen w-full bg-[url('/image/bg.png')] bg-cover flex text-white flex-col relative"
+    class="h-screen w-full bg-[url('/image/bg.png')] bg-cover flex text-white"
   >
-    <!-- 返回按钮 -->
-    <BackButton
-      class="absolute top-3 md:top-[70px] left-9"
-      @click="router.push('/')"
-    />
+    <!--  初始化后展示 -->
+    <div
+      v-if="localStore.initialized"
+      class="flex-col relative w-full h-screen"
+    >
+      <!-- 打上标记的点 -->
+      <ShowPoint
+        v-for="(item, i) in localStore.locals"
+        :key="i"
+        :local="item"
+      />
 
-    <div class="w-[691px] mx-auto">
-      <!-- 搜索框 -->
-      <div
-        class="h-[72px] backdrop-blur-sm mx-auto bg-gray-800 mt-[83px] bg-opacity-20 flex justify-between items-center rounded-xl overflow-hidden"
-      >
-        <div>
-          <Input
-            class="bg-transparent text-white text-lg px-4 placeholder:text-gray-100"
-            :bordered="false"
-            placeholder="请输入学生姓名"
-            v-model:value="inputValue"
-          />
-        </div>
+      <!-- 返回按钮 -->
+      <BackButton
+        class="absolute top-3 md:top-[70px] left-9"
+        @click="router.push('/')"
+      />
+
+      <div class="w-[691px] mx-auto">
+        <!-- 搜索框 -->
         <div
-          class="h-full select-none w-[134px] bg-blue-400 flex justify-center items-center font-medium text-xl cursor-pointer"
+          class="h-[72px] backdrop-blur-sm mx-auto bg-gray-800 mt-[83px] bg-opacity-20 flex justify-between items-center rounded-xl overflow-hidden"
         >
-          搜索
+          <div>
+            <Input
+              class="bg-transparent text-white text-lg px-4 placeholder:text-gray-100"
+              :bordered="false"
+              placeholder="请输入学生姓名"
+              v-model:value="inputValue"
+            />
+          </div>
+          <div
+            class="h-full select-none w-[134px] bg-blue-400 flex justify-center items-center font-medium text-xl cursor-pointer"
+          >
+            搜索
+          </div>
         </div>
-      </div>
 
-      <!-- 结果框 -->
-      <div
-        v-show="inputValue.length > 0"
-        class="bg-[#c7dfeb] bg-opacity-70 backdrop-blur-sm rounded-xl mt-2 text-black flex flex-col py-8 gap-2 max-h-[400px] overflow-auto"
-      >
-        <SearchCard v-for="i in 3" :key="i" class="flex-none" />
+        <!-- 结果框 -->
+        <div
+          v-show="inputValue.length > 0"
+          class="bg-[#c7dfeb] z-50 bg-opacity-70 backdrop-blur-sm rounded-xl mt-2 text-black flex flex-col py-8 gap-2 max-h-[400px] overflow-auto"
+        >
+          <SearchCard v-for="i in 3" :key="i" class="flex-none" />
+        </div>
       </div>
     </div>
+
+    <!-- 未初始化展示 -->
+    <Init v-else />
   </div>
 </template>
 

+ 29 - 8
src/store/local.ts

@@ -3,20 +3,41 @@ import { defineStore } from "pinia";
 export const useLocalStore = defineStore(
   "local",
   () => {
-    const locals = reactive<Local[]>([
-      { name: "探学楼" },
-      { name: "探问楼" },
-      { name: "探理楼" },
-      { name: "探真楼" },
+    const locals = ref<Local[]>([
+      { name: "探学楼", x: 0, y: 0 },
+      { name: "探真楼", x: 0, y: 0 },
+      { name: "探问楼", x: 0, y: 0 },
+      { name: "探理楼", x: 0, y: 0 },
     ]);
+    const initialized = computed(() => {
+      let total = 0;
+      locals.value.forEach((item) => {
+        if (item.x !== 0) {
+          total += 1;
+        }
+        if (item.y !== 0) {
+          total += 1;
+        }
+      });
 
+      return total === locals.value.length * 2;
+    });
+
+    // 设置x,y坐标
+    const setLocal = (newlocal: Local) => {
+      locals.value.forEach((local, i) => {
+        if (local.name === newlocal.name) {
+          locals.value[i] = { ...newlocal };
+        }
+      });
+    };
     return {
       locals,
+      initialized,
+      setLocal,
     };
   },
   {
-    persist: {
-      key: "lcoals",
-    },
+    persist: true,
   }
 );

+ 4 - 0
src/style.css

@@ -11,3 +11,7 @@ body {
   /* background-image: url("/public/image/bg.png");
   background-size: cover; */
 }
+
+.ant-tooltip-inner {
+  @apply text-3xl;
+}