【B站 heima】小兔鲜Vue3 项目学习笔记Day05

Day05

文章目录

    • Day05
    • 登录
      • 1. 整体认识和路由设置
      • 2. 表单校验实现
      • 3. 表单-统一校验
      • 4. 基础登录业务实现
      • 5. Pinia管理用户数据
      • 6. Pinia 数据持久化
      • 7. 登录和非登录状态下的模板适配
      • 8. 请求拦截器携带Token
      • 9. 退出登录功能的实现
      • 10. Token失效401拦截处理
    • 购物车
      • 1. 流程梳理
      • 2. 本地购物车-加入购物车功能实现
      • 3. 头部购物车列表渲染
      • 4. 头部购物车删除功能
      • 5. 头部购物车统计计算
    • 总结

登录

1. 整体认识和路由设置

准备模板

Login/index.vue
<script setup></script><template><div><header class="login-header"><div class="container m-top-20"><h1 class="logo"><RouterLink to="/">小兔鲜</RouterLink></h1><RouterLink class="entry" to="/">进入网站首页<i class="iconfont icon-angle-right"></i><i class="iconfont icon-angle-right"></i></RouterLink></div></header><section class="login-section"><div class="wrapper"><nav><a href="javascript:;">账户登录</a></nav><div class="account-box"><div class="form"><el-form label-position="right" label-width="60px"status-icon><el-form-item  label="账户"><el-input/></el-form-item><el-form-item label="密码"><el-input/></el-form-item><el-form-item label-width="22px"><el-checkbox  size="large">我已同意隐私条款和服务条款</el-checkbox></el-form-item><el-button size="large" class="subBtn">点击登录</el-button></el-form></div></div></div></section><footer class="login-footer"><div class="container"><p><a href="javascript:;">关于我们</a><a href="javascript:;">帮助中心</a><a href="javascript:;">售后服务</a><a href="javascript:;">配送与验收</a><a href="javascript:;">商务合作</a><a href="javascript:;">搜索推荐</a><a href="javascript:;">友情链接</a></p><p>CopyRight &copy; 小兔鲜儿</p></div></footer></div>
</template><style scoped lang='scss'>
.login-header {background: #fff;border-bottom: 1px solid #e4e4e4;.container {display: flex;align-items: flex-end;justify-content: space-between;}.logo {width: 200px;a {display: block;height: 132px;width: 100%;text-indent: -9999px;background: url("@/assets/images/logo.png") no-repeat center 18px / contain;}}.sub {flex: 1;font-size: 24px;font-weight: normal;margin-bottom: 38px;margin-left: 20px;color: #666;}.entry {width: 120px;margin-bottom: 38px;font-size: 16px;i {font-size: 14px;color: $xtxColor;letter-spacing: -5px;}}
}.login-section {background: url('@/assets/images/login-bg.png') no-repeat center / cover;height: 488px;position: relative;.wrapper {width: 380px;background: #fff;position: absolute;left: 50%;top: 54px;transform: translate3d(100px, 0, 0);box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);nav {font-size: 14px;height: 55px;margin-bottom: 20px;border-bottom: 1px solid #f5f5f5;display: flex;padding: 0 40px;text-align: right;align-items: center;a {flex: 1;line-height: 1;display: inline-block;font-size: 18px;position: relative;text-align: center;}}}
}.login-footer {padding: 30px 0 50px;background: #fff;p {text-align: center;color: #999;padding-top: 20px;a {line-height: 1;padding: 0 10px;color: #999;display: inline-block;~a {border-left: 1px solid #ccc;}}}
}.account-box {.toggle {padding: 15px 40px;text-align: right;a {color: $xtxColor;i {font-size: 14px;}}}.form {padding: 0 20px 20px 20px;&-item {margin-bottom: 28px;.input {position: relative;height: 36px;>i {width: 34px;height: 34px;background: #cfcdcd;color: #fff;position: absolute;left: 1px;top: 1px;text-align: center;line-height: 34px;font-size: 18px;}input {padding-left: 44px;border: 1px solid #cfcdcd;height: 36px;line-height: 36px;width: 100%;&.error {border-color: $priceColor;}&.active,&:focus {border-color: $xtxColor;}}.code {position: absolute;right: 1px;top: 1px;text-align: center;line-height: 34px;font-size: 14px;background: #f5f5f5;color: #666;width: 90px;height: 34px;cursor: pointer;}}>.error {position: absolute;font-size: 12px;line-height: 28px;color: $priceColor;i {font-size: 14px;margin-right: 2px;}}}.agree {a {color: #069;}}.btn {display: block;width: 100%;height: 40px;color: #fff;text-align: center;line-height: 40px;background: $xtxColor;&.disabled {background: #cfcdcd;}}}.action {padding: 20px 40px;display: flex;justify-content: space-between;align-items: center;.url {a {color: #999;margin-left: 10px;}}}
}.subBtn {background: $xtxColor;width: 100%;color: #fff;
}
</style>

在这里插入图片描述

主页有个 ‘请先登录’ 点击进入登录页,主页没有,我们适配一下

分为登录和非登录两种情况,我们将true改为false

在这里插入图片描述
在这里插入图片描述

<!--Layout/HomeNav.vue 跳转到登录页面--><li><a href="javascript:;" @click="router.push('/login')">请先登录</a></li>

2. 表单校验实现

校验:提前校验省去一些错误的请求提交,减小接口压力

elementPlus组件内置了表单校验功能,我们看官方文档完成校验功能。

在这里插入图片描述

步骤:

  • 按照接口字段准备表单对象并绑定
  • 按照产品要求准备规则对象并绑定
  • 指定表单域的校验字段名
  • 把表单对象进行双向绑定

在这里插入图片描述

校验相关代码如下,勾选框使用的是自定义校验

<script setup>
import { ref } from "vue"//登录-账户名,密码,是否勾选
const userInfo = ref({account: '1311111111',password: '123456',agree: true
})const rules = {account: [{ required: true, message: '账户名不能为空', trigger: 'blur' }],password: [{ required: true, message: '密码不能为空', trigger: 'blur' },{ min: 6, max: 14, message: '密码长度要求6-14个字符', trigger: 'blur' }],agree: [// 自定义校验{validator: (rule, value, callback) => {if (value) {callback()} else {callback(new Error("请勾选协议"))}}}]
}</script>
   <div class="form"><el-form label-position="right" label-width="60px" status-icon :rules="rules" :model="userInfo"><el-form-item label="账户" prop="account"><el-input v-model="userInfo.account" /></el-form-item><el-form-item label="密码" prop="password"><el-input v-model="userInfo.password" /></el-form-item><el-form-item label-width="22px" prop="agree"><el-checkbox size="large" v-model="userInfo.agree">我已同意隐私条款和服务条款</el-checkbox></el-form-item><el-button size="large" class="subBtn">点击登录</el-button></el-form></div>

在这里插入图片描述

3. 表单-统一校验

点击 登录 按钮时进行统一校验,弹幕有人说这个功能是防 鲨臂 的哈哈哈笑死

步骤:

获取form组件实例 =》 调用实例方法

通过ref获取组件实例,定义formRef,绑定给表单,给按钮绑定方法doValidate,获取组件实例调用validate方法,相关代码如下

const formRef = ref(null)<el-form label-position="right" label-width="60px" status-icon :rules="rules" :model="userInfo" ref="formRef"><el-button size="large" class="subBtn" @click="doValidate">点击登录</el-button>//表单统一校验
const doValidate = () => {formRef.value.validate((value) => {if (value) {//通过校验执行的逻辑}})
}

4. 基础登录业务实现

基础思想

  • 调用登录接口获取用户信息
//api/user.js
// 用户相关接口函数import httpInstance from "@/utils/http"export const loginAPI = ({ account, password }) => {return httpInstance({url: '/login',method: 'post',data: {account,password}})
}
const { account, password } = userInfo.valueformRef.value.validate(async (value) => {if (value) {//通过校验执行的逻辑const res = await loginAPI({ account, password })  //获取数据}}
  • 提示用户当前是否成功
  • 跳转到首页
//Login/index.vue
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'
import { useRouter } from "vue-router"const router = useRouter()
const doLogin = () => {const { account, password } = form.value// 调用实例方法formRef.value.validate(async (valid) => {// valid: 所有表单都通过校验  才为trueconsole.log(valid)// 以valid做为判断条件 如果通过校验才执行登录逻辑if (valid) {// TODO LOGINawait loginAPI({ account, password })// 1. 提示用户ElMessage({ type: 'success', message: '登录成功' })// 2. 跳转首页router.replace({ path: '/' })}})
}

在这里插入图片描述

响应拦截器写 统一的错误提示

//utils/http.jsimport { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'
// axios响应式拦截器
httpInstance.interceptors.response.use(res => res.data, e => {//统一错误提示ElMessage({type: 'warning',message:e.response.data.message})return Promise.reject(e)
})

当用户账号密码错误会有提示

在这里插入图片描述

5. Pinia管理用户数据

将和数据相关的所有操作(state+action)都放在Pinia中,组件只负责出发action函数

//Store/user.js
//用户相关数据
import { defineStore } from "pinia";
import { ref } from "vue";
import { loginAPI } from '@/apis/user.js'
export const useUserStore = defineStore('user', () => {//数据const userInfo = ref({})//actionconst getUserInfo = async ({ account, password }) => {const res = await loginAPI({ account, password })userInfo.value = res.result}// return,用对象格式return {userInfo,getUserInfo}
})
<!--Login/index.vue-->
import { useUserStore } from '@/stores/user.js'
const userStore = useUserStore()  //定义pinia实例if (value) {//通过校验执行的逻辑// const res = await loginAPI({ account, password })  //获取数据// console.log(res)await userStore.getUserInfo({ account, password })
...
}

6. Pinia 数据持久化

用户数据有个关键数据Token(用来标识当前用户是否登录),而Token需要持续一段时间才会过期

Pinia的存储时基于内存的,刷新就丢失,为了保持登录状态就要做到刷新不丢失,需要配合持久化进行存储。

目的:保持token不丢失,保持登录状态

最终效果:操作state时会自动把用户数据在本地的localStorage也存一份,刷新的时候会从localStorage中先取。

我们使用的是:

在这里插入图片描述

安装,在main.js引入注册这个插件,添加一个配置项persist(看文档使用哈)

npm i pinia-plugin-persistedstate
//main.js
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
//store/user.js
export const useUserStore = defineStore('user', () => {//数据const userInfo = ref({})//actionconst getUserInfo = async ({ account, password }) => {const res = await loginAPI({ account, password })userInfo.value = res.result}// return,用对象格式return {userInfo,getUserInfo}
}, {persist: true
})

验证,看后台localStorage是否能在登录时同步

运行机制:设置state时会自动把数据同步给localStorage,在获取state数据时候会优先从localStorage中取。

在这里插入图片描述

7. 登录和非登录状态下的模板适配

区分登录状态和非登录状态 ,根据是否有token 这个条件判别,来使用不同的模板渲染

Store中拿到token

<script setup>
import { useUserStore } from "@/stores/user";const userStore = useUserStore()
</script><template v-if="userStore.userInfo.token">...<!--用户名动态渲染--><li><a href="javascript:;"><i class=" iconfont icon-user"></i>{{ userStore.userInfo.account }}</a>

8. 请求拦截器携带Token

Token数据会被注入到header中,格式按照后端要求的格式进行拼接处理。

//utils/http.js// axios请求拦截器
httpInstance.interceptors.request.use(config => {// 1. 从pinia获取token数据const userStore = useUserStore()// 2. 按照后端的要求拼接token数据const token = userStore.userInfo.tokenif (token) {config.headers.Authorization = `Bearer ${token}`}return config
}, e => Promise.reject(e))

请求里都会带,只需要这一次配置
在这里插入图片描述

9. 退出登录功能的实现

通用逻辑:清除当前用户信息 =》跳转到登录页面

confirm点击确认触发的事件。

清除信息需要使用pinia管理,在组件中调用。跳回登录页使用useRouter

相关代码如下:

 <!--HomeNav.vue--><script setup>
import { useUserStore } from "@/stores/user";
import { useRouter } from "vue-router";const router = useRouter()
const userStore = useUserStore()//退出登录
const logoutConfirm = () => {userStore.clearData()router.push('/login')
}
</script><el-popconfirm @confirm="logoutConfirm" title="确认退出吗?" confirm-button-text="确认" ...
//store/user.js//退出登录,数据清空const clearData = () => {userInfo.value = {}}

10. Token失效401拦截处理

Token有效性可以保持一定的时间,如果用户一段时间不做任何操作Token就会失效,使用失效的Token请求一些接口,接口会报401错误,需要我们做额外的处理。

我们要做的:

  • 失败回调拦截401

  • 清除过期的用户信息,跳转到登录页

utils/http.js中书写逻辑

// axios响应式拦截器
httpInstance.interceptors.response.use(res => res.data, e => {//统一错误提示ElMessage({type: 'warning',message: e.response.data.message})//处理401const userStore = useUserStore()if (e.response.status === 401) {//1.清除用户数据,数据在pinia中存储着userStore.clearData()//2.跳转到登录页面router.push('/login')}return Promise.reject(e)
})

购物车

难度较大,建议认真学习

1. 流程梳理

业务逻辑梳理拆解:

在这里插入图片描述

2. 本地购物车-加入购物车功能实现

非登录状态

  • 封装cartStore
  • 添加该商品原count+1,未添加过直接push
// 封装购物车模块import { defineStore } from 'pinia'
import { ref } from 'vue'export const useCartStore = defineStore('cart', () => {// 1. 定义state - cartListconst cartList = ref([])// 2. 定义action - addCartconst addCart = (goods) => {console.log('添加', goods)// 添加购物车操作// 已添加过 - count + 1// 没有添加过 - 直接push// 思路:通过匹配传递过来的商品对象中的skuId能不能在cartList中找到,找到了就是添加过const item = cartList.value.find((item) => goods.skuId === item.skuId)if (item) {// 找到了item.count++} else {// 没找到cartList.value.push(goods)}}return {cartList,addCart}
}, {persist: true,
})

数据组件用的是elementPlusinput-number

<el-input-number v-model="count" @change="countChange" />//js  购物车件数count
const count = ref(1)
const countChange = (count) => {   
}
//规格操作时
let skuObj = {}
const skuChange = (sku) => {console.log(sku)skuObj = skuconsole.log(skuObj)  //选满了就有值,可以作为一个判断条件
}
  • 组件点击 添加 按钮
<el-button size="large" class="btn" @click="addCart">
加入购物车
</el-button>
  • 选中规格 -> 调用action添加(传递商品参数)。规格两个都要选中对象不为空
//添加购物车
const addCart = () => {if (skuObj.skuId) {//规格选择全了,触发action} else {ElMessage.warning('请选择规格')}
}

在这里插入图片描述

引入cartStore,调用方法,传参

import { useCartStore } from '@/stores/cartStore';const cartStore = useCartStore()
//添加购物车
const addCart = () => {if (skuObj.skuId) {//规格选择全了,触发actioncartStore.addCart({//传参id: goods.value.id,  //商品idname: goods.value.name,  //商品名称picture: goods.value.mainPictures[0],  //图片price: goods.value.price,  //最新价格count: count.value,  //商品数量skuId: skuObj.skuId,attrsText: skuObj.specsText,  //商品规格文本selected: true  //商品是否选中})} else {ElMessage.warning('请选择规格')}
}

3. 头部购物车列表渲染

在这里插入图片描述

头部购物车组件Layout/components/HeaderCart.vue,在LayoutHeader中引入并使用:

<script setup></script><template><div class="cart"><a class="curr" href="javascript:;"><i class="iconfont icon-cart"></i><em>2</em></a><div class="layer"><div class="list"><!--<div class="item" v-for="i in cartList" :key="i"><RouterLink to=""><img :src="i.picture" alt="" /><div class="center"><p class="name ellipsis-2">{{ i.name }}</p><p class="attr ellipsis">{{ i.attrsText }}</p></div><div class="right"><p class="price">&yen;{{ i.price }}</p><p class="count">x{{ i.count }}</p></div></RouterLink><i class="iconfont icon-close-new" @click="store.delCart(i.skuId)"></i></div>--></div><div class="foot"><div class="total"><p>共 10 件商品</p><p>&yen; 100.00 </p></div><el-button size="large" type="primary" >去购物车结算</el-button></div></div>
</div>
</template><style scoped lang="scss">
.cart {width: 50px;position: relative;z-index: 600;.curr {height: 32px;line-height: 32px;text-align: center;position: relative;display: block;.icon-cart {font-size: 22px;}em {font-style: normal;position: absolute;right: 0;top: 0;padding: 1px 6px;line-height: 1;background: $helpColor;color: #fff;font-size: 12px;border-radius: 10px;font-family: Arial;}}&:hover {.layer {opacity: 1;transform: none;}}.layer {opacity: 0;transition: all 0.4s 0.2s;transform: translateY(-200px) scale(1, 0);width: 400px;height: 400px;position: absolute;top: 50px;right: 0;box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);background: #fff;border-radius: 4px;padding-top: 10px;&::before {content: "";position: absolute;right: 14px;top: -10px;width: 20px;height: 20px;background: #fff;transform: scale(0.6, 1) rotate(45deg);box-shadow: -3px -3px 5px rgba(0, 0, 0, 0.1);}.foot {position: absolute;left: 0;bottom: 0;height: 70px;width: 100%;padding: 10px;display: flex;justify-content: space-between;background: #f8f8f8;align-items: center;.total {padding-left: 10px;color: #999;p {&:last-child {font-size: 18px;color: $priceColor;}}}}}.list {height: 310px;overflow: auto;padding: 0 10px;&::-webkit-scrollbar {width: 10px;height: 10px;}&::-webkit-scrollbar-track {background: #f8f8f8;border-radius: 2px;}&::-webkit-scrollbar-thumb {background: #eee;border-radius: 10px;}&::-webkit-scrollbar-thumb:hover {background: #ccc;}.item {border-bottom: 1px solid #f5f5f5;padding: 10px 0;position: relative;i {position: absolute;bottom: 38px;right: 0;opacity: 0;color: #666;transition: all 0.5s;}&:hover {i {opacity: 1;cursor: pointer;}}a {display: flex;align-items: center;img {height: 80px;width: 80px;}.center {padding: 0 10px;width: 200px;.name {font-size: 16px;}.attr {color: #999;padding-top: 5px;}}.right {width: 100px;padding-right: 20px;text-align: center;.price {font-size: 16px;color: $priceColor;}.count {color: #999;margin-top: 5px;font-size: 16px;}}}}}
}
</style>

pinia获取数据,渲染:

<script setup>
import { useCartStore } from '@/stores/cartStore';const cartStore = useCartStore()
</script><template><div class="cart"><a class="curr" href="javascript:;"><i class="iconfont icon-cart"></i><em>{{ cartStore.cartList.length }}</em></a><div class="layer"><div class="list"><div class="item" v-for="i in cartStore.cartList" :key="i"><RouterLink to=""><img :src="i.picture" alt="" /><div class="center"><p class="name ellipsis-2">{{ i.name }}</p><p class="attr ellipsis">{{ i.attrsText }}</p></div><div class="right"><p class="price">&yen;{{ i.price }}</p><p class="count">x{{ i.count }}</p></div></RouterLink><i class="iconfont icon-close-new" @click="store.delCart(i.skuId)"></i></div></div><div class="foot"><div class="total"><p>共 10 件商品</p><p>&yen; 100.00 </p></div><el-button size="large" type="primary">去购物车结算</el-button></div></div></div>
</template><style scoped lang="scss">
.cart {width: 50px;position: relative;z-index: 600;.curr {height: 32px;line-height: 32px;text-align: center;position: relative;display: block;.icon-cart {font-size: 22px;}em {font-style: normal;position: absolute;right: 0;top: 0;padding: 1px 6px;line-height: 1;background: $helpColor;color: #fff;font-size: 12px;border-radius: 10px;font-family: Arial;}}&:hover {.layer {opacity: 1;transform: none;}}.layer {opacity: 0;transition: all 0.4s 0.2s;transform: translateY(-200px) scale(1, 0);width: 400px;height: 400px;position: absolute;top: 50px;right: 0;box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);background: #fff;border-radius: 4px;padding-top: 10px;&::before {content: "";position: absolute;right: 14px;top: -10px;width: 20px;height: 20px;background: #fff;transform: scale(0.6, 1) rotate(45deg);box-shadow: -3px -3px 5px rgba(0, 0, 0, 0.1);}.foot {position: absolute;left: 0;bottom: 0;height: 70px;width: 100%;padding: 10px;display: flex;justify-content: space-between;background: #f8f8f8;align-items: center;.total {padding-left: 10px;color: #999;p {&:last-child {font-size: 18px;color: $priceColor;}}}}}.list {height: 310px;overflow: auto;padding: 0 10px;&::-webkit-scrollbar {width: 10px;height: 10px;}&::-webkit-scrollbar-track {background: #f8f8f8;border-radius: 2px;}&::-webkit-scrollbar-thumb {background: #eee;border-radius: 10px;}&::-webkit-scrollbar-thumb:hover {background: #ccc;}.item {border-bottom: 1px solid #f5f5f5;padding: 10px 0;position: relative;i {position: absolute;bottom: 38px;right: 0;opacity: 0;color: #666;transition: all 0.5s;}&:hover {i {opacity: 1;cursor: pointer;}}a {display: flex;align-items: center;img {height: 80px;width: 80px;}.center {padding: 0 10px;width: 200px;.name {font-size: 16px;}.attr {color: #999;padding-top: 5px;}}.right {width: 100px;padding-right: 20px;text-align: center;.price {font-size: 16px;color: $priceColor;}.count {color: #999;margin-top: 5px;font-size: 16px;}}}}}
}
</style>

在这里插入图片描述

4. 头部购物车删除功能

 // 删除购物车const delCart = async (skuId) => {// 思路:// 1. 找到要删除项的下标值 - splice// 2. 使用数组的过滤方法 - filterconst idx = cartList.value.findIndex((item) => skuId === item.skuId)cartList.value.splice(idx, 1)}
  <i class="iconfont icon-close-new" @click="cartStore.delCart(i.skuId)"></i>

5. 头部购物车统计计算

在这里插入图片描述

使用computed计算属性

计算逻辑是什么:

  • 商品总数计算逻辑:商品列表中的所商品 count 累加之和
  • 商品总价钱计算逻辑:商品列表中的所有商品的 count*price 累加之和
//计算购物车件数和总价格//总数const allCount = computed(() => cartList.value.reduce((a, c) => a + c.count, 0))//总价const allPrice = computed(() => cartList.value.reduce((a, c) => a + c.count * c.price, 0))return {cartList,allCount,allPrice,addCart,delCart}
 <div class="total"><p>共 {{ cartStore.allCount }}件商品</p><p>&yen; {{ cartStore.allPrice }}</p></div>

在这里插入图片描述

总结

love and peace
持续更新~~
在这里插入图片描述

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

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

相关文章

韬光养晦的超绝项目

发展方向 竞技闯关类 可以加入对战系统积累积分&#xff0c;竞技类的接受程度更高&#xff0c;小孩&#xff08;我和我身边大多数人小时候&#xff09;都喜欢玩王者吃鸡这种经济类游戏&#xff0c;开放世界探索&#xff08;本项目、一梦江湖、逆水寒&#xff09;的受众群体年…

一文讲清楚SpringBoot项目打包jar后运行报错template might not exist - 第514篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

定个小目标之每天刷LeetCode热题(1)

有两种解决方法&#xff1a; 第一种&#xff1a;利用哈希集合不重复的特性&#xff0c;代码展示如下 public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {Set<ListNode> listNode new HashSet<ListNode>();ListNode…

搭贝低代码平台:重塑房地产行业的工作流程与效率

随着数字化转型浪潮席卷全球&#xff0c;房地产行业也开始积极探索利用科技力量提升业务效率与服务质量。搭贝低代码平台&#xff0c;作为一款强大的数字化工具&#xff0c;正逐渐成为房地产企业优化管理流程、加速决策制定的重要推手。本文将深入探讨搭贝如何在房地产行业多个…

QT使用gsoap获取手机归属地

1-环境变量 用的win32 E:\hes_scc\tools\gsoap_2.8.134\gsoap-2.8\gsoap\bin\win32 2-生成代码接口 自己建一个目录&#xff0c;在此打开cmd窗口&#xff0c;生成的文件都会在这个文件夹中。 这里用的手机归宿地。 wsdl2h -o GetPhoneInfo.h -s -n Phone -t ....\typemap.…

集智书童 | YOLOv10开源|清华用端到端YOLOv10在速度精度上都生吃YOLOv8和YOLOv9

本文来源公众号“集智书童”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;YOLOv10开源&#xff5c;清华用端到端YOLOv10在速度精度上都生吃YOLOv8和YOLOv9 在过去几年中&#xff0c;YOLO系列模型已成为实时目标检测领域的主导范式…

生产订单工序新增BAPI:CO_SE_PRODORD_OPR_CREATE增强

背景&#xff1a; 创建生产订单工序时需要通过BAPI来维护圈起来的字段&#xff0c;但是BAPI不包含这些字段&#xff0c;所以对BAPI进行一些增强处理。 实现过程&#xff1a; 1.拷贝标准BAPI:CO_SE_PRODORD_OPR_CREATE至ZCO_SE_PRODORD_OPR_CREATE&#xff08;最好放在新的自定…

解决:java.util.concurrent.RejectedExecutionException

一 发现RejectedExecutionException错误 今天查看服务器的时候发现了一些java.util.concurrent.RejectedExecutionException错误&#xff0c;这个是由于线程池里的线程忙不过来报出的。如下图&#xff1a; 像这种 RejectedExecutionException 错误&#xff0c;表明在Java应…

QT如何将生成的exe文件打包成安装包

一、生成exe文件 1、生成exe文件 QT编译模式选择release&#xff0c;然后点击编译&#xff1a; 2、找到exe文件 在开发文件夹下找到build-xxxxxxx-Release文件夹里面找到exe文件 3、相关依赖dll文件查找 新建个空文件夹将exe文件拷贝进去&#xff1a; 然后找到如下程序…

恒创科技:Linux 服务器和 Windows 服务器哪个更好?

选择正确的服务器系统至关重要&#xff0c;目前广泛使用的选项是 Windows 服务器 和 Linux 服务器&#xff0c;它们各有优缺点。本文将比较 Linux 与 Windows 服务器&#xff0c;让我们来看看它们的主要区别&#xff0c;然后再决定哪种操作系统适合使用。 主要区别&#xff1a;…

HTTP方法、状态码和请求过程

一、HTTP方法概念&#xff1a; HTTP客户端发出请求&#xff0c;告知服务端需要执行不同类型的请求命令&#xff0c;这些命令被称为HTTP方法。 简说:HTTP方法是告诉服务器要做什么。 1、GET方法&#xff1a;获取资源 作用&#xff1a; ①通常用于请求服务器发送某个资源&am…

Tensors张量操作

定义Tensor 下面是一个常见的tensor&#xff0c;包含了里面的数值&#xff0c;属性&#xff0c;以及存储位置 tensor([[0.3565&#xff0c;0.1826&#xff0c;0.6719],[0.6695&#xff0c;0.5364&#xff0c;0.7057]]&#xff0c;dtypetorch.float32,devicecuda:0)Tensor的属…

Bootstrap5

Bootstrap 5 是 Bootstrap 框架的最新版本&#xff0c;这是一个广受欢迎且功能强大的开源前端开发框架&#xff0c;专为快速构建响应式和移动优先的网站而设计。Bootstrap 由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 创建&#xff0c;它以 HTML、CSS 和 JavaScript 为基…

【uniapp】uniapp基本介绍

目录 介绍体验uni-app优势功能框架图 uni-app组成和跨端原理基本语言和开发规范 编译器运行时&#xff08;runtime&#xff09;uni-app runtime包括3部分&#xff1a;基础框架、组件、API基础框架&#xff1a;组件&#xff1a;组件的扩展&#xff1a; API&#xff1a; 逻辑层和…

vue2的方法与监听

vue2的方法 不可以使用箭头函数 <template> <div><div>{{sum2()}}</div><button click"add">add</button> </div></template><script> export default {data(){return{name:"张三",num:20,num2:3…

基于形态学滤波的心电信号ECG处理(MATLAB 2021B)

数学形态学简称形态学&#xff0c;在数学意义上&#xff0c;其基于集合理论、积分几何和网格代数&#xff0c;是一门严格建立在数学基础之上的学科&#xff0c;着重用来研究图像的几何结构和形状&#xff0c;因而称之为形态学。其基本思想是用结构元素对待分析图像进行“探测”…

机器人回调接口完善

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 免责声明&#xff1a;该工具仅供学习使用&#xff0c;禁止使用该工具从事违法活动&#xff0c;否则永久拉黑封禁账号&#xff01;&#xff01;&#xff01;本人不对任何工具的使用负责&am…

计算机类主题会议推荐之——ACAIB 2024

【北方民族大学40 周年校庆学术活动】 第四届自动化控制、算法与智能仿生学术会议(ACAIB 2024) 2024年6月7-9日 中国银川 往届均已见刊检索 EI、SCOPUS双检索 基本信息 会议官网&#xff1a;www.acaib.org 最终截稿时间&#xff1a;2024年6月3日晚23&#xff1a;…

Mac 电脑给android手机传输文件提示 No android device found

在开发过程中&#xff0c;我们有时候会有在电脑和手机之间传输文件的需求。 Mac电脑给android手机传输文件并不是很方便。 Google 官方提供了一个软件叫Android File Transfer&#xff0c;这个软件免费且好用。 Android File Transfer下载地址 但是使用过程中会遇到一些问题…

白银现货价格对这两种形态形成突破 应当予以关注

在白银现货价格分析和交易中&#xff0c;突破这个行为一直是一个重要的、具有可分析性的市场动作。本文要讨论的&#xff0c;是基于价格形态之上的突破行为&#xff0c;下面我们就来看看。 中继形态的突破。白银现货价格波动中有中继形态有反转形态&#xff0c;中继形态的意思是…