Vue--》Vue3打造可扩展的项目管理系统后台的完整指南(六)

news2024/11/15 8:44:29

今天开始使用 vue3 + ts 搭建一个项目管理的后台,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多前端vue知识,然后开篇先简单介绍一下本项目用到的技术栈都有哪几个方面(阅读本文章能够学习到的技术):

vite:快速轻量且功能丰富的前端构建工具,帮助开发人员更高效构建现代Web应用程序。

pnpm:高性能、轻量级npm替代品,帮助开发人员更加高效地处理应用程序的依赖关系。

Vue3:Vue.js最新版本的用于构建用户界面的渐进式JavaScript框架。

TypeScript:JavaScript的超集,提供了静态类型检查,使得代码更加健壮。

Animate:基于JavaScript的动画框架,它使开发者可以轻松创建各种炫酷的动画效果。

vue-router:Vue.js官方提供的路由管理器与Vue.js紧密耦合,非常方便与Vue.js一同使用。

Pinia:Vue3构建的Vuex替代品,具有响应式能力,提供非常简单的 API,进行状态管理。

element-plus:基于Vue.js 3.0的UI组件库,用于构建高品质的响应式Web应用程序。

axios:基于Promise的HTTP客户端,可以在浏览器和node.js中使用。

three:基于JavaScript的WebGL库,开发者可以编写高性能、高质量的3D场景呈现效果。

echarts:基于JavaScript的可视化图表库,支持多种类型的图表,可根据需要自行安装。

当然还有许多其他的需要安装的第三方库,这里就不再一一介绍了,在项目中用到的地方自行会进行讲解,大家自行学习即可,现在就让我们走进vue3+ts的实战项目吧。

目录

属性管理模块静态搭建

一级分类数据的收集与展示

分类组件业务实现

根据分类展示相关属性及属性值

属性业务的增改删操作


属性管理模块静态搭建

属性管理模块的静态搭建这里需要使用element-plus组件库提供的相关标签实现快速搭建样式,我们采用卡片样式,最外层用el-card进行包裹,接下来线设置三级分类的样式:

<template>
  <el-card>
    <el-form :inline="true">
      <el-form-item label="一级分类">
        <el-select>
          <el-option label="北京"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="二级分类">
        <el-select>
          <el-option label="北京"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="三级分类">
        <el-select>
          <el-option label="北京"></el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script setup lang="ts"></script>

<style scoped></style>

因为三级分类的模块有其他的管理模块仍然要使用,这里我将三级分类模块注册为全局组件进行处理,如下:

接下来我们在属性管理模块的路由组件中进行基本样式的搭建,如下:

<template>
  <div>
    <!-- 三级分类全局组件 -->
    <Category></Category>
    <el-card style="margin: 10px 0px">
      <el-button type="primary" size="default" icon="Plus">添加属性</el-button>
      <el-table border style="margin: 10px 0px">
        <el-table-column label="序号" type="index" align="center" width="80px"></el-table-column>
        <el-table-column label="属性名称" width="120px"></el-table-column>
        <el-table-column label="属性值名称"></el-table-column>
        <el-table-column label="操作" width="120px"></el-table-column>
      </el-table>
    </el-card>
  </div>
</template>

<script setup lang="ts"></script>

<style scoped></style>

最终呈现的结果如下所示:

一级分类数据的收集与展示

接下来我们需要编写接口文档来获取分类列表的数据,如下:

// 这是是书写属性相关的API文件
import request from '@/utils/request'
// 属性管理模块接口地址
enum API {
  // 获取一级分类接口地址
  C1_URL = '/admin/product/getCategory1',
  // 获取二级分类的接口地址
  C2_URL = '/admin/product/getCategory2/',
  // 获取三级分类的接口地址
  C3_URL = '/admin/product/getCategory3/',
}
// 获取一级分类的接口方法
export const reqC1 = () => request.get<any, any>(API.C1_URL)
// 获取二级分类的接口方法
export const reqC2 = (category1Id: number) => request.get<any, any>(API.C2_URL + category1Id)
// 获取三级分类的接口方法
export const reqC3 = (category2Id: number) => request.get<any, any>(API.C3_URL + category2Id)

为了方便我们拿到数据,不需要进行跨组件通信,这里我们可以将获取到的一级分类的数据及其相关ID存放在pinia仓库中去,方便后期的调用,如下:

// 商品分类全局组件的小仓库
import { defineStore } from 'pinia'
// 引入分类接口的方法
import { reqC1 } from '@/api/product/attr'

