uniapp前端支付篇(微信、抖音、快手、h5)四个平台支付

前言

微信、快手、h5支付步骤大致相同,只有抖音是有自己的支付组件
项目同时支持多个(微信、快手、h5)平台支付,后端那边代码可以封装的

各平台支付大致流程都是相同的,总结了一下分为五个步骤

  1. 点击支付
  2. 创建订单
  3. 生成密钥和支付所需要的参数
  4. 支付成功
  5. 查询订单状态

一、微信支付

1.支付按钮

<button @click="payTap">立即抢购</button>

2.支付事件

payTap() {
	let that = this
	// 这些参数后端一般要的
	let data = {
		openid: this.openId, //用户id 必需
		courseId: this.detailsObj.id, //课程id(商品id)必需
		promoterId: this.promoterShareId ? this.promoterShareId : '', // 分销员id
		couponId: this.detailsObj.receiveCouponId ? this.detailsObj.receiveCouponId : '', // 优惠卷id
	}
	// 如果一个项目里有多个平台支付,可以用传值来区分
	// #ifdef MP-WEIXIN
	data.platform = 1
	// #endif
	// #ifdef MP-KUAISHOU
	data.platform = 2
	// #endif
	//创建订单
	createWendaoOrder(data).then(res => {
		// 返回密钥
		createOrder({
			orderId: res.data.orderId, // 订单id
			openid: this.openId, // 用户id
		}).then(res1 => {
			// #ifdef MP-WEIXIN
			let twoData = res1.data
			// 微信支付api
			// 参数向后端要 要确保每个值就有
			uni.requestPayment({
				appId: twoData.appId,
				timeStamp: twoData.timeStamp,
				nonceStr: twoData.nonceStr,
				package: twoData.packageValue,
				signType: twoData.signType,
				paySign: twoData.paySign,
				success(result) {
					// 调起支付密码
					if (result.errMsg == "requestPayment:ok") {
						// 支付成功
						 uni.showLoading({
						 	title: '获取订单状态..',
						 	mask: true,
						 })
						orderSuccess({
							openid: that.openId, // 用户id
							orderId: res.data.orderId // 订单id
						}).then(res=>{
							uni.hideLoading();
							uni.showToast({
								title: '支付成功',
								icon: 'none'
							});
							// 重新请求下商品详情
							that.detailFn()
						})
					} else {
						uni.showModal({
							title: '',
							content: '支付失败',
							showCancel: false,
							icon: 'none',
							success(res) {}
						})
					}
				},
				fail(result) {
					console.log(result)
					uni.showModal({
						title: '',
						content: '支付失败',
						showCancel: false,
						icon: 'none',
						success(res) {}
					})
				},
			})
			// #endif
		}).catch(res => {
			console.log(res)
		})
	})
}

二、快手支付

1.支付按钮

<button @click="payTap">立即抢购</button>

2.支付事件

payTap() {
	let that = this
	// 这些参数后端一般要的
	let data = {
		openid: this.openId, //用户id 必需
		courseId: this.detailsObj.id, //课程id(商品id)必需
		promoterId: this.promoterShareId ? this.promoterShareId : '', // 分销员id
		couponId: this.detailsObj.receiveCouponId ? this.detailsObj.receiveCouponId : '', // 优惠卷id
	}
	// 如果一个项目里有多个平台支付,可以用传值来区分
	// #ifdef MP-WEIXIN
	data.platform = 1
	// #endif
	// #ifdef MP-KUAISHOU
	data.platform = 2
	// #endif
	//创建订单
	createWendaoOrder(data).then(res => {
		// 返回密钥
		createOrder({
			orderId: res.data.orderId, // 订单id
			openid: this.openId, // 用户id
		}).then(res1 => {
			// 后端返回的是这些数据
			// res1.data = {
				// order_no: "1231xxxxxxxxxxxxxxx450" 
				// order_info_token: "ChJrc01wUGF5LmxxxxxxxxxxxxxxxWYYeulijTrRyDdowh6Lvtp2MIm-t5nlq4s3xxxxxxxxxxxxxxxxxxxuh217_-giIIHDQ8yTqZqghjVraGC_NjxxxxxxxxxxxxxxKAUwAQ"
			// {
			// 快手支付api
			// #ifdef MP-KUAISHOU
			ks.pay({
				serviceId: '1',
				orderInfo: res1.data,
				success: function success(res2) {
					// 调起支付密码
					// 支付成功
					 uni.showLoading({
					 	title: '获取订单状态..',
					 	mask: true,
					 })
					orderSuccess({
						openid: that.openId, // 用户id
						orderId: res.data.orderId // 订单id
					}).then(res=>{
						uni.hideLoading();
						uni.showToast({
							title: '支付成功',
							icon: 'none'
						});
						// 重新请求下商品详情
						that.detailFn()
					})
				},
				fail: function fail(res) {
					uni.showToast({
						title: '支付失败',
						icon: 'none'
					})
				}
			})
			// #endif
		}).catch(res => {
			console.log(res)
		})
	})
}

