Vue3+Vite+Pinia+Naive后台管理系统搭建之九:layout 动态路由布局

news2024/12/24 9:32:07

前言

如果对 vue3 的语法不熟悉的,可以移步Vue3.0 基础入门,快速入门。

1. 系统页面结构

由 menu,面包屑,用户信息,页面标签,页面内容构建

 2. 创建页面

创建 src/pages/layout.vue 布局页

创建 src/pages/components/layout-menu.vue menu 组件

创建 src/pages/components/layout-crumbs.vue 面包屑 组件

创建 src/pages/components/layout-user.vue 用户信息 组件

创建 src/pages/components/layout-tag.vue 页面标签 组件

创建 src/pages/components/layout-content.vue 页面内容 组件

 3. 构建 src/pages/layout.vue 布局页

<script setup>
  import { ref } from "vue";
  import {
    NLayout,
    NLayoutSider,
    NLayoutHeader,
    NLayoutContent,
  } from "naive-ui";
  // menu
  import layoutMenu from "./components/layout-menu.vue";
  // 面包屑
  import layoutCrumbs from "./components/layout-crumbs.vue";
  // 用户信息
  import layoutUser from "./components/layout-user.vue";
  // 页面标签
  import layoutTag from "./components/layout-tag.vue";
  // 页面内容
  import layoutContent from "./components/layout-content.vue";

  // 是否展开menu
  let isOpen = ref(true);
  // n-layout-sider 折叠状态发生改变时的回调函数
  function handleChangeSider(isHide) {
    if (isHide) {
      isOpen.value = !isHide;
    }
  }
  // n-layout-sider 完成展开后的回调
  function handleEnter() {
    isOpen.value = true;
  }

  // n-layout-sider 是否显示边框
  let bordered = ref(true);
  // n-layout-sider 是否反转背景色
  let inverted = ref(false);
  // n-layout-sider 是否在自身使用原生滚动条。如果设定为 false,Sider 将会对内容使用 naive-ui 风格的滚动条
  let scrollbar = ref(false);
  // n-layout-sider 折叠宽度
  let colWidth = ref(50);
  // n-layout-sider 展开宽度
  let siderWidth = ref(155);
</script>

<template>
  <!-- layout 盒子 -->
  <n-layout has-sider class="layout-box">
    <!-- 左侧导航 -->
    <n-layout-sider
      collapse-mode="width"
      show-trigger="arrow-circle"
      :bordered="bordered"
      :inverted="inverted"
      :native-scrollbar="scrollbar"
      :collapsed-width="colWidth"
      :width="siderWidth"
      @update:collapsed="handleChangeSider"
      @after-enter="handleEnter"
    >
      <layout-menu :isOpen="isOpen" :inverted="inverted"></layout-menu>
    </n-layout-sider>
    <!-- 右侧内容 -->
    <n-layout>
      <n-layout-header :bordered="bordered">
        <div class="layout-header__box">
          <layout-crumbs></layout-crumbs>
          <layout-user></layout-user>
        </div>
        <!--  -->
        <layout-tag></layout-tag>
        <div class="layout-header__shadow"></div>
      </n-layout-header>
      <n-layout-content>
        <layout-content></layout-content>
      </n-layout-content>
    </n-layout>
  </n-layout>
</template>

<style lang="scss" scoped>
  .layout-box {
    width: 100vw;
    height: 100vh;
    box-sizing: border-box;
  }
  .layout-header__box {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px;
    box-sizing: border-box;
    height: 50px;
    border-bottom: 1px solid rgb(239, 239, 245);
  }
  .layout-header__shadow {
    width: 100%;
    height: 2px;
    background: #d9d9d9;
  }
</style>

4. 构建 src/pages/components/layout-menu.vue menu 组件

