小兔鲜--项目总结3

目录

结算模块-地址切换交互实现

地址切换交互需求分析

打开弹框交互实现

地址激活交互实现

订单模块-生成订单功能实现 

 支付模块-实现支付功能

支付业务流程

 支付模块-支付结果展示

支付模块-封装倒计时函数

理解需求

 实现思路分析

会员中心-个人中心信息渲染

分页逻辑实现

SKU组件封装

认识SKU组件

 点击规格更新选中状态

 点击规格更新禁用状态 - 生成有效路径字典(1)

点击规格更新禁用状态 - 生成有效路径字典(2)

点击规格更新禁用状态 - 初始化规格禁用

击规格更新禁用状态 - 点击时组合禁用更新

产出有效的SKU信息

完整代码


结算模块-地址切换交互实现

地址切换交互需求分析

1. 打开弹框交互:点击切换地址按钮,打开弹框,回显用户可选地址列表
2. 切换地址交互:点击切换地址,点击确定按钮,激活地址替换默认收货地址

打开弹框交互实现

1. 准备弹框模版

<el-dialog title="切换收货地址" width="30%" center>
  <div class="addressWrapper">
    <div class="text item" v-for="item in checkInfo.userAddresses"  :key="item.id">
      <ul>
      <li><span>收<i />货<i />人:</span>{{ item.receiver }} </li>
      <li><span>联系方式:</span>{{ item.contact }}</li>
      <li><span>收货地址:</span>{{ item.fullLocation + item.address }}</li>
      </ul>
    </div>
  </div>
  <template #footer>
    <span class="dialog-footer">
      <el-button>取消</el-button>
      <el-button type="primary">确定</el-button>
    </span>
  </template>
</el-dialog>

 2. 控制弹框打开

const showDialog = ref(false)

<el-button size="large" @click="showDialog = true">切换地址</el-button>

<el-dialog v-model="showDialog" title="切换收货地址" width="30%" center>
    <!-- 省略 -->
</el-dialog>

地址激活交互实现

原理:地址切换是我们经常遇到的 `tab切换类` 需求,这类需求的实现逻辑都是相似的
1. 点击时记录一个当前激活地址对象activeAddress, 点击哪个地址就把哪个地址对象记录下来
2. 通过动态类名:class 控制激活样式类型 active是否存在,判断条件为:激活地址对象的id === 当前项id

<script setup>
// 切换地址
const activeAddress = ref({})
const switchAddress = (item) => {
  activeAddress.value = item
}
</script>

<template>
<div class="text item" 
  :class="{ active: activeAddress.id === item.id }" 
  @click="switchAddress(item)"
  :key="item.id">
  <!-- 省略... -->
</div>
</template>

切换地址属于哪类通用型交互功能?

tab切换类交互
记录激活项(整个对象/id/index) + 动态类名控制

订单模块-生成订单功能实现 

业务需求说明

确定结算信息没有问题之后,点击提交订单按钮,需要做以下俩个事情:

1. 调用接口生成订单id,并且携带id跳转到支付页
2. 调用更新购物车列表接口,更新购物车状态

<script setup>
import { createOrderAPI } from '@/apis/checkout'

// 创建订单
const createOrder = async () => {
  const res = await createOrderAPI({
    deliveryTimeType: 1,
    payType: 1,
    payChannel: 1,
    buyerMessage: '',
    goods: checkInfo.value.goods.map(item => {
      return {
        skuId: item.skuId,
        count: item.count
      }
    }),
    addressId: curAddress.value.id
  })
  const orderId = res.result.id
  router.push({
    path: '/pay',
    query: {
      id: orderId
    }
  })
}

</script>

<template>
    <!-- 提交订单 -->
    <div class="submit">
      <el-button @click="createOrder" type="primary" size="large">提交订单</el-button>
    </div>
</template>

 支付模块-实现支付功能

支付业务流程

// 支付地址
const baseURL = 'http://pcapi-xiaotuxian-front-devtest.itheima.net/'
const backURL = 'http://127.0.0.1:5173/paycallback'
const redirectUrl = encodeURIComponent(backURL)
const payUrl = `${baseURL}pay/aliPay?orderId=${route.query.id}&redirect=${redirectUrl}`

 支付模块-支付结果展示

业务需求理解

<script setup>
import { getOrderAPI } from '@/apis/pay'
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const orderInfo = ref({})