三、抖音支付

抖音有自己的支付组件和自己的下单页面,所以需要创建一个专属于抖音的组件,并把需要的参数进行传递

1.创建组件

1.新建ttcomponents文件夹,创建完后在ttcomponents下面再新建DyPayButton文件夹,然后在DyPayButton下面创建四个文件,分别为index.js、index.json、index.ttml、index.ttss
2.要创建在App.vue同级

在这里插入图片描述

先在App.vue 写baseUrl和getPhoneNumber函数

<script>
	
	export default {
		onLaunch: function() {
		
		},
		onShow: function() {
			console.log('App Show')
		},
		onHide: function() {
			console.log('App Hide')
		},
		methods: {
			// 这个是接口基地址
			baseUrl(){
				return 'https://kspaycallback.wendao101.com/douyin'
			},
			/**
			 * desc: 获取手机号
			 * params:加密数据
			 * success:成功回调
			 * fail: 失败回调
			 */
			 // 这个是抖音下单页获取手机号调用的函数
			getPhoneNumber({
				params,
				success,
				fail
			}) {
				const {
					iv,
					encryptedData
				} = params;
				miniLogin().then(data=>{
					getTtOpen(data).then(data1 => {
						// 获取手机号函数
						savePhone({
							openid: data1.data.data.openId,
							iv,
							encryptedData
						}).then(data4 => {
							miniLogin().then(data6=>{
								getTtOpen(data6).then(data5 => {
									const result = {
										phoneNumber: data5.data.data.telNumber,
									}
									// 回调前端模板
									success(result)
								})
							})
						})
					})
				})
			},

		},
	}
</script>

<style lang="scss">
	@import "@/uni_modules/uview-ui/index.scss";

	@import '@/utlis/index.scss';

	/*每个页面公共css */
</style>

下面是那四个文件的内容
index.js

// 可以调用到app.vue里的方法
const app = getApp();