const useCategoryStore = defineStore('Category', {
  state: () => {
    return {
      // 存储一级分类的数据
      c1Arr: [],
      // 存储一级分类的ID
      c1Id: '',
    }
  },
  actions: {
    // 获取一级分类的方法
    async getC1() {
      // 发请求获取一级分类的数据
      const result: any = await reqC1()
      if (result.code == 200) {
        this.c1Arr = result.data
      }
    },
  },
  getters: {},
})
export default useCategoryStore

接下来我们就可以通过仓库拿到一级分类的数据,并将其展示到一级分类列表里面,如下:

<template>
  <el-card>
    <el-form :inline="true">
      <el-form-item label="一级分类">
        <el-select v-model="categoryStore.c1Id">
          <!-- option中label即为显示文字  value属性即为select下拉菜单收集的数据 -->
          <el-option v-for="c1 in categoryStore.c1Arr" :key="c1.id" :label="c1.name" :value="c1.id"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="二级分类">
        <el-select>
          <el-option label="北京"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="三级分类">
        <el-select>
          <el-option label="北京"></el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'
// 引入分类相关的仓库
import useCategoryStore from '@/store/category'
let categoryStore = useCategoryStore()

// 通知仓库获取一级分类的方法
const getC1 = async () => {
  // 通知分类仓库发请求获取一级分类的数据
  categoryStore.getC1()
}

// 组件挂载完毕
onMounted(() => {
  // 获取一级分类的数据
  getC1()
})
</script>

<style scoped></style>

接下来开始为分类接口编写ts类型限制,如下:

// 分类相关的数据ts类型
export interface ResponseData {
  code: number
  message: string
  ok: boolean
}

// 分类ts类型
export interface CategoryObj {
  id: number | string
  name: string
  category1Id?: number
  category2Id?: number
}

// 相应的分类接口返回数据的类型
export interface CategoryResponseData extends ResponseData {
  data: CategoryObj[]
}

编写好ts类型之后,接下来就可以对接口进行类型限制,如下:

当然在仓库中也对其类型进行相关的限制,如下:

分类组件业务实现

在上文我们已经完成了对一级分类的实现,接下来开始实现二级分类和三级分类的功能,要知道一级分类我们在组件刚刚加载的时候就获取到相关数据了,但是二三级分类却不行,只有在一级分类选择了相关分类产生了ID之后,才会加载二和三级分类的相关数据,秉持着这个原则进行如下实现

我们在仓库中声明获取分类数据的所有方法和state数据,如下:

// 商品分类全局组件的小仓库
import { defineStore } from 'pinia'
// 引入分类接口的方法
import { reqC1, reqC2, reqC3 } from '@/api/product/attr'
// 引入ts类型
import type { CategoryResponseData } from '@/api/product/attr/type'
import type { CategoryState } from './type'

const useCategoryStore = defineStore('Category', {
  state: (): CategoryState => {
    return {
      // 存储一级分类的数据
      c1Arr: [],
      // 存储一级分类的ID
      c1Id: '',
      // 存储对应一级分类下的二级分类
      c2Arr: [],
      // 存储二级分类的ID
      c2Id: '',
      // 存储三级分类的数据
      c3Arr: [],
      // 存储三级分类的ID
      c3Id: '',
    }
  },
  actions: {
    // 获取一级分类的方法
    async getC1() {
      // 发请求获取一级分类的数据
      const result: CategoryResponseData = await reqC1()
      if (result.code == 200) {
        this.c1Arr = result.data
      }
    },
    // 获取二级分类的数据
    async getC2() {
      // 获取对应一级分类下的二级分类
      const result: CategoryResponseData = await reqC2(this.c1Id)
      if (result.code == 200) {
        this.c2Arr = result.data
      }
    },
    // 获取三级分类的数据
    async getC3() {
      // 获取对应二级分类下的三级分类
      const result: CategoryResponseData = await reqC3(this.c2Id)
      if (result.code == 200) {
        this.c3Arr = result.data
      }
    },
  },
  getters: {},
})
export default useCategoryStore

给分类设置v-for遍历数据,然后通过change监听事件来监视下拉框数据的变化:

在给每个监听事件设置获取仓库数据之前,先对其子分类的数据进行一个清空,防止在更改分类数据之后,其子分类的数据没有发生变化:

接下来设置添加属性的按钮禁用状态,如果有三级分类的ID,才能进行点击否则就处于禁用状态:

最后呈现的结果如下:

根据分类展示相关属性及属性值