const getOrderInfo = async () => {
  const res = await getOrderAPI(route.query.orderId)
  orderInfo.value = res.result
}

onMounted(() => getOrderInfo())

</script>


<template>
  <div class="xtx-pay-page">
    <div class="container">
      <!-- 支付结果 -->
      <div class="pay-result">
        <!-- 路由参数获取到的是字符串而不是布尔值 -->
        <span class="iconfont icon-queren2 green" v-if="$route.query.payResult === 'true'"></span>
        <span class="iconfont icon-shanchu red" v-else></span>
        <p class="tit">支付{{ $route.query.payResult === 'true' ? '成功' : '失败' }}</p>
        <p class="tip">我们将尽快为您发货,收货期间请保持手机畅通</p>
        <p>支付方式:<span>支付宝</span></p>
        <p>支付金额:<span>¥{{ orderInfo.payMoney?.toFixed(2) }}</span></p>
        <div class="btn">
          <el-button type="primary" style="margin-right:20px">查看订单</el-button>
          <el-button>进入首页</el-button>
        </div>
        <p class="alert">
          <span class="iconfont icon-tip"></span>
          温馨提示:小兔鲜儿不会以订单异常、系统升级为由要求您点击任何网址链接进行退款操作,保护资产、谨慎操作。
        </p>
      </div>
    </div>
  </div>
</template>

支付模块-封装倒计时函数

理解需求

 实现思路分析

import { computed, onUnmounted, ref } from 'vue'
import dayjs from 'dayjs'
// 封装倒计时逻辑
export const useCountDown = () => {
    const formatTime = computed(() => dayjs.unix(time.value).format('mm分ss秒'))
    // 1. 响应式的数据
    let timer = null
    const time = ref(0)
    // 2. 开启倒计时的函数
    const start = (currentTime) => {
        // 开始倒计时的逻辑
        // 核心逻辑的编写:每隔1s就减一
        time.value = currentTime
        timer = setInterval(() => {
            time.value--
        }, 1000)
    }
    // 组件销毁时清除定时器
    onUnmounted(() => {
        timer && clearInterval(timer)
    })

    return {
        formatTime,
        start
    }
}

会员中心-个人中心信息渲染

分页逻辑实现

页数 = 总条数 / 每页条数 

<script setup>
// 补充总条数
const total = ref(0)
const getOrderList = async () => {
  const res = await getUserOrder(params.value)
  // 存入总条数
  total.value = res.result.counts
}
// 页数切换
const pageChange = (page) => {
  params.value.page = page
  getOrderList()
}
</script>

<template>
   <el-pagination 
     :total="total" 
     @current-change="pageChange" 
     :page-size="params.pageSize" 
     background
     layout="prev, pager, next" />
</template>

SKU组件封装

认识SKU组件

SKU组件的作用是为了让用户能够选择商品的规格,从而提交购物车,在选择的过程中,组件的选中状态要进行更新, 组件还要提示用户当前规格是否禁用,每次选择都要产出对应的Sku数据\

 点击规格更新选中状态

 

基本思路:

  1. 每一个规格按钮都拥有自己的选中状态数据-selected,true为选中,false为取消选中
  2. 配合动态class,把选中状态selected作为判断条件,true让active类名显示,false让active类名不显示
  3. 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中;点击的是已选中,直接取消
script setup>
// 省略代码

// 选中和取消选中实现
const changeSku = (item, val) => {
  // 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中,点击的是已选中,直接取消
  if (val.selected) {
    val.selected = false
  } else {
    item.values.forEach(valItem => valItem.selected = false)
    val.selected = true
  }
}

</script>

<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="val in item.values" :key="val.name">
          <img v-if="val.picture" 
            @click="changeSku(item, val)" 
            :class="{ selected: val.selected }" 
            :src="val.picture"
            :title="val.name">
          <span v-else 
            @click="changeSku(val)" 
            :class="{ selected: val.selected }">{{ val.name }}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>

 点击规格更新禁用状态 - 生成有效路径字典(1)

规格禁用的判断依据是什么?

 核心原理:当前的规格Sku,或者组合起来的规格Sku,在skus数组中对应项的库存为零时,当前规格会被禁用,生成 路径字典是为了协助和简化这个匹配过程

点击规格更新禁用状态 - 生成有效路径字典(2)

 