Component({


	properties: {
		mode: Number,
		openId: {
			type: [String, Number],
		},
		orderStatus:{
			type: [String, Number],
		},
		detailsObj: {
			type: Object,
		},
		goodsId: {
			type: String,
			value: "",
		},
		promoterShareId: Number,
	},
	data: {

	},

	methods: {
		// 提交商品信息 这个函数一进页面就会调用的
		getGoodsInfo(event) {
			const that = this
			return new Promise(resolve => {
				// 定时器是为解决 优惠卷id获取不到问题
				setTimeout(()=>{
					tt.getSystemInfo({
						success: (resPlatform)=> {
							
							let pay = that.data.detailsObj.price * 100 // 价格单位是分
							let promoterShareId = that.data.promoterShareId // 分销员id
							let required = that.data.detailsObj.giveEntityIsNeedPhone // 是否强制获取手机号
							let CouponId = that.data.detailsObj.receiveCouponId // 优惠卷id
							// 用不到的值就不用传
							let data = {
								currentPrice: pay,
								GoodsLabel: [{
										type: 'NON_REFUNDABLE'
									}
								],
								minLimits: 1,
								maxLimits: 1,
								dateRule: '周一至周日可用',
								extra: {
									promoterId: promoterShareId,
									receiveCouponId: CouponId
								},
								validation: {
									phoneNumber: {
										required: required // 手机号是否必填
									}
								},
								marketingVersion: 1,
							}
							// im客服需要提前开通
							// 判断如果用户手机是ios就走客服支付, 把imId传上就自动跳转im客服页面了,安卓不要传这个id,否则可能会导致支付不了
							if(resPlatform.platform == 'ios'){
								data.imId = '3xxxxxxxx42'
							}	
							// 然后将商品信息传入 resolve 函数
							resolve(data);
						}
					});
				},600)
			})
		},
		onError(e) {
			const {
				errNo,
				errMsg
			} = e.detail;
			if (errNo === 21514) {
				tt.showToast({
					title: "失败", // 内容
					icon: "none", // 图标
				});
			} else if (errNo === 21513) {
				tt.showToast({
					title: "获取中", // 内容
					icon: "none", // 图标
				});
			}
		},
		
		userLogin(event) {
			const {
				goodsId,
				goodsType
			} = event.detail
			return new Promise((resolve, reject) => {
				tt.login({
					success(e) {
						// 用户登录成功并获取信息,则调用 resolve 函数,跳转至提单页
						resolve();
					},
					fail() {
						// 用户登录失败,则跳转提单页失败
						_this.showTost("登录失败")
					}
				});
			});
		},
		payError(event) {
			this.showTost(event.errMsg)
		},
		// 继续支付
		handleContinutePay(event) {
		    const { status, outOrderNo, result } = event.detail;
		    if (status === 'success') {
		        const { code } = result;
		        if (code === 0) {
		            // 继续支付成功
		            // 刷新页面
					this.triggerEvent("refreshData")
					tt.showToast({
						title: "支付成功",
					});
		        }
		    } else {
		        // 继续支付失败
				tt.showToast({
					title: "继续支付失败",
					icon: "none"
				});
		    }
		},
		// 正式支付
		newButtonPay(event) {
			const {
				status,
				orderId,
				outOrderNo,
				result
			} = event.detail;
			if (status === 'success') {
				const {
					code
				} = result;
				if (code === 0) {
					tt.showLoading({
						title: "订单确认中...",
					}); 
					this.getOrderIsHaveData(outOrderNo)
				} else {
					// 支付失败(超时、取消、关闭)
					this.showTost('支付失败(超时、取消、关闭)')
				}
			} else {
				const {
					errMsg
				} = result;
				this.showTost(errMsg)
			}
		},
		showTost(tit, timeMs) {
			let time = timeMs > 0 ? timeMs : 1500;
			tt.showToast({
				title: tit,
				icon: "none",
				duration: time,
			});
		},
		// 重新订单
		getOrderIsHaveData(orderId) {
			let data = {
				openid: this.data.openId,
				orderId,
			}
			tt.request({
				url: app.baseUrl() + "/order/order_success",
				method: 'POST',
				data,
				success: (res) => {
					this.setOrderIsHaveData(res.data.orderStatus, orderId)
				}
			})
		},
		setOrderIsHaveData(data, orderId) {
			if (data == 0) {
				setTimeout(() => {
					_this.getOrderIsHaveData(orderId)
				}, 1000);
			} else {
				tt.hideLoading();
				tt.navigateBack(-1);
				this.triggerEvent("refreshData")
			}
		},

		// 退款
		onApplyrefund(event) {
			console.log(event)

			const {
				orderId
			} = event.detail;
			const extra = {
				orderId
			}; // 开发者需要透传的参数,可自定义内容
			return new Promise(resolve => {
				resolve(extra);
			});
		},
		onRefund(event) {
			console.log(event)
			const {
				status,
				result
			} = event.detail;
			if (status === 'success') {
				const {
					refundId,
					outRefundNo
				} = result;
			} else {
				const {
					errMsg
				} = result;
				tt.showToast({
					title: e.detail.errMsg ? e.detail.errMsg : '失败',
					icon: "none"
				});
			}
		},
		refundError(e) {
			console.log(e)
			if (e.detail.errNo == 21531) {
				tt.showToast({
					title: "不符合退款要求",
					icon: "none"
				});
			} else {
				tt.showToast({
					title: e.detail.errMsg ? e.detail.errMsg : '失败',
					icon: "none"
				});
			}
		},
	},
});

index.json

{
  "component": true,
  "usingComponents": {}
}

index.ttml

<!-- 立即抢购 -->
<block tt:if="{{mode==2}}">  
	<pay-button class="{{classsname}}" mode="{{2}}" goods-id="{{detailsObj.productId}}" goods-type="{{1}}"
		biz-line="{{2}}" bind:getgoodsinfo="getGoodsInfo" bind:placeorder="userLogin" marketing-ready="{{true}}"
		bind:pay="newButtonPay" bind:error="onError"></pay-button>
</block>