根据选择的分类数据获取相应的属性及其属性值,这就要求我们要将选择的分类数据对应的ID值作为参数传递给接口,从而拿到相应的属性和属性值,如下:

给数据编写相应的ts类型数据进行类型限制:

// 属性与属性值的ts类型
export interface AttrValue {
  id: number
  valueName: string
  attrId: number
}

// 存储每一个属性值的数组类型
export type AttrValueList = AttrValue[]
// 属性对象
export interface Attr {
  id: number
  attrName: string
  categoryId: number
  categoryLevel: number
  attrValueList: AttrValueList
}
// 存储每一个属性对象的数组ts类型
export type AttrList = Attr[]
// 属性接口返回的数据ts类型
export interface AttrResponseData extends ResponseData {
  data: Attr[]
}

通过设置watch监听器属性用来监听三级分类id的变化,一旦存在三级分类的id,就将每个分类的id值进行一个获取,作为参数传递给获取属性及属性值的接口,然后获取相应的数据:

<script setup lang="ts">
// 引用watch监听
import { watch, ref } from 'vue'
// 引入获取已有属性和属性值接口
import { reqAttr } from '@/api/product/attr'
import type { AttrResponseData, Attr } from '@/api/product/attr/type'
// 获取分类仓库
import useCategoryStore from '@/store/category'
let categoryStore = useCategoryStore()
// 存储已有的属性与属性值
let attrArr = ref<Attr[]>([])

// 监听仓库三级分类ID的变化
watch(
  () => categoryStore.c3Id,
  () => {
    // 清空上一次查询的属性与属性值
    attrArr.value = []
    // 保证三级分类得有才能发起请求
    if (!categoryStore.c3Id) return
    // 获取分类的ID
    getAttr()
  },
)
// 获取已有的属性与属性值方法
const getAttr = async () => {
  // 获取分类的ID
  const { c1Id, c2Id, c3Id } = categoryStore
  let result: AttrResponseData = await reqAttr(c1Id, c2Id, c3Id)
  if (result.code == 200) {
    attrArr.value = result.data
  }
}
</script>

通过接口获取到的数据,然后在html代码中进行数据绑定呈现数据

最终的结果如下所示:

属性业务的增改删操作

接下来实现属性及其属性值的增改删操作,因为都是和后端数据库进行交互的,所以这里需要我们撰写相应的接口进行实现,如下:

// 这是是书写属性相关的API文件
import request from '@/utils/request'
// 引入ts类型
import type { CategoryResponseData, AttrResponseData, Attr } from './type'
// 属性管理模块接口地址
enum API {
  // 获取一级分类接口地址
  C1_URL = '/admin/product/getCategory1',
  // 获取二级分类的接口地址
  C2_URL = '/admin/product/getCategory2/',
  // 获取三级分类的接口地址
  C3_URL = '/admin/product/getCategory3/',
  // 获取分类下的已有属性与属性值
  ATTR_URL = '/admin/product/attrInfoList/',
  // 添加或者修改已有的属性的接口
  ADDORUPDATEATTR_URL = '/admin/product/saveAttrInfo',
  // 删除某一个已有的属性
  DELETEATTR_URL = '/admin/product/deleteAttr/',
}
// 获取一级分类的接口方法
export const reqC1 = () => request.get<any, CategoryResponseData>(API.C1_URL)
// 获取二级分类的接口方法
export const reqC2 = (category1Id: number | string) => request.get<any, CategoryResponseData>(API.C2_URL + category1Id)
// 获取三级分类的接口方法
export const reqC3 = (category2Id: number | string) => request.get<any, CategoryResponseData>(API.C3_URL + category2Id)
// 获取对应分类下已有的属性与属性值接口
export const reqAttr = (category1Id: number | string, category2Id: number | string, category3Id: number | string) =>
  request.get<any, AttrResponseData>(API.ATTR_URL + `${category1Id}/${category2Id}/${category3Id}`)
// 新增或者修改已有的属性接口
export const reqAddOrUpdateAttr = (data: Attr) => request.post<any, any>(API.ADDORUPDATEATTR_URL, data)
// 删除某一个已有的属性业务
export const reqRemoveAttr = (attrId: number) => request.delete<any, any>(API.DELETEATTR_URL + attrId)

这里设置两个场景进行切换,当场景为0时展示具体数据页面,当场景为1时展示添加或修改数据的页面,具体操作如下:

接下来开始实现添加或修改数据页面的实现,其具体搭建与数据交互样式如下:

<div v-show="scene == 1">
  <!-- 展示添加属性以及修改属性的结构 -->
  <el-form :inline="true">
    <el-form-item label="属性名称">
      <el-input placeholder="请输入属性的名称" v-model="attrParams.attrName"></el-input>
    </el-form-item>
  </el-form>
  <el-button
    @click="addAttrValue"
    :disabled="attrParams.attrName ? false : true"
    type="primary"
    size="default"
    icon="Plus"
  >
    添加属性值
  </el-button>
  <el-button type="primary" size="default" @click="cancel">取消</el-button>
  <el-table border style="margin: 10px 0px" :data="attrParams.attrValueList">
    <el-table-column label="序号" width="80px" type="index" align="center"></el-table-column>
    <el-table-column label="属性值名称">
      <!-- row:即为当前属性值对象 -->
      <template #default="{ row, $index }">
        <el-input
          :ref="(vc: any) => inputArr[$index] = vc"
          v-if="row.flag"
          @blur="toLook(row, $index)"
          placeholder="请你输入当前的属性值名称"
          v-model="row.valueName"
        ></el-input>
        <div v-else @click="toEdit(row, $index)">{{ row.valueName }}</div>
      </template>
    </el-table-column>
    <el-table-column label="属性值操作">
      <template #default="{ row, $index }">
        <el-button
          type="primary"
          size="small"
          icon="Delete"
          @click="attrParams.attrValueList.splice($index, 1)"
        ></el-button>
      </template>
    </el-table-column>
  </el-table>
  <el-button
    type="primary"
    size="default"
    @click="save"
    :disabled="attrParams.attrValueList.length > 0 ? false : true"
  >
    保存
  </el-button>
  <el-button type="primary" size="default" @click="cancel">取消</el-button>
</div>

给添加按钮设置相应的回调函数:

const addAttrValue = () => {
  // 点击添加属性值按钮的时候,向数组添加一个属性值对象
  attrParams.attrValueList.push({
    valueName: '',
    flag: true, // 控制每一个属性值编辑模式与文字模式的切换
  })
  // 获取最后el-input组件聚焦
  nextTick(() => {
    inputArr.value[attrParams.attrValueList.length - 1].focus()
  })
}

给添加的数据设置了两种模式,一开始是聚焦的输入框,一旦失去焦点就会变成div文字样式,当再次点击div的时候,文字样式又会变成聚焦的输入框,样式如下:

// 属性值表单元素失去焦点的方法
const toLook = (row: AttrValue, $index: number) => {
  // 非法情况的判断1
  if (row.valueName.trim() == '') {
    // 删除掉对应属性值为空的元素
    attrParams.attrValueList.splice($index, 1)
    ElMessage({
      type: 'error',
      message: '属性值不能为空',
    })
    return
  }
  // 非法情况的判断2
  let repeat = attrParams.attrValueList.find((item) => {
    // 把当前失去焦点属性值重复对象从当前数组扣除
    if (item != row) {
      return item.valueName === row.valueName
    }
  })
  if (repeat) {
    // 删除掉对应属性值为空的元素
    attrParams.attrValueList.splice($index, 1)
    ElMessage({
      type: 'error',
      message: '属性值不能重复!',
    })
    return
  }
  row.flag = false
}
// 点击div切换到编辑模式
const toEdit = (row: AttrValue, $index: number) => {
  row.flag = true
  // nextTick:响应式数据发生变化,获取更新的DOM(组件实例)
  nextTick(() => {
    inputArr.value[$index].focus()
  })
}

然后给保存按钮设置函数:

// 保存按钮的回调
const save = async () => {
  // 发起请求
  let result: any = await reqAddOrUpdateAttr(attrParams)
  // 添加|修改属性成功,切换场景
  if (result.code == 200) {
    // 切换场景
    scene.value = 0
    // 提示信息
    ElMessage({
      type: 'success',
      message: attrParams.id ? '修改成功' : '添加成功',
    })
    // 获取全部已有的属性和属性值
    getAttr()
  } else {
    // 提示信息
    ElMessage({
      type: 'error',
      message: attrParams.id ? '修改失败' : '添加失败',
    })
  }
}

修改功能很简单,只要获取相应要修改数据的id即可,这里将要修改数据的id作为参数传递给接口函数就能实现相应的修改:

// table表格修改已有属性按钮的回调
const updateAttr = (row: Attr) => {
  // 切换为添加与修改属性的结构
  scene.value = 1
  // 将已有的属性对象赋值给attrParams对象即为Object.assign进行对象的合并
  Object.assign(attrParams, JSON.parse(JSON.stringify(row)))
  getAttr()
}