实现步骤:
1. 根据库存字段得到有效的Sku数组
2. 根据有效的Sku数组使用powerSet算法得到所有子集 3. 根据子集生成路径字典对象

export default function bwPowerSet (originalSet) {
  const subSets = []

  // We will have 2^n possible combinations (where n is a length of original set).
  // It is because for every element of original set we will decide whether to include
  // it or not (2 options for each set element).
  const numberOfCombinations = 2 ** originalSet.length

  // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
  // it shows by its bits (0 or 1) whether to include related element from the set or not.
  // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
  // include only "2" to the current set.
  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
    const subSet = []

    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
      // Decide whether we need to include current element into the subset or not.
      if (combinationIndex & (1 << setElementIndex)) {
        subSet.push(originalSet[setElementIndex])
      }
    }

    // Add current subset to the list of all subsets.
    subSets.push(subSet)
  }

  return subSets
}
// 创建生成路径字典对象函数
const getPathMap = (goods) => {
  const pathMap = {};
  // 1. 得到所有有效的Sku集合
  const effectiveSkus = goods.filter((sku) => sku.inventory > 0);

  // 2. 根据有效的Sku集合使用powerSet算法得到所有子集 [1,2] => [[1], [2], [1,2]]
  effectiveSkus.forEach((sku) => {
    // 2.1 获取可选规格值数组
    const selectedValArr = sku.specs.map((val) => val.valueName);
    // 2.2 获取可选值数组的子集
    const valueArrPowerSet = bwPowerSet(selectedValArr);
    // 3. 根据子集生成路径字典对象
    // 3.1 遍历子集 往pathMap中插入数据
    valueArrPowerSet.forEach((arr) => {
      // 根据Arr得到字符串的key,约定使用-分割 ['蓝色','美国'] => '蓝色-美国'
      const key = arr.join("-");
      // 给pathMap设置数据
      if (pathMap[key]) {
        pathMap[key].push(sku.id);
      } else {
        pathMap[key] = [sku.id];
      }
    });
  });
  console.log(pathMap);
  return pathMap;
};

点击规格更新禁用状态 - 初始化规格禁用

思路:遍历每一个规格对象,使用name字段作为key去路径字典pathMap中做匹配,匹配不上则禁用

 思路:判断规格的name属性是否能在有效路径字典中找到,如果找不到就禁用

// 1. 定义初始化函数
// specs:商品源数据 pathMap:路径字典
const initDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach((item) => {
    item.values.forEach((val) => {
      console.log(val);
      if (pathMap[val.name]) {
        val.disabled = false;
      } else {
        val.disabled = true;
      }
    });
  });
};

击规格更新禁用状态 - 点击时组合禁用更新

思路(点击规格时):
1. 按照顺序得到规格选中项的数组 [‘蓝色’,‘20cm’, undefined]

2. 遍历每一个规格

2.1 把name字段的值填充到对应的位置
2.2 过滤掉undefined项使用join方法形成一个有效的key
2.3 使用key去pathMap中进行匹配,匹配不上,则当前项禁用

// 获取选中匹配数组 ['黑色',undefined,undefined]
const getSelectedValues = (specs) => {
  const arr = []
  specs.forEach(spec => {
    const selectedVal = spec.values.find(value => value.selected)
    arr.push(selectedVal ? selectedVal.name : undefined)
  })
  return arr
}

// 切换时更新选中状态
const updateDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach((item, i) => {
    const selectedValues = getSelectedValues(specs);
    console.log(selectedValues);
    item.values.forEach((val) => {
      selectedValues[i] = val.name;
      const key = selectedValues.filter((value) => value).join("-");
      console.log(key);
      if (pathMap[key]) {
        val.disabled = false;
      } else {
        val.disabled = true;
      }
    });
  });
};

产出有效的SKU信息

什么是有效的SKU?

如何判断当前用户已经选择了所有有效的规格?
已选择项数组 [‘蓝色’,‘20cm’, undefined] 中找不到undefined, 那么用户已经选择了所有的有效规格,此时可以产出数据

如何获取当前的SKU信息对象?

把已选择项数组拼接为路径字典的key,去路径字典pathMap中找即可

 