<block tt:if="{{mode==1}}">
	<!-- 继续支付 -->
	<pay-button tt:if="{{orderStatus==0}}" class="{{classsname}}" order-status="{{0}}" order-id="{{orderData.orderId}}"
		bind:pay="handleContinutePay"></pay-button>

	<!-- 退款 -->
	<pay-button class="order_ljzf" mode="{{1}}" goods-type="{{1}}" order-status="{{1}}" order-id="{{orderData.orderId}}"
		:refund-total-amount="{{orderData.coursePrice}}" biz-line="{{2}}" marketing-ready="{{true}}"
		catch:applyrefund="onApplyrefund" catch:refund="onRefund" catch:error="refundError"
		tt:if="{{orderData.orderStatus==1}}"></pay-button>

	<!-- 退款状态 -->
	<pay-button class="order_tk" mode="{{1}}" goods-type="{{1}}"
		order-status="{{orderData.orderStatus=='4'?2:orderData.orderStatus=='2'?3:orderData.orderStatus=='5'?4:4 }}"
		refund-id="{{orderData.orderId}}" biz-line="{{2}}" marketing-ready="{{true}}" catch:applyrefund="onApplyrefund"
		catch:refund="onRefund" catch:error="refundError"
		tt:if="{{orderData.orderStatus!=1 && orderData.orderStatus!=0}}"></pay-button>
</block>

index.ttss

按钮样式根据自己的来

.save_one {
	width: 100%;
	height: 100%;
}

.payButton {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 310rpx;
	height: 90rpx;
	border-radius: 45rpx;
	box-sizing: border-box;
	background-color: #E10000;
	color: #fff;
	border: 2rpx solid #E10000;
}

.payButtonItem {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 183rpx;
	height: 57rpx;
	background: #E10000;
	border-radius: 29rpx;
	border: 1rpx solid #E10000;
	font-size: 26rpx;
	font-family: "Noto Sans SC";
	font-weight: 600;
	color: #fff;
	line-height: 37rpx;
	box-sizing: border-box;
	margin-right: 16rpx;
}

2.在pages.json给商品详情页面注册组件

"pages": [{
	"path": "details/details",
	"style": {
		// #ifdef MP-TOUTIAO
		// 这个是需要加的,否则显示不出来
		"usingComponents": {
			"zijie-pay-button": "/ttcomponents/DyPayButton/index"
		},
		//#endif
		"navigationBarTitleText": "xxxx",
		"enablePullDownRefresh": false
	}
}]

3.在商品详情页面中使用组件

components:{
	// #ifdef MP-TOUTIAO
	"zijie-pay-button": "../../ttcomponents/DyPayButton/index",
	//#endif
}
<zijie-pay-button 
	v-if="detailsObj.productId"
	:openId="openId"
	:mode='2' 
	:detailsObj="detailsObj" 
	:classsname="'save_one'"
	:promoterShareId="promoterShareId"
	@refreshData="refreshData"
></zijie-pay-button>
>
// v-if: 判断有没有商品id
// openId: 用户id
// mode: 商品类型
// detailsObj: 商品详情页的数据
// classsname: 按钮类名
// promoterShareId: 分销员id
// @refreshData: 用于支付成功回调刷新页面

4.h5支付

主要是为解决微信ios无法支付的问题,ios走h5支付渠道

1.创建按钮

// 这个按钮是uView组件
<u-button 
text="联系老师" 
v-if="isIosDouYin" 
shape="circle" 
color="#E10000"
:send-message-title="detailsObj.title?detailsObj.title:''"
:send-message-img="detailsObj.coverPicUrl"
:send-message-path="'/pages_details/details/details?courseId=' + detailsObj.id + '&promoterId=' + promoterShareId + '&couponId=' + detailsObj.receiveCouponId + '&appNameType=1&platform=1&openid=' + openId"
show-message-card="true" 
open-type="contact"></u-button>

// isIosDouYin: 判断是否为ios系统
// send-message-title: 商品标题
// :send-message-img: 商品封面
// :send-message-path: 跳转路径
// show-message-card: 发送卡片


2.创建页面

在详情页同级目录创建一个页面detailsContact.vue,后端可以重定向到这个页面