<script setup>
  import { ref, watch, computed } from "vue";
  import { useRoute } from "vue-router";
  import { NMenu } from "naive-ui";
  import { usePermissionStore } from "@/store/permission.js";
  import { useTagStore } from "@/store/tag.js";
  import router from "@/router/index.js";

  defineProps({
    isOpen: Boolean,
    inverted: Boolean,
  });

  let route = useRoute();
  let permissionStore = usePermissionStore();
  let tagStore = useTagStore();

  let menuOptions = computed(() => {
    return permissionStore.siderMenu;
  });

  let activeMenuValue = ref("");
  watch(
    () => route.name,
    () => {
      activeMenuValue.value = route.name;
      permissionStore.activeMenuValue = route.name;
    },
    { immediate: true, deep: true }
  );

  // 新增 tag
  let obj = { title: route.meta.title, key: route.name };
  tagStore.addTag(obj);

  let handleUpdateMenu = (value, item) => {
    // 新增 tag
    let { title, key } = item;
    let obj = { title, key };
    tagStore.addTag(obj);

    router.push(`/${value}`);
    activeMenuValue.value = value;
  };
</script>

<template>
  <!-- logo -->
  <div
    class="layout-sider__logo c-center"
    :class="{ isHide: !isOpen }"
    @click="$router.push('/home')"
  >
    <svg-icon name="vite"></svg-icon>
    <!-- <img src="@/assets/images/logo.png" /> -->
    <h1 v-show="isOpen">后台管理系统</h1>
  </div>
  <!-- menu组件 -->
  <n-menu
    :inverted="inverted"
    :indent="15"
    :root-indent="15"
    :options="menuOptions"
    :value="activeMenuValue"
    @update:value="handleUpdateMenu"
  ></n-menu>
</template>

<style lang="scss" scoped>
  .layout-sider__logo {
    height: 50px;
    font-size: 14px;
    font-weight: bold;
    cursor: pointer;
    img {
      margin-right: 5px;
      width: 25px;
      object-fit: contain;
    }
    svg {
      margin-right: 5px;
    }
  }
  .isHide {
    img {
      width: 30px;
    }
  }
</style>

4.1 构建 src/store/permission.js 权限状态管理

根据后端返回动态路由数据,构建导航 menu 和动态路由。

import { defineStore } from "pinia";
import { h } from "vue";
import { RouterLink } from "vue-router";
// 接口获取路由 自己对接口
// import { getRouters } from "@/api/menu.js";
import SvgIcon from "@/components/SvgIcon.vue";
import { routerData } from "@/mock/datas.js";

const modules = import.meta.glob("../pages/*.vue");

//  icon 标签
let renderIcon = (name) => {
  return () => h(SvgIcon, { name }, null);
};

// 单个路由
let getRouterItem = (item) => {
  let { name, path, meta, component } = item;
  let obj = {
    path,
    name,
    meta,
    component: modules[`../pages/${component}`],
  };
  return obj;
};

// 获取异步路由
// 所有异步路由都是layout的子路由,并且routers只有一层children,没有考虑很复杂的情况。
// 将所有异步路由都存放在rmenu数组中,返回。
let getAayncRouter = (routers) => {
  let rmenu = [];
  routers.forEach((item) => {
    if (item.children && item.children.length) {
      item.children.map((_item) => {
        let obj = getRouterItem(_item);
        obj.meta.parentTitle = item.meta.title;
        rmenu.push(obj);
      });
    } else {
      rmenu.push(getRouterItem(item));
    }
  });
  return rmenu;
};

// 获取侧边栏导航
let getSiderMenu = (routers) => {
  let smenu = [];

  routers.forEach((item) => {
    let children = [];
    let obj = {};

    if (item.children && item.children.length) {
      // 二级 menu
      item.children.map((_item) => {
        if (!_item.hidden) {
          children.push({
            label: () =>
              h(
                RouterLink,
                { to: _item.path },
                { default: () => _item.meta.title }
              ),
            title: _item.meta.title,
            key: _item.name,
            icon: renderIcon(_item.meta.icon),
          });
        }
      });

      obj = {
        label: item.meta.title,
        title: item.meta.title,
        key: item.name,
        icon: renderIcon(item.meta.icon),
        children,
      };
    } else {
      // 一级 menu
      obj = {
        label: () =>
          h(RouterLink, { to: item.path }, { default: () => item.meta.title }),
        title: item.meta.title,
        key: item.name,
        icon: renderIcon(item.meta.icon),
      };
    }

    smenu.push(obj);
  });
  return smenu;
};