// 选中和取消选中实现
const changeSku = (item, val) => {
  if (val.disabled) return;
  // 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中,点击的是已选中,直接取消
  if (val.selected) {
    val.selected = false;
  } else {
    item.values.forEach((valItem) => (valItem.selected = false));
    val.selected = true;
  }
  updateDisabledState(goods.value.specs, pathMap);
  const index = getSelectedValues(goods.value.specs).findIndex(
    (item) => item === undefined
  );
  if (index > -1) {
    console.log("找到了,信息不完整");
  } else {
    console.log("没有找到,信息完整,可以产出");
    // 获取sku对象
    const key = getSelectedValues(goods.value.specs).join("-");
    const skuIds = pathMap[key];
    console.log(skuIds);
    // 以skuId作为匹配项去goods.value.skus数组中找
    const skuObj = goods.value.skus.find((item) => item.id === skuIds[0]);
    console.log("sku对象为", skuObj);
  }
};

完整代码

<script setup>
import { onMounted, ref } from "vue";
import axios from "axios";
import { bwPowerSet } from "@/utils/getPathMap";
// 商品数据
const goods = ref({});
let pathMap = {};
const getGoods = async () => {
  // 1135076  初始化就有无库存的规格
  // 1369155859933827074 更新之后有无库存项(蓝色-20cm-中国)
  const res = await axios.get(
    "http://pcapi-xiaotuxian-front-devtest.itheima.net/goods?id=1369155859933827074"
  );
  goods.value = res.data.result;

  // 后端返回的库存列表
  let skus = res.data.result.skus;
  // 规格列表
  let specs = res.data.result.specs;
  pathMap = getPathMap(skus);
  initDisabledState(specs, pathMap);
};
onMounted(() => getGoods());
// 创建生成路径字典对象函数
const getPathMap = (goods) => {
  const pathMap = {};
  // 1. 得到所有有效的Sku集合
  const effectiveSkus = goods.filter((sku) => sku.inventory > 0);

  // 2. 根据有效的Sku集合使用powerSet算法得到所有子集 [1,2] => [[1], [2], [1,2]]
  effectiveSkus.forEach((sku) => {
    // 2.1 获取可选规格值数组
    const selectedValArr = sku.specs.map((val) => val.valueName);
    // 2.2 获取可选值数组的子集
    const valueArrPowerSet = bwPowerSet(selectedValArr);
    // 3. 根据子集生成路径字典对象
    // 3.1 遍历子集 往pathMap中插入数据
    valueArrPowerSet.forEach((arr) => {
      // 根据Arr得到字符串的key,约定使用-分割 ['蓝色','美国'] => '蓝色-美国'
      const key = arr.join("-");

      // 给pathMap设置数据
      if (pathMap[key]) {
        pathMap[key].push(sku.id);
      } else {
        pathMap[key] = [sku.id];
      }
    });
  });
  console.log(pathMap);
  return pathMap;
};
// 1. 定义初始化函数
// specs:商品源数据 pathMap:路径字典
const initDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach((item) => {
    item.values.forEach((val) => {
      console.log(val);
      if (pathMap[val.name]) {
        val.disabled = false;
      } else {
        val.disabled = true;
      }
    });
  });
};
// 获取选中匹配数组 ['黑色',undefined,undefined]
const getSelectedValues = (specs) => {
  const arr = [];
  specs.forEach((spec) => {
    const selectedVal = spec.values.find((value) => value.selected);
    arr.push(selectedVal ? selectedVal.name : undefined);
  });
  return arr;
};
// 切换时更新选中状态
const updateDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach((item, i) => {
    const selectedValues = getSelectedValues(specs);
    console.log(selectedValues);
    item.values.forEach((val) => {
      selectedValues[i] = val.name;
      const key = selectedValues.filter((value) => value).join("-");
      console.log(key);
      if (pathMap[key]) {
        val.disabled = false;
      } else {
        val.disabled = true;
      }
    });
  });
};
// 选中和取消选中实现
const changeSku = (item, val) => {
  if (val.disabled) return;
  // 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中,点击的是已选中,直接取消
  if (val.selected) {
    val.selected = false;
  } else {
    item.values.forEach((valItem) => (valItem.selected = false));
    val.selected = true;
  }
  updateDisabledState(goods.value.specs, pathMap);
  const index = getSelectedValues(goods.value.specs).findIndex(
    (item) => item === undefined
  );
  if (index > -1) {
    console.log("找到了,信息不完整");
  } else {
    console.log("没有找到,信息完整,可以产出");
    // 获取sku对象
    const key = getSelectedValues(goods.value.specs).join("-");
    const skuIds = pathMap[key];
    console.log(skuIds);
    // 以skuId作为匹配项去goods.value.skus数组中找
    const skuObj = goods.value.skus.find((item) => item.id === skuIds[0]);
    console.log("sku对象为", skuObj);
  }
};
</script>

