• .NET经销商实战(十六)——计算总价格,efcore部分更新实现,已经选择的购物车数量更新


    1.productService代码如下:

    点击查看代码
    public async Task<List<ProductDto>> GetProductByProductNos(params string[] postProductNos)
    		{
    			var productNoList = postProductNos.Distinct().ToList();
    			var productNos = ProductRepo.GetList(s => productNoList.Contains(s.ProductNo));
    			var productDtos = Mapper.Map<List<Product>, List<ProductDto>>(productNos);
    			var productSales = await GetProductSalesByProductNo(productDtos.Select(s => s.ProductNo).ToArray());
    			productDtos.ForEach(s =>
    			{
    				s.ProductSale = productSales.Where(c => c.ProductNo == s.ProductNo).FirstOrDefault();
    			});
    			return productDtos;
    		}
    

    2.shoppingcart.vue代码如下(计算总价格):

    点击查看代码
    <template>
      <div>
        <div class="cart-list">
          <ul>
            <li v-for="type in types" :key="type.typeNo">
              <p>
                <i
                  :class="{ 'cart-select': type.typeSelected }"
                  @click="onSelectType(type)"
                  >√</i
                >
                <span>{{ transTypeWhenNull(type.typeName) }}</span>
              </p>
              <template v-for="cart in carts" :key="cart.cartGuid">
                <div v-if="cart.productDto?.typeNo == type.typeNo">
                  <i
                    :class="{ 'cart-select': cart.cartSelected }"
                    @click="onSelectCart(cart)"
                    >√</i
                  >
                  <img src="" alt="" />
                  <p class="p-name">{{ cart.productDto?.productName }}</p>
                  <p class="p-price">
                    &yen;{{ cart.productDto?.productSale?.salePrice ?? 0 }}
                  </p>
                  <p class="p-num">
                    <span class="sub-num" @click="onSubNum(cart)">-</span>
                    <input v-model="cart.productNum" @change="onChangeNum(cart)" />
                    <span class="add0num" @click="onAddNum(cart)">+</span>
                    <b>块</b>
                  </p>
                </div>
              </template>
            </li>
          </ul>
        </div>
        <div class="total-pad">
          <i :class="{ 'cart-select': isAllSelected }">√</i>
          <span>全选</span>
          <span>
            合计:&yen; <b>{{ totalPrice }}</b>
          </span>
          <button>确定下单</button>
        </div>
      </div>
    </template>
    
    <script>
    import { reactive, toRefs, onMounted, watch } from 'vue'
    import { getCarts } from '@/httpRequests/ShoppingCartRequest'
    export default {
      // mounted() {
      //   this.$store.comm
      //   this.$store.dispatch('setFootMenuIndexAsync', 2)
      // },
      setup() {
        //数据发生改变时,这个方式不能及时获取变化后的数据
        //const productNumRef = ref()
        const shoppingCartInfo = reactive({
          carts: [],
          types: [],
          isAllSelected: true,
          // buyNum: 1,
          totalPrice: 0,
          onAddNum(cart) {
            cart.productNum++
          },
          onSubNum(cart) {
            if (cart.productNum > 1) {
              cart.productNum--
            }
          },
          onChangeNum(cart) {
            var currNum = event.target.value
            if (!isNaN(currNum) && currNum > 0) {
              cart.productNum = currNum
            } else {
              event.target.value = cart.productNum
            }
          },
          /**
           * 获取购物车信息
           */
          onGetShoppingCarts: async () => {
            var customerNo = localStorage['customerNo']
            var res = await getCarts(customerNo)
            shoppingCartInfo.carts = res.carts
            shoppingCartInfo.types = res.types
            // console.log(res)
          },
          /**
           * 点击选择购物车时触发
           */
          onSelectCart: (cart) => {
            cart.cartSelected = !cart.cartSelected
            //找到类型中对应设置物品的类型
            // var type = shoppingCartInfo.types.filter(
            //   (m) => m.typeNo == cart.productDto?.typeNo
            // )[0]
            // var cartsOfType = shoppingCartInfo.carts.filter(
            //   (s) => s.productDto?.typeNo == type?.typeNo
            // )
            // shoppingCartInfo.checkTypeSelected()
          },
          /**
           * 检测选择类型时触发
           */
          onSelectType: (type) => {
            type.typeSelected = !type.typeSelected
            shoppingCartInfo.carts
              .filter((s) => s.productDto?.typeNo == type?.typeNo)
              .forEach((s) => {
                s.cartSelected = type.typeSelected
              })
            // shoppingCartInfo.checkAllSelected()
          },
          /**
           * 检测是否选中某一类下的所有物品
           */
          checkTypeSelected: () => {
            shoppingCartInfo.types.forEach((type) => {
              var cartsOfType = shoppingCartInfo.carts.filter(
                (s) => s.productDto?.typeNo == type?.typeNo
              )
              //查看当前类型下的物品是否都被选择,是则将属于类型选中
              //否则不选中
              if (cartsOfType.every((m) => m.cartSelected)) {
                type.typeSelected = true
              } else {
                type.typeSelected = false
              }
            })
            shoppingCartInfo.checkAllSelected()
          },
          /**
           * 检测是否选中所有物品时触发
           */
          checkAllSelected: () => {
            if (shoppingCartInfo.carts.every((m) => m.cartSelected)) {
              shoppingCartInfo.isAllSelected = true
            } else {
              shoppingCartInfo.isAllSelected = false
            }
          },
          /**
           * 计算总价
           */
          calcTotalPrice: () => {
            shoppingCartInfo.totalPrice = 0
            shoppingCartInfo.carts
              .filter((m) => m.cartSelected == true)
              .forEach((c) => {
                var singlePrice = c.productDto?.productSale?.salePrice ?? 0
                shoppingCartInfo.totalPrice += singlePrice * c.productNum
              })
          },
          transTypeWhenNull: (typeName) => typeName ?? '未分类产品',
        })
    
        /**
         * 对carts进行深度监听
         */
        watch(
          () => shoppingCartInfo.carts,
          (newValue, oldValue) => {
            shoppingCartInfo.checkTypeSelected()
            shoppingCartInfo.calcTotalPrice()
            //
          },
          {
            //是否深度监听,一般监听对象或者数组,咱都需要深度监听
            deep: true,
          }
        )
        /**
         * 页面加载时触发
         */
        onMounted(() => {
          shoppingCartInfo.onGetShoppingCarts()
          shoppingCartInfo.checkTypeSelected()
          shoppingCartInfo.calcTotalPrice()
        })
        return { ...toRefs(shoppingCartInfo) }
      },
    }
    </script>
    
    <style lang="scss" scoped>
    .cart-list {
      text-align: left;
      ul {
        margin-bottom: 108px;
    
        li {
          background-color: #fff;
          margin-bottom: 12px;
    
          > p {
            padding-left: 46px;
            position: relative;
            height: 46px;
            border-bottom: 1px solid #ddd;
    
            i {
              border: 1px solid #a9a9a9;
               18px;
              height: 18px;
              line-height: 18px;
              border-radius: 18px;
              position: absolute;
              left: 13px;
              top: 13px;
              text-align: center;
              font-size: 12px;
              color: #fff;
              font-style: normal;
            }
    
            i.cart-select {
              background-color: crimson;
              border: 1px solid crimson;
            }
    
            span {
              display: inline-block;
              border-left: 3px solid crimson;
              height: 28px;
              margin: 9px 0;
              padding-left: 8px;
              line-height: 30px;
            }
          }
    
          div {
            padding-left: 46px;
            position: relative;
            height: 98px;
            padding: 8px 14px 8px 148px;
    
            i {
              border: 1px solid #a9a9a9;
               18px;
              height: 18px;
              line-height: 18px;
              border-radius: 18px;
              position: absolute;
              left: 13px;
              top: 28px;
              text-align: center;
              font-size: 12px;
              color: #fff;
              font-style: normal;
            }
    
            i.cart-select {
              background-color: crimson;
              border: 1px solid crimson;
            }
    
            img {
               68px;
              height: 68px;
              background-color: #ccc;
              position: absolute;
              left: 58px;
              top: 20px;
            }
    
            p.p-name {
              font-size: 13px;
              margin-top: 10px;
              height: 30px;
            }
            p.p-price {
              font-size: 13px;
              height: 20px;
              color: crimson;
            }
            p.p-num {
              text-align: right;
              padding-right: 20px;
    
              span {
                display: inline-block;
                 18px;
                height: 18px;
                border: 1px solid crimson;
                color: crimson;
                border-radius: 9px;
                text-align: center;
                line-height: 18px;
              }
    
              input {
                 28px;
                border: none 0px;
                outline: none;
                text-align: center;
              }
    
              b {
                font-weight: normal;
                margin-left: 10px;
                font-size: 13px;
              }
            }
          }
        }
      }
    }
    
    .total-pad {
      height: 58px;
       100%;
      background-color: #383838;
      position: fixed;
      left: 0;
      bottom: 40px;
    
      i {
        display: inline-block;
        border: 1px solid #a9a9a9;
         18px;
        height: 18px;
        line-height: 18px;
        border-radius: 18px;
        background-color: #fff;
        margin-left: 13px;
        margin-top: 20px;
        vertical-align: bottom;
        height: 18px;
        text-align: center;
        font-size: 12px;
        color: #fff;
        font-style: normal;
      }
    
      i.cart-select {
        background-color: crimson;
        border: 1px solid crimson;
      }
    
      span {
        color: #fff;
        margin-left: 6px;
        font-size: 13px;
    
        b {
          font-size: 15px;
        }
      }
    
      button {
        float: right;
        height: 58px;
         120px;
        border: 0 none;
        background-color: #ddd;
        color: #aaa;
        font-size: 15px;
        font-weight: bold;
      }
    }
    </style>
    
    

    3.ShoppingCartService代码如下:

    点击查看代码
    /// <summary>
    		/// 指定更新某个字段
    		/// </summary>
    		/// <param name="cartGuid"></param>
    		/// <param name="cartSelected"></param>
    		/// <returns></returns>
    		public async Task<bool> UpdateCartSelected(ShoppingCartSelectedEditDto dto)
    		{
    			//EFcore部分更新
    			try
    			{
    				ShoppingCart cart = new()
    				{
    					CartGuid = dto.CartGuid,
    					CartSelected = dto.CartSelected
    				};
    				Context.Attach(cart);
    				Context.Entry(cart).Property(m => m.CartSelected).IsModified = true;
    				return (await Context.SaveChangesAsync()) > 0;
    			}
    			catch (System.Exception)
    			{
    				return false;
    				throw;
    			}
    		}
    

    4.修改部分更新的接口,为了让它更新多行数据,多次savechange会影响性能

    点击查看代码
    /// <summary>
    		/// 指定更新某个字段
    		/// </summary>
    		/// <param name="cartGuid"></param>
    		/// <param name="cartSelected"></param>
    		/// <returns></returns>
    		public async Task<bool> UpdateCartSelected(ShoppingCartSelectedEditDto dto)
    		{
    			//EFcore部分更新
    			try
    			{
    				foreach (var cartGuid in dto.CartGuids)
    				{
    					ShoppingCart cart = new()
    					{
    						CartGuid = cartGuid,
    						CartSelected = dto.CartSelected
    					};
    					Context.Attach(cart);
    					Context.Entry(cart).Property(m => m.CartSelected).IsModified = true;
    				}
    				return (await Context.SaveChangesAsync()) > 0;
    
    			}
    			catch (System.Exception)
    			{
    				return false;
    				throw;
    			}
    		}
    

    5.前端界面修改:ShoppingCart.vue

    点击查看代码
    <template>
      <div>
        <div class="cart-list">
          <ul>
            <li v-for="type in types" :key="type.typeNo">
              <p>
                <i
                  :class="{ 'cart-select': type.typeSelected }"
                  @click="onSelectType(type)"
                  >√</i
                >
                <span>{{ transTypeWhenNull(type.typeName) }}</span>
              </p>
              <template v-for="cart in carts" :key="cart.cartGuid">
                <div v-if="cart.productDto?.typeNo == type.typeNo">
                  <i
                    :class="{ 'cart-select': cart.cartSelected }"
                    @click="onSelectCart(cart)"
                    >√</i
                  >
                  <img src="" alt="" />
                  <p class="p-name">{{ cart.productDto?.productName }}</p>
                  <p class="p-price">
                    &yen;{{ cart.productDto?.productSale?.salePrice ?? 0 }}
                  </p>
                  <p class="p-num">
                    <span class="sub-num" @click="onSubNum(cart)">-</span>
                    <input v-model="cart.productNum" @change="onChangeNum(cart)" />
                    <span class="add0num" @click="onAddNum(cart)">+</span>
                    <b>块</b>
                  </p>
                </div>
              </template>
            </li>
          </ul>
        </div>
        <div class="total-pad">
          <i :class="{ 'cart-select': isAllSelected }">√</i>
          <span>全选</span>
          <span>
            合计:&yen; <b>{{ totalPrice }}</b>
          </span>
          <button>确定下单</button>
        </div>
      </div>
    </template>
    
    <script>
    import { reactive, toRefs, onMounted, watch } from 'vue'
    import { getCarts, updateCartSelect } from '@/httpRequests/ShoppingCartRequest'
    export default {
      // mounted() {
      //   this.$store.comm
      //   this.$store.dispatch('setFootMenuIndexAsync', 2)
      // },
      setup() {
        //数据发生改变时,这个方式不能及时获取变化后的数据
        //const productNumRef = ref()
        const shoppingCartInfo = reactive({
          carts: [],
          types: [],
          isAllSelected: true,
          // buyNum: 1,
          totalPrice: 0,
          onAddNum(cart) {
            cart.productNum++
          },
          onSubNum(cart) {
            if (cart.productNum > 1) {
              cart.productNum--
            }
          },
          onChangeNum(cart) {
            var currNum = event.target.value
            if (!isNaN(currNum) && currNum > 0) {
              cart.productNum = currNum
            } else {
              event.target.value = cart.productNum
            }
          },
          /**
           * 获取购物车信息
           */
          onGetShoppingCarts: async () => {
            var customerNo = localStorage['customerNo']
            var res = await getCarts(customerNo)
            shoppingCartInfo.carts = res.carts
            shoppingCartInfo.types = res.types
            // console.log(res)
          },
          /**
           * 点击选择购物车时触发
           */
          onSelectCart: (cart) => {
            cart.cartSelected = !cart.cartSelected
            var cartGuids = []
            cartGuids.push(cart.cartGuid)
            updateCartSelect(cartGuids, cart.cartSelected)
            //找到类型中对应设置物品的类型
            // var type = shoppingCartInfo.types.filter(
            //   (m) => m.typeNo == cart.productDto?.typeNo
            // )[0]
            // var cartsOfType = shoppingCartInfo.carts.filter(
            //   (s) => s.productDto?.typeNo == type?.typeNo
            // )
            // shoppingCartInfo.checkTypeSelected()
          },
          /**
           * 检测选择类型时触发
           */
          onSelectType: (type) => {
            var cartGuids = []
    
            type.typeSelected = !type.typeSelected
            shoppingCartInfo.carts
              .filter((s) => s.productDto?.typeNo == type?.typeNo)
              .forEach((s) => {
                cartGuids.push(s.cartGuid)
                s.cartSelected = type.typeSelected
              })
            updateCartSelect(cartGuids, type.typeSelected)
            // shoppingCartInfo.checkAllSelected()
          },
          /**
           * 检测是否选中某一类下的所有物品
           */
          checkTypeSelected: () => {
            shoppingCartInfo.types.forEach((type) => {
              var cartsOfType = shoppingCartInfo.carts.filter(
                (s) => s.productDto?.typeNo == type?.typeNo
              )
              //查看当前类型下的物品是否都被选择,是则将属于类型选中
              //否则不选中
              if (cartsOfType.every((m) => m.cartSelected)) {
                type.typeSelected = true
              } else {
                type.typeSelected = false
              }
            })
            shoppingCartInfo.checkAllSelected()
          },
          /**
           * 检测是否选中所有物品时触发
           */
          checkAllSelected: () => {
            if (shoppingCartInfo.carts.every((m) => m.cartSelected)) {
              var cartGuids = []
              shoppingCartInfo.isAllSelected = true
              shoppingCartInfo.carts.filter((s) => {
                cartGuids.push(s.cartGuid)
              })
              updateCartSelect(cartGuids, true)
            } else {
              shoppingCartInfo.isAllSelected = false
            }
          },
          /**
           * 计算总价
           */
          calcTotalPrice: () => {
            shoppingCartInfo.totalPrice = 0
            shoppingCartInfo.carts
              .filter((m) => m.cartSelected == true)
              .forEach((c) => {
                var singlePrice = c.productDto?.productSale?.salePrice ?? 0
                shoppingCartInfo.totalPrice += singlePrice * c.productNum
              })
          },
          transTypeWhenNull: (typeName) => typeName ?? '未分类产品',
        })
    
        /**
         * 对carts进行深度监听
         */
        watch(
          () => shoppingCartInfo.carts,
          (newValue, oldValue) => {
            shoppingCartInfo.checkTypeSelected()
            shoppingCartInfo.calcTotalPrice()
            //
          },
          {
            //是否深度监听,一般监听对象或者数组,咱都需要深度监听
            deep: true,
          }
        )
        /**
         * 页面加载时触发
         */
        onMounted(() => {
          shoppingCartInfo.onGetShoppingCarts()
          shoppingCartInfo.checkTypeSelected()
          shoppingCartInfo.calcTotalPrice()
        })
        return { ...toRefs(shoppingCartInfo) }
      },
    }
    </script>
    
    <style lang="scss" scoped>
    .cart-list {
      text-align: left;
      ul {
        margin-bottom: 108px;
    
        li {
          background-color: #fff;
          margin-bottom: 12px;
    
          > p {
            padding-left: 46px;
            position: relative;
            height: 46px;
            border-bottom: 1px solid #ddd;
    
            i {
              border: 1px solid #a9a9a9;
               18px;
              height: 18px;
              line-height: 18px;
              border-radius: 18px;
              position: absolute;
              left: 13px;
              top: 13px;
              text-align: center;
              font-size: 12px;
              color: #fff;
              font-style: normal;
            }
    
            i.cart-select {
              background-color: crimson;
              border: 1px solid crimson;
            }
    
            span {
              display: inline-block;
              border-left: 3px solid crimson;
              height: 28px;
              margin: 9px 0;
              padding-left: 8px;
              line-height: 30px;
            }
          }
    
          div {
            padding-left: 46px;
            position: relative;
            height: 98px;
            padding: 8px 14px 8px 148px;
    
            i {
              border: 1px solid #a9a9a9;
               18px;
              height: 18px;
              line-height: 18px;
              border-radius: 18px;
              position: absolute;
              left: 13px;
              top: 28px;
              text-align: center;
              font-size: 12px;
              color: #fff;
              font-style: normal;
            }
    
            i.cart-select {
              background-color: crimson;
              border: 1px solid crimson;
            }
    
            img {
               68px;
              height: 68px;
              background-color: #ccc;
              position: absolute;
              left: 58px;
              top: 20px;
            }
    
            p.p-name {
              font-size: 13px;
              margin-top: 10px;
              height: 30px;
            }
            p.p-price {
              font-size: 13px;
              height: 20px;
              color: crimson;
            }
            p.p-num {
              text-align: right;
              padding-right: 20px;
    
              span {
                display: inline-block;
                 18px;
                height: 18px;
                border: 1px solid crimson;
                color: crimson;
                border-radius: 9px;
                text-align: center;
                line-height: 18px;
              }
    
              input {
                 28px;
                border: none 0px;
                outline: none;
                text-align: center;
              }
    
              b {
                font-weight: normal;
                margin-left: 10px;
                font-size: 13px;
              }
            }
          }
        }
      }
    }
    
    .total-pad {
      height: 58px;
       100%;
      background-color: #383838;
      position: fixed;
      left: 0;
      bottom: 40px;
    
      i {
        display: inline-block;
        border: 1px solid #a9a9a9;
         18px;
        height: 18px;
        line-height: 18px;
        border-radius: 18px;
        background-color: #fff;
        margin-left: 13px;
        margin-top: 20px;
        vertical-align: bottom;
        height: 18px;
        text-align: center;
        font-size: 12px;
        color: #fff;
        font-style: normal;
      }
    
      i.cart-select {
        background-color: crimson;
        border: 1px solid crimson;
      }
    
      span {
        color: #fff;
        margin-left: 6px;
        font-size: 13px;
    
        b {
          font-size: 15px;
        }
      }
    
      button {
        float: right;
        height: 58px;
         120px;
        border: 0 none;
        background-color: #ddd;
        color: #aaa;
        font-size: 15px;
        font-weight: bold;
      }
    }
    </style>
    
    

    6.计算购物车数量

    点击查看代码
    /// <summary>
    		/// 获取购物车数量
    		/// </summary>
    		/// <param name="customerNo"></param>
    		/// <returns></returns>
    		public async Task<int> GetShoppingCartNum(string customerNo)
    		{
    			var carts = await CartRepo.GetListAsync(s => s.CustomerNo == customerNo && s.CartSelected);
    			var currentCartNum = 0;
    			carts.ForEach(c =>
    			{
    				currentCartNum += c.ProductNum;
    			});
    			return currentCartNum;
    		}
    

    7.main.vue代码如下:

    点击查看代码
    <template>
      <div>
        <div class="user-box">
          <div class="user-info">
            <div class="user-head">
              <img src="/img/dealerImgs/picUser.png" alt="" class="" />
            </div>
            <p class="user-name">安徽安庆王跃争</p>
            <p>销售员:菜菜</p>
            <p>单位地址:安庆市光彩大市场四期C区</p>
          </div>
        </div>
        <div class="menu-item">
          <img src="/img/dealerImgs/purchase_order.png" alt="" />
          <div class="menu-info">
            <p class="m-title">我的订单</p>
            <p class="m-info">未完成的订单:8个</p>
          </div>
        </div>
        <div class="menu-item">
          <img src="/img/dealerImgs/shopping212.png" alt="" />
          <div class="menu-info">
            <p class="m-title">购物车</p>
            <p class="m-info">购物车中有:{{ shoppingCartNum }}个待下单的物品</p>
          </div>
        </div>
        <div class="menu-item">
          <img src="/img/dealerImgs/door.png" alt="" />
          <div class="menu-info">
            <p class="m-title">退出账号</p>
            <p class="m-info">退出当前帐号</p>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    import { getCartNum } from '../httpRequests/mainRequest'
    import { shoppingCartNum } from '@/store'
    import { onMounted } from 'vue'
    export default {
      setup() {
        const onGetCartNum = async () => {
          var customerNo = localStorage['customerNo']
          shoppingCartNum.value = await getCartNum(customerNo)
        }
        onMounted(async () => {
          await onGetCartNum()
        })
        return { shoppingCartNum }
      },
    }
    </script>
    <style lang="scss" scoped>
    body {
      background-color: #ccc;
    }
    
    .user-box {
      padding: 10px;
      background-color: #fff;
    
      .user-info {
        padding: 25px 0 25px 80px;
        height: 100px;
        border-radius: 10px;
        position: relative;
        background: -webkit-linear-gradient(left, #b70101, #f20505);
    
        p {
          color: #fff;
          text-align: left;
          font-size: 14px;
          margin-bottom: 16px;
          color: hsla(0, 0%, 100%, 0.7);
        }
    
        p.user-name {
          letter-spacing: 2px;
          font-weight: bold;
          font-size: 16px;
          color: #fff;
        }
    
        .user-head {
           40px;
          height: 40px;
          border-radius: 40px;
          border: 2px solid #fff;
          overflow: hidden;
          background-color: #fff;
          position: absolute;
          top: 36px;
          left: 20px;
    
          img {
             40px;
            height: 40px;
          }
        }
      }
    }
    
    .menu-item {
      text-align-last: left;
      height: 60px;
      background-color: #fff;
      margin-top: 10px;
      padding: 6px;
      position: relative;
      padding-left: 60px;
    
      img {
        position: absolute;
        top: 20px;
        left: 20px;
      }
    
      .menu-info {
        p.m-title {
          margin-top: 10px;
          font-weight: bold;
          font-size: 15px;
        }
        p.m-info {
          margin-top: 8px;
          font-size: 12px;
        }
      }
    }
    </style>
    
    
  • 相关阅读:
    hibernate笔记--实体类映射文件"*.hbm.xml"详解
    struts2学习笔记--使用struts2插件实现ajax处理(返回json数据)
    struts2学习笔记--使用servletAPI实现ajax的一个小Demo
    Struts2学习笔记--使用Response下载文件和Struts2的StreamResult文件下载
    struts2学习笔记--上传单个和批量文件示例
    struts2学习笔记--拦截器(Interceptor)和登录权限验证Demo
    struts2学习笔记--使用Validator校验数据
    struts2学习笔记--OGNL表达式1
    easyui dialog 扩展load
    easyui filter 过滤时间段
  • 原文地址:https://www.cnblogs.com/humblexwang/p/16350259.html
Copyright © 2020-2023  润新知