export const usePermissionStore = defineStore({
  id: "permissionStore",
  state: () => {
    return {
      siderMenu: [],
      activeMenuValue: "",
    };
  },
  actions: {
    getRouters() {
      return new Promise((resolve, reject) => {
        this.siderMenu = getSiderMenu(routerData);
        resolve(getAayncRouter(routerData));
        // getRouters()
        //   .then(({ data }) => {
        //     this.siderMenu = getSiderMenu(data);
        //     resolve(data);
        //   })
        //   .catch((err) => {
        //     reject(err);
        //   });
      });
    },
  },
});

4.1.1 构建 src/mock/datas.js 虚拟路由数据

模仿后端返回动态路由数据结构

export const routerData = [
  {
    name: "home",
    path: "/home",
    hidden: false,
    component: "home.vue",
    meta: {
      title: "首页",
      icon: "home",
    },
    children: null,
  },
  {
    name: "system",
    path: "/system",
    hidden: false,
    component: null,
    meta: {
      title: "系统管理",
      icon: "system",
    },
    children: [
      {
        name: "system-menu",
        path: "/system-menu",
        hidden: false,
        component: "system-menu.vue",
        meta: {
          title: "系统菜单",
          icon: "system-menu",
        },
        children: null,
      },
      {
        name: "system-dict",
        path: "/system-dict",
        hidden: false,
        component: "system-dict.vue",
        meta: {
          title: "系统字典",
          icon: "system-dict",
        },
        children: null,
      },
    ],
  },
  {
    name: "user",
    path: "/user",
    hidden: false,
    component: null,
    meta: {
      title: "用户管理",
      icon: "user",
    },
    children: [
      {
        name: "user-user",
        path: "/user-user",
        hidden: false,
        component: "user-user.vue",
        meta: {
          title: "用户管理",
          icon: "user-user",
        },
        children: null,
      },
      {
        name: "user-role",
        path: "/user-role",
        hidden: false,
        component: "user-role.vue",
        meta: {
          title: "角色管理",
          icon: "user-role",
        },
        children: null,
      },
    ],
  },
];


4.1.2 新增 src/assets/svg 路由图标

 

4.2 构建 src/store/tag.js 页面标签状态管理

点击左侧导航路由,页面标签变化

import { defineStore } from "pinia";

export const useTagStore = defineStore({
  id: "tag",
  state: () => {
    return {
      tags: [{ title: "首页", key: "home" }],
      activeTagIndex: 0,
    };
  },
  getters: {
    tagsKey(state) {
      let arr = [];
      state.tags.map((tag) => {
        arr.push(tag.key);
      });
      return arr;
    },
  },
  actions: {
    addTag(tag) {
      if (!this.tagsKey.includes(tag.key)) {
        this.tags.push(tag);
      }
    },
    removeTag(key) {
      let index = this.tagsKey.indexOf(key);
      this.tags.splice(index, 1);
      this.activeTagIndex = index - 1;
    },
  },
});

4.3 完善 src/router/index.js 路由

路由监听动态加载路由

import { createRouter, createWebHistory } from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import baseRouters from "./baseRouter.js";
import { getToken } from "@/utils/cookie.js";
import { useUserStore } from "@/store/user.js";
import { usePermissionStore } from "@/store/permission.js";

const whiteList = ["/", "/login"];

const routes = [...baseRouters];
const _createRouter = () =>
  createRouter({
    history: createWebHistory(),
    routes,
    scrollBehavior() {
      return {
        el: "#app",
        top: 0,
        behavior: "smooth",
      };
    },
  });

export function resetRouter() {
  const newRouter = _createRouter();
  router.matcher = newRouter.matcher;
}

const router = _createRouter();