<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="val in item.values" :key="val.name">
          <img
            v-if="val.picture"
            @click="changeSku(item, val)"
            :class="{ selected: val.selected, disabled: val.disabled }"
            :src="val.picture"
            :title="val.name"
          />
          <span
            v-else
            @click="changeSku(item, val)"
            :class="{ selected: val.selected, disabled: val.disabled }"
            >{{ val.name }}</span
          >
        </template>
      </dd>
    </dl>
  </div>
</template>
<style scoped lang="scss">
@mixin sku-state-mixin {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
    border-color: #27ba9b;
  }

  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      > img {
        width: 50px;
        height: 50px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }

      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }
    }
  }
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

solr快速上手:managed-schema标签详解(三)

0. 引言 core核心是solr中的重中之重&#xff0c;类似数据库中的表&#xff0c;在搜索引擎中也叫做索引&#xff0c;在solr中索引的建立&#xff0c;要先创建基础的数据结构&#xff0c;即schema的相关配置&#xff0c;今天继续来学习solr的核心知识&#xff1a; solr快速上手…

OpenCV——最小外接矩形

目录 一、主要函数二、代码实现三、结果展示 一、主要函数 cv::RotatedRect cv::minAreaRect(const cv::Mat& points );emspminAreaRect 函数用于计算给定点集的最小外接矩形。该矩形的长和宽是可以任意旋转的&#xff0c;因此被称为旋转矩形。 points &#xff1a;是一个…

article-码垛机器人admas仿真

按照运动学仿真的类似步骤为机器人添加材料、运动副和关节驱动&#xff0c;给机器人手腕末端施加50N最大负载&#xff0c;仿真模型如图5-17。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AXYQVZPq-1684936426972)(data:image/svgxml;utf8, )] 图…