var _this;
export default {
		data() {
			return {
				openid: '', // 用户id
				h5PayData:{}, // h5提交的参数
				h5OrderId: '' // 订单id
			}
		},
		onLoad(options) {
			_this = this
			// 页面一进来就调用支付 带上路径传的值
			this.payTap(options)
		},
		methods:{
			payTap(queryObj) {
				let that = this
				that.openid = queryObj.openid
				let data = {
					openid: queryObj.openid, // 用户id
					courseId: queryObj.courseId, // 课程id
					promoterId: queryObj.promoterId ? queryObj.promoterId : 0, // 推广员id
					couponId: queryObj.couponId ? queryObj.couponId : 0, // 优惠卷id
					appNameType: queryObj.appNameType, // 区分哪个小程序
					platform : queryObj.platform // 区分平台
				}
				
				createWendaoOrder1(data).then(res => {
					createOrder1({
						orderId: res.data.orderId,
						openid: queryObj.openid,
					}).then(res1 => {
						// #ifdef H5
						that.h5PayData = res1.data
						that.h5OrderId = res.data.orderId
						that.getWxOfficePay()
						// #endif
					}).catch(res => {
						console.log(res)
					})
				})
				
			},
			getWxOfficePay() {
				if (typeof WeixinJSBridge == "undefined") {
					if (document.addEventListener) {
						document.addEventListener('WeixinJSBridgeReady', _this.getWxOfficePayPage, false);
					} else if (document.attachEvent) {
						document.attachEvent('WeixinJSBridgeReady', _this.getWxOfficePayPage);
						document.attachEvent('onWeixinJSBridgeReady', _this.getWxOfficePayPage);
					}
				} else {
					_this.getWxOfficePayPage()
				}

			},
			getWxOfficePayPage() {
				const that = this
				console.log("h5支付调起支付面板 ")
				WeixinJSBridge.invoke(
					'getBrandWCPayRequest', {
						appId: _this.h5PayData.appId,
						timeStamp: _this.h5PayData.timeStamp,
						nonceStr: _this.h5PayData.nonceStr,
						package: _this.h5PayData.packageValue,
						signType: _this.h5PayData.signType,
						paySign: _this.h5PayData.paySign,
					},
					function(res) {
						if (res.err_msg == "get_brand_wcpay_request:ok") {
							uni.showLoading({
								title: '获取订单状态..',
								mask: true,
							})
							// 确认订单
							uni.request({
								url: app.baseUrl() + "/order/order_success",
								method: 'POST',
								data: {
									openid: that.openId,
									orderId: that.h5OrderId
								},
								success: (res) => {
									uni.hideLoading();
									uni.showModal({
										title: '',
										content: '支付成功,请返回小程序查看课程',
										showCancel: false,
										icon: 'none'
									})
								}
							})
						} else {
							uni.showModal({
								title: '',
								content: '支付失败',
								showCancel: false,
								icon: 'none',
								success(res) {}
							})
						}
					}
				);
			},
		}
	}

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

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

相关文章

深搜回溯剪枝优化策略-全排列II

LCR 084. 全排列 II - 力扣&#xff08;LeetCode&#xff09; 这道题的主体思想和之前讲过的全排列是相似的&#xff0c;不同的是思考的角度要侧重于剪枝方向&#xff0c;所以可以通过这道题对剪枝思想的进一步扩展&#xff1b; 通过题意&#xff0c;可以知道&#xff0c;在上一…

非得让你会之MyBatis插件与Java动态代理

引言 咱们今天聊聊Java动态代理&#xff0c;这东西在开发中真的太常见了。比如Spring AOP、RPC&#xff0c;它们都离不开动态代理。然后&#xff0c;咱们再来说说MyBatis插件&#xff0c;这可是MyBatis框架中的一个超实用的功能&#xff0c;它就像是给MyBatis加了个“超能力”…

SmartSoftHelp8,Web前端性能提升,js,css,html 优化压缩工具

Web前端js&#xff0c;css&#xff0c;html 优化压缩工具 提高web 前端性能&#xff0c;访问速度优化专业工具 CSS&#xff0c;js&#xff0c;html 单文件&#xff0c;多文件 单个&#xff0c;批量压缩优化 web前端优化&#xff1a;减少空格&#xff0c;体积压缩&#xff0…

【C++初阶(十)】set、map、multiset、multimap的介绍及使用

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

【Rust】快速教程——自定义类型、数字转枚举、Cargo运行

前言 超过一定的年龄之后&#xff0c;所谓人生&#xff0c;无非是一个不断丧失的过程而已。宝贵的东西&#xff0c;会像梳子豁了齿一样从手中滑落下去。你所爱的人会一个接着一个&#xff0c;从身旁悄然消逝。——《1Q84》 \;\\\;\\\; 目录 前言自定义类型数字转枚举Cargo.tom…

2022年高校大数据挑战赛A题工业机械设备故障预测求解全过程论文及程序

2022年高校大数据挑战赛 A题 工业机械设备故障预测 原题再现&#xff1a; 制造业是国民经济的主体&#xff0c;近十年来&#xff0c;嫦娥探月、祝融探火、北斗组网&#xff0c;一大批重大标志性创新成果引领中国制造业不断攀上新高度。作为制造业的核心&#xff0c;机械设备在…