// 路由监听
router.beforeEach((to, from, next) => {
  NProgress.start();
  let userStore = useUserStore();
  let permissionStore = usePermissionStore();

  // 判断是否登录
  if (!!getToken()) {
    // 已登录,跳转登录页,转跳首页
    if (to.path === "/login") {
      next("");
      NProgress.done();
    } else {
      if (userStore.roles.length === 0) {
        userStore
          .getInfo()
          .then((res) => {
            // 获取动态路由
            permissionStore.getRouters().then((_res) => {
              let resetRouters = {
                path: "/layout",
                name: "layout",
                component: () => import("@/pages/layout.vue"),
                children: _res,
              };
              router.addRoute(resetRouters);

              // 这句代码,重要!重要!重要!
              // 来确保addRoute()时动态添加的路由已经被完全加载上去。没有这句,动态路由加载后无效
              next({ ...to, replace: true });
            });
          })
          .catch((err) => {
            window.$msg.error(err);
            userStore.logout().then(() => {
              next({ name: "login" });
            });
          });
      } else {
        next();
      }
    }
    NProgress.done();
  } else {
    // 判断路由是否在白名单,是直接跳转
    if (whiteList.indexOf(to.path) !== -1) {
      next();
      // 未登录页面跳转,直接跳转到登录页
    } else {
      next(`/login?redirect=${to.fullPath}`);
    }
    NProgress.done();
  }
});

export default router;

5. 构建 src/pages/components/layout-crumbs.vue 面包屑组件

<script setup>
  import { watch, ref } from "vue";
  import { NBreadcrumb, NBreadcrumbItem } from "naive-ui";
  import { useRoute } from "vue-router";

  let route = useRoute();

  // 判断是二级目录
  let getCrumList = (nowRoute) => {
    let arr = [nowRoute.meta.title];
    !!nowRoute.meta.parentTitle && arr.unshift(nowRoute.meta.parentTitle);
    return arr;
  };

  let crumbList = ref([]);
  // 监听路由,获取crumlist
  watch(
    () => route,
    (newRoute) => {
      crumbList.value = getCrumList(newRoute);
    },
    { immediate: true, deep: true }
  );
</script>

<template>
  <n-breadcrumb>
    <n-breadcrumb-item
      class="layout-crumbs-item"
      v-for="(item, index) in crumbList"
      :key="index"
      >{{ item }}</n-breadcrumb-item
    >
  </n-breadcrumb>
</template>

<style lang="scss" scoped>
  .layout-crumbs-item {
    font-size: 16px;
  }
</style>

6. 构建 src/pages/components/layout-user.vue 用户信息 组件

<script setup>
  import { reactive, h, computed } from "vue";
  import { useDialog, NDropdown, NButton } from "naive-ui";
  import { useUserStore } from "@/store/user.js";
  import { useTagStore } from "@/store/tag.js";
  import router from "@/router/index.js";

  let userStore = useUserStore();
  let tagStore = useTagStore();

  // 登录才获取用户信息
  userStore.getInfo();
  // 获取 用户信息
  let avatar = computed(() => {
    if (!!userStore.user?.avatar) {
      return userStore.user.avatar;
    } else {
      return "";
    }
  });
  let userName = computed(() => {
    if (!!userStore.user?.userName) {
      return userStore.user.userName;
    } else {
      return "";
    }
  });

  // 下拉选项
  let baseOptions = reactive([
    {
      label: "个人信息",
      key: "userinfo",
    },
    {
      label: "修改密码",
      key: "editpassword",
    },
    {
      label: "退出系统",
      key: "logout",
    },
  ]);

  // 选择操作
  let dialog = useDialog();
  // 确认登出
  let submitLogout = () => {
    userStore.logout().then(() => {
      router.push("/home");
      dialog.destroyAll();
      window.location.reload();
    });
  };
  // 取消登出
  let cancelLogOut = () => {
    dialog.destroyAll();
  };
  let handleSelect = (key, item) => {
    if (["userinfo", "editpassword"].includes(key)) {
      // 新增 tag
      let obj = { title: item.label, key };
      tagStore.addTag(obj);

      router.push(`/${key}`);
    } else {
      dialog.warning({
        closable: false,
        showIcon: false,
        style: {
          width: "20%",
        },
        title: () => {
          return h(
            "div",
            {
              style: {
                position: "absolute",
                top: 0,
                left: 0,
                right: 0,
                textAlign: "center",
                height: "40px",
                lineHeight: "40px",
                background: "#cee6f0",
                color: "#1d69a3",
                fontWeight: "bold",
                fontSize: "16px",
              },
            },
            "退出登录"
          );
        },
        content: () => {
          return h(
            "p",
            {
              style: {
                textAlign: "center",
                height: "80px",
                lineHeight: "108px",
                color: "#000",
                fontSize: "14px",
                fontWeight: "bolder",
                userSelect: "none",
              },
            },
            "是否退出当前账号?"
          );
        },
        action: () => {
          return h(
            "div",
            {
              style: {
                width: "100%",
                display: "flex",
                justifyContent: "space-around",
              },
            },
            [
              h(
                NButton,
                {
                  onClick: cancelLogOut,
                  style: {
                    width: "40%",
                  },
                },
                {
                  default: () => "取消",
                }
              ),
              h(
                NButton,
                {
                  onClick: submitLogout,
                  type: "info",
                  style: {
                    width: "40%",
                  },
                },
                {
                  default: () => "退出",
                }
              ),
            ]
          );
        },
      });
    }
  };