Python实现ACO蚁群优化算法优化BP神经网络回归模型(BP神经网络回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁群优化算法(Ant Colony Optimization, ACO)是一种源于大自然生物世界的新的仿生进化算法&#xff0c…

Qt自定义的ColorDialog--仿QColorDialog

Qt已经有了色板选择&#xff0c;但是它使用QDialog形成的&#xff0c;每次调用基本上都成了点一个按钮&#xff0c;谈一个模态框&#xff0c;选择好颜色之后再关掉模态框。 但是&#xff0c;如果想将颜色选择板放在窗口上&#xff0c;并不会有模态的功能就会比较麻烦&#xff…

docker安装mysql8.0.33

1 从docker仓库中拉去mysql 8.0 docker pull mysql:8.0如果使用 docker pull mysql 默认拉取的是最新版本的mysql 上面我拉去的是8.0的版本&#xff0c;最后拉取过来的是8.0.33 如果有想要指定的版本&#xff0c;可以直接写指定版本&#xff0c;如&#xff1a; docker pull my…

pytorch:nn.ModuleList和nn.Sequential、list的用法以及区别

文章目录 在构建网络的时候&#xff0c;pytorch有一些基础概念很重要&#xff0c;比如nn.Module&#xff0c;nn.ModuleList&#xff0c;nn.Sequential&#xff0c;这些类我们称为为容器&#xff08;containers&#xff09;&#xff0c;可参考containers。本文中我们主要学习nn.…

【Python】正则表达式应用

知识目录 一、写在前面✨二、姓名检查三、解析电影排行榜四、总结撒花&#x1f60a; 一、写在前面✨ 大家好&#xff01;我是初心&#xff0c;希望我们一路走来能坚守初心&#xff01; 今天跟大家分享的文章是 正则表达式的应用 &#xff0c;希望能帮助到大家&#xff01;本篇…

把字节大佬花3个月时间整理的软件测试面经偷偷给室友,差点被他开除了···

写在前面 “这份软件测试面经看起来不错&#xff0c;等会一起发给他吧”&#xff0c;我看着面前的面试笔记自言自语道。 就在这时&#xff0c;背后传来了leder“阴森森”的声音&#xff1a;“不错吧&#xff0c;我可是足足花了三个月整理的” 始末 刚入职字节的我收到了大学室…

Windows 10 X64 内核对象句柄表解析

fweWindows 很多API函数都会创建和使用句柄(传入参数)&#xff0c;句柄代表一个内核对象的内存地址&#xff0c;每个进程都有一个句柄表&#xff0c;它保存着进程拥有的句柄&#xff0c;内核也有一个句柄表 PspCidTable&#xff0c;它保存着整个系统的句柄。 ExpLookupHandleTa…

DNS风险分析及安全防护研究(一):DNS自身风险分析(中科三方)

作为互联网上的一项基础服务&#xff0c;DNS在网站运行中起到了至关重要的作用&#xff0c;然而其安全性在很长一段时间内都没有得到足够的重视。DNS采用不可靠的UDP协议&#xff0c;安全性具有较大的漏洞&#xff0c;攻击者很容易利用这些漏洞发动攻击&#xff0c;从而引起一些…

华为设备这14个广域网命令,值得每位做广域网业务的网工收藏!

你好&#xff0c;这里是网络技术联盟站。 华为设备广域网命令是网络管理员在运维过程中常用的一类命令。该命令集涵盖了DCC配置命令、PPP配置命令、MP配置命令、PPPoE命令、ATM配置命令、帧中继配置命令、HDLC配置命令、LAPB配置命令、X.25配置命令、IP-Trunk配置命令、ISDN配…

Java 与数据结构(6):快速排序

ChatGPT 中文指南(大全) 内容包含&#xff1a;如何开通chatgpt、chatgpt的同类站点、prompts 、AI绘图、ChatGPT 工具、相关报告论文、ChatGPT应用项目等 链接&#xff1a;ChatGPT 中文指南(大全) 指令指南&#xff0c;精选资源清单&#xff0c;更好的使用 chatGPT 让你的生产力…

详解如何使用LAMP架构搭建论坛

文章目录 1.LAMP概述2.编译安装Apache httpd服务1.关闭防火墙&#xff0c;将安装Apache所需软件包传到/opt目录下2.安装环境依赖包 3.配置软件模块4.编译及安装5.优化配置文件路径&#xff0c;并把httpd服务的可执行程序文件放入路径环境变量的目录中便于系统识别6.添加httpd系…

复杂的C++继承

文章目录 什么是继承继承方式赋值规则继承中的作用域&#xff08;隐藏&#xff09;子类中的默认成员函数需要自己写默认成员函数的情况 继承与友元及静态成员多继承菱形继承菱形继承的问题菱形虚拟继承 继承和组合 面向对象三大特性&#xff1a;封装继承和多态。封装在类和对象…

(四)调整PID控制器参数的指南

一、控制系统设计快速入门和环境 首先确定一下控制任务。快速、精准地控制&#xff0c;必要的稳定性&#xff0c;时域&#xff08;上升时间、超调等&#xff09;&#xff0c;频域&#xff08;带宽、阻尼比&#xff09;然后明白控制系统特点。类积分器&#xff1f;开环稳定性、高…

注解实现自动装配

要使用注解须知&#xff1a; 1.导入约束 context约束 2.配置注解的支持 官方配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/…

详解知识蒸馏原理和代码

目录 知识蒸馏原理概念技巧举例说明KL 散度及损失 KD训练代码导入包网络架构teacher网络student网络 teacher网络训练定义基本函数训练主函数 student网络训练&#xff08;重点&#xff09;理论部分定义kd的loss定义基本函数训练主函数 绘制结果teacher网络的暗知识softmax_t推…

C4d Octane渲染器内存满、卡顿、崩溃、缓慢、updating解决办法

最近碰到Octane渲染动画序列&#xff0c;总是会渲染一段时间后卡在某一张图片上&#xff0c;图片查看器左下角一直显示updating。 偶然发现在C4D界面点击octane工具栏的设置&#xff0c;它又会开始渲染&#xff0c;但渲染一些序列帧后又会卡在一张图上显示updating 点击octane工…

【Netty】 工作原理详解(十一)

文章目录 前言一、Netty 模型二、代码示例2.1、引入Maven依赖2.2、服务端的管道处理器2.3、服务端主程序2.4、客户端管道处理器2.5、客户端主程序2.6、测试运行 总结 前言 回顾Netty系列文章&#xff1a; Netty 概述&#xff08;一&#xff09;Netty 架构设计&#xff08;二&…