2025-09-28 聊天修改
This commit is contained in:
21
App.vue
21
App.vue
@@ -1,6 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import {
|
||||||
|
createRequestPermissionListener,
|
||||||
|
stopRequestPermissionListener
|
||||||
|
} from '@/uni_modules/colorful-uni-perm';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onLaunch: function() {
|
onLaunch: function() {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
if (plus.runtime.channel === 'huawei') {
|
||||||
|
// 创建权限申请监听
|
||||||
|
createRequestPermissionListener();
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
console.log('App Launch')
|
console.log('App Launch')
|
||||||
let token = uni.getStorageSync("token")
|
let token = uni.getStorageSync("token")
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -19,7 +30,15 @@
|
|||||||
},
|
},
|
||||||
onHide: function() {
|
onHide: function() {
|
||||||
console.log('App Hide')
|
console.log('App Hide')
|
||||||
}
|
},
|
||||||
|
onExit() {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
if (plus.runtime.channel === 'huawei') {
|
||||||
|
// 清除权限申请监听
|
||||||
|
stopRequestPermissionListener();
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import {
|
|||||||
http
|
http
|
||||||
} from "../util/api";
|
} from "../util/api";
|
||||||
|
|
||||||
|
const baseURL = "http://192.168.0.15:3007"
|
||||||
|
|
||||||
export const groupAPI = {
|
export const groupAPI = {
|
||||||
getList: (params) => http.get('/group/list', params)
|
getList: (params) => http.get(baseURL + '/group/list', params),
|
||||||
|
add: (data) => http.post(baseURL + '/group/', data),
|
||||||
|
getOne: (params) => http.get(baseURL + '/group/one', params),
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path" : "pages/program/chat",
|
"path" : "pages/message/chat",
|
||||||
"style" :
|
"style" :
|
||||||
{
|
{
|
||||||
"navigationBarTitleText" : "聊天页面",
|
"navigationBarTitleText" : "聊天页面",
|
||||||
|
|||||||
535
pages/message/chat.vue
Normal file
535
pages/message/chat.vue
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
<template>
|
||||||
|
<view class="chat-container">
|
||||||
|
<u-navbar title="聊天" id="navBarId" :background="{background: 'transparent' }" :border-bottom="false"
|
||||||
|
back-icon-color="#000" title-color="#000">
|
||||||
|
<template v-slot:right>
|
||||||
|
<image class="collection" src="/static/icon/Bookmark.png" mode=""></image>
|
||||||
|
</template>
|
||||||
|
</u-navbar>
|
||||||
|
|
||||||
|
<view class="bottom-view" id="bottomId">
|
||||||
|
<!-- 麦克风/文本切换 -->
|
||||||
|
<view class="icon u-m-r-10" @click="handleChangeMic">
|
||||||
|
<image src="/static/icon/Mic.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||||
|
</view>
|
||||||
|
<textarea v-if="!showMic" name="" v-model="text" class="text" maxlength="3000"></textarea>
|
||||||
|
<u-button v-else class="btn-mic" @click="handleSay">点击说话</u-button>
|
||||||
|
<!-- 表情包 -->
|
||||||
|
<view v-show="text==null || text==''" class="icon u-m-r-10 u-m-l-10">
|
||||||
|
<image src="/static/icon/expression.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||||
|
</view>
|
||||||
|
<!-- 文本域展开 -->
|
||||||
|
<view v-show="text!=null && text!=''" class="icon u-m-r-10 u-m-l-10" @click="handleMagnify">
|
||||||
|
<image src="/static/icon/big.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||||
|
</view>
|
||||||
|
<!-- 相机 -->
|
||||||
|
<view v-show="text==null || text==''" class="icon" @click="handleCamera">
|
||||||
|
<image src="/static/icon/Camera.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||||
|
</view>
|
||||||
|
<!-- 文本发送 -->
|
||||||
|
<view v-show="text!=null && text!=''" class="icon u-m-r-10 u-m-l-10" @click="handleSend">
|
||||||
|
<image src="/static/icon/send.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view :style="'height:'+scrollHeight+'px'" scroll-y="true" class="scroll-main">
|
||||||
|
<view v-for="(item, index) in dataList">
|
||||||
|
<view v-if="item.createId==userId" class="my-message">
|
||||||
|
<view class="msg-main">
|
||||||
|
<view class="msg-content" v-if="item.type=='text'">
|
||||||
|
<view class="text">
|
||||||
|
{{item.content}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mp3-content" v-if="item.type=='mp3'">
|
||||||
|
<view class="mp3">
|
||||||
|
<view class="mp3-icon">
|
||||||
|
<image style="width: 100%;height: 100%;" src="/static/icon/listen.png" mode="">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
点击播放
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="msg-avatar">
|
||||||
|
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)" mode="">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else class="other-message">
|
||||||
|
<view class="msg-main">
|
||||||
|
<view class="msg-avatar">
|
||||||
|
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)" mode="">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
<view class="msg-content">
|
||||||
|
<view class="text">
|
||||||
|
{{item.content}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<u-popup v-model="showLongText" mode="bottom" height="80%">
|
||||||
|
<view class="long-text">
|
||||||
|
<u-input v-model="text" type="textarea" maxlength="3000" />
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
|
||||||
|
|
||||||
|
<u-mask :show="showMask" @click="handleStopMic" blur="10">
|
||||||
|
<view class="mask-warp">
|
||||||
|
<view class="mask-text">
|
||||||
|
{{!showMaskBtn?'正在说话...点击结束': '点击播放录音'}}
|
||||||
|
</view>
|
||||||
|
<view v-if="showMaskBtn" class="mask-btn">
|
||||||
|
<u-button class="btn" @click.stop="handleCancel">取消</u-button>
|
||||||
|
<u-button class="btn" @click.stop="handleSendMp3">发送</u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-mask>
|
||||||
|
|
||||||
|
<u-toast ref="msgToast" duration="6000" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref, getCurrentInstance, onBeforeMount } from 'vue';
|
||||||
|
import {
|
||||||
|
onLoad, onLaunch
|
||||||
|
} from "@dcloudio/uni-app";
|
||||||
|
import io from '@hyoga/uni-socket.io';
|
||||||
|
import { getImageUrl } from '../../util/common';
|
||||||
|
import { permissionUtil } from '@/uni_modules/colorful-uni-perm';
|
||||||
|
|
||||||
|
|
||||||
|
const text = ref('')
|
||||||
|
|
||||||
|
const socket = ref()
|
||||||
|
|
||||||
|
const navBarRef = ref()
|
||||||
|
const dataList = ref([])
|
||||||
|
|
||||||
|
const mockData = () => {
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
dataList.value.push({
|
||||||
|
"createId": 3641,
|
||||||
|
"groupId": "1",
|
||||||
|
"content": "即使在没有空格的地方也 ",
|
||||||
|
"type": "text",
|
||||||
|
"messageId": 44,
|
||||||
|
"createTime": "2025-09-27T18:32:42.000Z",
|
||||||
|
"userInfo": {
|
||||||
|
"id": 9958,
|
||||||
|
"username": "15867461647",
|
||||||
|
"userType": "user",
|
||||||
|
"isSystemAccount": 0,
|
||||||
|
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dataList.value.push({
|
||||||
|
"createId": 9955,
|
||||||
|
"groupId": "1",
|
||||||
|
"content": "2222",
|
||||||
|
"type": "text",
|
||||||
|
"messageId": 44,
|
||||||
|
"createTime": "2025-09-27T18:32:42.000Z",
|
||||||
|
"userInfo": {
|
||||||
|
"id": 9958,
|
||||||
|
"username": "15867461647",
|
||||||
|
"userType": "user",
|
||||||
|
"isSystemAccount": 0,
|
||||||
|
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
dataList.value.push(
|
||||||
|
{
|
||||||
|
"createId": 3641,
|
||||||
|
"groupId": "5",
|
||||||
|
"content": "http://114.55.111.44:9000/jurongquan/app_records/1759049412254.mp3",
|
||||||
|
"type": "mp3",
|
||||||
|
"messageId": 56,
|
||||||
|
"createTime": "2025-09-28T00:50:16.000Z",
|
||||||
|
"userInfo": {
|
||||||
|
"id": 3641,
|
||||||
|
"username": "15867461617",
|
||||||
|
"userType": "agent",
|
||||||
|
"isSystemAccount": 0,
|
||||||
|
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSend = () => {
|
||||||
|
socket.value.emit('clientMsg', {
|
||||||
|
createId: userId.value,
|
||||||
|
groupId: groupId.value,
|
||||||
|
content: text.value,
|
||||||
|
type: "text"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const showLongText = ref(false)
|
||||||
|
const showMic = ref(false)
|
||||||
|
const showMask = ref(false)
|
||||||
|
const showMaskBtn = ref(false)
|
||||||
|
|
||||||
|
const msgToast = ref(null)
|
||||||
|
|
||||||
|
const voicePath = ref('')
|
||||||
|
|
||||||
|
const recorderManager = uni.getRecorderManager();
|
||||||
|
const innerAudioContext = uni.createInnerAudioContext();
|
||||||
|
innerAudioContext.autoplay = true;
|
||||||
|
|
||||||
|
// 选择麦克风
|
||||||
|
const handleChangeMic = () => {
|
||||||
|
showMic.value = !showMic.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始录音
|
||||||
|
const handleSay = () => {
|
||||||
|
permissionUtil.requestAndroidPermission('android.permission.READ_MEDIA_AUDIO').then((status) => {
|
||||||
|
// status 为 1 表示用户已授权,0 表示用户已拒绝, -1 表示用户永久拒绝
|
||||||
|
console.log('权限申请结果:', status);
|
||||||
|
if (status == -1) {
|
||||||
|
// 弹窗提示开启权限
|
||||||
|
msgToast.value.show({
|
||||||
|
title: '您已关闭录音权限,请在设置开启应用录音权限',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
} else if (status == 1) {
|
||||||
|
showMask.value = true
|
||||||
|
recorderManager.start();
|
||||||
|
recorderManager.onStart(() => {
|
||||||
|
console.log('录音开始');
|
||||||
|
});
|
||||||
|
recorderManager.onError((err) => {
|
||||||
|
console.error('录音错误', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止录音
|
||||||
|
const handleStopMic = () => {
|
||||||
|
showMaskBtn.value = true
|
||||||
|
if (voicePath.value) {
|
||||||
|
console.log("播放录音");
|
||||||
|
innerAudioContext.src = voicePath.value
|
||||||
|
innerAudioContext.play();
|
||||||
|
} else {
|
||||||
|
recorderManager.stop()
|
||||||
|
// showMask.value = false
|
||||||
|
recorderManager.onStop(function (res) {
|
||||||
|
console.log('recorder stop' + JSON.stringify(res));
|
||||||
|
voicePath.value = res.tempFilePath;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消发送录音
|
||||||
|
const handleCancel = () => {
|
||||||
|
showMask.value = false
|
||||||
|
showMaskBtn.value = false
|
||||||
|
voicePath.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送录音文件
|
||||||
|
const handleSendMp3 = () => {
|
||||||
|
const token = uni.getStorageSync("token")
|
||||||
|
uni.uploadFile({
|
||||||
|
// url: 'http://192.168.0.4:3005/upload',
|
||||||
|
url: 'http://192.168.0.15:3007/upload/file',
|
||||||
|
filePath: voicePath.value,
|
||||||
|
header: {
|
||||||
|
"Authorization": "Bearer " + token
|
||||||
|
},
|
||||||
|
name: "file",
|
||||||
|
success: (uploadFileRes) => {
|
||||||
|
let result = JSON.parse(uploadFileRes.data)
|
||||||
|
if (result.data.fileUrl) {
|
||||||
|
// 上传文件成功,添加消息记录
|
||||||
|
socket.value.emit('clientMsg', {
|
||||||
|
createId: userId.value,
|
||||||
|
groupId: groupId.value,
|
||||||
|
content: result.data.fileUrl,
|
||||||
|
type: "mp3"
|
||||||
|
})
|
||||||
|
showMask.value = false
|
||||||
|
showMaskBtn.value = false
|
||||||
|
voicePath.value = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (res) => {
|
||||||
|
console.log(JSON.stringify(res));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文本放大
|
||||||
|
const handleMagnify = () => {
|
||||||
|
showLongText.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCamera = () => {
|
||||||
|
permissionUtil.requestAndroidPermission('android.permission.READ_EXTERNAL_STORAGE').then((status) => {
|
||||||
|
console.log('相册权限申请结果:', status);
|
||||||
|
if (status == -1) {
|
||||||
|
// 弹窗提示开启权限
|
||||||
|
msgToast.value.show({
|
||||||
|
title: '您已关闭读取相册权限,请在设置开启应用相册权限',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
} else if (status == 1) {
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 10, //默认9
|
||||||
|
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
||||||
|
sourceType: ['album'], //从相册选择
|
||||||
|
success: function (res) {
|
||||||
|
uploadImages(res.tempFilePaths)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadImages = (value) => {
|
||||||
|
console.log(value);
|
||||||
|
const token = uni.getStorageSync("token")
|
||||||
|
uni.uploadFile({
|
||||||
|
// url: 'http://192.168.0.4:3005/upload/image',
|
||||||
|
url: 'http://192.168.0.15:3007/upload/files',
|
||||||
|
filePath: value,
|
||||||
|
header: {
|
||||||
|
"Authorization": "Bearer " + token
|
||||||
|
},
|
||||||
|
name: 'file',
|
||||||
|
success: (uploadFileRes) => {
|
||||||
|
console.log(uploadFileRes);
|
||||||
|
// console.log(JSON.stringify(uploadFileRes.data));
|
||||||
|
},
|
||||||
|
fail: (res) => {
|
||||||
|
console.log(JSON.stringify(res));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupId = ref()
|
||||||
|
const userId = ref()
|
||||||
|
|
||||||
|
onLoad((val) => {
|
||||||
|
groupId.value = val.groupId
|
||||||
|
});
|
||||||
|
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
const scrollHeight = ref(0)
|
||||||
|
const loadHeight = () => {
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success(res) {
|
||||||
|
let screenHeight = res.screenHeight
|
||||||
|
uni.createSelectorQuery().in(instance.proxy).select("#navBarId").boundingClientRect((data : any) => {
|
||||||
|
scrollHeight.value = screenHeight - data.height
|
||||||
|
}).exec()
|
||||||
|
uni.createSelectorQuery().in(instance.proxy).select("#bottomId").boundingClientRect((data : any) => {
|
||||||
|
scrollHeight.value = scrollHeight.value - data.height
|
||||||
|
}).exec()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = () => {
|
||||||
|
socket.value = io('http://192.168.0.15:3007', {
|
||||||
|
query: {},
|
||||||
|
transports: ['websocket', 'polling'],
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
socket.value.on('connect', async () => {
|
||||||
|
console.log("连接成功");
|
||||||
|
})
|
||||||
|
socket.value.emit('addGroup', {
|
||||||
|
groupId: groupId.value,
|
||||||
|
})
|
||||||
|
socket.value.on('serverMsg', async (message) => {
|
||||||
|
dataList.value.push(message)
|
||||||
|
console.log(dataList.value);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadData = () => {
|
||||||
|
userId.value = uni.getStorageSync("user").id
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
mockData()
|
||||||
|
loadData()
|
||||||
|
|
||||||
|
loadHeight()
|
||||||
|
connection()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.chat-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
background: linear-gradient(180deg, #E3E8FF 0%, #FFFFFF 100%);
|
||||||
|
background-blend-mode: lighten;
|
||||||
|
|
||||||
|
|
||||||
|
.collection {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
margin-right: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100rpx;
|
||||||
|
// background-color: #aaffff;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10rpx;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
flex: 1;
|
||||||
|
height: 96%;
|
||||||
|
border: 2rpx solid #DEEFFF;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
padding: 0 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-mic {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-main {
|
||||||
|
.my-message {
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
.msg-main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 0 10rpx;
|
||||||
|
|
||||||
|
.msg-content {
|
||||||
|
// background-color: #00ffff;
|
||||||
|
padding: 2rpx;
|
||||||
|
width: 70%;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
// border: 1rpx solid #c7c7c7;
|
||||||
|
box-sizing: content-box;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mp3-content {
|
||||||
|
padding: 2rpx;
|
||||||
|
// width: 70%;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
box-sizing: content-box;
|
||||||
|
|
||||||
|
|
||||||
|
.mp3 {
|
||||||
|
display: flex;
|
||||||
|
// border: 1rpx solid #000;
|
||||||
|
padding: 15rpx 10rpx;
|
||||||
|
background-color: #55ff7f;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.mp3-icon {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
width: 25rpx;
|
||||||
|
height: 25rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-avatar {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.other-message {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
.msg-main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 0 10rpx;
|
||||||
|
|
||||||
|
.msg-content {
|
||||||
|
// background-color: #00ffff;
|
||||||
|
padding: 2rpx;
|
||||||
|
width: 70%;
|
||||||
|
// border: 1rpx solid #c7c7c7;
|
||||||
|
box-sizing: content-box;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-avatar {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.long-text {
|
||||||
|
padding: 40rpx 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mask-warp {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.mask-text {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mask-btn {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 80rpx;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
} from '@dcloudio/uni-app';
|
} from '@dcloudio/uni-app';
|
||||||
import { onReady as onUniReady } from '@dcloudio/uni-app';
|
import { onReady as onUniReady } from '@dcloudio/uni-app';
|
||||||
import { groupAPI } from '../../api/group';
|
import { groupAPI } from '../../api/group';
|
||||||
|
import { getUserInfo } from '../../util/common';
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance();
|
||||||
|
|
||||||
const height = ref(0)
|
const height = ref(0)
|
||||||
@@ -92,23 +93,23 @@
|
|||||||
|
|
||||||
// 项目
|
// 项目
|
||||||
const messageList = ref([])
|
const messageList = ref([])
|
||||||
|
const user = ref()
|
||||||
const mockData = () => {
|
const size = 10
|
||||||
for (var i = 0; i < 20; i++) {
|
const params = ref({
|
||||||
messageList.value.push({
|
page: 1,
|
||||||
messageName: "test" + i
|
size: size,
|
||||||
})
|
userId: '',
|
||||||
}
|
customerId: '',
|
||||||
}
|
})
|
||||||
|
|
||||||
const handleChat = (item) => {
|
const handleChat = (item) => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/program/chat?groupId=' + item.groupId
|
url: '/pages/message/chat?groupId=' + item.groupId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadData = () => {
|
const loadData = () => {
|
||||||
groupAPI.getList().then((res) => {
|
groupAPI.getList(params.value).then((res) => {
|
||||||
messageList.value = res.data.list
|
messageList.value = res.data.list
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -120,7 +121,8 @@
|
|||||||
|
|
||||||
onUniReady(() => {
|
onUniReady(() => {
|
||||||
loadHeight()
|
loadHeight()
|
||||||
|
user.value = getUserInfo()
|
||||||
|
params.value.userId = user.value.id
|
||||||
loadData()
|
loadData()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="my-container">
|
<view class="my-container">
|
||||||
|
|
||||||
{{user.real_name}}
|
<view v-if="user!=null">
|
||||||
|
{{user.real_name}}
|
||||||
|
</view>
|
||||||
|
|
||||||
<u-button @click="loginOut">退出登录</u-button>
|
<u-button @click="loginOut">退出登录</u-button>
|
||||||
|
|
||||||
@@ -16,7 +18,6 @@
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
user.value = uni.getStorageSync("user")
|
user.value = uni.getStorageSync("user")
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const loginOut = () => {
|
const loginOut = () => {
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="chat-container">
|
|
||||||
<u-navbar title="聊天" id="navBarId" :background="{background: 'transparent' }" :border-bottom="false"
|
|
||||||
back-icon-color="#000" title-color="#000">
|
|
||||||
<template v-slot:right>
|
|
||||||
<image class="collection" src="/static/icon/Bookmark.png" mode=""></image>
|
|
||||||
</template>
|
|
||||||
</u-navbar>
|
|
||||||
|
|
||||||
<view class="bottom-view" id="bottomId">
|
|
||||||
<view class="icon u-m-r-10">
|
|
||||||
<image src="/static/icon/Mic.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
||||||
</view>
|
|
||||||
<textarea name="" v-model="text" class="text" maxlength="3000"></textarea>
|
|
||||||
<view v-if="text==null || text==''" class="icon u-m-r-10 u-m-l-10">
|
|
||||||
<image src="/static/icon/expression.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
||||||
</view>
|
|
||||||
<view v-else class="icon u-m-r-10 u-m-l-10">
|
|
||||||
<image src="/static/icon/big.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
||||||
</view>
|
|
||||||
<view v-if="text==null || text==''" class="icon">
|
|
||||||
<image src="/static/icon/Camera.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
||||||
</view>
|
|
||||||
<view v-else class="icon u-m-r-10 u-m-l-10" @click="handleSend">
|
|
||||||
<image src="/static/icon/send.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<scroll-view :style="'height:'+scrollHeight+'px'" scroll-y="true" class="scroll-main">
|
|
||||||
<view v-for="(item, index) in dataList">
|
|
||||||
<view v-if="item.createId==userId" class="my-message">
|
|
||||||
{{item.content}}
|
|
||||||
</view>
|
|
||||||
<view v-else class="other-message">
|
|
||||||
{{item.content}}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
|
|
||||||
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { onMounted, ref, getCurrentInstance, onBeforeMount } from 'vue';
|
|
||||||
import {
|
|
||||||
onLoad,
|
|
||||||
} from "@dcloudio/uni-app";
|
|
||||||
import io from '@hyoga/uni-socket.io';
|
|
||||||
|
|
||||||
const text = ref('')
|
|
||||||
|
|
||||||
const socket = ref()
|
|
||||||
|
|
||||||
const navBarRef = ref()
|
|
||||||
const dataList = ref([])
|
|
||||||
|
|
||||||
const mockData = () => {
|
|
||||||
for (var i = 0; i < 40; i++) {
|
|
||||||
dataList.value.push("测试" + (i + 1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSend = () => {
|
|
||||||
socket.value.emit('clientMsg', {
|
|
||||||
createId: userId.value,
|
|
||||||
groupId: groupId.value,
|
|
||||||
content: text.value,
|
|
||||||
type: "text"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const groupId = ref()
|
|
||||||
const userId = ref()
|
|
||||||
|
|
||||||
onLoad((val) => {
|
|
||||||
groupId.value = val.groupId
|
|
||||||
});
|
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
|
||||||
const scrollHeight = ref(0)
|
|
||||||
const loadHeight = () => {
|
|
||||||
uni.getSystemInfo({
|
|
||||||
success(res) {
|
|
||||||
let screenHeight = res.screenHeight
|
|
||||||
uni.createSelectorQuery().in(instance.proxy).select("#navBarId").boundingClientRect((data : any) => {
|
|
||||||
scrollHeight.value = screenHeight - data.height
|
|
||||||
}).exec()
|
|
||||||
uni.createSelectorQuery().in(instance.proxy).select("#bottomId").boundingClientRect((data : any) => {
|
|
||||||
scrollHeight.value = scrollHeight.value - data.height
|
|
||||||
}).exec()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = () => {
|
|
||||||
socket.value = io('http://192.168.0.15:3007', {
|
|
||||||
query: {},
|
|
||||||
transports: ['websocket', 'polling'],
|
|
||||||
timeout: 5000,
|
|
||||||
});
|
|
||||||
socket.value.on('connect', async () => {
|
|
||||||
console.log("连接成功");
|
|
||||||
})
|
|
||||||
socket.value.emit('addGroup', {
|
|
||||||
groupId: groupId.value,
|
|
||||||
})
|
|
||||||
socket.value.on('serverMsg', async (message) => {
|
|
||||||
console.log(message);
|
|
||||||
dataList.value.push(message)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadData = () => {
|
|
||||||
userId.value = uni.getStorageSync("user").id
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// mockData()
|
|
||||||
loadData()
|
|
||||||
|
|
||||||
loadHeight()
|
|
||||||
connection()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.chat-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
background: linear-gradient(180deg, #E3E8FF 0%, #FFFFFF 100%);
|
|
||||||
background-blend-mode: lighten;
|
|
||||||
|
|
||||||
|
|
||||||
.collection {
|
|
||||||
width: 48rpx;
|
|
||||||
height: 48rpx;
|
|
||||||
margin-right: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom-view {
|
|
||||||
width: 100%;
|
|
||||||
height: 80rpx;
|
|
||||||
// background-color: #aaffff;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 10rpx;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 48rpx;
|
|
||||||
height: 48rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 2rpx solid #DEEFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll-main {
|
|
||||||
.my-message {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.other-message {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -96,7 +96,8 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<u-row justify="flex-end" class="u-m-r-40 btn-group">
|
<u-row justify="flex-end" class="u-m-r-40 btn-group">
|
||||||
<u-col span="3"><u-button class="btn" type="primary">{{isChat?"继续聊":"聊一聊"}}</u-button></u-col>
|
<u-col span="3"><u-button class="btn" type="primary"
|
||||||
|
@click="handleChat">{{isChat?"继续聊":"聊一聊"}}</u-button></u-col>
|
||||||
<u-col span="3"><u-button class="btn" type="success" @click="handleOpen">立刻融</u-button></u-col>
|
<u-col span="3"><u-button class="btn" type="success" @click="handleOpen">立刻融</u-button></u-col>
|
||||||
</u-row>
|
</u-row>
|
||||||
|
|
||||||
@@ -171,6 +172,7 @@
|
|||||||
import { getUserInfo } from '../../util/common';
|
import { getUserInfo } from '../../util/common';
|
||||||
import { programAPI } from '../../api/program';
|
import { programAPI } from '../../api/program';
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { groupAPI } from '../../api/group';
|
||||||
|
|
||||||
const userId = ref()
|
const userId = ref()
|
||||||
const programId = ref()
|
const programId = ref()
|
||||||
@@ -213,6 +215,30 @@
|
|||||||
loadData()
|
loadData()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const handleChat = () => {
|
||||||
|
if (isChat.value) {
|
||||||
|
// 继续聊
|
||||||
|
groupAPI.getOne({programId: programId.value, userId: userId.value}).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
// 进入聊天
|
||||||
|
uni.redirectTo({
|
||||||
|
url: '/pages/message/chat?groupId=' + res.data.groupId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 开启群组聊天
|
||||||
|
groupAPI.add({ programId: programId.value, userId: userId.value }).then(res => {
|
||||||
|
if(res.code==200){
|
||||||
|
// 创建成功,进入聊天
|
||||||
|
uni.redirectTo({
|
||||||
|
url: '/pages/message/chat?groupId=' + res.data.groupId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 立刻融 弹窗
|
// 立刻融 弹窗
|
||||||
const showWarning = ref(false)
|
const showWarning = ref(false)
|
||||||
|
|||||||
BIN
static/icon/listen.png
Normal file
BIN
static/icon/listen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
4
uni_modules/colorful-uni-perm/changelog.md
Normal file
4
uni_modules/colorful-uni-perm/changelog.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
## 1.0.0(2025-06-09)
|
||||||
|
- 两行代码完成全局监听权限申请
|
||||||
|
- 自动化弹窗实现权限申请描述
|
||||||
|
- 轻松通过华为应用商店审核
|
||||||
262
uni_modules/colorful-uni-perm/index.js
Normal file
262
uni_modules/colorful-uni-perm/index.js
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
import { popup } from './popup.js'
|
||||||
|
import permissionUtil from './permission.js'
|
||||||
|
|
||||||
|
let permissionListener = null
|
||||||
|
|
||||||
|
const prefix = 'permissionStatus_'
|
||||||
|
const { uniPlatform, platform } = uni.getSystemInfoSync()
|
||||||
|
|
||||||
|
// 默认权限申请说明信息
|
||||||
|
const defaultPermissionExplainMap = {
|
||||||
|
'android.permission.BLUETOOTH_SCAN': {
|
||||||
|
title: '蓝牙扫描权限申请说明',
|
||||||
|
content: '应用需要扫描附近的蓝牙设备,以便进行连接或数据传输。'
|
||||||
|
},
|
||||||
|
'android.permission.BLUETOOTH_CONNECT': {
|
||||||
|
title: '蓝牙连接权限申请说明',
|
||||||
|
content: '应用需要连接蓝牙设备,以便提供音频播放或数据通信功能。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_IMAGE': {
|
||||||
|
title: '读取图片权限申请说明',
|
||||||
|
content: '应用需要访问您的图片库,以便加载和选择照片。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_IMAGES': {
|
||||||
|
title: '读取图片权限申请说明',
|
||||||
|
content: '应用需要访问您的图片库,以便加载和选择照片。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_VIDEO': {
|
||||||
|
title: '读取视频权限申请说明',
|
||||||
|
content: '应用需要访问您的视频库,以便播放和选择视频文件。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_AUDIO': {
|
||||||
|
title: '读取音频权限申请说明',
|
||||||
|
content: '应用需要访问您的音频文件,以便播放音乐或录音。'
|
||||||
|
},
|
||||||
|
'android.permission.CALL_PHONE': {
|
||||||
|
title: '拨打电话权限申请说明',
|
||||||
|
content: '应用需要拨打电话权限,以便直接拨打联系人或客服热线。'
|
||||||
|
},
|
||||||
|
'android.permission.INTERNET': {
|
||||||
|
title: '网络权限申请说明',
|
||||||
|
content: '应用需要访问网络,以提供最新的内容和服务。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_EXTERNAL_STORAGE': {
|
||||||
|
title: '存储读取权限申请说明',
|
||||||
|
content: '应用需要读取您的存储,以便加载图片、视频等多媒体文件。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_EXTERNAL_STORAGE': {
|
||||||
|
title: '存储写入权限申请说明',
|
||||||
|
content: '应用需要写入您的存储,以便保存图片、视频等多媒体文件。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_PHONE_STATE': {
|
||||||
|
title: '设备信息权限申请说明',
|
||||||
|
content: '应用需要访问设备信息,以便提供更好的用户体验。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_NETWORK_STATE': {
|
||||||
|
title: '网络状态权限申请说明',
|
||||||
|
content: '应用需要获取网络状态,以便优化网络请求。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_WIFI_STATE': {
|
||||||
|
title: 'WiFi 状态权限申请说明',
|
||||||
|
content: '应用需要获取 WiFi 状态,以便优化网络连接。'
|
||||||
|
},
|
||||||
|
'android.permission.CAMERA': {
|
||||||
|
title: '相机权限申请说明',
|
||||||
|
content: '应用需要访问您的相机,以便拍摄照片或扫描二维码。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_COARSE_LOCATION': {
|
||||||
|
title: '定位权限申请说明',
|
||||||
|
content: '应用需要获取您的大致位置信息,以便提供基于位置的服务。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_FINE_LOCATION': {
|
||||||
|
title: '精确定位权限申请说明',
|
||||||
|
content: '应用需要获取您的精确位置信息,以便提供导航等精准服务。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS': {
|
||||||
|
title: '额外定位权限申请说明',
|
||||||
|
content: '应用需要使用额外的定位功能,以提升定位精度。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_MOCK_LOCATION': {
|
||||||
|
title: '模拟定位权限申请说明',
|
||||||
|
content: '应用需要访问模拟位置,以便进行测试或特定功能。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_CONTACTS': {
|
||||||
|
title: '读取联系人权限申请说明',
|
||||||
|
content: '应用需要读取您的联系人信息,以便提供通讯录相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_CONTACTS': {
|
||||||
|
title: '写入联系人权限申请说明',
|
||||||
|
content: '应用需要写入您的联系人信息,以便管理通讯录。'
|
||||||
|
},
|
||||||
|
'android.permission.BLUETOOTH': {
|
||||||
|
title: '蓝牙权限申请说明',
|
||||||
|
content: '应用需要访问蓝牙功能,以便连接设备或传输数据。'
|
||||||
|
},
|
||||||
|
'android.permission.BLUETOOTH_ADMIN': {
|
||||||
|
title: '蓝牙管理权限申请说明',
|
||||||
|
content: '应用需要管理蓝牙功能,以便优化连接体验。'
|
||||||
|
},
|
||||||
|
'android.permission.RECEIVE_SMS': {
|
||||||
|
title: '短信接收权限申请说明',
|
||||||
|
content: '应用需要读取短信,以便自动填充验证码或提供相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.SEND_SMS': {
|
||||||
|
title: '短信发送权限申请说明',
|
||||||
|
content: '应用需要发送短信,以便提供短信验证等功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_SMS': {
|
||||||
|
title: '短信写入权限申请说明',
|
||||||
|
content: '应用需要写入短信,以便存储和管理您的短信信息。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_SMS': {
|
||||||
|
title: '短信读取权限申请说明',
|
||||||
|
content: '应用需要读取短信,以便自动填充验证码或提供相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.INSTALL_PACKAGES': {
|
||||||
|
title: '安装应用权限申请说明',
|
||||||
|
content: '应用需要安装其他应用,以便提供扩展功能。'
|
||||||
|
},
|
||||||
|
'android.permission.REQUEST_INSTALL_PACKAGES': {
|
||||||
|
title: '安装包权限申请说明',
|
||||||
|
content: '应用需要请求安装应用包权限,以便下载安装更新。'
|
||||||
|
},
|
||||||
|
'com.android.launcher.permission.INSTALL_SHORTCUT': {
|
||||||
|
title: '创建快捷方式权限申请说明',
|
||||||
|
content: '应用需要创建桌面快捷方式,以便您快速访问应用。'
|
||||||
|
},
|
||||||
|
'com.android.launcher.permission.UNINSTALL_SHORTCUT': {
|
||||||
|
title: '删除快捷方式权限申请说明',
|
||||||
|
content: '应用需要删除桌面快捷方式,以便管理您的快捷方式。'
|
||||||
|
},
|
||||||
|
'android.permission.RECORD_AUDIO': {
|
||||||
|
title: '麦克风权限申请说明',
|
||||||
|
content: '应用需要访问麦克风,以便进行语音输入或语音通话。'
|
||||||
|
},
|
||||||
|
'android.permission.MODIFY_AUDIO_SETTINGS': {
|
||||||
|
title: '音频设置修改权限申请说明',
|
||||||
|
content: '应用需要修改音频设置,以便优化音量或声音效果。'
|
||||||
|
},
|
||||||
|
'android.permission.GET_ACCOUNTS': {
|
||||||
|
title: '账户权限申请说明',
|
||||||
|
content: '应用需要访问您的账户信息,以便提供个性化服务。'
|
||||||
|
},
|
||||||
|
'android.permission.USE_FINGERPRINT': {
|
||||||
|
title: '指纹识别权限申请说明',
|
||||||
|
content: '应用需要使用指纹识别,以便进行身份验证。'
|
||||||
|
},
|
||||||
|
'android.permission.USE_BIOMETRIC': {
|
||||||
|
title: '生物识别权限申请说明',
|
||||||
|
content: '应用需要使用生物识别功能(如面部识别),以便进行身份验证。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_CALENDAR': {
|
||||||
|
title: '读取日历权限申请说明',
|
||||||
|
content: '应用需要读取您的日历,以便提供日程管理功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_CALENDAR': {
|
||||||
|
title: '写入日历权限申请说明',
|
||||||
|
content: '应用需要写入您的日历,以便添加或修改日程。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_CALL_LOG': {
|
||||||
|
title: '读取通话记录权限申请说明',
|
||||||
|
content: '应用需要访问通话记录,以便提供通话管理或统计功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_CALL_LOG': {
|
||||||
|
title: '写入通话记录权限申请说明',
|
||||||
|
content: '应用需要写入通话记录,以便管理通话历史。'
|
||||||
|
},
|
||||||
|
'android.permission.PROCESS_OUTGOING_CALLS': {
|
||||||
|
title: '处理拨出电话权限申请说明',
|
||||||
|
content: '应用需要访问拨出电话,以便提供通话拦截或号码识别功能。'
|
||||||
|
},
|
||||||
|
'android.permission.BODY_SENSORS': {
|
||||||
|
title: '传感器权限申请说明',
|
||||||
|
content: '应用需要访问您的传感器数据,以便提供健康或运动相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.ACTIVITY_RECOGNITION': {
|
||||||
|
title: '活动识别权限申请说明',
|
||||||
|
content: '应用需要访问您的活动状态,以便提供运动检测等功能。'
|
||||||
|
},
|
||||||
|
'android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS': {
|
||||||
|
title: '电池优化忽略权限申请说明',
|
||||||
|
content: '应用需要忽略电池优化,以便在后台稳定运行。'
|
||||||
|
},
|
||||||
|
'android.permission.FOREGROUND_SERVICE': {
|
||||||
|
title: '前台服务权限申请说明',
|
||||||
|
content: '应用需要运行前台服务,以便提供持续运行的功能,如音乐播放、导航等。'
|
||||||
|
},
|
||||||
|
'android.permission.SYSTEM_ALERT_WINDOW': {
|
||||||
|
title: '悬浮窗权限申请说明',
|
||||||
|
content: '应用需要显示悬浮窗,以便提供浮动窗口功能,如聊天气泡、屏幕录制等。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_SETTINGS': {
|
||||||
|
title: '系统设置修改权限申请说明',
|
||||||
|
content: '应用需要修改系统设置,以便调整亮度、铃声等个性化配置。'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节流函数
|
||||||
|
let previous = 0
|
||||||
|
function throttle(func, wait = 500) {
|
||||||
|
let now = Date.now()
|
||||||
|
if (now - previous > wait) {
|
||||||
|
typeof func === 'function' && func()
|
||||||
|
previous = now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建请求权限的监听器
|
||||||
|
* 该函数用于在特定平台上创建和管理权限请求的监听器,并根据权限请求的结果做出相应处理
|
||||||
|
* @param {Object} permissionExplainMap - 包含权限名称和对应解释内容的映射对象,用于向用户展示权限请求的说明,默认为空对象
|
||||||
|
*/
|
||||||
|
const createRequestPermissionListener = (permissionExplainMap = {}) => {
|
||||||
|
if (uniPlatform != 'app' || platform != 'android') return
|
||||||
|
|
||||||
|
if (typeof permissionExplainMap != 'object') throw Error('permissionExplainMap 类型错误')
|
||||||
|
|
||||||
|
permissionListener = permissionListener || uni.createRequestPermissionListener()
|
||||||
|
|
||||||
|
permissionListener.onRequest(e => {
|
||||||
|
console.log('onRequest', e)
|
||||||
|
})
|
||||||
|
|
||||||
|
permissionListener.onConfirm(e => {
|
||||||
|
const [permissionName] = e
|
||||||
|
|
||||||
|
const status = uni.getStorageSync(prefix + permissionName)
|
||||||
|
console.log('onConfirm permissionName', permissionName, status)
|
||||||
|
const content = permissionExplainMap[permissionName] || defaultPermissionExplainMap[permissionName]
|
||||||
|
|
||||||
|
if (!status && content) {
|
||||||
|
throttle(() => popup.show(content))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
permissionListener.onComplete(e => {
|
||||||
|
const [permissionName] = e
|
||||||
|
|
||||||
|
const status = uni.getStorageSync(prefix + permissionName)
|
||||||
|
console.log('onComplete permissionName', permissionName, status)
|
||||||
|
popup.close()
|
||||||
|
|
||||||
|
const content = permissionExplainMap[permissionName] || defaultPermissionExplainMap[permissionName]
|
||||||
|
|
||||||
|
if (status === -1 && content) {
|
||||||
|
throttle(() => showModal(content.content))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function showModal(content) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '权限申请已被拒绝',
|
||||||
|
content: content + '请前往 APP 设置界面打开对应权限!',
|
||||||
|
showCancel: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopRequestPermissionListener = () => {
|
||||||
|
permissionListener && permissionListener.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
export { permissionUtil, createRequestPermissionListener, stopRequestPermissionListener }
|
||||||
87
uni_modules/colorful-uni-perm/package.json
Normal file
87
uni_modules/colorful-uni-perm/package.json
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"id": "colorful-uni-perm",
|
||||||
|
"displayName": "全局监听权限申请,安卓权限申请的使用目的说明弹窗,华为应用商店上架处理",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "解决华为、小米等应用商店上架审核时,未向用户告知权限申请的目的,导致应用审核被拒绝问题",
|
||||||
|
"keywords": [
|
||||||
|
"华为上架",
|
||||||
|
"监听权限申请",
|
||||||
|
"权限申请的使用目的",
|
||||||
|
"权限申请的使用目说明弹窗"
|
||||||
|
],
|
||||||
|
"repository": "",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": "^4.01"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"type": "sdk-js",
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": ""
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "y"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
},
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "u",
|
||||||
|
"app-uvue": "u",
|
||||||
|
"app-harmony": "u"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "u",
|
||||||
|
"Android Browser": "u",
|
||||||
|
"微信浏览器(Android)": "u",
|
||||||
|
"QQ浏览器(Android)": "u"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "u",
|
||||||
|
"IE": "u",
|
||||||
|
"Edge": "u",
|
||||||
|
"Firefox": "u",
|
||||||
|
"Safari": "u"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "u",
|
||||||
|
"阿里": "u",
|
||||||
|
"百度": "u",
|
||||||
|
"字节跳动": "u",
|
||||||
|
"QQ": "u",
|
||||||
|
"钉钉": "u",
|
||||||
|
"快手": "u",
|
||||||
|
"飞书": "u",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
uni_modules/colorful-uni-perm/permission.js
Normal file
55
uni_modules/colorful-uni-perm/permission.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* 此文件来源于 https://ext.dcloud.net.cn/plugin?id=594 部分片段
|
||||||
|
*
|
||||||
|
* 获取权限状态
|
||||||
|
* @param {String} permissionID 权限ID
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const prefix = 'permissionStatus_';
|
||||||
|
function requestAndroidPermission(permissionID) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
plus.android.requestPermissions(
|
||||||
|
// 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
|
||||||
|
[permissionID],
|
||||||
|
function (resultObj) {
|
||||||
|
var result = 0;
|
||||||
|
for (var i = 0; i < resultObj.granted.length; i++) {
|
||||||
|
var grantedPermission = resultObj.granted[i];
|
||||||
|
console.log('已获取的权限:' + grantedPermission);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < resultObj.deniedPresent.length; i++) {
|
||||||
|
var deniedPresentPermission = resultObj.deniedPresent[i];
|
||||||
|
console.log('拒绝本次申请的权限:' + deniedPresentPermission);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < resultObj.deniedAlways.length; i++) {
|
||||||
|
var deniedAlwaysPermission = resultObj.deniedAlways[i];
|
||||||
|
console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
uni.setStorageSync(prefix + permissionID, result);
|
||||||
|
|
||||||
|
resolve(result);
|
||||||
|
// 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
|
||||||
|
if (result != 1) {
|
||||||
|
// uni.showModal({
|
||||||
|
// content: '权限已经被拒绝,请前往APP设置界面打开相应权限',
|
||||||
|
// showCancel: false,
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
console.log('申请权限错误:' + error.code + ' = ' + error.message);
|
||||||
|
resolve({
|
||||||
|
code: error.code,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
requestAndroidPermission,
|
||||||
|
};
|
||||||
119
uni_modules/colorful-uni-perm/popup.js
Normal file
119
uni_modules/colorful-uni-perm/popup.js
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* @description: 创建一个原生弹窗
|
||||||
|
* @param {*} options
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export class NativePopup {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.sysInfo = uni.getSystemInfoSync();
|
||||||
|
|
||||||
|
const { bgColor = '#fff', titleColor = '#000', contentColor = '#272727' } = options;
|
||||||
|
|
||||||
|
this.bgColor = bgColor;
|
||||||
|
this.titleColor = titleColor;
|
||||||
|
this.contentColor = contentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
createPopup = () => {
|
||||||
|
const { statusBarHeight, screenWidth } = this.sysInfo;
|
||||||
|
|
||||||
|
const popupView = new plus.nativeObj.View('popupView', {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: screenWidth,
|
||||||
|
height: 110 + statusBarHeight + 'px',
|
||||||
|
// backgroundColor: 'blue' // debug
|
||||||
|
});
|
||||||
|
|
||||||
|
popupView.addEventListener('click', this.close);
|
||||||
|
|
||||||
|
const bgPadding = 15;
|
||||||
|
|
||||||
|
popupView.drawRect(
|
||||||
|
{
|
||||||
|
color: 'rgba(0, 0, 0, 0.1)',
|
||||||
|
radius: '10px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
top: statusBarHeight + 7 + 'px',
|
||||||
|
left: bgPadding - 2 + 'px',
|
||||||
|
width: screenWidth - bgPadding * 2 + 4 + 'px',
|
||||||
|
height: '100px',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
popupView.drawRect(
|
||||||
|
{
|
||||||
|
color: this.bgColor,
|
||||||
|
radius: '10px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
top: statusBarHeight + 5 + 'px',
|
||||||
|
left: bgPadding + 'px',
|
||||||
|
width: screenWidth - bgPadding * 2 + 'px',
|
||||||
|
height: '100px',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const padding = 10;
|
||||||
|
|
||||||
|
popupView.drawText(
|
||||||
|
this.title,
|
||||||
|
{
|
||||||
|
top: statusBarHeight + 10 + 'px',
|
||||||
|
left: padding + bgPadding + 'px',
|
||||||
|
height: '30px',
|
||||||
|
width: screenWidth - bgPadding * 2 - padding * 2 + 'px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: '16px',
|
||||||
|
weight: 'bold',
|
||||||
|
align: 'left',
|
||||||
|
color: this.titleColor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onClick: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
popupView.drawText(
|
||||||
|
this.content,
|
||||||
|
{
|
||||||
|
top: statusBarHeight + 40 + 'px',
|
||||||
|
height: '60px',
|
||||||
|
left: padding + bgPadding + 'px',
|
||||||
|
width: screenWidth - bgPadding * 2 - padding * 2 + 'px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: '14px',
|
||||||
|
align: 'left',
|
||||||
|
color: this.contentColor,
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
this.popupView = popupView;
|
||||||
|
|
||||||
|
return popupView;
|
||||||
|
};
|
||||||
|
|
||||||
|
show = (options = {}) => {
|
||||||
|
this.close();
|
||||||
|
|
||||||
|
const { title = '权限申请说明', content = '' } = options;
|
||||||
|
this.title = title;
|
||||||
|
this.content = content;
|
||||||
|
|
||||||
|
this.createPopup();
|
||||||
|
|
||||||
|
this.popupView.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
close = () => {
|
||||||
|
this.popupView && this.popupView.close();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const popup = new NativePopup();
|
||||||
249
uni_modules/colorful-uni-perm/readme.md
Normal file
249
uni_modules/colorful-uni-perm/readme.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
### 用法说明
|
||||||
|
|
||||||
|
**在 App.vue 生命周期内调用对应函数**
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createRequestPermissionListener, stopRequestPermissionListener } from '@/uni_modules/colorful-uni-perm';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
onLaunch: function (opt) {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
if (plus.runtime.channel === 'huawei') {
|
||||||
|
// 创建权限申请监听
|
||||||
|
createRequestPermissionListener();
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
onExit() {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
if (plus.runtime.channel === 'huawei') {
|
||||||
|
// 清除权限申请监听
|
||||||
|
stopRequestPermissionListener();
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 已经支持以下安卓权限,对应的权限说明信息
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
'android.permission.BLUETOOTH_SCAN': {
|
||||||
|
title: '蓝牙扫描权限申请说明',
|
||||||
|
content: '应用需要扫描附近的蓝牙设备,以便进行连接或数据传输。'
|
||||||
|
},
|
||||||
|
'android.permission.BLUETOOTH_CONNECT': {
|
||||||
|
title: '蓝牙连接权限申请说明',
|
||||||
|
content: '应用需要连接蓝牙设备,以便提供音频播放或数据通信功能。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_IMAGE': {
|
||||||
|
title: '读取图片权限申请说明',
|
||||||
|
content: '应用需要访问您的图片库,以便加载和选择照片。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_IMAGES': {
|
||||||
|
title: '读取图片权限申请说明',
|
||||||
|
content: '应用需要访问您的图片库,以便加载和选择照片。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_VIDEO': {
|
||||||
|
title: '读取视频权限申请说明',
|
||||||
|
content: '应用需要访问您的视频库,以便播放和选择视频文件。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_MEDIA_AUDIO': {
|
||||||
|
title: '读取音频权限申请说明',
|
||||||
|
content: '应用需要访问您的音频文件,以便播放音乐或录音。'
|
||||||
|
},
|
||||||
|
'android.permission.CALL_PHONE': {
|
||||||
|
title: '拨打电话权限申请说明',
|
||||||
|
content: '应用需要拨打电话权限,以便直接拨打联系人或客服热线。'
|
||||||
|
},
|
||||||
|
'android.permission.INTERNET': {
|
||||||
|
title: '网络权限申请说明',
|
||||||
|
content: '应用需要访问网络,以提供最新的内容和服务。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_EXTERNAL_STORAGE': {
|
||||||
|
title: '存储读取权限申请说明',
|
||||||
|
content: '应用需要读取您的存储,以便加载图片、视频等多媒体文件。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_EXTERNAL_STORAGE': {
|
||||||
|
title: '存储写入权限申请说明',
|
||||||
|
content: '应用需要写入您的存储,以便保存图片、视频等多媒体文件。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_PHONE_STATE': {
|
||||||
|
title: '设备信息权限申请说明',
|
||||||
|
content: '应用需要访问设备信息,以便提供更好的用户体验。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_NETWORK_STATE': {
|
||||||
|
title: '网络状态权限申请说明',
|
||||||
|
content: '应用需要获取网络状态,以便优化网络请求。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_WIFI_STATE': {
|
||||||
|
title: 'WiFi 状态权限申请说明',
|
||||||
|
content: '应用需要获取 WiFi 状态,以便优化网络连接。'
|
||||||
|
},
|
||||||
|
'android.permission.CAMERA': {
|
||||||
|
title: '相机权限申请说明',
|
||||||
|
content: '应用需要访问您的相机,以便拍摄照片或扫描二维码。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_COARSE_LOCATION': {
|
||||||
|
title: '定位权限申请说明',
|
||||||
|
content: '应用需要获取您的大致位置信息,以便提供基于位置的服务。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_FINE_LOCATION': {
|
||||||
|
title: '精确定位权限申请说明',
|
||||||
|
content: '应用需要获取您的精确位置信息,以便提供导航等精准服务。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS': {
|
||||||
|
title: '额外定位权限申请说明',
|
||||||
|
content: '应用需要使用额外的定位功能,以提升定位精度。'
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_MOCK_LOCATION': {
|
||||||
|
title: '模拟定位权限申请说明',
|
||||||
|
content: '应用需要访问模拟位置,以便进行测试或特定功能。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_CONTACTS': {
|
||||||
|
title: '读取联系人权限申请说明',
|
||||||
|
content: '应用需要读取您的联系人信息,以便提供通讯录相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_CONTACTS': {
|
||||||
|
title: '写入联系人权限申请说明',
|
||||||
|
content: '应用需要写入您的联系人信息,以便管理通讯录。'
|
||||||
|
},
|
||||||
|
'android.permission.BLUETOOTH': {
|
||||||
|
title: '蓝牙权限申请说明',
|
||||||
|
content: '应用需要访问蓝牙功能,以便连接设备或传输数据。'
|
||||||
|
},
|
||||||
|
'android.permission.BLUETOOTH_ADMIN': {
|
||||||
|
title: '蓝牙管理权限申请说明',
|
||||||
|
content: '应用需要管理蓝牙功能,以便优化连接体验。'
|
||||||
|
},
|
||||||
|
'android.permission.RECEIVE_SMS': {
|
||||||
|
title: '短信接收权限申请说明',
|
||||||
|
content: '应用需要读取短信,以便自动填充验证码或提供相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.SEND_SMS': {
|
||||||
|
title: '短信发送权限申请说明',
|
||||||
|
content: '应用需要发送短信,以便提供短信验证等功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_SMS': {
|
||||||
|
title: '短信写入权限申请说明',
|
||||||
|
content: '应用需要写入短信,以便存储和管理您的短信信息。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_SMS': {
|
||||||
|
title: '短信读取权限申请说明',
|
||||||
|
content: '应用需要读取短信,以便自动填充验证码或提供相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.INSTALL_PACKAGES': {
|
||||||
|
title: '安装应用权限申请说明',
|
||||||
|
content: '应用需要安装其他应用,以便提供扩展功能。'
|
||||||
|
},
|
||||||
|
'android.permission.REQUEST_INSTALL_PACKAGES': {
|
||||||
|
title: '安装包权限申请说明',
|
||||||
|
content: '应用需要请求安装应用包权限,以便下载安装更新。'
|
||||||
|
},
|
||||||
|
'com.android.launcher.permission.INSTALL_SHORTCUT': {
|
||||||
|
title: '创建快捷方式权限申请说明',
|
||||||
|
content: '应用需要创建桌面快捷方式,以便您快速访问应用。'
|
||||||
|
},
|
||||||
|
'com.android.launcher.permission.UNINSTALL_SHORTCUT': {
|
||||||
|
title: '删除快捷方式权限申请说明',
|
||||||
|
content: '应用需要删除桌面快捷方式,以便管理您的快捷方式。'
|
||||||
|
},
|
||||||
|
'android.permission.RECORD_AUDIO': {
|
||||||
|
title: '麦克风权限申请说明',
|
||||||
|
content: '应用需要访问麦克风,以便进行语音输入或语音通话。'
|
||||||
|
},
|
||||||
|
'android.permission.MODIFY_AUDIO_SETTINGS': {
|
||||||
|
title: '音频设置修改权限申请说明',
|
||||||
|
content: '应用需要修改音频设置,以便优化音量或声音效果。'
|
||||||
|
},
|
||||||
|
'android.permission.GET_ACCOUNTS': {
|
||||||
|
title: '账户权限申请说明',
|
||||||
|
content: '应用需要访问您的账户信息,以便提供个性化服务。'
|
||||||
|
},
|
||||||
|
'android.permission.USE_FINGERPRINT': {
|
||||||
|
title: '指纹识别权限申请说明',
|
||||||
|
content: '应用需要使用指纹识别,以便进行身份验证。'
|
||||||
|
},
|
||||||
|
'android.permission.USE_BIOMETRIC': {
|
||||||
|
title: '生物识别权限申请说明',
|
||||||
|
content: '应用需要使用生物识别功能(如面部识别),以便进行身份验证。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_CALENDAR': {
|
||||||
|
title: '读取日历权限申请说明',
|
||||||
|
content: '应用需要读取您的日历,以便提供日程管理功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_CALENDAR': {
|
||||||
|
title: '写入日历权限申请说明',
|
||||||
|
content: '应用需要写入您的日历,以便添加或修改日程。'
|
||||||
|
},
|
||||||
|
'android.permission.READ_CALL_LOG': {
|
||||||
|
title: '读取通话记录权限申请说明',
|
||||||
|
content: '应用需要访问通话记录,以便提供通话管理或统计功能。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_CALL_LOG': {
|
||||||
|
title: '写入通话记录权限申请说明',
|
||||||
|
content: '应用需要写入通话记录,以便管理通话历史。'
|
||||||
|
},
|
||||||
|
'android.permission.PROCESS_OUTGOING_CALLS': {
|
||||||
|
title: '处理拨出电话权限申请说明',
|
||||||
|
content: '应用需要访问拨出电话,以便提供通话拦截或号码识别功能。'
|
||||||
|
},
|
||||||
|
'android.permission.BODY_SENSORS': {
|
||||||
|
title: '传感器权限申请说明',
|
||||||
|
content: '应用需要访问您的传感器数据,以便提供健康或运动相关功能。'
|
||||||
|
},
|
||||||
|
'android.permission.ACTIVITY_RECOGNITION': {
|
||||||
|
title: '活动识别权限申请说明',
|
||||||
|
content: '应用需要访问您的活动状态,以便提供运动检测等功能。'
|
||||||
|
},
|
||||||
|
'android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS': {
|
||||||
|
title: '电池优化忽略权限申请说明',
|
||||||
|
content: '应用需要忽略电池优化,以便在后台稳定运行。'
|
||||||
|
},
|
||||||
|
'android.permission.FOREGROUND_SERVICE': {
|
||||||
|
title: '前台服务权限申请说明',
|
||||||
|
content: '应用需要运行前台服务,以便提供持续运行的功能,如音乐播放、导航等。'
|
||||||
|
},
|
||||||
|
'android.permission.SYSTEM_ALERT_WINDOW': {
|
||||||
|
title: '悬浮窗权限申请说明',
|
||||||
|
content: '应用需要显示悬浮窗,以便提供浮动窗口功能,如聊天气泡、屏幕录制等。'
|
||||||
|
},
|
||||||
|
'android.permission.WRITE_SETTINGS': {
|
||||||
|
title: '系统设置修改权限申请说明',
|
||||||
|
content: '应用需要修改系统设置,以便调整亮度、铃声等个性化配置。'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**如果有不符合或缺少对应权限的提示信息,可以自己进行扩展**
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createRequestPermissionListener } from '@/uni_modules/colorful-uni-perm';
|
||||||
|
|
||||||
|
createRequestPermissionListener({
|
||||||
|
'android.permission.CAMERA': {
|
||||||
|
title: '相机权限申请说明',
|
||||||
|
content: '应用需要访问您的相机,以便拍摄照片或扫描二维码。',
|
||||||
|
},
|
||||||
|
'android.permission.ACCESS_COARSE_LOCATION': {
|
||||||
|
title: '定位权限申请说明',
|
||||||
|
content: '应用需要获取您的大致位置信息,以便提供基于位置的服务。',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注意
|
||||||
|
|
||||||
|
只能监听通过 uniapp 或 plus 提供的权限申请时弹出提示,如果你使用原生的权限申请操作,无法监听到!
|
||||||
|
|
||||||
|
所以,如果你是使用原生的权限申请操作,在使用权限前请主动使用以下方法请求权限
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { permissionUtil } from '@/uni_modules/colorful-uni-perm';
|
||||||
|
|
||||||
|
permissionUtil.requestAndroidPermission('android.permission.CAMERA').then((status) => {
|
||||||
|
// status 为 1 表示用户已授权,0 表示用户已拒绝, -1 表示用户永久拒绝
|
||||||
|
console.log('权限申请结果:', status);
|
||||||
|
});
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user