</script>

<template>
  <n-dropdown
    trigger="click"
    :options="baseOptions"
    @select="handleSelect"
    size="small"
  >
    <div class="header-right_user-box">
      <div class="header-right_user-avatar">
        <img v-if="avatar" class="header-right_avatar" :src="avatar" />
        <svg-icon v-else name="avatar" width="35" height="35"></svg-icon>
      </div>
      <div class="header-right_user-name">
        <span>{{ userName }}</span>
        <svg-icon name="down" width="10"></svg-icon>
      </div>
    </div>
  </n-dropdown>
</template>

<style lang="scss" scoped>
  .header-right_user-box {
    display: flex;
    align-items: center;
    cursor: pointer;
    user-select: none;
  }
  .header-right_user-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    overflow: hidden;

    img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
  .header-right_user-name {
    span {
      margin: 0 5px;
    }
  }
</style>

7. 构建 src/pages/components/layout-tag.vue 页面标签 组件

<script setup>
  import { computed } from "vue";
  import { NTag } from "naive-ui";
  import { useTagStore } from "@/store/tag.js";
  import { usePermissionStore } from "@/store/permission.js";
  import router from "@/router/index.js";

  let tagStore = useTagStore();
  let permissionStore = usePermissionStore();

  let tags = computed(() => {
    return tagStore.tags;
  });

  function handleClose(key) {
    tagStore.removeTag(key);

    if (permissionStore.activeMenuValue == key) {
      permissionStore.activeMenuValue = tags.value[tagStore.activeTagIndex].key;
      router.push(`/${permissionStore.activeMenuValue}`);
    }
  }
  function handleCheck(item) {
    let { key } = item;
    permissionStore.activeMenuValue = key;
    router.push(`/${key}`);
  }
</script>

<template>
  <div class="layout-header__tag">
    <n-tag
      v-for="item in tags"
      :key="item.key"
      class="tag-item"
      :closable="item.key !== 'home'"
      :type="item.key == permissionStore.activeMenuValue ? 'success' : ''"
      size="small"
      @close="handleClose(item.key)"
      @click="handleCheck(item)"
      >{{ item.title }}</n-tag
    >
  </div>
</template>

<style lang="scss" scoped>
  .layout-header__tag {
    padding-left: 10px;
    display: flex;
    align-items: center;
    height: 30px;
  }
  .tag-item {
    margin-right: 5px;
    cursor: pointer;
  }
</style>

8. 构建 src/pages/components/layout-content.vue 页面内容 组件

<script setup></script>

<template>
  <div class="layout-content">
    <router-view v-slot="{ Component, route }">
      <transition name="mainFade" mode="out-in">
        <component :is="Component" :key="route.path"></component>
      </transition>
    </router-view>
  </div>
</template>

<style lang="scss" scoped>
  .layout-content {
    padding: 20px;
    margin: 20px;
    // height: auto;
    height: calc(100vh - 170px);
    border: 1px solid #e9e9e9;
    border-radius: 5px;
    -webkit-box-shadow: rgba(0, 0, 0, 0.047) 0 0 5px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.047);
  }
  .mainFade-enter-from {
    transform: translate(-80px);
    opacity: 0;
  }

  .mainFade-leave-to {
    transform: translate(80px);
    opacity: 0;
  }

  .mainFade-leave-from,
  .mainFade-enter-to {
    transform: translate(0px);
    opacity: 1;
  }

  .mainFade-enter-active {
    transition: all 0.1s ease;
  }

  .mainFade-leave-active {
    transition: all 0.1s cubic-bezier(1, 0.6, 0.6, 1);
  }
