Compare commits
7 Commits
5200c73bc5
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a0b4b1a53e | |||
| b0b4bdf9b7 | |||
| 9ed1329b1a | |||
| 9b21329518 | |||
| bde552dcb3 | |||
| 2a8a3b6017 | |||
| c89c937bc7 |
@@ -4,6 +4,7 @@ let socketUrl = "";
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// 开发环境
|
||||
// baseUrl = "http://192.168.110.100:9200/pb/"; // 张川川
|
||||
// baseUrl = "http://192.168.110.131:9200/pb/"; // 王亚男
|
||||
baseUrl = "https://api.nuttyreading.com/"; // 线上正式
|
||||
} else if (process.env.NODE_ENV === 'production') {
|
||||
// baseUrl = "http://192.168.110.100:9200/pb/"; // 张川川
|
||||
|
||||
@@ -262,7 +262,8 @@ $http.dataFactory = async function (res) {
|
||||
// 返回错误的结果(catch接受数据)
|
||||
return Promise.reject({
|
||||
statusCode: 0,
|
||||
errMsg: "【request】" + (httpData.info || httpData.msg),
|
||||
// errMsg: "【request】" + (httpData.info || httpData.msg),
|
||||
errMsg: (httpData.info || httpData.msg),
|
||||
data: res.data
|
||||
});
|
||||
}
|
||||
|
||||
3
main.js
3
main.js
@@ -64,6 +64,9 @@ Vue.component('common-video', commonVideo);
|
||||
import CommonCourseVideo from 'edu-core/components/course-video'
|
||||
Vue.component('CommonCourseVideo', CommonCourseVideo);
|
||||
|
||||
import CommonRefundDestination from 'edu-core/components/order/refund-destination.vue'
|
||||
Vue.component('common-refund-destination', CommonRefundDestination);
|
||||
|
||||
import commonCurriculumVideo from '@/pages/component/commonComponents/curriculumVideo.vue'
|
||||
Vue.component('common-curriculum-video', commonCurriculumVideo);
|
||||
import commonRichDetail from '@/pages/component/commonComponents/richDetail.vue'
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"name" : "太湖云医",
|
||||
"appid" : "__UNI__1B1584A",
|
||||
"description" : "太湖云医",
|
||||
"versionName" : "1.0.09",
|
||||
"versionCode" : 1009,
|
||||
"versionName" : "1.0.16",
|
||||
"versionCode" : 1016,
|
||||
"transformPx" : false,
|
||||
"sassImplementationName" : "node-sass",
|
||||
/* 5+App特有相关 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"edu-core": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.8",
|
||||
"edu-core": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.14",
|
||||
"jquery": "^3.7.1",
|
||||
"lodash": "^4.17.21",
|
||||
"qs": "^6.14.0",
|
||||
|
||||
24
pages.json
24
pages.json
@@ -373,6 +373,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/refundDestination",
|
||||
"style": {
|
||||
"navigationBarTitleText": "钱款去向",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"bounce": "none",
|
||||
"titleNView": false,
|
||||
"popGesture": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/goods/order",
|
||||
"style": {
|
||||
@@ -457,6 +469,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/wumen/medurl",
|
||||
"style": {
|
||||
"navigationBarTitleText": "详细介绍",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"bounce": "none",
|
||||
"titleNView": false,
|
||||
"popGesture": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/wumen/recordDetail",
|
||||
"style": {
|
||||
|
||||
@@ -365,4 +365,8 @@ export default {
|
||||
/deep/.titleItem .related_courses_name{
|
||||
width: calc(100%) !important;
|
||||
}
|
||||
|
||||
.title_list {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
<CommonCourseVideo
|
||||
:video-list="videoArray"
|
||||
:current-index="currentVideoIndex !== null ? currentVideoIndex : 0"
|
||||
:course="{courseTitle:options.navTitle, chapterTitle: curriculumData.title}"
|
||||
:course="{courseTitle:options.navTitle, chapterTitle: curriculumData.title, catalogueId: curriculumData.catalogueId || '', courseId: curriculumData.courseId || ''}"
|
||||
:cover="options.curriculumImgUrl"
|
||||
:http="$http"
|
||||
:user-info="userInfo"
|
||||
/>
|
||||
|
||||
<view
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
});
|
||||
|
||||
const joinedText = this.textList.join('/');
|
||||
this.goBuyTitle = '购买'+joinedText+'VIP,即可畅享更多专属权益';
|
||||
this.goBuyTitle = '购买'+joinedText+'VIP,即可畅享更多专属权益(不包含论坛)';
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -34,12 +34,17 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="userInfoBox">
|
||||
<view class="name">{{
|
||||
userMes.nickname ? userMes.nickname : "未设置"
|
||||
}}</view>
|
||||
<view class="name">
|
||||
{{ userMes.nickname ? userMes.nickname : "未设置" }}
|
||||
<text v-if="userMes.profile" class="user-profile">({{userMes.profile}})</text>
|
||||
</view>
|
||||
<view class="phone" v-if="userMes.tel"
|
||||
>手机号:({{ userMes.tel }})</view
|
||||
>
|
||||
<view>
|
||||
<u-tag v-if="userMes.todayWatch" :text="userMes.todayWatch" size="mini" plain plainFill type="success" class="watch-time"></u-tag>
|
||||
<u-tag v-if="userMes.totalWatch" :text="userMes.totalWatch" size="mini" plain plainFill class="watch-time"></u-tag>
|
||||
</view>
|
||||
</view>
|
||||
<br clear="both" />
|
||||
</view>
|
||||
@@ -256,6 +261,9 @@ export default {
|
||||
if (this.userInfo.id != undefined) {
|
||||
this.$http.post("common/user/getUserInfo").then((res) => {
|
||||
this.userMes = res.result;
|
||||
this.userMes.profile = res.des || '';
|
||||
this.userMes.todayWatch = res.todayWatch || '';
|
||||
this.userMes.totalWatch = res.totalWatch || '';
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -429,6 +437,12 @@ export default {
|
||||
line-height: 40rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.user-profile{
|
||||
font-size: 28rpx;
|
||||
font-weight: normal;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.phone {
|
||||
font-size: 26rpx;
|
||||
@@ -442,6 +456,11 @@ export default {
|
||||
margin-left: 10rpx;
|
||||
vertical-align: super;
|
||||
}
|
||||
.watch-time {
|
||||
margin-top: 10rpx;
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,11 +11,13 @@
|
||||
</view>
|
||||
<view class="item_top">
|
||||
<text class="orderstatus" v-show="item.orderStatus == 0">未付款</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 1">待发货</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 2">已发货</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 1">待发出</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 2">已发出</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 3">交易成功</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 4">交易失败</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 5">已过期</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 6">已退款</text>
|
||||
<text class="orderstatus" v-show="item.orderStatus == 7">退款中</text>
|
||||
</view>
|
||||
<view class="order_infor" v-if="item.orderType=='aiVip'||item.orderType=='upgradeAiVip'">
|
||||
<view class="left">
|
||||
@@ -117,12 +119,24 @@
|
||||
<text v-if="item.jfDeduction > 0">{{ item.jfDeduction }} 积分</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="order_time">下单时间:{{item.createTime}}</text>
|
||||
<view v-if="item.orderStatus == 0 && $platform == 'android'" class="order_statusbtn">
|
||||
<text @click.stop="goPay(item)">继续付款</text>
|
||||
</view>
|
||||
<view v-if="item.orderStatus == 3" class="order_statusbtn">
|
||||
<text>申请售后</text>
|
||||
<text class="order_time">下单时间:{{ item.createTime }}</text>
|
||||
<view
|
||||
class="order_actions_row"
|
||||
v-if="orderItemHasActions(item)"
|
||||
@click.stop="noop"
|
||||
>
|
||||
<view v-if="item.orderStatus == 0 && $platform == 'android'" class="order_statusbtn">
|
||||
<text @click.stop="goPay(item)">继续付款</text>
|
||||
</view>
|
||||
<view v-if="item.orderStatus == 3" class="order_statusbtn">
|
||||
<text>申请售后</text>
|
||||
</view>
|
||||
<view v-if="item.orderStatus == 6 || item.orderStatus == 7" class="order_statusbtn">
|
||||
<text @click.stop="goRefundDestination(item)">钱款去向</text>
|
||||
</view>
|
||||
<view v-if="item.refundableStatus === true" class="order_statusbtn">
|
||||
<text @click.stop="confirmApplyRefund(item)">申请退款</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -157,6 +171,15 @@ export default {
|
||||
...mapState(["userInfo"]),
|
||||
},
|
||||
methods: {
|
||||
noop() {},
|
||||
orderItemHasActions(item) {
|
||||
if (!item) return false;
|
||||
if (item.orderStatus == 0 && this.$platform == "android") return true;
|
||||
if (item.orderStatus == 3) return true;
|
||||
if (item.orderStatus == 6 || item.orderStatus == 7) return true;
|
||||
if (item.refundableStatus === true) return true;
|
||||
return false;
|
||||
},
|
||||
//获取数据
|
||||
getData() {
|
||||
uni.showLoading({
|
||||
@@ -277,6 +300,45 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
goRefundDestination(row) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/refundDestination?orderId=${row.orderId}`,
|
||||
});
|
||||
},
|
||||
confirmApplyRefund(row) {
|
||||
uni.showModal({
|
||||
title: "申请退款",
|
||||
content: "请确认是否提交退款申请?",
|
||||
confirmText: "确认提交",
|
||||
cancelText: "取消",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.submitOrderRefund(row);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
submitOrderRefund(orderRow) {
|
||||
this.$http.request({
|
||||
url: "book/buyOrder/refundOrder",
|
||||
method: "POST",
|
||||
data: {
|
||||
orderId: orderRow.orderId,
|
||||
},
|
||||
header: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}).then((res)=> {
|
||||
if (res.code === 0) {
|
||||
this.$commonJS.showToast("申请退款成功");
|
||||
this.getData();
|
||||
return;
|
||||
}
|
||||
this.$commonJS.showToast(res.errMsg || "申请退款失败");
|
||||
}).catch(()=> {
|
||||
this.$commonJS.showToast("申请退款失败");
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -301,7 +363,7 @@ export default {
|
||||
.order_item{
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 20rpx 30rpx;
|
||||
padding: 20rpx 30rpx 88rpx;
|
||||
box-shadow: 0px 0px 10px 0px #a7bbe4;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
@@ -319,7 +381,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.item_top{
|
||||
.item_top {
|
||||
position: absolute;
|
||||
top: 70rpx;
|
||||
right: 30rpx;
|
||||
@@ -327,7 +389,7 @@ export default {
|
||||
font-weight: normal;
|
||||
color: red;
|
||||
}
|
||||
.order_infor{
|
||||
.order_infor {
|
||||
margin-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -355,7 +417,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.order_time{
|
||||
.order_time {
|
||||
display: block;
|
||||
margin-top: 20rpx;
|
||||
font-size: 26rpx;
|
||||
@@ -377,10 +439,19 @@ export default {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.order_statusbtn{
|
||||
.order_actions_row {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.order_statusbtn{
|
||||
flex-shrink: 0;
|
||||
padding: 0 15rpx;
|
||||
line-height: 45rpx;
|
||||
font-size: 24rpx;
|
||||
|
||||
@@ -10,16 +10,22 @@
|
||||
v-if="orderContet.orderStatus == 0">待支付</text>
|
||||
<text
|
||||
class="orderState orderState1"
|
||||
v-if="orderContet.orderStatus == 1">待发货</text>
|
||||
v-if="orderContet.orderStatus == 1">待发出</text>
|
||||
<text
|
||||
class="orderState orderState2"
|
||||
v-if="orderContet.orderStatus == 2">待收货</text>
|
||||
v-if="orderContet.orderStatus == 2">待收到</text>
|
||||
<text
|
||||
class="orderState orderState3"
|
||||
v-if="orderContet.orderStatus == 3">已完成</text>
|
||||
<text
|
||||
class="orderState orderState5"
|
||||
v-if="orderContet.orderStatus == 5">已超时</text>
|
||||
<text
|
||||
class="orderState orderState6"
|
||||
v-if="orderContet.orderStatus == 6">已退款</text>
|
||||
<text
|
||||
class="orderState orderState7"
|
||||
v-if="orderContet.orderStatus == 7">退款中</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
@@ -365,14 +371,15 @@ export default {
|
||||
text: "继续付款",
|
||||
});
|
||||
}
|
||||
if (this.orderContet.orderStatus == 0) {
|
||||
this.customButton.push({
|
||||
width: "160rpx",
|
||||
text: "取消订单",
|
||||
color: "#333",
|
||||
backgroundColor: "#f0f0f0",
|
||||
});
|
||||
}
|
||||
// taimed:注释取消订单按钮
|
||||
// if (this.orderContet.orderStatus == 0) {
|
||||
// this.customButton.push({
|
||||
// width: "160rpx",
|
||||
// text: "取消订单",
|
||||
// color: "#333",
|
||||
// backgroundColor: "#f0f0f0",
|
||||
// });
|
||||
// }
|
||||
if (this.orderContet.orderStatus == 0) {
|
||||
this.titleStat = "待支付";
|
||||
} else if (this.orderContet.orderStatus == 1) {
|
||||
@@ -381,6 +388,10 @@ export default {
|
||||
this.titleStat = "待收货";
|
||||
} else if (this.orderContet.orderStatus == 3) {
|
||||
this.titleStat = "已完成";
|
||||
} else if (this.orderContet.orderStatus == 6) {
|
||||
this.titleStat = "已退款";
|
||||
} else if (this.orderContet.orderStatus == 7) {
|
||||
this.titleStat = "退款中";
|
||||
}
|
||||
if (
|
||||
this.orderContet.orderStatus >= 2 &&
|
||||
@@ -551,6 +562,12 @@ view,uni-view {
|
||||
.orderState5 {
|
||||
background-color: #787878;
|
||||
}
|
||||
.orderState6 {
|
||||
background-color: #f56c6c;
|
||||
}
|
||||
.orderState7 {
|
||||
background-color: #f56c6c;
|
||||
}
|
||||
.guoqi {
|
||||
font-size: 28rpx;
|
||||
align-items: center;
|
||||
|
||||
26
pages/order/refundDestination.vue
Normal file
26
pages/order/refundDestination.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<view class="page-wrap">
|
||||
<common-refund-destination :order-id="orderId" :http="$http" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
orderId: "",
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options && options.orderId != null) {
|
||||
this.orderId = options.orderId;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrap {
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
@@ -36,8 +36,7 @@
|
||||
<view class="label_content AC_List">
|
||||
<view style=" display: flex; align-items: center; justify-content: space-between;">
|
||||
<view class="left">
|
||||
<view class="title" v-if="slotProps.row.orderType=='购买商品'&&slotProps.row.productName">{{ slotProps.row.orderType }} <br/> {{ slotProps.row.productName }}</view>
|
||||
<view class="title" v-else>{{ slotProps.row.orderType }}</view>
|
||||
<view class="title">{{ slotProps.row.productName || slotProps.row.orderType}}</view>
|
||||
</view>
|
||||
<view class="right Hot">
|
||||
<text v-if="slotProps.row.changeAmount > 0">+</text>
|
||||
@@ -215,6 +214,12 @@ export default {
|
||||
|
||||
.AC_List {
|
||||
overflow: hidden;
|
||||
.title,
|
||||
.AC_note,
|
||||
.AC_mark {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
.left {
|
||||
width: calc(100% - 140rpx) !important;
|
||||
font-weight: 700;
|
||||
@@ -234,6 +239,19 @@ export default {
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
> view:first-child {
|
||||
.left {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
width: auto !important;
|
||||
float: none;
|
||||
}
|
||||
.right {
|
||||
flex-shrink: 0;
|
||||
float: none;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.AC_title {
|
||||
font-size: 32rpx;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,11 +24,14 @@
|
||||
<view class="item" v-html="prescriptDetail.city_name">
|
||||
</view>
|
||||
</uni-section>
|
||||
<uni-section class="mb-10" titleFontSize="18px" title="详细介绍" type="line"
|
||||
<uni-section class="mb-10" titleFontSize="18px" title="说明" type="line"
|
||||
v-if="prescriptDetail.content && prescriptDetail.content != ''">
|
||||
<view class="item" v-html="prescriptDetail.content">
|
||||
</view>
|
||||
</uni-section>
|
||||
<div class="detail-link-wrap" v-if="prescriptDetail.url && prescriptDetail.url != ''">
|
||||
<text class="detail-link" @click="openDetailUrl">详细介绍>></text>
|
||||
</div>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
@@ -73,6 +76,11 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
openDetailUrl() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/wumen/medurl?url=' + encodeURIComponent(this.prescriptDetail.url)
|
||||
})
|
||||
},
|
||||
// 方剂详情
|
||||
getDetail() {
|
||||
$http.request({
|
||||
@@ -146,6 +154,18 @@ export default {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.detail-link-wrap {
|
||||
padding: 10rpx 20rpx;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
.detail-link {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #007aff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-section-header__decoration.line {
|
||||
background-color: #18bc37;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,25 @@
|
||||
};
|
||||
},
|
||||
onLoad(e) {
|
||||
this.id = uni.getStorageSync('prescriptUrl')
|
||||
this.id = e.url ? decodeURIComponent(e.url) : uni.getStorageSync('prescriptUrl')
|
||||
// #ifdef APP-PLUS
|
||||
const pages = getCurrentPages()
|
||||
const page = pages[pages.length - 1];
|
||||
const currentWebview = page.$getAppWebview()
|
||||
currentWebview.setStyle({
|
||||
titleNView: {
|
||||
buttons: [{
|
||||
float: 'right',
|
||||
type: 'close',
|
||||
onclick: function() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}
|
||||
}]
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
computed: {
|
||||
|
||||
|
||||
@@ -159,8 +159,9 @@
|
||||
if (this.curOneCateIndex == 0) {
|
||||
console.log('点我了');
|
||||
uni.showModal({
|
||||
content:'详细内容请跳转至"疯子读书app"内查看',
|
||||
content:'详细内容请前往"疯子读书app"内查看',
|
||||
cancelText:'知道了',
|
||||
// confirmText: '知道了'
|
||||
confirmText:'打开疯子读书',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
|
||||
@@ -350,4 +350,8 @@ button::after {
|
||||
// border-bottom: 0.5px solid #dadbde;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uni-text {
|
||||
white-space: normal;
|
||||
}
|
||||
BIN
static/icon/map_ic_search.png
Normal file
BIN
static/icon/map_ic_search.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
3
style/mixin.scss
Normal file
3
style/mixin.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
@charset "utf-8";
|
||||
//主题色
|
||||
$themeColor: #5188e5;
|
||||
2
uni_modules/uni-section/changelog.md
Normal file
2
uni_modules/uni-section/changelog.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## 0.0.1(2022-07-22)
|
||||
- 初始化
|
||||
167
uni_modules/uni-section/components/uni-section/uni-section.vue
Normal file
167
uni_modules/uni-section/components/uni-section/uni-section.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<view class="uni-section">
|
||||
<view class="uni-section-header" @click="onClick">
|
||||
<view class="uni-section-header__decoration" v-if="type" :class="type" />
|
||||
<slot v-else name="decoration"></slot>
|
||||
|
||||
<view class="uni-section-header__content">
|
||||
<text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text>
|
||||
<text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text>
|
||||
</view>
|
||||
|
||||
<view class="uni-section-header__slot-right">
|
||||
<slot name="right"></slot>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="uni-section-content" :style="{padding: _padding}">
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
/**
|
||||
* Section 标题栏
|
||||
* @description 标题栏
|
||||
* @property {String} type = [line|circle|square] 标题装饰类型
|
||||
* @value line 竖线
|
||||
* @value circle 圆形
|
||||
* @value square 正方形
|
||||
* @property {String} title 主标题
|
||||
* @property {String} titleFontSize 主标题字体大小
|
||||
* @property {String} titleColor 主标题字体颜色
|
||||
* @property {String} subTitle 副标题
|
||||
* @property {String} subTitleFontSize 副标题字体大小
|
||||
* @property {String} subTitleColor 副标题字体颜色
|
||||
* @property {String} padding 默认插槽 padding
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'UniSection',
|
||||
emits:['click'],
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: ''
|
||||
},
|
||||
titleFontSize: {
|
||||
type: String,
|
||||
default: '14px'
|
||||
},
|
||||
titleColor:{
|
||||
type: String,
|
||||
default: '#333'
|
||||
},
|
||||
subTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subTitleFontSize: {
|
||||
type: String,
|
||||
default: '12px'
|
||||
},
|
||||
subTitleColor: {
|
||||
type: String,
|
||||
default: '#999'
|
||||
},
|
||||
padding: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
_padding(){
|
||||
if(typeof this.padding === 'string'){
|
||||
return this.padding
|
||||
}
|
||||
|
||||
return this.padding?'10px':''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
title(newVal) {
|
||||
if (uni.report && newVal !== '') {
|
||||
uni.report('title', newVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" >
|
||||
$uni-primary: #2979ff !default;
|
||||
|
||||
.uni-section {
|
||||
background-color: #fff;
|
||||
.uni-section-header {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 12px 10px;
|
||||
font-weight: normal;
|
||||
|
||||
&__decoration{
|
||||
margin-right: 6px;
|
||||
background-color: $uni-primary;
|
||||
&.line {
|
||||
width: 4px;
|
||||
height: 12px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&.circle {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-top-right-radius: 50px;
|
||||
border-top-left-radius: 50px;
|
||||
border-bottom-left-radius: 50px;
|
||||
border-bottom-right-radius: 50px;
|
||||
}
|
||||
|
||||
&.square {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
color: #333;
|
||||
|
||||
.distraction {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
&-sub {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&__slot-right{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.uni-section-content{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
87
uni_modules/uni-section/package.json
Normal file
87
uni_modules/uni-section/package.json
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "uni-section",
|
||||
"displayName": "uni-section 标题栏",
|
||||
"version": "0.0.1",
|
||||
"description": "标题栏组件",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"标题栏"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"uni-scss"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
uni_modules/uni-section/readme.md
Normal file
8
uni_modules/uni-section/readme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## Section 标题栏
|
||||
> **组件名:uni-section**
|
||||
> 代码块: `uSection`
|
||||
|
||||
uni-section 组件主要用于文章、列表详情等标题展示
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-section)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
14
uni_modules/uni-usercapturescreen/changelog.md
Normal file
14
uni_modules/uni-usercapturescreen/changelog.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 1.0.6(2024-11-22)
|
||||
- 修复 HarmonyOS Next 上调用 setUserCaptureScreen 报错的 Bug
|
||||
## 1.0.5(2024-10-14)
|
||||
- 新增 支持 HarmonyOS Next 调用
|
||||
## 1.0.4(2023-03-24)
|
||||
新增开启/关闭防截屏功能
|
||||
## 1.0.3(2023-03-17)
|
||||
修复android平台 部分场景下js可能报错的问题
|
||||
## 1.0.2(2023-03-16)
|
||||
修复Android平台在小米设备无法监听的问题 修复Android平台调用uni.onUserCaptureScreen必然会触发回调的问题
|
||||
## 1.0.1(2022-10-27)
|
||||
修改插件描述
|
||||
## 1.0.0(2022-10-26)
|
||||
支持安卓、iOS、微信小程序平台
|
||||
157
uni_modules/uni-usercapturescreen/index.d.ts
vendored
Normal file
157
uni_modules/uni-usercapturescreen/index.d.ts
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
declare namespace UniNamespace {
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调参数
|
||||
*/
|
||||
type OnUserCaptureScreenCallbackResult = {
|
||||
/**
|
||||
* 截屏文件路径(仅Android返回)
|
||||
*/
|
||||
path ?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调函数定义
|
||||
*/
|
||||
type UserCaptureScreenCallback = (res : OnUserCaptureScreenCallbackResult) => void
|
||||
|
||||
type OnUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
type OffUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调参数
|
||||
*/
|
||||
type SetUserCaptureScreenSuccess = {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调函数定义
|
||||
*/
|
||||
type SetUserCaptureScreenSuccessCallback = (res : SetUserCaptureScreenSuccess) => void
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
* - 12001 "setUserCaptureScreen:system not support"
|
||||
* - 12010 "setUserCaptureScreen:system internal error"
|
||||
*/
|
||||
type SetUserCaptureScreenErrorCode = 12001 | 12010;
|
||||
|
||||
/**
|
||||
* SetUserCaptureScreen 的错误回调参数
|
||||
*/
|
||||
interface SetUserCaptureScreenFail {
|
||||
errCode : SetUserCaptureScreenErrorCode
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen失败回调函数定义
|
||||
*/
|
||||
type SetUserCaptureScreenFailCallback = (res : SetUserCaptureScreenFail) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen完成回调函数定义
|
||||
*/
|
||||
type SetUserCaptureScreenCompleteCallback = (res : any) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen参数
|
||||
*/
|
||||
type SetUserCaptureScreenOptions = {
|
||||
/**
|
||||
* true: 允许用户截屏 false: 不允许用户截屏,防止用户截屏到应用页面内容
|
||||
*/
|
||||
enable : boolean;
|
||||
/**
|
||||
* 接口调用成功的回调函数
|
||||
*/
|
||||
// success : SetUserCaptureScreenSuccessCallback | null,
|
||||
success ?: SetUserCaptureScreenSuccessCallback,
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
// fail : SetUserCaptureScreenFailCallback | null,
|
||||
fail ?: SetUserCaptureScreenFailCallback,
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
// complete : SetUserCaptureScreenSuccessCallback | SetUserCaptureScreenFailCallback | null
|
||||
complete ?: SetUserCaptureScreenCompleteCallback
|
||||
}
|
||||
|
||||
type SetUserCaptureScreen = (options : SetUserCaptureScreenOptions) => void
|
||||
}
|
||||
|
||||
declare interface Uni {
|
||||
/**
|
||||
* 开启截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "9.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
onUserCaptureScreen(callback : UniNamespace.UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "9.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
offUserCaptureScreen(callback : UniNamespace.UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 设置防截屏
|
||||
*
|
||||
* @param {SetUserCaptureScreenOptions} options
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "13.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
*/
|
||||
setUserCaptureScreen(options : UniNamespace.SetUserCaptureScreenOptions) : void
|
||||
}
|
||||
97
uni_modules/uni-usercapturescreen/package.json
Normal file
97
uni_modules/uni-usercapturescreen/package.json
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"id": "uni-usercapturescreen",
|
||||
"displayName": "uni-usercapturescreen",
|
||||
"version": "1.0.6",
|
||||
"description": "用户主动截屏事件监听",
|
||||
"keywords": [
|
||||
"截屏"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.7.7"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"uni-ext-api":{
|
||||
"uni": {
|
||||
"onUserCaptureScreen": {
|
||||
"web": false
|
||||
},
|
||||
"offUserCaptureScreen": {
|
||||
"web": false
|
||||
},
|
||||
"setUserCaptureScreen": {
|
||||
"web": false,
|
||||
"mp-weixin": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-android": "y",
|
||||
"app-ios": "y",
|
||||
"app-harmony": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "n",
|
||||
"Android Browser": "n",
|
||||
"微信浏览器(Android)": "n",
|
||||
"QQ浏览器(Android)": "n"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "n",
|
||||
"IE": "n",
|
||||
"Edge": "n",
|
||||
"Firefox": "n",
|
||||
"Safari": "n"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "n",
|
||||
"百度": "n",
|
||||
"字节跳动": "n",
|
||||
"QQ": "n",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
uni_modules/uni-usercapturescreen/readme.md
Normal file
21
uni_modules/uni-usercapturescreen/readme.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# uni-usercapturescreen
|
||||
|
||||
用户主动截屏事件监听
|
||||
|
||||
### uni.onUserCaptureScreen
|
||||
|
||||
监听用户主动截屏事件,用户使用系统截屏按键截屏时触发此事件。
|
||||
|
||||
> 使用文档:[https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen)
|
||||
|
||||
### uni.offUserCaptureScreen
|
||||
|
||||
用户主动截屏事件。取消事件监听。
|
||||
|
||||
> 使用文档:[https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen)
|
||||
|
||||
### uni.setUserCaptureScreen
|
||||
|
||||
开启/关闭防截屏。
|
||||
|
||||
> 使用文档:[https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen)
|
||||
139
uni_modules/uni-usercapturescreen/utssdk/app-android/index.uts
Normal file
139
uni_modules/uni-usercapturescreen/utssdk/app-android/index.uts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { UTSAndroid } from "io.dcloud.uts";
|
||||
import ActivityCompat from "androidx.core.app.ActivityCompat";
|
||||
import Manifest from "android.Manifest";
|
||||
import PackageManager from "android.content.pm.PackageManager";
|
||||
import Build from "android.os.Build";
|
||||
import FileObserver from "android.os.FileObserver";
|
||||
import File from "java.io.File";
|
||||
import Environment from "android.os.Environment";
|
||||
import System from 'java.lang.System';
|
||||
import WindowManager from 'android.view.WindowManager';
|
||||
import { OnUserCaptureScreenCallbackResult, UserCaptureScreenCallback, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreenSuccess, SetUserCaptureScreenOptions, SetUserCaptureScreen } from "../interface.uts";
|
||||
import string from 'android.R.string';
|
||||
|
||||
|
||||
/**
|
||||
* 文件监听器
|
||||
*/
|
||||
let observer : ScreenFileObserver | null = null;
|
||||
/**
|
||||
* 记录文件监听器上次监听的时间戳,避免重复监听
|
||||
*/
|
||||
let lastObserverTime : number = 0;
|
||||
/**
|
||||
* 截屏回调
|
||||
*/
|
||||
let listener : UserCaptureScreenCallback | null = null;
|
||||
|
||||
/**
|
||||
* android 文件监听实现
|
||||
*/
|
||||
class ScreenFileObserver extends FileObserver {
|
||||
|
||||
/**
|
||||
* 截屏文件目录
|
||||
*/
|
||||
private screenFile : File;
|
||||
|
||||
constructor(screenFileStr : string) {
|
||||
super(screenFileStr);
|
||||
this.screenFile = new File(screenFileStr);
|
||||
}
|
||||
|
||||
override onEvent(event : Int, path : string | null) : void {
|
||||
// 只监听文件新增事件
|
||||
if (event == FileObserver.CREATE) {
|
||||
if (path != null) {
|
||||
const currentTime = System.currentTimeMillis();
|
||||
if ((currentTime - lastObserverTime) < 1000) {
|
||||
// 本地截屏行为比上一次超过1000ms, 才认为是一个有效的时间
|
||||
return;
|
||||
}
|
||||
lastObserverTime = currentTime;
|
||||
|
||||
const screenShotPath = new File(this.screenFile, path).getPath();
|
||||
const res : OnUserCaptureScreenCallbackResult = {
|
||||
path: screenShotPath
|
||||
}
|
||||
listener?.(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启截图监听
|
||||
*/
|
||||
export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
|
||||
// 检查相关权限是否已授予
|
||||
if (ActivityCompat.checkSelfPermission(UTSAndroid.getAppContext()!, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
// 无权限,申请权限
|
||||
ActivityCompat.requestPermissions(UTSAndroid.getUniActivity()!, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1001);
|
||||
return;
|
||||
}
|
||||
// 更新监听
|
||||
listener = callback;
|
||||
|
||||
let directory_screenshot : File;
|
||||
if (Build.MANUFACTURER.toLowerCase() == "xiaomi") {
|
||||
// @Suppress("DEPRECATION")
|
||||
directory_screenshot = new File(new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM), "Screenshots");
|
||||
} else {
|
||||
// @Suppress("DEPRECATION")
|
||||
directory_screenshot = new File(new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES), "Screenshots");
|
||||
}
|
||||
// 先结束监听 再开启监听
|
||||
observer?.stopWatching();
|
||||
observer = new ScreenFileObserver(directory_screenshot.getPath());
|
||||
observer?.startWatching();
|
||||
|
||||
|
||||
UTSAndroid.onAppActivityDestroy(function(){
|
||||
observer?.stopWatching()
|
||||
observer = null
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*/
|
||||
export const offUserCaptureScreen : OffUserCaptureScreen = function (_ : UserCaptureScreenCallback | null) {
|
||||
// android10以上,关闭监听通过移除文件监听器实现
|
||||
observer?.stopWatching();
|
||||
observer = null;
|
||||
lastObserverTime = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否禁止截屏
|
||||
*/
|
||||
export const setUserCaptureScreen : SetUserCaptureScreen = function (option : SetUserCaptureScreenOptions) {
|
||||
// 切换到UI线程
|
||||
UTSAndroid.getUniActivity()?.runOnUiThread(new SetUserCaptureScreenRunnable(option.enable));
|
||||
const res : SetUserCaptureScreenSuccess = {}
|
||||
option.success?.(res);
|
||||
option.complete?.(res);
|
||||
}
|
||||
|
||||
class SetUserCaptureScreenRunnable extends Runnable {
|
||||
|
||||
/**
|
||||
* ture: 允许用户截屏
|
||||
* false: 不允许用户截屏,防止用户截屏到应用页面内容
|
||||
*/
|
||||
private enable : boolean;
|
||||
|
||||
constructor(enable : boolean) {
|
||||
super();
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
override run() : void {
|
||||
if (this.enable) {
|
||||
UTSAndroid.getUniActivity()?.getWindow()?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
} else {
|
||||
UTSAndroid.getUniActivity()?.getWindow()?.addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { display } from '@kit.ArkUI';
|
||||
import { window } from '@kit.ArkUI';
|
||||
import { Callback, BusinessError } from '@kit.BasicServicesKit';
|
||||
|
||||
import { getAbilityContext } from '@dcloudio/uni-runtime';
|
||||
|
||||
import {
|
||||
OnUserCaptureScreen, UserCaptureScreenCallback,
|
||||
OffUserCaptureScreen,
|
||||
SetUserCaptureScreen, SetUserCaptureScreenOptions, SetUserCaptureScreenSuccess
|
||||
} from '../interface.uts';
|
||||
|
||||
const onUserCaptureScreenCallbacks: Function[] = []
|
||||
|
||||
const harmonyCaptureStatusChange: Callback<boolean> = (captureStatus: boolean) => {
|
||||
if (captureStatus) {
|
||||
onUserCaptureScreenCallbacks.forEach(cb => {
|
||||
typeof cb === 'function' && cb()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
display.on('captureStatusChange', harmonyCaptureStatusChange)
|
||||
|
||||
export const onUserCaptureScreen: OnUserCaptureScreen = function (callback: UserCaptureScreenCallback | null) {
|
||||
if (callback) {
|
||||
onUserCaptureScreenCallbacks.push(callback)
|
||||
}
|
||||
}
|
||||
|
||||
export const offUserCaptureScreen: OffUserCaptureScreen = function (callback: UserCaptureScreenCallback | null) {
|
||||
if (callback) {
|
||||
const index = onUserCaptureScreenCallbacks.indexOf(callback)
|
||||
if (index > -1) {
|
||||
onUserCaptureScreenCallbacks.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const setUserCaptureScreen: SetUserCaptureScreen = function (options: SetUserCaptureScreenOptions) {
|
||||
const errSubject = 'uni-usercapturescreen'
|
||||
const setUserCaptureScreenSuccess: SetUserCaptureScreenSuccess = {}
|
||||
window.getLastWindow(getAbilityContext()!, (err, window) => {
|
||||
const errCode: number = err.code;
|
||||
if (errCode) {
|
||||
options.fail?.({
|
||||
errCode: (err as BusinessError).code,
|
||||
errSubject,
|
||||
errMsg: `setUserCaptureScreen:fail ${(err as BusinessError).message}`
|
||||
} as IUniError)
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
UTSHarmony.requestSystemPermission(['ohos.permission.PRIVACY_WINDOW'], (allRight: boolean, _grantedList: string[]) => {
|
||||
if (allRight) {
|
||||
window.setWindowPrivacyMode(!options.enable, (err: BusinessError) => {
|
||||
const errCode: number = err.code;
|
||||
if (errCode) {
|
||||
options.fail?.({
|
||||
errCode: err.code,
|
||||
errSubject,
|
||||
errMsg: `setUserCaptureScreen:fail ${err.message}`
|
||||
} as IUniError)
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
return;
|
||||
}
|
||||
options.success?.(setUserCaptureScreenSuccess);
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
});
|
||||
} else {
|
||||
throw new Error('permission denied')
|
||||
}
|
||||
}, (_doNotAskAgain: boolean, _grantedList: string[]) => {
|
||||
throw new Error('permission denied');
|
||||
})
|
||||
} catch (err) {
|
||||
options.fail?.({
|
||||
errCode: (err as BusinessError).code,
|
||||
errSubject,
|
||||
errMsg: `setUserCaptureScreen:fail ${(err as BusinessError).message}`
|
||||
} as IUniError)
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
141
uni_modules/uni-usercapturescreen/utssdk/app-ios/index.uts
Normal file
141
uni_modules/uni-usercapturescreen/utssdk/app-ios/index.uts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { NotificationCenter } from 'Foundation';
|
||||
import { CGRect } from "CoreFoundation";
|
||||
import { UIApplication, UIView, UITextField, UIScreen, UIDevice } from "UIKit"
|
||||
import { UTSiOS } from "DCloudUTSFoundation"
|
||||
import { DispatchQueue } from 'Dispatch';
|
||||
import { SetUserCaptureScreenOptions, OnUserCaptureScreenCallbackResult, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreen, UserCaptureScreenCallback, SetUserCaptureScreenSuccess } from "../interface.uts"
|
||||
import { SetUserCaptureScreenFailImpl } from "../unierror.uts"
|
||||
/**
|
||||
* 定义监听截屏事件工具类
|
||||
*/
|
||||
class CaptureScreenTool {
|
||||
static listener : UserCaptureScreenCallback | null;
|
||||
static secureView : UIView | null;
|
||||
|
||||
// 监听截屏
|
||||
static listenCaptureScreen(callback : UserCaptureScreenCallback | null) {
|
||||
this.listener = callback
|
||||
|
||||
// 注册监听截屏事件及回调方法
|
||||
// target-action 回调方法需要通过 Selector("方法名") 构建
|
||||
const method = Selector("userDidTakeScreenshot")
|
||||
NotificationCenter.default.addObserver(this, selector = method, name = UIApplication.userDidTakeScreenshotNotification, object = null)
|
||||
}
|
||||
|
||||
// 捕获截屏回调的方法
|
||||
// target-action 的方法前需要添加 @objc 前缀
|
||||
@objc static userDidTakeScreenshot() {
|
||||
// 回调
|
||||
const res: OnUserCaptureScreenCallbackResult = {
|
||||
}
|
||||
this.listener?.(res)
|
||||
}
|
||||
|
||||
// 移除监听事件
|
||||
static removeListen(callback : UserCaptureScreenCallback | null) {
|
||||
this.listener = null
|
||||
NotificationCenter.default.removeObserver(this)
|
||||
}
|
||||
|
||||
static createSecureView() : UIView | null {
|
||||
let field = new UITextField(frame = CGRect.zero)
|
||||
field.isSecureTextEntry = true
|
||||
if (field.subviews.length > 0 && UIDevice.current.systemVersion != '15.1') {
|
||||
let view = field.subviews[0]
|
||||
view.subviews.forEach((item) => {
|
||||
item.removeFromSuperview()
|
||||
})
|
||||
view.isUserInteractionEnabled = true
|
||||
return view
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 开启防截屏
|
||||
static onAntiScreenshot(option : SetUserCaptureScreenOptions) {
|
||||
// uts方法默认会在子线程中执行,涉及 UI 操作必须在主线程中运行,通过 DispatchQueue.main.async 方法可将代码在主线程中运行
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
let secureView = this.createSecureView()
|
||||
let window = UTSiOS.getKeyWindow()
|
||||
let rootView = window.rootViewController == null ? null : window.rootViewController!.view
|
||||
if (secureView != null && rootView != null) {
|
||||
let rootSuperview = rootView!.superview
|
||||
if (rootSuperview != null) {
|
||||
this.secureView = secureView
|
||||
rootSuperview!.addSubview(secureView!)
|
||||
rootView!.removeFromSuperview()
|
||||
secureView!.addSubview(rootView!)
|
||||
// secureView 充满父视图并随父视图宽高自适应(横竖屏、全屏切换时自动跟随)
|
||||
secureView!.frame = rootSuperview!.bounds
|
||||
secureView!.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
|
||||
// rootView 充满 secureView 并自适应,避免全屏时被固定在竖屏尺寸而缩到角落
|
||||
rootView!.frame = secureView!.bounds
|
||||
rootView!.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
|
||||
}
|
||||
}
|
||||
let res: SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
option.success?.(res)
|
||||
option.complete?.(res)
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭防截屏
|
||||
static offAntiScreenshot(option : SetUserCaptureScreenOptions) {
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
if (this.secureView != null) {
|
||||
let window = UTSiOS.getKeyWindow()
|
||||
let rootView = window.rootViewController == null ? null : window.rootViewController!.view
|
||||
if (rootView != null && this.secureView!.superview != null) {
|
||||
let rootSuperview = this.secureView!.superview
|
||||
if (rootSuperview != null) {
|
||||
rootSuperview!.addSubview(rootView!)
|
||||
this.secureView!.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
this.secureView = null
|
||||
}
|
||||
let res: SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
option.success?.(res)
|
||||
option.complete?.(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启截图监听
|
||||
*/
|
||||
export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
|
||||
CaptureScreenTool.listenCaptureScreen(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*/
|
||||
export const offUserCaptureScreen : OffUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
|
||||
CaptureScreenTool.removeListen(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启/关闭防截屏
|
||||
*/
|
||||
export const setUserCaptureScreen : SetUserCaptureScreen = function (options : SetUserCaptureScreenOptions) {
|
||||
if (UIDevice.current.systemVersion < "13.0") {
|
||||
let res = new SetUserCaptureScreenFailImpl(12001)
|
||||
options.fail?.(res);
|
||||
options.complete?.(res);
|
||||
|
||||
} else if (UIDevice.current.systemVersion == "15.1") {
|
||||
let res = new SetUserCaptureScreenFailImpl(12010)
|
||||
options.fail?.(res);
|
||||
options.complete?.(res);
|
||||
} else {
|
||||
if (options.enable == true) {
|
||||
CaptureScreenTool.offAntiScreenshot(options)
|
||||
} else {
|
||||
CaptureScreenTool.onAntiScreenshot(options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
170
uni_modules/uni-usercapturescreen/utssdk/interface.uts
Normal file
170
uni_modules/uni-usercapturescreen/utssdk/interface.uts
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调参数
|
||||
*/
|
||||
export type OnUserCaptureScreenCallbackResult = {
|
||||
/**
|
||||
* 截屏文件路径(仅Android返回)
|
||||
*/
|
||||
path ?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调函数定义
|
||||
*/
|
||||
export type UserCaptureScreenCallback = (res : OnUserCaptureScreenCallbackResult) => void
|
||||
|
||||
export type OnUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
export type OffUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调参数
|
||||
*/
|
||||
export type SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调函数定义
|
||||
*/
|
||||
export type SetUserCaptureScreenSuccessCallback = (res : SetUserCaptureScreenSuccess) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen失败回调函数定义
|
||||
*/
|
||||
export type SetUserCaptureScreenFailCallback = (res : IUniError) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen完成回调函数定义
|
||||
*/
|
||||
export type SetUserCaptureScreenCompleteCallback = (res : any) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen参数
|
||||
*/
|
||||
|
||||
export type SetUserCaptureScreenOptions = {
|
||||
/**
|
||||
* true: 允许用户截屏 false: 不允许用户截屏,防止用户截屏到应用页面内容
|
||||
*/
|
||||
enable : boolean;
|
||||
/**
|
||||
* 接口调用成功的回调函数
|
||||
*/
|
||||
// success : SetUserCaptureScreenSuccessCallback | null,
|
||||
success ?: SetUserCaptureScreenSuccessCallback,
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
// fail : SetUserCaptureScreenFailCallback | null,
|
||||
fail ?: SetUserCaptureScreenFailCallback,
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
// complete : SetUserCaptureScreenSuccessCallback | SetUserCaptureScreenFailCallback | null
|
||||
complete ?: SetUserCaptureScreenCompleteCallback
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
* - 12001 "setUserCaptureScreen:system not support"
|
||||
* - 12010 "setUserCaptureScreen:system internal error"
|
||||
*/
|
||||
export type SetUserCaptureScreenErrorCode = 12001 | 12010;
|
||||
/**
|
||||
* SetUserCaptureScreen 的错误回调参数
|
||||
*/
|
||||
export interface SetUserCaptureScreenFail extends IUniError {
|
||||
errCode : SetUserCaptureScreenErrorCode
|
||||
};
|
||||
|
||||
export type SetUserCaptureScreen = (options : SetUserCaptureScreenOptions) => void
|
||||
|
||||
export interface Uni {
|
||||
/**
|
||||
* 开启截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "12.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "4.11"
|
||||
* },
|
||||
* "harmony": {
|
||||
* "osVer": "3.0",
|
||||
* "uniVer": "4.25",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
onUserCaptureScreen(callback : UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "12.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "4.11"
|
||||
* },
|
||||
* "harmony": {
|
||||
* "osVer": "3.0",
|
||||
* "uniVer": "4.25",,
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
offUserCaptureScreen(callback : UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 设置防截屏
|
||||
*
|
||||
* @param {SetUserCaptureScreenOptions} options
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "13.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "4.11"
|
||||
* },
|
||||
* "harmony": {
|
||||
* "osVer": "3.0",
|
||||
* "uniVer": "4.25",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
*/
|
||||
setUserCaptureScreen(options : SetUserCaptureScreenOptions) : void
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export function onUserCaptureScreen (callback) {
|
||||
return wx.onUserCaptureScreen(callback)
|
||||
}
|
||||
|
||||
export function offUserCaptureScreen (callback) {
|
||||
return wx.offUserCaptureScreen(callback)
|
||||
}
|
||||
35
uni_modules/uni-usercapturescreen/utssdk/unierror.uts
Normal file
35
uni_modules/uni-usercapturescreen/utssdk/unierror.uts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { SetUserCaptureScreenErrorCode, SetUserCaptureScreenFail } from "./interface.uts"
|
||||
/**
|
||||
* 错误主题
|
||||
*/
|
||||
export const UniErrorSubject = 'uni-usercapturescreen';
|
||||
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @UniError
|
||||
*/
|
||||
export const UniErrors : Map<SetUserCaptureScreenErrorCode, string> = new Map([
|
||||
/**
|
||||
* 错误码及对应的错误信息
|
||||
*/
|
||||
[12001, 'setUserCaptureScreen:system not support'],
|
||||
[12010, 'setUserCaptureScreen:system internal error'],
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* 错误对象实现
|
||||
*/
|
||||
export class SetUserCaptureScreenFailImpl extends UniError implements SetUserCaptureScreenFail {
|
||||
|
||||
/**
|
||||
* 错误对象构造函数
|
||||
*/
|
||||
constructor(errCode : SetUserCaptureScreenErrorCode) {
|
||||
super();
|
||||
this.errSubject = UniErrorSubject;
|
||||
this.errCode = errCode;
|
||||
this.errMsg = UniErrors[errCode] ?? "";
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,11 @@
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
//是否显示倍速提示
|
||||
showRateTips: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//循环播放
|
||||
loop: {
|
||||
type: Boolean,
|
||||
@@ -260,7 +265,6 @@
|
||||
created() {
|
||||
//获取当前运行的平台
|
||||
this.updateHeight()
|
||||
console.log('倍速列表是否是ios YINGBING' + JSON.stringify(this.playbackRates))
|
||||
},
|
||||
methods: {
|
||||
//接收消息
|
||||
|
||||
@@ -65,13 +65,18 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
this.loop = loop; //是否循环播放
|
||||
this.muted = muted; //是否静音
|
||||
this.playbackRate = playbackRate || 1; //默认播放倍速
|
||||
console.log('倍速列表' + JSON.stringify(playbackRates))
|
||||
this.playbackRates = playbackRates && playbackRates.length > 0 ? playbackRates : [{
|
||||
text: '0.5倍速',
|
||||
value: 0.5
|
||||
}, {
|
||||
text: '0.75倍速',
|
||||
value: 0.75
|
||||
}, {
|
||||
text: '正常倍速',
|
||||
value: 1
|
||||
}, {
|
||||
text: '1.25倍速',
|
||||
value: 1.25
|
||||
}, {
|
||||
text: '1.5倍速',
|
||||
value: 1.5
|
||||
@@ -120,6 +125,9 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
this._toastTimer = null; //消息隐藏定时器
|
||||
this._danmuTimer = null; //弹幕定时器
|
||||
this._seizingTimer = null; //卡死定时器(播放一些直播源的时候,可能会出现卡死无反应的情况,需要做出处理)
|
||||
this._rateTimer = null; //倍速显示定时器
|
||||
this._errorRetryCount = 0; //错误重试次数
|
||||
this._maxErrorRetry = 0; //最大重试次数
|
||||
this._event = {};
|
||||
}
|
||||
//开启全屏按钮
|
||||
@@ -157,6 +165,7 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
this._clearDanmuTimer();
|
||||
this._clearToastTimer();
|
||||
this._clearControlsTimer();
|
||||
this._clearRateTimer();
|
||||
this._removeBackbuttonListener();
|
||||
this._event = {}; //卸载所有监听事件
|
||||
if (this.container) {
|
||||
@@ -226,8 +235,8 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
_this2.emit('durationchange', _this2.getDuration());
|
||||
};
|
||||
this.video.onloadeddata = function () {
|
||||
//非直播时初始化播放时长
|
||||
if (_this2.initialTime && !_this2.isLive) _this2.seek(_this2.initialTime);
|
||||
//非直播时初始化播放时长(错误恢复时不执行)
|
||||
if (_this2.initialTime && !_this2.isLive && !_this2._isErrorRecovering) _this2.seek(_this2.initialTime);
|
||||
_this2.emit('loadeddata', {
|
||||
duration: _this2.getDuration(),
|
||||
videoWidth: _this2.video.videoWidth,
|
||||
@@ -255,12 +264,18 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
if (_this2.cm) _this2.cm.setConfig('playbackRate', playbackRate);
|
||||
_this2.emit('ratechange', playbackRate);
|
||||
_this2.setInnerHTML('yb-player-header-rate', '倍速x' + playbackRate);
|
||||
_this2._clearRateTimer();
|
||||
var rateEl = _this2.container.getElementsByClassName('yb-player-rate')[0] || document.createElement('DIV');
|
||||
if (![1, 1.0].includes(playbackRate)) {
|
||||
rateEl.setAttribute('class', 'yb-player-rate');
|
||||
rateEl.innerHTML = "\n\t\t\t\t\t<div class=\"yb-player-rate-icon\">\n\t\t\t\t\t\t<i></i><i></i><i></i>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"yb-player-rate-span\">".concat(playbackRate + '倍速播放中', "</span>\n\t\t\t\t");
|
||||
var wrapperEl = _this2.container.getElementsByClassName('yb-player-wrapper')[0];
|
||||
if (wrapperEl) wrapperEl.appendChild(rateEl);
|
||||
_this2._rateTimer = window.setTimeout(function () {
|
||||
if (rateEl && rateEl.parentNode) {
|
||||
rateEl.parentNode.removeChild(rateEl);
|
||||
}
|
||||
}, 2000);
|
||||
} else {
|
||||
if (rateEl) rateEl.remove();
|
||||
}
|
||||
@@ -353,7 +368,6 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
};
|
||||
this.video.onerror = function (e) {
|
||||
if (e && e.target.error) {
|
||||
// 网络问题或其他不可恢复的错误
|
||||
var code = e.target.error.code;
|
||||
var errorMsg = '';
|
||||
switch (code) {
|
||||
@@ -370,10 +384,26 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
errorMsg = '视频源不支持或地址无效';
|
||||
break;
|
||||
}
|
||||
_this2.showError(errorMsg);
|
||||
_this2.unloadVideo();
|
||||
console.log('[video.onerror] 检测到视频错误,错误码:' + code + ', 错误信息:' + errorMsg);
|
||||
|
||||
// 错误码 3 尝试跳过问题区间后继续播放
|
||||
if (code === 3) {
|
||||
_this2._skipErrorAndRetry(errorMsg);
|
||||
} else {
|
||||
// 其他错误直接提示错误信息
|
||||
_this2.showError(errorMsg);
|
||||
_this2.unloadVideo();
|
||||
}
|
||||
|
||||
// emit 错误事件,传递详细的错误信息
|
||||
_this2.emit('error', {
|
||||
code: code,
|
||||
message: errorMsg,
|
||||
error: e
|
||||
});
|
||||
} else {
|
||||
_this2.emit('error', e);
|
||||
}
|
||||
_this2.emit('error', e);
|
||||
};
|
||||
//视频长按菜单取消
|
||||
this.video.oncontextmenu = function (e) {
|
||||
@@ -410,6 +440,7 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
key: "unloadVideo",
|
||||
value: function unloadVideo() {
|
||||
this._clearSeizingTimer();
|
||||
this._errorRetryCount = 0; // 重置错误计数
|
||||
this.unloadCustom();
|
||||
this.unloadDecoder();
|
||||
this.unloadPano();
|
||||
@@ -1430,7 +1461,7 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
if (['timeDiffrence', 'disableScroll', 'disableTop', 'disableBottom', 'fontScale'].includes(key)) _this.cm.reset();
|
||||
}
|
||||
_this.emit('danmuconfigchange', config); //派发弹幕配置更改事件,以便开发者外部记录
|
||||
}, 500);
|
||||
}, 2000);
|
||||
}
|
||||
this.showPopup('弹幕设置', div);
|
||||
}
|
||||
@@ -2451,7 +2482,14 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
value: function hideLoading() {
|
||||
var div = this.container.getElementsByClassName('yb-player-loading')[0];
|
||||
if (div) div.remove();
|
||||
if (this.video.paused) this.showCenterPlay();else this.hideCenter();
|
||||
// if (this.video.paused) this.showCenterPlay();else this.hideCenter();
|
||||
if (this._isErrorRecovering) {
|
||||
this.hideCenter();
|
||||
} else if (this.video.paused) {
|
||||
this.showCenterPlay();
|
||||
} else {
|
||||
this.hideCenter();
|
||||
}
|
||||
}
|
||||
//展示中间播放按钮
|
||||
}, {
|
||||
@@ -2561,6 +2599,152 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
value: function seek(time) {
|
||||
if (this.video) this.video.currentTime = time;
|
||||
}
|
||||
/**
|
||||
* 跳过错误区间并重试播放
|
||||
* @param {String} errorMsg 错误信息
|
||||
*/
|
||||
}, {
|
||||
key: "_skipErrorAndRetry",
|
||||
value: function _skipErrorAndRetry(errorMsg) {
|
||||
var _this = this;
|
||||
|
||||
// 检查 video 对象是否存在
|
||||
if (!this.video) {
|
||||
console.log('[错误恢复] video 对象不存在,无法恢复');
|
||||
this.showError(errorMsg);
|
||||
this.unloadVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
// 超过最大重试次数,显示错误并卸载视频
|
||||
if (this._errorRetryCount >= this._maxErrorRetry) {
|
||||
this.showError(errorMsg);
|
||||
this.unloadVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
this._errorRetryCount++;
|
||||
|
||||
// 第 1 次错误静默处理,显示 loading
|
||||
if (this._errorRetryCount === 1) {
|
||||
this.showLoading();
|
||||
}
|
||||
|
||||
// 获取当前播放时间,向后跳过 1 秒(跳过损坏的 GOP 区间)
|
||||
var currentTime = this.video.currentTime || 0;
|
||||
// 确保 currentTime 是有效数字
|
||||
if (isNaN(currentTime) || currentTime < 0) {
|
||||
currentTime = 0;
|
||||
}
|
||||
var duration = this.getDuration() || 0;
|
||||
var skipTime = Math.min(currentTime + 1, duration);
|
||||
|
||||
console.log('[错误恢复] 开始处理,当前时间:' + currentTime + 's, 跳转到:' + skipTime + 's');
|
||||
|
||||
// 关键:保存当前 src,然后重新加载视频来恢复状态
|
||||
// var currentSrc = this.video.currentSrc || this.video.src;
|
||||
console.log('[错误恢复] 重新加载视频...');
|
||||
|
||||
// 保存当前倍速设置
|
||||
var currentPlaybackRate = this.video.playbackRate || 1;
|
||||
console.log('[错误恢复] 保存倍速:' + currentPlaybackRate);
|
||||
|
||||
// 设置标志,告诉 loadeddata 不要执行 seek
|
||||
this._isErrorRecovering = true;
|
||||
|
||||
// 重新设置 src 并加载
|
||||
// this.video.src = currentSrc;
|
||||
this.video.load();
|
||||
|
||||
// 清除之前的定时器(如果有)
|
||||
if (this._errorRecoveryTimer) {
|
||||
clearTimeout(this._errorRecoveryTimer);
|
||||
}
|
||||
|
||||
// 等待元数据加载完成
|
||||
var onLoadedMetadata = function() {
|
||||
// 检查 video 对象是否仍然存在
|
||||
if (!_this.video) {
|
||||
console.log('[错误恢复] loadedmetadata 触发,但 video 对象已不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[错误恢复] loadedmetadata 触发,设置 currentTime = ' + skipTime);
|
||||
_this.video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
||||
|
||||
// 清除超时定时器
|
||||
if (_this._errorRecoveryTimer) {
|
||||
clearTimeout(_this._errorRecoveryTimer);
|
||||
}
|
||||
|
||||
// 恢复倍速设置
|
||||
_this.video.playbackRate = currentPlaybackRate;
|
||||
console.log('[错误恢复] 恢复倍速:' + currentPlaybackRate);
|
||||
|
||||
// 设置跳转位置
|
||||
_this.video.currentTime = skipTime;
|
||||
|
||||
// 等待 seek 完成后立即播放
|
||||
var onSeeked = function() {
|
||||
// 检查 video 对象是否仍然存在
|
||||
if (!_this2.video) {
|
||||
console.log('[错误恢复] seeked 触发,但 video 对象已不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[错误恢复] seeked 触发,实际位置:' + _this2.video.currentTime);
|
||||
_this2.video.removeEventListener('seeked', onSeeked);
|
||||
_this2.tryPlayAfterSeek(errorMsg);
|
||||
};
|
||||
|
||||
_this.video.addEventListener('seeked', onSeeked);
|
||||
};
|
||||
|
||||
this.video.addEventListener('loadedmetadata', onLoadedMetadata);
|
||||
|
||||
// loadedmetadata 超时处理
|
||||
this._errorRecoveryTimer = setTimeout(function() {
|
||||
console.log('[错误恢复] loadedmetadata 超时,直接尝试播放');
|
||||
if (_this.video) {
|
||||
_this.video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
||||
}
|
||||
_this.tryPlayAfterSeek(errorMsg);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// 尝试播放
|
||||
}, {
|
||||
key: "tryPlayAfterSeek",
|
||||
value: function tryPlayAfterSeek(errorMsg) {
|
||||
var _this2 = this;
|
||||
|
||||
console.log('[错误恢复] 准备播放,当前状态:paused=' + this.video.paused + ', readyState=' + this.video.readyState + ', currentTime=' + this.video.currentTime);
|
||||
|
||||
// 直接调用 play(),Promise 会处理缓冲
|
||||
var playPromise = this.video.play();
|
||||
console.log('[错误恢复] play() 已调用');
|
||||
|
||||
if (playPromise && typeof playPromise.then === 'function') {
|
||||
playPromise.then(function() {
|
||||
console.log('[错误恢复] 播放成功!');
|
||||
_this2._errorRetryCount = 0;
|
||||
_this2._isErrorRecovering = false; // 清除错误恢复标志
|
||||
// 清除所有定时器
|
||||
if (_this2._errorRecoveryTimer) {
|
||||
clearTimeout(_this2._errorRecoveryTimer);
|
||||
_this2._errorRecoveryTimer = null;
|
||||
}
|
||||
_this2.hideLoading();
|
||||
}).catch(function(err) {
|
||||
console.log('[错误恢复] 播放失败:', err);
|
||||
_this2._skipErrorAndRetry(errorMsg);
|
||||
});
|
||||
} else {
|
||||
_this2._errorRetryCount = 0;
|
||||
_this2._isErrorRecovering = false;
|
||||
_this2.hideLoading();
|
||||
}
|
||||
}
|
||||
//播放上一个视频
|
||||
}, {
|
||||
key: "prev",
|
||||
@@ -2962,6 +3146,14 @@ var YbPlayer = /*#__PURE__*/function () {
|
||||
this._seizingTimer = null;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "_clearRateTimer",
|
||||
value: function _clearRateTimer() {
|
||||
if (this._rateTimer) {
|
||||
window.clearTimeout(this._rateTimer);
|
||||
this._rateTimer = null;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "_removeBackbuttonListener",
|
||||
value: function _removeBackbuttonListener() {
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user