删除按钮的回调也是相应的道理,获取要删除的数据的ID然后作为参数传递给接口函数进行相应的删除即可,如下:

// 删除某一个已有的属性方法的回调
const deleteAttr = async (attrId: number) => {
  // 发相应的删除已有属性的请求
  let result: any = await reqRemoveAttr(attrId)
  // 删除成功
  if (result.code == 200) {
    ElMessage({
      type: 'success',
      message: '删除成功!',
    })
    // 删除成功之后在次调用获取数据函数
    getAttr()
  } else {
    ElMessage({
      type: 'error',
      message: '删除失败!',
    })
  }
}

当然删除的这个按钮采用的是组件库给我们提供的气泡提示框,具体的样式实现如下:

这里有个小bug,当我们切换路由组件然后再切回属性管理模块时,仓库的还会存有以前的数据,这里我将其仓库中的数据引用相关API函数进行一个数据的重置,操作如下:

// 路由组件销毁的时候,把仓库分类相关的数据进行清空
onBeforeUnmount(() => {
  // 清空仓库的数据
  categoryStore.$reset()
})

最终呈现的结果如下:

本项目的属性管理页面功能的搭建就讲解到这,下一篇文章将继续讲解其它模块的主体内容,关注博主学习更多前端vue知识,您的支持就是博主创作的最大动力! 

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

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

相关文章

翻过那座山——Gitlab流水线任务疑难之编译有子模块的项目指南

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不是…

【C/C++】详解 类和对象的概念、基本用法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

2023-01-31 LightDB Agent安装.md