</style>

9. 创建如下内容页

src/pages/404.vue

src/pages/demo.vue

src/pages/eidtpassword.vue

src/pages/userinfo.vue

src/pages/system-dict.vue

src/pages/system-menu.vue

src/pages/user-user.vue

src/pages/user-role.vue

 页面基础构建如 demo.vue

<script setup></script>

<template>
  <div class="demo">demo</div>
</template>

<style lang="scss" scoped></style>

 综上

layout 动态路由布局构建完成。下一章:基础框架搭建完了,后续完善到哪更新哪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/842818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口测试——电商网站接口测试实战(四)

1. 接口测试需求分析 常见接口文档提供的两种方式 ①word文档 ②在线文档 电商网站网址模拟练习&#xff1a;Swagger UI 2. 登陆的分析 慕慕生鲜网址&#xff1a;慕慕生鲜账号密码点击execute后 输入账号密码后点击开发者工具&#xff0c;再登录&#xff0c;点击网络&…

PHP 门户信息网站系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 门户信息网站系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 下载地址https://download.csdn.net/download/qq_41221322/88179035https://downlo…

EVE-NG MPLS LDP LSP

目录 1 拓扑 2 配置步骤 2.1 配置接口IP 2.2 配置OSPF 2.3 使能LDP 2.3 在VPC上验证 1 拓扑 2 配置步骤 2.1 配置接口IP LER1 interface LoopBack 0ip address 1.1.1.9 32 quitinterface GigabitEthernet1/0ip address 10.1.1.1 255.255.255.0quitinterface GigabitEth…

Harbor企业镜像仓库部署

目录 一、Harbor 架构构成 二、部署harbor环境 1、安装docker-ce&#xff08;所有主机&#xff09; 2、阿里云镜像加速器 3、部署Docker Compose 服务 4、部署 Harbor 服务 5、启动并安装 Harbor 6、创建一个新项目 三、客户端上传镜像 1、在 Docker 客户端配置操作如下…

Leetcode 每日一题 - 删除有序数组中的重复项题 #算法 #Java

1.1 题目 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff…

寻找最佳项目管理工具?这些优秀选择值得一试!

优秀的项目管理工具可以帮助提高管理效率&#xff0c;缩短完成时间&#xff0c;减少困惑和挫折等等。 你的团队是否面临以下问题&#xff1a; 各组织信息独立&#xff0c;缺乏统一管理&#xff1f; 数字建设成本高、周期长、落地难&#xff1f; 数据孤岛&#xff0c;无法复用、…

抖音怎么录屏?这3种方法请你收好

抖音作为全球流行的短视频平台&#xff0c;让我们可以分享生活中的精彩瞬间&#xff0c;欣赏他人的创意作品。有时候&#xff0c;我们可能会遇到一些特别喜欢的视频&#xff0c;希望将其保存下来或与他人分享。本文将为您介绍抖音怎么录屏的全套攻略。通过本文的指导&#xff0…

A33 QT 主线例程 opengl

点击查看 HW33-050 HW33-070 规格书 HW33-050 HW33-070 支持 android 系统和 Linux QT。 HW33-XXX采用4 核Cortex-A7 ARM、Mali400MP2 GPU架构&#xff0c;主频 1.2GHz 的 CPU。内存 存储标配分别为1GB、8GB&#xff0c;内置显卡为Mali400MP2&#xff0c;支持 H.264 1080P …

segment-anything使用说明

文章目录 一. segment-anything介绍二. 官网Demo使用说明三. 安装教程四. python调用生成掩码教程五. python调用SAM分割后转labelme数据集 一. segment-anything介绍 Segment Anything Model&#xff08;SAM&#xff09;根据点或框等输入提示生成高质量的对象遮罩&#xff0c…

提货卡小程序怎么做