[计算机网络] 高手常用的几个抓包工具(上)

文章目录 高手常用的抓包工具一览什么是抓包工具优秀抓包工具WiresharkFiddlerTcpdumpCharles 高手常用的抓包工具一览 什么是抓包工具 抓包工具是一种可以捕获、分析和修改网络流量的软件。它可以帮助您进行网络调试、性能测试、安全审计等任务。 抓包工具可以实时地显示网…

XML处理相关——(待完善)

记录 || Python | 提取xml/tmx文件中的文本内容 python xml处理 xml内容提取

Hdoop学习笔记(HDP)-Part.02 核心组件原理

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

[论文阅读]Generalized Attention——空间注意力机制

Generalized Attention An Empirical Study of Spatial Attention Mechanisms in Deep Networks 论文网址&#xff1a;Generalized Attention 论文代码&#xff1a;文章最后有GeneralizedAttention的实现代码 简读论文 本文主要研究了深度学习网络中的注意力机制。作者们从不…

iOS Class Guard 成功了,但无法区分差异

​ 我正在开发一个静态库&#xff0c;并使用 Polidea 的 iOS Class Guard 来混淆我的静态库。我按照步骤在项目的根路径中下载 obfuscate_project&#xff0c;更改其中所需的名称&#xff0c;最后在终端中运行 bash obfuscate_project。我收到一条消息&#xff0c;说我的构建成…

【linux】/etc/security/limits.conf配置文件详解、为什么限制、常见限制查看操作

文章目录 一. limits.conf常见配置项详解二. 文件描述符&#xff08;file descriptor&#xff09;简述三. 为什么限制四. 相关操作1. 展示当前资源限制2. 查看系统当前打开的文件描述符数量3. 查看某个进程打开的文件描述符数量4. 各进程占用的文件描述符 /etc/security/limits…

树和二叉树的基本概念和堆的实现

树的概念及结构 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 1.有一个特殊的结点&#…

第一类瑞利索末菲标量衍射模型的方孔衍射的空间像计算(附python计算代码)

记第一类瑞利索末菲标量衍射模型的方孔衍射的空间像计算(附python计算代码) RS type 1 衍射空间像计算傅里叶变换采样条件实际计算计算要求傅立叶变换法计算直接卷积方法计算代码傅立叶变换方法直接卷积https://zhuanlan.zhihu.com/p/624292239 Goodman, J. W. (2004). Intro…

logistic回归详解

为什么不直接统计标签数和预测结果数&#xff0c;计算精度&#xff1f; 因为 存在梯度为0的情况梯度不连续 为什么叫logistic回归 logistic是因为加了一个sigmoid函数&#xff0c;将输出预测值映射到【0&#xff0c;1】 有时候使用MSE损失函数&#xff0c;拟合 有时候使用c…

PyLMKit(5):基于网页知识库的检索增强生成RAG

基于网页知识库的检索增强生成RAG 0.项目信息 日期&#xff1a; 2023-12-2作者&#xff1a;小知课题: RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;是一种利用知识库检索的方法&#xff0c;提供与用户查询相关的内容&#xff0c;从而…

基于SpringBoot实现SSMP整合

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

【Gstreamer】自定义Plugin及调用Plugin

Gstreamer自定义Plugin及调用自定义Plugin Gstreamer支持开发者自己创建Plugin&#xff0c;创建后的Plugin可以通过工具gst-inspect-1.0查看&#xff0c;并在代码中调用自定义的plugin。 Gstreamer 官网中给出了Plugin创建教程&#xff0c;但实际上如果按照教程一步步走&…

kali学习

目录 黑客法则&#xff1a; 一&#xff1a;页面使用基础 二&#xff1a;msf和Windows永恒之蓝漏洞 kali最强渗透工具——metasploit 介绍 使用永恒之蓝进行攻击 ​编辑 使用kali渗透工具生成远程控制木马 渗透测试——信息收集 域名信息收集 黑客法则&#xff1a; 一&…

你好!二分查找【JAVA】

1.初次相识 二分查找又称折半查找&#xff0c;是一种在有序数组中查找特定元素的算法。二分查找的基本思想是&#xff1a;通过不断地二分数组的中间元素&#xff0c;缩小查找区间&#xff0c;直到找到目标元素或者确定目标元素不存在为止。 二分查找的时间复杂度为O(logn)&…