Vue2电商前台项目——完成加入购物车功能和购物车页面

news2025/1/18 6:55:13

Vue2电商前台项目——完成加入购物车功能和购物车页面

文章目录

  • Vue2电商前台项目——完成加入购物车功能和购物车页面
    • 一、加入购物车
      • 1、路由跳转前先发请求把商品数据给服务器
        • (1)观察接口文档
        • (2)写接口
        • (3)dispatch传数据
        • (4)判断服务器是否已经收到商品数据
      • 2、请求成功后进行路由跳转
        • (1)创建路由并配置路由规则
        • (2)路由跳转并传参(练习本地存储)
    • 二、完成购物车页面的业务
      • 1、生成游客id
      • 2、获取相应的购物车数据
      • 3、计算打勾商品总价
      • 4、全选和商品的打勾联动
        • (1)全选按钮是否选中
        • (2)修改单个产品的选中状态
        • (3)点击全选时所有商品状态跟着切换
      • 5、删除购物车数据
        • (1)删除单个商品
        • (2)删除选中的所有商品
      • 6、购物车商品数量加减改(难点)
        • (1)分析一下
        • (2)配置请求的方法

一、加入购物车

1、路由跳转前先发请求把商品数据给服务器

(1)观察接口文档

这里其实只需要把已有物品的id和数量传给后台,后台不需要返回数据

请添加图片描述

请添加图片描述

(2)写接口

又到了咱滚瓜烂熟的写接口环节:

src/api/index.js
// 将产品添加到购物车中
export const reqAddShopCart = (skuId, skuNum) => {
  return requests({
    url: `/cart/addToCart/{skuId}/{skuNum}`,
    method: "post",
  });

(3)dispatch传数据

1、给加入购物车按钮添加点击事件

请添加图片描述

2、派送actions,然后把数据以对象的形式传过去,第一个键值对是商品id(当从Search到Detail路由跳转时就传过来的params参数),第二个键值对是购物车数量(我们之前已经存到了Detail组件的data里了)

    // 加入购物车的回调函数
    addShopcar() {
      // 派发actions
      // 1、发请求——将产品加入到数据库(通知服务、传递参数器)
      this.$store.dispatch("getShopCart", {
        skuId: this.$route.params.skuid,
        skuNum: this.skuNum,
      });
      // 2、服务器存储成功——进行路由跳转
      // 3、失败——给用户进行提示
    },

3、actions这边通过解构赋值,调用接口并把数据传给服务器(后端数据库)

const actions = {
  ......
  async getShopCart({ commit }, { skuId, skuNum }) {
    let result = await reqAddShopCart(skuId, skuNum);
    console.log("添加到购物车的信息" + result);
  },
};

(4)判断服务器是否已经收到商品数据

这里要判断请求是否已经成功,也就是服务器是否收到了要加入购物车商品的数据,若成功了就要进行路由跳转并传参,若失败了就要给用户提示。

dispatch就会调用这个actions里的函数,调用这个async函数返回一个promise对象,这个Promise对象的状态和结果值取决于这个async函数的返回值。

1、如果返回一个非Promise对象,那么就是成功,值就是返回值;
2、如果返回Promise对象,那么状态和结果值取决于该Promise
3、如果不写返回值,且await后是失败的Promise,那么就会抛出异常,既然抛出异常,那么async函数返回的就是一个失败的Promise。
4、如果不写返回值,且await后是成功的Promise,那么就会返回undefined,async函数返回的就是一个成功的Promise,值是undefined。

const actions = {
  ......
  //加入购物车
  //异步请求,把商品id和数量发送给服务器
  async getShopCart({ commit }, { skuId, skuNum }) {
    //其实这里不用try-catch,因为那边已经try了,不写return默认返回undefined(成功的Primise)
    //如果await后成功则返回undefined(没写return,返回成功的Promise)
    //如果失败则抛出异常(返回失败的Promise)
    let result = await reqAddShopCart(skuId, skuNum);
    console.log("添加到购物车的信息" + result);
    //这里只是把购物车数据给服务器,但是服务器不需要返回什么东西。所以这里我们不用再三连环了,通过dispatch把数据给服务器就已经好了
    // if (result.code == 200) {
    //   commit("GETSHOPCART", result.data);
    // }
  },
};
  methods: {
    ......
    // 加入购物车的回调函数
    async addShopcar() {
      // 派发actions
      // 1、发请求——将产品加入到数据库(通知服务、传递参数器)
      try {
        // 2、服务器存储成功——进行路由跳转
        this.$store.dispatch("getShopCart", {
          skuId: this.$route.params.skuid,
          skuNum: this.skuNum,
        });
      } catch (error) {
        // 3、失败——给用户进行提示
        console.log("请求失败", error.message);
      }
    },
  },

2、请求成功后进行路由跳转

路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。

(1)创建路由并配置路由规则

1、所以我们先创建路由

请添加图片描述

2、配置路由规则src/router/routes.js

  {
    name: "addcat",
    path: "/addcartsuccess",
    component: AddCartSuccess,
    meta: {
      showFooter: true,
  },

(2)路由跳转并传参(练习本地存储)

3、写路由跳转和传参的代码

请添加图片描述

这里要传两个值:skuInfo对象和商品数量shopCarNum(其实skuInfo根本不用传,直接去仓库读就行了)。传参的时候最好别用params和query,因为带过去的需要是skuInfo这个对象,那么对象传过去的话,地址栏可能会是乱码。这里采用的方案是:会话存储——点此复习

1、使用query传简单的商品数量shopCarNum,因为数字不会乱码
2、使用会话存储(本地存储也行)带skuInfo过去(其实直接从仓库读就行了;或者你用query也行,无非就是地址栏乱码)

async addShopcar() {
      // 派发actions
      // 1、发请求——将产品加入到数据库(通知服务、传递参数器)
      try {
        // 2、服务器存储成功——进行路由跳转
        await this.$store.dispatch("getShopCart", {
          skuId: this.$route.params.skuid,
          skuNum: this.skuNum,
        });
        // 进行路由跳转并传参
        // 一些简单的数据可以通过query形式传参
        // 此处的产品信息比较复杂,是一个对象,所以我们可以采用会话存储sessionStorage
        // 本地存储和会话存储一般存的是字符串,所以我们把对象转化成JSON字符串进行存储
        sessionStorage.setItem("SKUINFO", JSON.stringify(this.skuInfo));
        this.$router.push({ name: "addcat", query: { skuNum: this.skuNum } });
      } catch (error) {
        // 3、失败——给用户进行提示
        console.log("请求失败", error.message);
      }
    },

注意:

  • 本地存储 里面只能存储字符串格式 ,因此需要把对象转换为字符串JSON.stringify()
  • 获取本地存储数据,需要把里面的字符串转换为对象格式JSON.parse() 我们才能使用里面的数据。

请添加图片描述

然后把相应的数据放到页面上

请添加图片描述

请添加图片描述

二、完成购物车页面的业务

点击查看商品详情就直接跳回去就行了,数据仓库本来就有不用重新发请求

<router-link class="sui-btn btn-xlarge" :to="`/detail/${skuInfo.id}`">
    查看商品详情
</router-link>

接下来是点击去购物车结算,跳到购物车结算页面
把购物车部分的静态搞过来,然后注册一下路由,并写个路由跳转。

<router-link to="/shopcart">去购物车结算 > </router-link>

请添加图片描述

1、生成游客id

这里后端应该是写了个逻辑,用一个叫userTempId的请求头字段来判断你是谁,然后返回给你相应的数据。

一般来说正常的逻辑应该是每个用户有自己的token,然后点击加入购物车之后,往用户-商品这个表里添加一行数据;读购物车取数据的时候呢,应该是传用户token参数获取相应的商品列表。而这里为了模拟,后端写好了useTempId字段,刷新时我们就给他个游客id(唯一id),它就拿着这个字段直接作为本地浏览器游客,所以请求购物车数据也不用传参。

这里随机生成游客id的方法有很多,可以使用nanoid、uuid、时间戳,这里我使用的是uuid。并且需要持久存储我们可以使用localStorage。

1、进入页面的时候先随机生成一个时间戳,作为用户的id。

请添加图片描述

请添加图片描述

2、请求数据时,在请求拦截器中将该id作为请求中userTempId的值。也就是把这个id放在请求头里传给服务器。

请添加图片描述

3、这样就完成了,只要本地存储中这个id没有被手动清除,那么每次都可以获取该id的购物车数据。

2、获取相应的购物车数据

写接口

// 获取购物车列表数据
export const reqCartList = () => {
  return requests({
    url: "/cart/cartList",
    method: "get",
  });
};

发请求,三连环。

请添加图片描述

请添加图片描述

最后,把数据展示在页面上
请添加图片描述

请添加图片描述

3、计算打勾商品总价

这个好算,利用isChecked属性,只计算选中(isChecked=1)的价格,forEach循环一下就行了。

请添加图片描述

  computed: {
    ......
    // 计算购买商品的总价
    totalPrice() {
      let totalPrice = 0;
      this.cartInfoList.forEach((element) => {
        if (element.isChecked == 1) {
          totalPrice += element.skuNum * element.skuPrice;
        }
      });
      return totalPrice;
    },

4、全选和商品的打勾联动

(1)全选按钮是否选中

全选按钮是否选中,取决于每个复选框是否都选中,也就是判断每个元素的isChecked是不是都为1

    // 判断全选框是否勾选(若每个产品都勾选了,也就是isCheck都等于一,则勾选)
    isAllChecked() {
      // every:遍历每个元素
      // 只要有一个不等于1就返回false
      return this.cartInfoList.every((item) => item.isChecked == 1);
    },

(2)修改单个产品的选中状态

修改单个产品状态需要去发送请求修改isChecked字段,这是因为总价那里用到了这个字段去计算,我们要实现勾选的计算总价,取消勾选就不计算。
修改产品勾选状态的接口,需要传两个参数:skuId(产品id)、isChecked(产品的选中状态)

下面依旧是咱们熟悉的步骤。

写接口:

// 修改购物车产品选中状态
export const reqUpdateCheck = (skuId, isChecked) => {
  return requests({
    url: `/cart/checkCart/${skuId}/${isChecked}`,
    method: "get",
  });
};

三连环vuex调用接口:

const actions = {
  // 修改购物车某个产品的选中状态
  async updateChecked({ commit }, { skuId, isChecked }) {
    let result = await reqUpdateCheck(skuId, isChecked);
    if (result.code == 200) {
      return "ok";
    } else {
      return Promise.reject(new Error("fail"));
    }
  },
};

每个购物车商品按钮配置一个点击事件(或者切换事件)如果当前勾选状态为1(勾选),那么改成0(取消勾选),反之也一样。

在html添加事件:

请添加图片描述

// 修改某个产品的勾选状态
    async updateChecked(cart, $event) {
      // 带过去的isChecked原本是布尔值,但是我们需要的应该是0或者1
      // console.log(event.target.checked);
      try {
        // 如果修改成功,再次获取服务器数据
        let checked = event.target.checked ? "1" : "0";
        await this.$store.dispatch("updateChecked", {
          skuId: cart.skuId,
          isChecked,
        });
        this.getData();
      } catch (error) {
        alert("修改失败" + error);
      }
    },

(3)点击全选时所有商品状态跟着切换

给全选的勾选框添加点击事件。总体来说主要思路就是点击全选时派发请求,这个请求需要把每个商品的勾选状态改成当前全选框的状态。
所以需要在actions中遍历购物车数据并派发请求,(当然其实在组件中写也一样,就是这样规范点),用try-catch捕获,如果都请求成功,那么就使用Promise.all获取成功的标志

  // 修改购物车某个产品的选中状态
  async updateChecked({ commit }, { skuId, isChecked }) {
    let result = await reqUpdateCheck(skuId, isChecked);
    if (result.code == 200) {
      return "ok";
    } else {
      return Promise.reject(new Error("fail"));
    }
  },
  // 点击全选按钮修改所有商品的状态
  changeAllChecked({ dispatch, state }, isChecked) {
    let promiseAll = [];
    state.cartList[0].cartInfoList.forEach((el) => {
      try {
        let promise = dispatch("updateChecked", {
          skuId: el.skuId,
          isChecked,
        });
        promiseAll.push(promise);
      } catch (error) {
        console.log(`${el.skuNum}修改失败`, err);
      }
    });
    return Promise.all(promiseAll);
  },

然后去组件中给全选添加点击事件就行

    // 修改全部产品的选中状态
    async changeAllChecked() {
      try {
        let isChecked = event.target.checked ? "1" : "0";
        await this.$store.dispatch("changeAllChecked", isChecked);
        this.getData();
      } catch (error) {
        console.log("全选修改失败", error);
      }
    },

5、删除购物车数据

(1)删除单个商品

这个就比较简单了,不多说了,就是写接口——三连环——派发action

  1. 写接口
//删除购物车商品的接口
// /api/cart/deleteCart/{skuId}
export const reqDeleteGoodById = (skuId) => {
    return requests({
        url: `/cart/deleteCart/${skuId}`,
        method: 'delete',
    })
}

写接口要注意,一般带参的url要用反引号(一般处于电脑键盘Tab上面那个)而不是引号。

  1. 三连环
  // 删除购物车产品
  async deleteCartGood({ commit }, skuId) {
    let result = await reqDeleteCart(skuId);
    console.log("被删除的产品信息" + result);
    if (result.code == 200) {
      return "ok";
    } else {
      return Promise.reject(new Error("fail"));
    }
  },
  1. 添加点击事件并派发action重新请求并展示

先在对应位置添加点击事件:

请添加图片描述

    // 删除某个购物车产品
    async deleteCartById(cart) {
      try {
        // 如果删除成功,再次发请求获取数据进行展示
        await this.$store.dispatch("deleteCartGood", cart.skuId);
        this.getData();
      } catch (error) {
        console.log("删除失败", error);
      }
    },

(2)删除选中的所有商品

这个逻辑和点击全选修改每个商品的勾选状态有点像。

  1. vuex中利用遍历购物车数据,查出来哪个是选中的,然后依次发请求删除 删除成功与否的结果利用Promise.all传给组件
// 删除某个购物车产品
async deleteCartGood({ commit }, skuId) {
  let result = await reqDeleteCart(skuId);
  console.log("被删除的产品信息" + result);
  if (result.code == 200) {
    return "ok";
  } else {
    return Promise.reject(new Error("faile"));
  }
},
// 删除购物车所有被选中的产品
deleteAllCartGood(context) {
  // context身上有dispatch、commit、getters、state等数据
  // 获取购物车中全部的产品
  // console.log(context.getters.cartList.cartInfoList);
  let PromiseArr = [];
  context.getters.cartList.cartInfoList.forEach((el) => {
    let promise =
      el.isChecked==1 ? context.dispatch("deleteCartGood", el.skuId): "";
    // 将每一次返回的promise添加到数组中
    PromiseArr.push(promise);
  });
  // 只要有一个失败都返回失败的结果
  return Promise.all(PromiseArr);
},
  1. 点击删除选中商品按钮生效,方法中派发请求
// 删除被选中的产品
// 这个回调函数收集不到cart.skuId,因为它不在v-for内
async deleteAllCheckedCart() {
  try {
    // 派发一个action
    await this.$store.dispatch("deleteAllCartGood");
    this.getData();
  } catch (error) {
    alert(error.message);
  }
},

6、购物车商品数量加减改(难点)

(1)分析一下

请添加图片描述

这个修改商品数量主要有三个地方,加号、减号、用户输入,那么每改一次实际上都要重新发送请求。这个修改商品数量的接口和加入购物车的接口是一样的(带上要修改的产品id和数量)。

请添加图片描述

注意这里的skuNum参数类型,它并不是说直接把修改后的数量直接传到服务器,而是传与原来数量的差值。参数的规则就是传正数代表增加,传负数代表减少。

(2)配置请求的方法

首先找到修改数量的位置:

<li class="cart-list-con5">
  <a
    href="javascript:void(0)"
    class="mins"
    @click="handler('mins', -1, cart)"  //减一
    >-</a
  >
  <input
    autocomplete="off"
    type="text"
    minnum="1"
    class="itxt"
    :value="cart.skuNum"
    @change="handler('change', $event.target.value * 1, cart)"  //直接编辑修改
  />
  <a
    href="javascript:void(0)"
    class="plus"
    @click="handler('plus', 1, cart)"  //加一
    >+</a
  >
</li>

仔细看注释:

  methods: {
    // 获取个人购物车
    getData() {
      this.$store.dispatch("getCartList");
    },
    // 修改某个产品数量
    //有个bug,如果连续点减号,那么可能会变成负数
    //这是因为连续快速点击,请求还来不及发送,数据没改,所以每次disnum都是-1
    //解决办法就是节流,给服务器一些缓冲的时间,防止数据不同步出现上述bug
    handler: throttle(async function (type, disNum, cart) {
      // type:为了区分三个元素
      // 目前disNum形参:+变化量(1) -变化量(-1)
      // cart:哪一个产品
      // console.log("派发action,通知服务器修改个数" + type);
      // 向服务器发请求,修改数量
      switch (type) {
        // 加
        case "plus":
          // 带给服务器变化的量
          disNum = 1;
          break;
        case "mins":
          // 判断产品是否大于1,大于1才能减
          if (cart.skuNum > 1) {
            disNum = -1;
          } else {
            disNum = 0;
          }
          // 上面这判断可以用三元表达式disNum=cart.skuNum>1?-1:0
          break;
        case "change":
          // 如果用户输入的是非数字字符,则保留原数量不变,也就是disNum=0
          if (isNaN(disNum) || disNum < 1) {
            disNum = 0;
          } else {
            // 正常情况(避免用户输入小数,转化为整数)
            disNum = parseInt(disNum) - cart.skuNum; //需要传的是它们的差值(接口规定)
          }
          break;
      }
      // 派发action
      try {
        await this.$store.dispatch("getShopCart", {
          skuId: cart.skuId,
          skuNum: disNum,
        });
        //如果成功,就再次请求数据刷新页面
        this.getData();
      } catch {
        alert("修改数量失败", err);
      }
    }, 800),
  },

至此,购物车模块的笔记也基本整理完了。下一篇笔记是登录注册模块。

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

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

相关文章

知识深度 VS 知识广度

知识深度&#xff1a;帮助更快的朝着目标进。 发知识广度&#xff1a;帮助找到最优的路径。 职业生涯的前期需要执行力&#xff0c;因此需要更多的锻炼知识深度。越往后需要更多的做决策&#xff0c;因此要更多提升知识广度。

git 远程名称 远程分支 介绍

原文&#xff1a; 开发者社区> 越前君> 细读 Git | 让你弄懂 origin、HEAD、FETCH_HEAD 相关内容 读书笔记&#xff1a;担心大佬文章搬家&#xff0c;故整理此学习笔记 远程名称&#xff08;Remote Name&#xff09; Origin 1、 origin 只是远程仓库的一个名称&#xff…

代码管理工具git1

ctrl 加滚轮 放大字体 在计算机任意位置单击右键&#xff0c;选择&#xff1a;&#xff1a;Git Bash Here git version git清屏命令&#xff1a;ctrl L查看用户名和邮箱地址&#xff1a; $ git config user.name$ git config user.email修改用户名和邮箱地址&#xff1a;$ git…

防止泄露,保护隐私!如何清除你的谷歌搜索历史记录

按照以下说明学习如何从你的谷歌帐户、谷歌Chrome浏览器、谷歌iOS或Android应用程序或谷歌应用程序中删除你的谷歌历史记录。 如何从你的谷歌帐户中删除搜索历史记录 清除你的谷歌搜索历史并不意味着谷歌实际上会删除你的搜索数据。谷歌仍然会记录你如何以及何时使用某些功能…

数据结构——二叉树提升

二叉树题型练习 前言一、节点个数以及高度等二、二叉树OJ题二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历单值二叉树二叉树最大深度检查两颗树是否相同.翻转二叉树对称二叉树另一颗树的子树 总结 前言 现在我们开始一轮新的自我提升吧&#xff01; 二叉树的题目当然也更有…

【每日一题】34. 在排序数组中查找元素的第一个和最后一个位置

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 […

【LeetCode每日一题合集】2023.9.11-2023.9.17(⭐反悔贪心拓扑排序Floyd)

文章目录 630. 课程表 III解法——反悔贪心⭐⭐⭐⭐⭐ 1462. 课程表 IV⭐解法1——拓扑排序预处理解法2——Floyd算法判断是否存在路径 2596. 检查骑士巡视方案&#xff08;方向模拟&#xff09;1222. 可以攻击国王的皇后&#xff08;方向模拟&#xff09;LCP 50. 宝石补给&…

Java学习之常见易错点总结--第一期

&#x1f495;"不要同情自己&#xff0c;那是卑劣懦夫干的勾当。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;Java学习之常见易错点总结--第一期 1.什么时候变量不用初始化&#xff1f; 先来看如下代码&#xff1a; public static void main(…

MediaPipe+OpenCV 实现实时手势识别(附Python源码)

MediaPipe官网&#xff1a;https://developers.google.com/mediapipe MediaPipe仓库&#xff1a;https://github.com/google/mediapipe 一、MediaPipe介绍 MediaPipe 是一个由 Google 开发的开源跨平台机器学习框架&#xff0c;用于构建视觉和感知应用程序。它提供了一系列预训…

C#中Visual Studio如何为解决方案设置启动项目

目录 第一种方法:快速选定启动项目的方法1.在解决方案资源管理器中,选择解决方案(最高层节点)2.选择解决方案节点的上下文(右键单击)菜单,然后选择“属性”。 “解决方案属性页”对话框随即显示第二种方法:右击First11或者second11,点击设置启动项目即可Visual Studio…

C++ PrimerPlus 复习 第七章 函数——C++的编程模块(上)

第一章 命令编译链接文件 make文件 第二章 进入c 第三章 处理数据 第四章 复合类型 &#xff08;上&#xff09; 第四章 复合类型 &#xff08;下&#xff09; 第五章 循环和关系表达式 第六章 分支语句和逻辑运算符 第七章 函数——C的编程模块&#xff08;上&#xff…

【红包雨】中间件与环境安装

创建环境 创建专用网络VPC 安全组 创建云服务器 打包部署 2. Java环境 #下载jdk17 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz #安装上传工具 以后使用命令 rz 选中文件进行上传 yum install -y lrzsz#解压 tar -xzvf jdk-17_linux-x64…

Hive参数与性能调优-V2.0

Hive作为大数据平台举足轻重的框架&#xff0c;以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。 但是如果我们只局限于会使用Hive&#xff0c;而不考虑性能问题&#xff0c;就难搭建出一个完美的数仓&#xff0c;所以Hive性能调优是我们大数据从业…

VMware Fusion 13+Ubuntu ARM Server 22.04.3在M2芯片的Mac上共享文件夹

因为Server版没有桌面&#xff0c;VMware Tools不能直接装&#xff0c;导致没办法共享文件。 Ubuntu中的包如果需要更新&#xff0c;先执行下面的步骤 sudo apt update 再执行 sudo apt upgrade 不需要更新的话&#xff0c;直接执行下面的步骤 先把open-vm-tools卸载了 …

【JavaSE笔记】抽象类与接口

一、抽象类 1、概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 package demo2…

React 开发一个移动端项目(2)

配置基础路由 目标&#xff1a;配置登录页面的路由并显示在页面中 步骤&#xff1a; 安装路由&#xff1a; yarn add react-router-dom5.3.0 5 和 6 两个版本对组件类型的兼容性和函数组件支持有所改变&#xff0c;在这里使用的是 5。 和路由的类型声明文件 yarn add types…

AI AIgents时代-(三.)AutoGPT和AgentGPT

前两篇讲解了Agent的原理和组件&#xff0c;这节我将给大家介绍两个agent项目&#xff0c;给出它们的工作原理和区别&#xff0c;并教大家亲手尝试使用 Agents&#x1f389; &#x1f7e2; AutoGPT&#x1f916;️ 我们的老朋友&#xff0c;之前文章也专门写过。AutoGPT 是一…

关于硬盘质量大数据分析的思考

近日&#xff0c;看到Backblaze分享了一遍关于硬盘运行监控数据架构的文章&#xff0c;觉得挺有意义的&#xff0c;本文就针对这方面跟大家聊聊。 作为一家在2021年在美国纳斯达克上市的云端备份公司&#xff0c;Backblaze一直保持着对外定期发布HDD和SSD的故障率稳定性质量报告…

中国智能客服发展历程

中国智能客服的发展历程&#xff1a; 在2000年以前&#xff0c;互联网尚未普及&#xff0c;客服主要以电话沟通为主。从2000年到2010年&#xff0c;得益于计算机技术、计算机电话集成技术&#xff08;CTI&#xff09;、网络技术、多媒体机技术以及CRM、BI、ERP、OA等企业信息化…

Centos7部署单机版MongoDB

目录 Centos7部署单机版MongoDBMongoDB介绍数据模型索引分布式高可用性查询语言驱动和社区用途缺点 下载并解压安装包创建相关文件夹和文件编辑mongod.conf文件启动mongodb创建管理员用户终止MongoDB服务配置自启动服务关闭SELinux编辑自启动服务文件mongodb服务命令 Centos7部…