提货卡小程序是一款功能强大的应用&#xff0c;为用户提供了便捷的购物和提货体验。以下是其主要功能介绍&#xff1a; 1. 兑换码生成&#xff1a;提货卡小程序可以帮助商家批量生成兑换码。商家可以自定义兑换码的数量和规则&#xff0c;并将其分发给用户。这样&#xff0c;用…

小研究 - Mysql快速全同步复制技术的设计和应用(三)

Mysql半同步复制技术在高性能的数据管理中被广泛采用&#xff0c;但它在可靠性方面却存在不足.本文对半同步复制技术进行优化&#xff0c;提出了一种快速全同步复制技术&#xff0c;通过对半同步数据复制过程中的事务流程设置、线程资源合理应用、批量日志应用等技术手段&#…

网络安全(黑客)工作篇

一、网络安全行业的就业前景如何&#xff1f; 网络安全行业的就业前景非常广阔和有吸引力。随着数字化、云计算、物联网和人工智能等技术的迅速发展&#xff0c;网络安全的需求持续增长。以下是网络安全行业就业前景的一些关键因素&#xff1a; 高需求&#xff1a;随着互联网的…

Segment Anything【论文翻译】

文章目录 论文基础信息如下Abstract1. Introduction2. Segment Anything Task3. Segment Anything Model4. Segment Anything Data Engine5. Segment Anything Dataset6. Segment Anything RAI Analysis7. Zero-Shot Transfer Experiments7.1. Zero-Shot Single Point Valid Ma…

numpy 转换成 cupy 利用GPU执行 错误

ModuleNotFoundError: No module named cupy._core. routines_sorting 提示缺少包 使用 pyinstaller -D views.py --nocons 可以正常打包出来 但是运行出现报错 说明这个打包工具 忽略了很多 隐式导入的包 解决方法很简单 hiddenimports [fastrlock, fastrlock.rlock, cu…

F5洞察2023年网络威胁,助力网络安全防护

2023已经过半&#xff0c;关于网络安全防护的相关讨论话题热度始终居高不下。对于网络安全领域的从业者来说&#xff0c;应当对相关的前瞻分析有所了解。前段时间&#xff0c;我阅读了F5 安全运营中心工程师对威胁网络安全的预测&#xff0c;深受启发&#xff0c;故此选取了几则…

17款奔驰S400升级原厂前排座椅通风系统,夏天必备的功能

通风座椅的主动通风功能可以迅速将座椅表面温度降至适宜程度&#xff0c;从而确保最佳座椅舒适性。该功能启用后&#xff0c;车内空气透过打孔皮饰座套被吸入座椅内部&#xff0c;持续时间为 8 分钟。然后&#xff0c;风扇会自动改变旋转方向&#xff0c;将更凉爽的环境空气从座…

时序预测 | MATLAB实现BO-LSTM贝叶斯优化长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现BO-LSTM贝叶斯优化长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现BO-LSTM贝叶斯优化长短期记忆神经网络时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-LSTM贝叶斯优化长短期记忆神经网络时间序列预…

uniapp 微信小程序 分包

1、manifest.json内添加如图所示&#xff1a; "optimization" : {"subPackages" : true },2、在与pages同级上创建各个分包的文件夹 把需要分包的文件对应移入分包文件夹内 3、page.json内修改分包文件的路径 比如&#xff1a; {"path" : &qu…

【从零开始学习JAVA | 第四十篇】了解线程池

目录 前言&#xff1a; 线程池&#xff1a; 线程池的工作流程&#xff1a; 代码实现线程池&#xff1a; 任务拒绝策略&#xff1a; 线程池多大才算合适&#xff1f; 总结&#xff1a; 前言&#xff1a; 在Java编程中&#xff0c;线程池是一个强大的工具&#xff0c;它能…

CentOS下ZLMediaKit的可视化管理网站MediaServerUI使用

一、简介 按照 ZLMediaKit快速开始 编译运行ZLMediaKit成功后&#xff0c;我们可以运行其合作开源项目MediaServerUI&#xff0c;来对ZLMediaKit进行可视化管理。通过MediaServerUI&#xff0c;我们可以实现在浏览器查看ZLMediaKit的延迟率、负载率、正在进行的推拉流、服务器…