LightDB Agent安装 简介 LightDB Enterprise Manager(即 LightDB数据库监控管理平台&#xff0c;下文均简称为LightDB EM)是一个综合性的数据库监控和管理系统&#xff0c; 旨在满足数据库用户的需求&#xff0c;提供强大的图形界面&#xff0c;简化了对LightDB数据库的维护和使…

<C语言> 函数与递归

函数 1.函数的分类 库函数自定义函数 1.1 库函数 C语言提供了许多库函数&#xff08;library functions&#xff09;来简化开发过程并提供常用功能的实现。库函数是预先编写好的函数&#xff0c;可以通过调用这些函数来执行特定的任务。 为什么会有库函数&#xff1f; ​…

Docker中为RabbitMQ安装rabbitmq_delayed_message_exchange插件

Docker中为RabbitMQ安装rabbitmq_delayed_message_exchange插件 1、前言1、下载插件2、拷贝插件到RabbitMQ容器3、启用插件 1、前言 rabbitmq_delayed_message_exchange是一款向RabbitMQ添加延迟消息传递&#xff08;或计划消息传递&#xff09;的插件。 插件下载地址&#x…

Java Web框架对比:选择适合你的项目

导言 选择合适的Java Web框架是开发成功的关键之一。本文将详细对比几个常见的Java Web框架&#xff0c;包括Spring MVC、JavaServer Faces (JSF)、Struts、Play Framework、Apache Wicket和Vaadin&#xff0c;并分析它们的特点、优缺点&#xff0c;以帮助您做出明智的选择。 …

IP笔记全部整合(参考)

高级网络工程师 HCIA回顾1、网络基础2、动态路由协议3、路由认证4、路由控制&#xff08;AD metric &#xff09; 一、知识巩固二、场景模拟1、获取IP地址1.1 DHCP --- 动态主机配置协议1.1.1 DHCP客户端1.1.2 DHCP服务器1.1.3 DHCP客户端1.1.4 DHCP服务器 2、打开浏览器3、路由…

C语言全章总结

数据类型 ​ 用不同数据类型所定义的变量所占空间大小不一样&#xff0c;定义的变量不是保存于数据类型中&#xff0c;而是因为只有定义了该数据类型的变量才能保存数据。 一、整型 1、整型&#xff08;int&#xff09; 四字节&#xff0c;默认有符号&#xff08;-231-231-1…

Spark中python和jvm的通信杂谈--ArrowConverter

背景 要提起ArrowConverters&#xff0c;就得说起Arrow这个项目&#xff0c;该项目的初衷是加速进程间的数据交换&#xff0c;从目前的社区发展以及它的周边来看&#xff0c;其实是一个很不错的项目。 那为什么Spark要引入Arrow呢&#xff1f;其实还得从Pyspark中python和jvm的…

io.netty学习(十)Netty 程序引导类

目录 前言 引导程序类 AbstractBootStrap 抽象类 Bootstrap 类 ServerBootstrap 类 引导服务器 1、实例化引导程序类 2、设置 EventLoopGroup 3、指定 Channel 类型 4、指定 ChannelHandler 5、设置 Channel 选项 6、绑定端口启动服务 引导客户端 1、实例化引导程…

设计模式之代理模式笔记

设计模式之代理模式笔记 说明Proxy(代理)目录代理模式静态代理示例类图买火车票的接口火车站类代售点类测试类 JDK动态代理买火车票的接口火车站类获取代理对象的工厂类测试类 CGLIB动态代理火车站类代理工厂类测试类 三种代理对比优缺点 说明 记录下学习设计模式-代理模式的写…

windows pwn

环境搭建 checksec winchecksec winchecksec 是 windows 版的 checksec &#xff0c;不过有时候结果不太准确。 checksec&#xff08;x64dbg&#xff09; x64dbg 的插件 checksec 检查效果比较准确&#xff0c;并且可以连同加载的 dll 一起检测。 将 release 的插件按 3…

RK3288 Android8.1添加EC25

首先拿到供应商提供的so库&#xff0c;将so放到vendor\rockchip\common\phone\lib下 修改对应的phone.mk&#xff0c;将so库移动指定位置&#xff08;Android7以下移动到system/lib,android8以后移动到vendor/lib&#xff09; CUR_PATH : vendor/rockchip/common#############…

mysql避免重复插入记录insert ignore 、on duplicate key update、replace into

星标▲Java学习之道▲一起成长&#xff0c;一起学习~ 哈喽&#xff0c;大家好&#xff0c;我是阿淼。今天梳理一下mysql中避免重复插入记录的集中操作。 1序 回顾以前写的项目&#xff0c;发现在规范的前提下&#xff0c;还是可以做点骚操作的。 假如项目使用的MySQL&#xff0…

基于Informer的股票价格预测(量化交易综述)

摘要 股票市场是金融市场中不可或缺的组成部分。准确预测股票趋势对于投资者和市场参与者具有重要意义&#xff0c;因为它们可以指导投资决策、优化投资组合以及降低金融风险。而且可以提升国家国际地位以及金融风险控制能力&#xff0c;还可以促进股票市场发展以及资源优化利…

Java常用类库与技巧

1、String&#xff0c;StringBuffer&#xff0c;StringBuilder的区别&#xff1f; 2、Java异常 异常处理机制主要回答了三个问题 What&#xff1a;异常类型回答了什么被抛出&#xff1f;Where&#xff1a;异常堆栈跟踪回答了在哪抛出&#xff1f;Why&#xff1a;异常信息回答…

PowerDesigner165安装

PowerDesigner安装及解析 一、PowerDesigner安装1.双击开始安装2.一路“Next”3.选择地区4.安装路径5.按图勾选6.一路“Next”7.安装中8.安装完成 二、解析三、使用 一、PowerDesigner安装 1.双击开始安装 2.一路“Next” 3.选择地区 选择软件安装所属地区,一定要选择“Hong …

vue3-实战-12-管理后台-权限管理之菜单管理模块-首页-主题颜色-暗黑模式

目录 1-列表页面功能开发 1.1-需求原型分析 1.2-接口和数据类型定义 1.3-获取服务端数据渲染页面 2-新增编辑菜单 2.1-原型需求分析 2.2-表单数据收集和页面结构开发 2.3-提交或者取消 3-删除菜单 4-首页开发 5-暗黑模式的切换和主题颜色 5.1-暗黑模式 5.2-主题颜…

three.js几何体的_UV_、法向属性以及BufferGeometry类介绍

一、几何体的_UV_以及法向属性 UV属性是一组二维坐标&#xff0c;每个顶点都有一个对应的UV坐标。在三维模型上贴上二维的纹理贴图时&#xff0c;需要将所有顶点映射到纹理上的对应位置。UV属性的取值范围一般是[0,1]&#xff0c;表示纹理上的相对位置。通过修改UV属性&#xf…

Shell - 02_shell变量

一、shell的自定义变量 1.定义变量&#xff1a;变量名变量值 如&#xff1a;num10 2.引用变量&#xff1a;$变量名 如&#xff1a;i$num 把变量 num 的值付给变量 i 3.显示变量&#xff1a;使用 echo 命令可以显示单个变量取值 如&#xff1a;echo $num 4.清除变量&…