diff --git a/.env.development b/.env.development index ec141c0a..acccd2fd 100644 --- a/.env.development +++ b/.env.development @@ -6,7 +6,7 @@ ENV = 'development' # VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001' -VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001' +#VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002' # VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002' @@ -14,7 +14,7 @@ VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001' # VITE_APP_BASE_API_Url = 'http://aitscdn.jlbank.com.cn:7001' # VITE_APP_BASE_API_Url = 'http://192.168.108.129' # dev -#VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001' +VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001' # sit #VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786' diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json index e4668703..15f11888 100644 --- a/.hbuilderx/launch.json +++ b/.hbuilderx/launch.json @@ -2,7 +2,7 @@ "version" : "1.0", "configurations" : [ { - "playground" : "standard", + "playground" : "custom", "type" : "uni-app:app-android" }, { diff --git a/src/App.vue b/src/App.vue index 5b1d72d2..df02f786 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,6 @@ + \ No newline at end of file diff --git a/src/common/app-permission.js b/src/common/app-permission.js new file mode 100644 index 00000000..954263ce --- /dev/null +++ b/src/common/app-permission.js @@ -0,0 +1,306 @@ +let popupView = null // 窗口实例 +export function showModal(info) { + const title = info && info.title ? info.title : '标题' + const content = info && info.content ? info.content : '请输入内容' + let screenWidth = plus.screen.resolutionWidth + let screenHeight = plus.screen.resolutionHeight + const popupViewWidth = screenWidth * 0.85 + const viewContentPadding = 20 // 减小内边距 + const viewContentWidth = parseInt(popupViewWidth - (viewContentPadding * 2)) + const descriptionList = drawtext(content, viewContentWidth) + let popupViewHeight = 60 + 20 + 20 // 减小整体高度 + let popupViewContentList = [{ + tag: 'font', + id: 'title', + text: title, + textStyles: { + size: '18px', + color: "#333333", + weight: "bold", + whiteSpace: "normal" + }, + position: { + top: '25px', // 调整标题位置 + left: viewContentPadding + "px", + width: viewContentWidth + "px", + height: "25px", + } + }] + + const textHeight = 24 // 调整行高 + let contentTop = 60 // 调整内容起始位置 + + descriptionList.forEach((item, index) => { + if (index > 0) { + popupViewHeight += textHeight; + contentTop += textHeight; + } + popupViewContentList.push({ + tag: 'font', + id: 'content' + index + 1, + text: item.content, + textStyles: { + size: '15px', + color: "#666666", + lineSpacing: "50%", // 调整行间距 + align: "left" + }, + position: { + top: contentTop + "px", + left: viewContentPadding + "px", + width: viewContentWidth + "px", + height: textHeight + "px", + } + }); + if (item.type == "break") { + contentTop += 8; // 减小段落间距 + popupViewHeight += 8; + } + }) + + popupView = new plus.nativeObj.View("popupView", { + tag: "rect", + top: "80px", // 固定在靠近顶部的位置 + left: (screenWidth - popupViewWidth) / 2 + "px", + height: popupViewHeight + "px", + width: popupViewWidth + "px" + }) + + // 绘制主体背景 + popupView.drawRect({ + color: "#FFFFFF", + radius: "12px", + borderWidth: "1px", + borderColor: "#E5E5E5" + }, { + top: "0px", + height: popupViewHeight + "px", + }) + + popupView.draw(popupViewContentList) + popupView.show() +} + + +function closeModal() { + // 在不再需要 popupView 时关闭它 + popupView && popupView.close(); + popupView = null; +} + +// 文字换行 +function drawtext(text, maxWidth) { + let textArr = text.split(""); + let len = textArr.length; + // 上个节点 + let previousNode = 0; + // 记录节点宽度 + let nodeWidth = 0; + // 文本换行数组 + let rowText = []; + // 如果是字母,侧保存长度 + let letterWidth = 0; + // 汉字宽度 + let chineseWidth = 14; + // otherFont宽度 + let otherWidth = 7; + for (let i = 0; i < len; i++) { + if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) { + if (letterWidth > 0) { + if (nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth) { + rowText.push({ + type: "text", + content: text.substring(previousNode, i) + }); + previousNode = i + nodeWidth = chineseWidth + letterWidth = 0 + } else { + nodeWidth += chineseWidth + letterWidth * otherWidth + letterWidth = 0 + } + } else { + if (nodeWidth + chineseWidth > maxWidth) { + rowText.push({ + type: "text", + content: text.substring(previousNode, i) + }) + previousNode = i + nodeWidth = chineseWidth + } else { + nodeWidth += chineseWidth + } + } + } else { + if (/\n/g.test(textArr[i])) { + rowText.push({ + type: "break", + content: text.substring(previousNode, i) + }) + previousNode = i + 1 + nodeWidth = 0 + letterWidth = 0 + } else if (textArr[i] == "\\" && textArr[i + 1] == "n") { + rowText.push({ + type: "break", + content: text.substring(previousNode, i) + }) + previousNode = i + 2 + nodeWidth = 0 + letterWidth = 0 + } else if (/[a-zA-Z0-9]/g.test(textArr[i])) { + letterWidth += 1; + if (nodeWidth + letterWidth * otherWidth > maxWidth) { + rowText.push({ + type: "text", + content: text.substring(previousNode, i + 1 - letterWidth) + }) + previousNode = i + 1 - letterWidth + nodeWidth = letterWidth * otherWidth + letterWidth = 0 + } + } else { + if (nodeWidth + otherWidth > maxWidth) { + rowText.push({ + type: "text", + content: text.substring(previousNode, i) + }); + previousNode = i + nodeWidth = otherWidth + } else { + nodeWidth += otherWidth + } + } + } + } + if (previousNode < len) { + rowText.push({ + type: "text", + content: text.substring(previousNode, len) + }) + } + return rowText +} + + + +//权限检测 +export function requestPermissions(info) { + const permissionID = info.permissionID + console.log(info,permissionID) + return new Promise((rev, jec) => { + if (!permissionID) { + rev({ + isSuc: false, + msg: "缺少permissionID" + }) + return false + } + //判断安卓与ios设备 + if (plus.os.name == 'Android') { + let _permissionID = 'android.permission.' + permissionID; + plus.android.checkPermission(_permissionID, + granted => { + console.log(granted) + if (granted.checkResult == 0) { + rev({ + isSuc: true + }) + } + if (granted.checkResult == -1) { + //还未授权当前查询的权限,打开权限申请目的自定义弹框 + closeModal() // 先关闭再弹窗 + showModal(info) + plus.android.requestPermissions([_permissionID], + (e) => { + console.log(e) + //关闭权限申请目的自定义弹框 + if (e.granted.length > 0) { + closeModal() + //当前查询权限已授权,此时可以通知页面执行接下来的操作 + rev({ + isSuc: true + }) + } + if (e.deniedPresent.length > 0) { + closeModal() + //当前查询权限已授权,此时可以通知页面执行接下来的操作 + rev({ + isSuc: false, + msg: "用户已拒绝" + }) + } + if (e.deniedAlways.length > 0) { + //当前查询权限已被永久禁用,此时需要引导用户跳转手机系统设置去开启 + uni.showModal({ + title: '温馨提示', + content: '还没有该权限,立即去设置开启?', + cancelText: "取消", + confirmText: "去设置", + showCancel: true, + confirmColor: '#000', + cancelColor: '#666', + success: (res) => { + if (res.confirm) { + goSetting(); + } + if (res.cancel) { + rev({ + isSuc: false, + msg: "取消前往权限设置页面" + }) + } + }, + fail(e) { + rev({ + isSuc: false, + msg: e.message || "弹窗失败" + }) + }, + complete() { + closeModal() + } + }) + } + }) + } + }, + error => { + rev({ + isSuc: false, + mes: error.message || '检查权限失败' + }) + } + ); + + } else { + //IOS不需要添加自定义弹框来描述权限目的,因为在配置文件的隐私信息访问的许可描述里可添加 + rev({ + isSuc: true + }) + } + }) +} +//跳转手机系统设置 +export function goSetting() { + if (plus.os.name == "iOS") { + var UIApplication = plus.ios.import("UIApplication"); + var application2 = UIApplication.sharedApplication(); + var NSURL2 = plus.ios.import("NSURL"); + var setting2 = NSURL2.URLWithString("app-settings:"); + application2.openURL(setting2); + plus.ios.deleteObject(setting2); + plus.ios.deleteObject(NSURL2); + plus.ios.deleteObject(application2); + } else { + var Intent = plus.android.importClass("android.content.Intent"); + var Settings = plus.android.importClass("android.provider.Settings"); + var Uri = plus.android.importClass("android.net.Uri"); + var mainActivity = plus.android.runtimeMainActivity(); + var intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + var uri = Uri.fromParts("package", mainActivity.getPackageName(), null); + intent.setData(uri); + mainActivity.startActivity(intent); + } +} \ No newline at end of file diff --git a/src/common/permission.js b/src/common/permission.js index 67164297..70571bd5 100644 --- a/src/common/permission.js +++ b/src/common/permission.js @@ -2,7 +2,13 @@ * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启 */ -var isIos +import common from '@/common/common.js' +import { + getPhoneEnvBool +} from '@/common/common.js' +const IsAndEnv = getPhoneEnvBool('AND') + +let isIos // #ifdef APP-PLUS isIos = (plus.os.name == "iOS") // #endif @@ -63,35 +69,90 @@ function judgeIosPermissionLocation() { // 判断麦克风权限是否开启 function judgeIosPermissionRecord() { - var result = false; - var avaudiosession = plus.ios.import("AVAudioSession"); - var avaudio = avaudiosession.sharedInstance(); - var permissionStatus = avaudio.recordPermission(); - console.log("permissionStatus:" + permissionStatus); - if (permissionStatus == 1684369017 || permissionStatus == 1970168948) { - console.log("麦克风权限没有开启"); - } else { - result = true; - console.log("麦克风权限已经开启"); - } - plus.ios.deleteObject(avaudiosession); - return result; + return new Promise(async (resolve, reject) => { + const authSetting = uni.getAppAuthorizeSetting(); + const state = authSetting.microphoneAuthorized; + console.log('麦克风state', state); + switch (state) { + case 'authorized': + console.log("麦克风权限是否开启"); + resolve() + break; + case 'denied': // ios拒绝,安卓拒绝或者未授权都是这个 + if (IsAndEnv) { // 安卓二次判定 + const result = await requestAndroidPermission('android.permission.RECORD_AUDIO') + if (result === 1) { + resolve() + break; + } + } + const resultT = await common.show( + '提示信息', + '当前页面需要使用录音权限,是否前往开启?' + ) + if (resultT) { + // 前往权限设置页面 + uni.openAppAuthorizeSetting(); + } + reject() + break; + case 'not determined': // 表示尚未请求授权,仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关 + resolve() + break; + case 'config error': // 只有在 App 端时返回 + resolve() + break; + default: + resolve() + break; + } + }) } + // 判断相机权限是否开启 function judgeIosPermissionCamera() { - var result = false; - var AVCaptureDevice = plus.ios.import("AVCaptureDevice"); - var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide'); - console.log("authStatus:" + authStatus); - if (authStatus == 3) { - result = true; - console.log("相机权限已经开启"); - } else { - console.log("相机权限没有开启"); - } - plus.ios.deleteObject(AVCaptureDevice); - return result; + + return new Promise(async (resolve, reject) => { + const authSetting = uni.getAppAuthorizeSetting(); + const state = authSetting.cameraAuthorized; + console.log('相机权限', state); + switch (state) { + case 'authorized': + console.log("相机权限已经开启"); + resolve() + break; + case 'denied': // ios拒绝,安卓拒绝或者未授权都是这个 + console.log('IsAndEnv', IsAndEnv); + if (IsAndEnv) { // 安卓二次判定 + const result = await requestAndroidPermission('android.permission.CAMERA') + console.log('安卓二次判定', result); + if (result === 1) { + resolve() + break; + } + } + const resultT = await common.show( + '提示信息', + '当前页面需要使用相机权限,是否前往开启?' + ) + if (resultT) { + // 前往权限设置页面 + uni.openAppAuthorizeSetting(); + } + reject() + break; + case 'not determined': // 表示尚未请求授权,仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关 + resolve() + break; + case 'config error': // 只有在 App 端时返回 + resolve() + break; + default: + resolve() + break; + } + }) } // 判断相册权限是否开启 @@ -264,9 +325,11 @@ function checkSystemEnableLocation() { } } -export default ({ - judgeIosPermission: judgeIosPermission, - requestAndroidPermission: requestAndroidPermission, - checkSystemEnableLocation: checkSystemEnableLocation, - gotoAppPermissionSetting: gotoAppPermissionSetting -}) + + +export default { + judgeIosPermission, + requestAndroidPermission, + checkSystemEnableLocation, + gotoAppPermissionSetting +} \ No newline at end of file diff --git a/src/components/examination/subject.vue b/src/components/examination/subject.vue index f193d26a..392a171c 100644 --- a/src/components/examination/subject.vue +++ b/src/components/examination/subject.vue @@ -194,19 +194,11 @@ watch( () => props.modelValue, (newVal) => { - console.log('modelValue', newVal); + // console.log('modelValue', newVal); item_answer.value = typeof newVal === 'string' ? newVal.split(',') : newVal; }, { deep: true } ); - // watch( - // item_answer, - // (newVal) => { - // console.log('item_answer', newVal); - // emit('update:modelValue', newVal); - // }, - // { deep: true } - // ); const feedback_click = () => { emit('subject_click', 'feedback', props.item); diff --git a/src/manifest.json b/src/manifest.json index 3a5e9a32..686c8548 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -33,8 +33,8 @@ /* 模块配置 */ "modules" : { "Camera" : { - "description": "用于访问摄像头进行实时预览" - }, + "description" : "用于访问摄像头进行实时预览" + }, "Barcode" : {}, "Record" : {}, "VideoPlayer" : {}, @@ -66,16 +66,16 @@ /* ios打包配置 */ "ios" : { "dSYMs" : false, - "deploymentTarget": "11.0", - "privacyDescription": { - "NSCameraUsageDescription": "此应用需要访问您的摄像头来进行视频录制和拍照功能", - "NSMicrophoneUsageDescription": "此应用需要访问您的麦克风来录制音频" - }, - "capabilities": { - "entitlements": { - "com.apple.developer.avfoundation.multitasking-camera-access": true - } - } + "deploymentTarget" : "11.0", + "privacyDescription" : { + "NSCameraUsageDescription" : "此应用需要访问您的摄像头来进行视频录制和拍照功能", + "NSMicrophoneUsageDescription" : "此应用需要访问您的麦克风来录制音频" + }, + "capabilities" : { + "entitlements" : { + "com.apple.developer.avfoundation.multitasking-camera-access" : true + } + } }, /* SDK配置 */ "sdkConfigs" : {}, diff --git a/src/pages/competition/pk.vue b/src/pages/competition/pk.vue index d7807f7e..8efad330 100644 --- a/src/pages/competition/pk.vue +++ b/src/pages/competition/pk.vue @@ -147,6 +147,7 @@ const pkData = reactive({ comLimit: 0, crsId: '', + comId: '', name: '', // 名称 orgId: '', papersId: '', @@ -247,7 +248,7 @@ traQnsInfoVo = res.body.traQnsInfoVo; } topic.value.isPreview = true; // 不能在点击了,打开预览模式 - console.log('给出来的traQnsInfoVo', traQnsInfoVo); + // console.log('给出来的traQnsInfoVo', traQnsInfoVo); common.hideLoading(); topic.value.clearResult = false; // 不清除正确答案 topic.value.analyContent = traQnsInfoVo.analyContent; // 答案解析 @@ -257,7 +258,6 @@ topic.value.judgeResult = traQnsInfoVo.judgeResult; // 正确答案字符串分割 if (questionNumber.value >= topicList.length - 1) { - console.log('pk页答完了,带走的数据', pkData); common.setPageCache('competition_pk_to_resulf', pkData); nextTick(() => { common.redirectTo( @@ -418,7 +418,7 @@ } nextTick(() => { common.redirectTo( - `/pages/competition/result?mode=${mode}&execId=${pkData.execId}&orgId=${pkData.orgId}&papersId=${pkData.papersId}&autoSub=01` + `/pages/competition/result?mode=${mode}&execId=${pkData.execId}&orgId=${pkData.orgId}&papersId=${pkData.papersId}&autoSub=01&comId=${pkData.comId}` ); }); diff --git a/src/pages/pointsAndRank/badge.vue b/src/pages/pointsAndRank/badge.vue index cc0c9dc0..1ef23d38 100644 --- a/src/pages/pointsAndRank/badge.vue +++ b/src/pages/pointsAndRank/badge.vue @@ -68,7 +68,7 @@ {{ detailedInfo.badgeName }} {{ detailedInfo.remark }} - {{ detailedInfo.obtainTm }} + 获得时间:{{ detailedInfo.obtainTm }} { @@ -54,15 +55,12 @@ export default function useWebSocket(aaas = null, options = {}) { } }); ws.value.onOpen((res) => { - console.log('onOpen', finalAuthParams); ws.value.send({ data: ProtocolCodec.pack(MessageType.IDENTITY, finalAuthParams) }); }); ws.value.onError((err) => onError(err)) - - ws.value.onClose((err) => { console.log('onClose', err); onClose(err) diff --git a/src/pages/sparring/talk.vue b/src/pages/sparring/talk.vue index 7e67f9ef..42e699ab 100644 --- a/src/pages/sparring/talk.vue +++ b/src/pages/sparring/talk.vue @@ -3,7 +3,7 @@ - + {{ formattedTime }} @@ -28,9 +28,29 @@