diff --git a/tra-app/.env.development b/tra-app/.env.development
index f235ef7..27b8fd6 100644
--- a/tra-app/.env.development
+++ b/tra-app/.env.development
@@ -3,9 +3,11 @@ ENV = 'development'
# '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'
# VITE_APP_BASE_API_Url = 'http://192.168.247.200'
@@ -17,6 +19,7 @@ VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
#VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
+
# UAT
# VITE_APP_BASE_API_Url = 'http://25.18.122.78:9786'
@@ -30,6 +33,17 @@ VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
# h5专用地址x2
# VITE_APP_BASE_H5_API_Url_TRAAPP = 'http://25.64.32.150:9601'
# dev
-# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
+#VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
+
# sit
-#VITE_APP_BASE_H5_API_Url = 'http://25.18.122.91:9786'
\ No newline at end of file
+# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.91:9786'
+
+# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.78:9786'
+
+# VITE_APP_BASE_H5_API_Url_TRAAPP = 'http://25.64.16.130:9601'
+# VITE_APP_BASE_H5_API_Url_TRASTUDY = 'http://25.64.16.130:9602'
+
+# VITE_APP_BASE_H5_API_Url_TRAASK = 'http://25.64.16.144:9605'
+#VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.16.139:9604'
+
+
diff --git a/tra-app/.env.development.yh b/tra-app/.env.development.yh
index 193ce29..95d4857 100644
--- a/tra-app/.env.development.yh
+++ b/tra-app/.env.development.yh
@@ -4,8 +4,8 @@ ENV = 'development.yh'
# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
-VITE_APP_BASE_H5_API_Url = 'http://25.18.122.91:9786'
-# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.78:9786'
+# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.91:9786'
+VITE_APP_BASE_H5_API_Url = 'http://25.18.122.78:9786'
# VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
# VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.32.154:9604'
# VITE_APP_BASE_H5_API_Url_TRAPRACTICE = 'http://25.64.32.156:9603'
diff --git a/tra-app/.npmrc b/tra-app/.npmrc
new file mode 100644
index 0000000..0c65878
--- /dev/null
+++ b/tra-app/.npmrc
@@ -0,0 +1,14 @@
+# 启用严格模式,确保依赖版本一致
+strict-peer-dependencies=false
+
+# 配置依赖安装目录(pnpm 特有,节省磁盘空间)
+store-dir=~/.pnpm-store
+
+# 兼容 uniapp 对依赖的查找逻辑
+node-linker=hoisted
+
+# 忽略废弃依赖警告
+ignore-deprecations=all
+
+# 忽略对等依赖警告
+strict-peer-dependencies=false
\ No newline at end of file
diff --git a/tra-app/src/App.vue b/tra-app/src/App.vue
index 63d8caf..df02f78 100644
--- a/tra-app/src/App.vue
+++ b/tra-app/src/App.vue
@@ -1,31 +1,34 @@
+
\ No newline at end of file
diff --git a/tra-app/src/api/socket.js b/tra-app/src/api/socket.js
index 0869f8d..2b304f9 100644
--- a/tra-app/src/api/socket.js
+++ b/tra-app/src/api/socket.js
@@ -86,7 +86,7 @@ export default class WebSocketUtil {
// console.log('WebSocket连接已关闭', res);
clearInterval(this.heartbeatTimer); // 清除心跳计时器
this.triggerEvent('close', res); // 触发连接关闭事件
- this.tryReconnect(); // 尝试重连
+ // this.tryReconnect(); // 尝试重连
});
// 监听WebSocket错误事件
@@ -106,7 +106,7 @@ export default class WebSocketUtil {
*/
on(event, callback) {
if (this.callbacks[event]) {
- this.callbacks[event].push(callback);
+ this.callbacks[event] = [callback];
}
return this;
}
diff --git a/tra-app/src/api/sparring.js b/tra-app/src/api/sparring.js
index 2b9c8f0..d34cc3e 100644
--- a/tra-app/src/api/sparring.js
+++ b/tra-app/src/api/sparring.js
@@ -62,6 +62,7 @@ export const partnerChatReportTrigger = (data) => {
export const partnerChatPrompt = (data) => {
return request({
url: base_url + '/traPartnerChat/partnerChatPrompt',
+ timeout: 60000,
method: 'post',
data
});
diff --git a/tra-app/src/common/app-permission.js b/tra-app/src/common/app-permission.js
new file mode 100644
index 0000000..954263c
--- /dev/null
+++ b/tra-app/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/tra-app/src/common/permission.js b/tra-app/src/common/permission.js
index 6716429..70571bd 100644
--- a/tra-app/src/common/permission.js
+++ b/tra-app/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/tra-app/src/components/examination/subject.vue b/tra-app/src/components/examination/subject.vue
index f193d26..392a171 100644
--- a/tra-app/src/components/examination/subject.vue
+++ b/tra-app/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/tra-app/src/components/markdown-preview/markdown-preview.vue b/tra-app/src/components/markdown-preview/markdown-preview.vue
index 0ce9ed5..27615af 100644
--- a/tra-app/src/components/markdown-preview/markdown-preview.vue
+++ b/tra-app/src/components/markdown-preview/markdown-preview.vue
@@ -24,7 +24,8 @@
watch:{
mdString: {
handler(val){
- this.contentHtml = this.parseContent(val)
+ let _text = val.replace(//g,'>')
+ this.contentHtml = this.parseContent(_text)
},
deep: true,
immediate: true
diff --git a/tra-app/src/manifest.json b/tra-app/src/manifest.json
index 0a4b6c0..686c854 100644
--- a/tra-app/src/manifest.json
+++ b/tra-app/src/manifest.json
@@ -32,7 +32,9 @@
},
/* 模块配置 */
"modules" : {
- "Camera" : {},
+ "Camera" : {
+ "description" : "用于访问摄像头进行实时预览"
+ },
"Barcode" : {},
"Record" : {},
"VideoPlayer" : {},
@@ -57,12 +59,23 @@
"",
"",
"",
- ""
+ "",
+ ""
]
},
/* ios打包配置 */
"ios" : {
- "dSYMs" : false
+ "dSYMs" : false,
+ "deploymentTarget" : "11.0",
+ "privacyDescription" : {
+ "NSCameraUsageDescription" : "此应用需要访问您的摄像头来进行视频录制和拍照功能",
+ "NSMicrophoneUsageDescription" : "此应用需要访问您的麦克风来录制音频"
+ },
+ "capabilities" : {
+ "entitlements" : {
+ "com.apple.developer.avfoundation.multitasking-camera-access" : true
+ }
+ }
},
/* SDK配置 */
"sdkConfigs" : {},
diff --git a/tra-app/src/pages.json b/tra-app/src/pages.json
index 68ecbeb..690c298 100644
--- a/tra-app/src/pages.json
+++ b/tra-app/src/pages.json
@@ -590,6 +590,7 @@
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"navigationStyle": "custom",
+ "screenOrientation": "portrait",
"app-plus": {
"titleView": false,
"bounce": "none",
diff --git a/tra-app/src/pages/analytics/study.vue b/tra-app/src/pages/analytics/study.vue
index 42a3cf6..cd94d9d 100644
--- a/tra-app/src/pages/analytics/study.vue
+++ b/tra-app/src/pages/analytics/study.vue
@@ -16,6 +16,8 @@
:current="currentTab" class="font_pf my_tabs"
:inactive-style="{ color: '#333333', fontSize: '28rpx', fontWeight: '500' }"
:activeStyle="{ color: '#333333', fontSize: '28rpx', fontWeight: '600' }">
+
+
@@ -107,36 +109,36 @@
-
+
-
+
{{item.title}}
{{item.content}}
-
+
-
+
{{item.title}}
{{item.content}}
-
+
-
-
+
+
{{suggestObj.content}}
-
+
-
+
暂无数据
@@ -225,26 +227,57 @@
}
}
const loading = ref(false)
+ const loading1 = ref(false)
+ const loading2 = ref(false)
+ const loading3 = ref(false)
+ const loading4 = ref(false)
+ const overLoading = computed(()=>{
+ return !loading.value && !loading1.value && !loading2.value && !loading3.value && !loading4.value
+ })
+ const showToast = () => {
+ common.msg('学习分析生成中,请稍后再试!')
+ }
const getInfoNow = async (params) => {
+ statisticsObj.value = []
+ dimesionList.value =[]
loading.value = true
- try {
- let _res1 = await queryStudyStatistics(params)
+ loading2.value = true
+ loading1.value = true
+ loading3.value = true
+ queryStudyStatistics(params).then(_res1 => {
statisticsObj.value = {
..._res1.body
}
- let _res2 = await queryDimesionInfo(params)
+ loading.value = false
+ }).catch(() => {
+ loading.value = false
+ })
+ queryDimesionInfo(params).then(_res2 => {
dimesionList.value = [..._res2.body]
- let _res3 = await queryHabitInfo(params)
+ loading1.value = false
+ }).catch(() => {
+ loading1.value = false
+ })
+ queryHabitInfo(params).then(_res3 => {
studyList.value = [..._res3.body]
- let _res4 = await querySuggestInfo(params)
+ loading2.value = false
+ }).catch(() => {
+ loading2.value = false
+ })
+ querySuggestInfo(params).then(_res4 => {
if (_res4.body && _res4.body.length > 0) {
suggestObj.value = {
..._res4.body[0]
}
+ }else{
+ suggestObj.value = {
+ content: ''
+ }
}
- } catch {} finally {
- loading.value = false
- }
+ loading3.value = false
+ }).catch(() => {
+ loading3.value = false
+ })
}
// 跳转 课程详情
const toCourseDetail = item => {
@@ -263,9 +296,12 @@
}
const getCrsListNow = () => {
+ loading4.value = true
queryRecmdCrsInfo().then(res => {
- console.log(res)
courseList.value = res.body || []
+ loading4.value = false
+ }).catch(() => {
+ loading4.value = false
})
}
onMounted(() => {
@@ -377,8 +413,9 @@
backdrop-filter: blur(10rpx);
z-index: 1;
- &.loading-box-cont{
+ &.loading-box-cont {
background: #ddeafa;
+
&::before {
content: '';
display: block;
@@ -417,6 +454,17 @@
.tabs-box {
width: 600rpx;
+ height: 88rpx;
+ position: relative;
+ .tab-btn{
+ position: absolute;
+ width: 600rpx;
+ height: 88rpx;
+ top: 0;
+ left: 0;
+ z-index: 23;
+ // background-color: #ccc;
+ }
}
.analytics-items {
diff --git a/tra-app/src/pages/competition/pk.vue b/tra-app/src/pages/competition/pk.vue
index d7807f7..8efad33 100644
--- a/tra-app/src/pages/competition/pk.vue
+++ b/tra-app/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/tra-app/src/pages/course/components/talkingItem.vue b/tra-app/src/pages/course/components/talkingItem.vue
index 5cced8f..b5899af 100644
--- a/tra-app/src/pages/course/components/talkingItem.vue
+++ b/tra-app/src/pages/course/components/talkingItem.vue
@@ -694,7 +694,7 @@
voiceTime.value = (Math.ceil(talkVoiceObj.value.duration) || 0) + 's';
} else {
if (sum === 100) {
- voiceTime.value = 0 + 's';
+ voiceTime.value = (unref(dataInfo).voiceTime || 0) + 's';
return;
}
setTimeout(() => {
diff --git a/tra-app/src/pages/course/components/touchBtn.vue b/tra-app/src/pages/course/components/touchBtn.vue
index 3d1a24b..3bd0a45 100644
--- a/tra-app/src/pages/course/components/touchBtn.vue
+++ b/tra-app/src/pages/course/components/touchBtn.vue
@@ -174,6 +174,7 @@
const initRecord = () => {
recordObjCom.value = uni.getRecorderManager();
unref(recordObjCom)?.onStop((res, duration) => {
+ isRecording.value = false
if(isGettingPermission.value){
isGettingPermission.value = false
return
@@ -196,13 +197,20 @@
});
} else {
closeModel();
- emit('uploadVoice', audioPath.value);
+ emit('uploadVoice', audioPath.value, recordTime.value);
}
} else {
closeModel();
}
});
unref(recordObjCom).onStart(() => {
+ isRecording.value = true
+ recordTime.value = 0
+ setRecordTime()
+ if(isGettingPermission.value){
+ isGettingPermission.value = false
+ return
+ }
startFlag.value = 1;
setTimeout(() => {
startFlag.value = 2;
@@ -219,6 +227,16 @@
}
});
};
+ const setRecordTime = () => {
+ setTimeout(()=>{
+ if(isRecording.value){
+ recordTime.value += 1
+ setRecordTime()
+ }
+ },1000)
+ }
+ const isRecording = ref(false)
+ const recordTime = ref(0)
const startFlag = ref(1);
// const canStart = ref(true)
const startRecord = () => {
diff --git a/tra-app/src/pages/course/study.vue b/tra-app/src/pages/course/study.vue
index 9413450..62073b7 100644
--- a/tra-app/src/pages/course/study.vue
+++ b/tra-app/src/pages/course/study.vue
@@ -839,7 +839,7 @@ const testAnswer = computed(() => {
let _num = _arr.map(t => [1, 2, 6].indexOf(Number(t.type)) >= 0).filter(t => !!t)
return _num.length < 5
})
-const uploadRecordNow = voicePath => {
+const uploadRecordNow = (voicePath, voiceTime) => {
if (!testAnswer.value) {
common.msg('每个问题最多连续发送五次答案!')
return
@@ -911,7 +911,8 @@ const uploadRecordNow = voicePath => {
userInfo: {
...choiceTeacherInfo.value
},
- id: _id
+ id: _id,
+ voiceTime: voiceTime
}
} else {
return t
diff --git a/tra-app/src/pages/index/components/class_scroll.vue b/tra-app/src/pages/index/components/class_scroll.vue
index 10ea912..3925fac 100644
--- a/tra-app/src/pages/index/components/class_scroll.vue
+++ b/tra-app/src/pages/index/components/class_scroll.vue
@@ -1,4 +1,4 @@
-
+
@@ -13,23 +13,25 @@
-
-
+
+ {{ item.crsName }}
-
-
- {{ item.crsName }}
+
+
+
- 更新:{{ (item.mtTime || '').substr(0, 10) }}
-
+
+ 更新:{{ (item.mtTime || '').substr(0, 10) }}
已学:{{ item.accmStdyCnt }}人次
- 去学习
+
+ 去学习
+
@@ -115,8 +117,7 @@
}
];
const get_data = () => {
-
- class_list.value = [...init_class_data]
+ class_list.value = [...init_class_data];
fetchFunction().then((res) => {
if (props.name === 'hot_class') {
} else {
@@ -143,74 +144,78 @@
white-space: nowrap;
width: 100%;
}
-
+
.scroll-view-item {
display: inline-block;
margin-right: 30rpx;
background-color: #ffffff;
border-radius: 22rpx;
box-shadow: #eaeaea 0 0 6rpx;
- padding: 32rpx 20rpx 36rpx 34rpx;
+ padding: 20rpx 20rpx 36rpx 34rpx;
}
.item_div {
- // width: 562rpx;
width: calc(562rpx + 56rpx);
- // display: block;
}
.item {
display: flex;
width: calc(562rpx + 56rpx);
- .left {
- border-radius: 16rpx;
- overflow: hidden;
- width: 256rpx;
- height: 144rpx;
- .img {
+ flex-direction: column;
+ .title {
+ font-weight: 500;
+ font-size: 30rpx;
+ color: #333333;
+ margin-bottom: 10rpx;
+ width: 100%;
+ }
+ .content {
+ display: flex;
+ .left {
+ border-radius: 16rpx;
+ overflow: hidden;
width: 256rpx;
height: 144rpx;
- }
- }
-
- .right {
- overflow: hidden;
- flex: 1;
- padding-left: 16rpx;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- .title {
- font-weight: 500;
- font-size: 30rpx;
- color: #333333;
- line-height: 40rpx;
- }
- .note {
- font-family: PingFangSC, PingFang SC;
- font-weight: 400;
- font-size: 23rpx;
- color: #666666;
- line-height: 33rpx;
- text-align: left;
- font-style: normal;
+ .img {
+ width: 256rpx;
+ height: 144rpx;
+ }
}
- .button_div {
+ .right {
+ overflow: hidden;
+ flex: 1;
+ padding-left: 16rpx;
display: flex;
+ flex-direction: column;
justify-content: space-between;
- .button {
- text-align: center;
- line-height: 62rpx;
- width: 138rpx;
- height: 62rpx;
- background: #ebf1ff;
- border-radius: 30rpx;
- font-weight: 500;
- font-size: 30rpx;
- color: #0066ff;
+
+ .note {
+ font-family: PingFangSC, PingFang SC;
+ font-weight: 400;
+ font-size: 23rpx;
+ color: #666666;
+ line-height: 33rpx;
+ text-align: left;
font-style: normal;
- margin-right: 10rpx;
+ }
+
+ .button_div {
+ display: flex;
+ justify-content: flex-end;
+ .button {
+ text-align: center;
+ line-height: 62rpx;
+ width: 138rpx;
+ height: 62rpx;
+ background: #ebf1ff;
+ border-radius: 30rpx;
+ font-weight: 500;
+ font-size: 30rpx;
+ color: #0066ff;
+ font-style: normal;
+ margin-right: 10rpx;
+ }
}
}
}
@@ -221,7 +226,7 @@
display: flex;
margin: 30rpx $bg-margin-left;
align-items: center;
-
+
.icon {
margin-right: 6rpx;
}
@@ -249,7 +254,7 @@
height: 31rpx;
}
}
-
+
.title {
font-size: 34rpx;
color: #323e57;
diff --git a/tra-app/src/pages/index/components/question.vue b/tra-app/src/pages/index/components/question.vue
index d8623d8..1d59196 100644
--- a/tra-app/src/pages/index/components/question.vue
+++ b/tra-app/src/pages/index/components/question.vue
@@ -131,7 +131,7 @@ import { onUnload } from '@dcloudio/uni-app';
voiceTime.value = (Math.ceil(talkVoiceObj.value.duration) || 1 ) + 's'
}else{
if(sum === 20) {
- voiceTime.value = 0 + 's'
+ voiceTime.value = (unref(dataInfo).voiceTime || 0) + 's';
return
}
setTimeout(()=>{
diff --git a/tra-app/src/pages/index/dialog.vue b/tra-app/src/pages/index/dialog.vue
index 4d0f6bc..1dfdd62 100644
--- a/tra-app/src/pages/index/dialog.vue
+++ b/tra-app/src/pages/index/dialog.vue
@@ -662,7 +662,7 @@
submitAnswerNow(item);
};
// 发送语音
- const uploadRecordNow = (voicePath) => {
+ const uploadRecordNow = (voicePath, voiceTime) => {
// /traask/traAskchat/voiceTrans
//#ifndef APP-PLUS
// h5 假数据
@@ -683,7 +683,8 @@
intrctContent: _res.body.transContent,
bucketKey: _res.body.fileId,
ossFileAddr: _res.body.ossFileAddr,
- talkingVoice: voicePath
+ talkingVoice: voicePath,
+ voiceTime: voiceTime
};
sendMessage({
commond: 'ASK',
@@ -791,6 +792,9 @@
initsocketTask();
};
onLoad(() => {
+ //#ifdef APP-PLUS
+ plus.screen.lockOrientation('portrait-primary')
+ // #endif
changeAppHeightBottom();
if (!common.isLogin()) {
common.navigateTo('/pages/login/login');
@@ -919,6 +923,14 @@
font-weight: 500;
color: #000;
position: relative;
+ .top-desc{
+ position: absolute;
+ bottom: -10rpx;
+ font-size: 18rpx;
+ color: #999;
+ left: 50%;
+ transform: translateX(-50%);
+ }
.top-desc{
position: absolute;
diff --git a/tra-app/src/pages/pointsAndRank/badge.vue b/tra-app/src/pages/pointsAndRank/badge.vue
index 93dc713..1ef23d3 100644
--- a/tra-app/src/pages/pointsAndRank/badge.vue
+++ b/tra-app/src/pages/pointsAndRank/badge.vue
@@ -42,7 +42,7 @@
-
+
-
+
diff --git a/tra-app/src/pages/preview/components/previewAiSparring.vue b/tra-app/src/pages/preview/components/previewAiSparring.vue
index 9451638..d3ade40 100644
--- a/tra-app/src/pages/preview/components/previewAiSparring.vue
+++ b/tra-app/src/pages/preview/components/previewAiSparring.vue
@@ -64,6 +64,7 @@
traId: item.traId
}).then(res=>{
if(res.body.inRange){
+ // todo
common.navigateTo('/pages/sparring/detail?traId=' + item.traId + '&isPreview=1')
}else{
common.show(res.body.message)
diff --git a/tra-app/src/pages/setting/index.vue b/tra-app/src/pages/setting/index.vue
index 3e2fab4..c47bfaf 100644
--- a/tra-app/src/pages/setting/index.vue
+++ b/tra-app/src/pages/setting/index.vue
@@ -23,6 +23,7 @@
+
-
+
-
+
@@ -16,7 +16,7 @@
:isAnswering="props.isAnswering" @handleEvents="handleEvents" :activeVoiceId="activeVoiceId">
-
+
回答提示
@@ -131,11 +131,19 @@
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/detail.vue b/tra-app/src/pages/sparring/detail.vue
index 1bb1291..e64fb57 100644
--- a/tra-app/src/pages/sparring/detail.vue
+++ b/tra-app/src/pages/sparring/detail.vue
@@ -18,7 +18,8 @@
已陪练次数:{{ detailInfo.practiceTimes }}
类型:{{ detailInfo.traInterTypDesc }}
- 截止时间:{{detailInfo.limitTyp === '01' ? '不限制' : detailInfo.endTm}}
+ 截止时间:{{detailInfo.limitTyp === '01' ? '不限制' : detailInfo.endTm}}
+ 通过分数:{{detailInfo.passGrade || 0}} 分
@@ -62,14 +63,13 @@
@click="previewFile(item)"> {{ item.dataName }}.{{ item.dataSuffix }}
-
-
-
+
去练习
去考试
+
+ 去考试
+
@@ -296,6 +296,9 @@
display: inline-block;
width: 50%;
margin-bottom: 15rpx;
+ &.full{
+ width: 100%;
+ }
}
&-tags {
@@ -358,6 +361,9 @@
margin-left: 36rpx;
background: #06f;
color: #fff;
+ &.no-margin{
+ margin-left: 0;
+ }
}
}
}
@@ -388,7 +394,8 @@
font-size: 28rpx;
line-height: 52rpx;
color: #333;
-
+ white-space: pre-line;
+
&-file {
color: #06f;
}
diff --git a/tra-app/src/pages/sparring/index.vue b/tra-app/src/pages/sparring/index.vue
index d620118..c80502d 100644
--- a/tra-app/src/pages/sparring/index.vue
+++ b/tra-app/src/pages/sparring/index.vue
@@ -18,7 +18,7 @@
:inactive-style="{ color: '#333333', fontSize: '30rpx', fontWeight: '500' }"
:activeStyle="{ color: '#333333', fontSize: '30rpx', fontWeight: '600' }">
diff --git a/tra-app/src/pages/sparring/js/ProtocolCodec.ts b/tra-app/src/pages/sparring/js/ProtocolCodec.ts
index 3beeeb5..c114cd0 100644
--- a/tra-app/src/pages/sparring/js/ProtocolCodec.ts
+++ b/tra-app/src/pages/sparring/js/ProtocolCodec.ts
@@ -60,10 +60,8 @@ export enum CompressionType {
* 控制指令枚举(配合 MessageType.CONTROL_CMD 使用)
*/
export enum ControlCommand {
- HEARTBEAT = 0b0001,
- PAUSE = 0b0010,
- RESUME = 0b0011,
- STOP = 0b0100,
+ START_PLAY = 0b0001, // 一句话播放开始
+ FINISH_PLAY = 0b0010, // 一句话播放结束
}
/**
@@ -171,7 +169,6 @@ export class ProtocolCodec {
// STRING 序列化:必须传入字符串(非 PING 消息已校验非空)
serializedBody = textEncoder.encode(body as string);
break;
-
case SerializationType.JSON:
// 断言:body 是 string 或 object
if (typeof body === 'string') {
diff --git a/tra-app/src/pages/sparring/js/processor.worklet.js b/tra-app/src/pages/sparring/js/processor.worklet.js
new file mode 100644
index 0000000..05d2977
--- /dev/null
+++ b/tra-app/src/pages/sparring/js/processor.worklet.js
@@ -0,0 +1,300 @@
+! function() {
+ "use strict";
+
+ function t(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object
+ .defineProperty(t, (i = n.key, o = void 0, "symbol" == typeof(o = function(t, e) {
+ if ("object" != typeof t || null === t) return t;
+ var r = t[Symbol.toPrimitive];
+ if (void 0 !== r) {
+ var n = r.call(t, e || "default");
+ if ("object" != typeof n) return n;
+ throw new TypeError("@@toPrimitive must return a primitive value.")
+ }
+ return ("string" === e ? String : Number)(t)
+ }(i, "string")) ? o : String(o)), n)
+ }
+ var i, o
+ }
+
+ function e(t) {
+ return e = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function(t) {
+ return t.__proto__ || Object.getPrototypeOf(t)
+ }, e(t)
+ }
+
+ function r(t, e) {
+ return r = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(t, e) {
+ return t.__proto__ = e, t
+ }, r(t, e)
+ }
+
+ function n() {
+ if ("undefined" == typeof Reflect || !Reflect.construct) return !1;
+ if (Reflect.construct.sham) return !1;
+ if ("function" == typeof Proxy) return !0;
+ try {
+ return Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], (function() {}))), !0
+ } catch (t) {
+ return !1
+ }
+ }
+
+ function i(t, e, o) {
+ return i = n() ? Reflect.construct.bind() : function(t, e, n) {
+ var i = [null];
+ i.push.apply(i, e);
+ var o = new(Function.bind.apply(t, i));
+ return n && r(o, n.prototype), o
+ }, i.apply(null, arguments)
+ }
+
+ function o(t) {
+ var n = "function" == typeof Map ? new Map : void 0;
+ return o = function(t) {
+ if (null === t || (o = t, -1 === Function.toString.call(o).indexOf("[native code]"))) return t;
+ var o;
+ if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
+ if (void 0 !== n) {
+ if (n.has(t)) return n.get(t);
+ n.set(t, a)
+ }
+
+ function a() {
+ return i(t, arguments, e(this).constructor)
+ }
+ return a.prototype = Object.create(t.prototype, {
+ constructor: {
+ value: a,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), r(a, t)
+ }, o(t)
+ }
+
+ function a(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t
+ }
+
+ function s(t) {
+ var r = n();
+ return function() {
+ var n, i = e(t);
+ if (r) {
+ var o = e(this).constructor;
+ n = Reflect.construct(i, arguments, o)
+ } else n = i.apply(this, arguments);
+ return function(t, e) {
+ if (e && ("object" == typeof e || "function" == typeof e)) return e;
+ if (void 0 !== e) throw new TypeError(
+ "Derived constructors may only return object or undefined");
+ return a(t)
+ }(this, n)
+ }
+ }
+
+ function f(t) {
+ return function(t) {
+ if (Array.isArray(t)) return u(t)
+ }(t) || function(t) {
+ if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"]) return Array
+ .from(t)
+ }(t) || function(t, e) {
+ if (!t) return;
+ if ("string" == typeof t) return u(t, e);
+ var r = Object.prototype.toString.call(t).slice(8, -1);
+ "Object" === r && t.constructor && (r = t.constructor.name);
+ if ("Map" === r || "Set" === r) return Array.from(t);
+ if ("Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)) return u(t, e)
+ }(t) || function() {
+ throw new TypeError(
+ "Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+ )
+ }()
+ }
+
+ function u(t, e) {
+ (null == e || e > t.length) && (e = t.length);
+ for (var r = 0, n = new Array(e); r < e; r++) n[r] = t[r];
+ return n
+ }
+
+ function l(t, e, r, n) {
+ this.fromSampleRate = t, this.toSampleRate = e, this.channels = 0 | r, this.noReturn = !!n, this.initialize()
+ }
+ l.prototype.initialize = function() {
+ if (!(this.fromSampleRate > 0 && this.toSampleRate > 0 && this.channels > 0)) throw new Error(
+ "Invalid settings specified for the resampler.");
+ this.fromSampleRate == this.toSampleRate ? (this.resampler = this.bypassResampler, this.ratioWeight = 1) : (
+ this.fromSampleRate < this.toSampleRate ? (this.lastWeight = 1, this.resampler = this
+ .compileLinearInterpolation) : (this.tailExists = !1, this.lastWeight = 0, this.resampler = this
+ .compileMultiTap), this.ratioWeight = this.fromSampleRate / this.toSampleRate)
+ }, l.prototype.compileLinearInterpolation = function(t) {
+ var e = t.length;
+ this.initializeBuffers(e);
+ var r, n, i = this.outputBufferSize,
+ o = this.ratioWeight,
+ a = this.lastWeight,
+ s = 0,
+ f = 0,
+ u = 0,
+ l = this.outputBuffer;
+ if (e % this.channels == 0) {
+ if (e > 0) {
+ for (; a < 1; a += o)
+ for (s = 1 - (f = a % 1), r = 0; r < this.channels; ++r) l[u++] = this.lastOutput[r] * s + t[
+ r] * f;
+ for (a--, e -= this.channels, n = Math.floor(a) * this.channels; u < i && n < e;) {
+ for (s = 1 - (f = a % 1), r = 0; r < this.channels; ++r) l[u++] = t[n + r] * s + t[n + this
+ .channels + r] * f;
+ a += o, n = Math.floor(a) * this.channels
+ }
+ for (r = 0; r < this.channels; ++r) this.lastOutput[r] = t[n++];
+ return this.lastWeight = a % 1, this.bufferSlice(u)
+ }
+ return this.noReturn ? 0 : []
+ }
+ throw new Error("Buffer was of incorrect sample length.")
+ }, l.prototype.compileMultiTap = function(t) {
+ var e = [],
+ r = t.length;
+ this.initializeBuffers(r);
+ var n = this.outputBufferSize;
+ if (r % this.channels == 0) {
+ if (r > 0) {
+ for (var i = this.ratioWeight, o = 0, a = 0; a < this.channels; ++a) e[a] = 0;
+ var s = 0,
+ f = 0,
+ u = !this.tailExists;
+ this.tailExists = !1;
+ var l = this.outputBuffer,
+ h = 0,
+ c = 0;
+ do {
+ if (u)
+ for (o = i, a = 0; a < this.channels; ++a) e[a] = 0;
+ else {
+ for (o = this.lastWeight, a = 0; a < this.channels; ++a) e[a] += this.lastOutput[a];
+ u = !0
+ }
+ for (; o > 0 && s < r;) {
+ if (!(o >= (f = 1 + s - c))) {
+ for (a = 0; a < this.channels; ++a) e[a] += t[s + a] * o;
+ c += o, o = 0;
+ break
+ }
+ for (a = 0; a < this.channels; ++a) e[a] += t[s++] * f;
+ c = s, o -= f
+ }
+ if (0 != o) {
+ for (this.lastWeight = o, a = 0; a < this.channels; ++a) this.lastOutput[a] = e[a];
+ this.tailExists = !0;
+ break
+ }
+ for (a = 0; a < this.channels; ++a) l[h++] = e[a] / i
+ } while (s < r && h < n);
+ return this.bufferSlice(h)
+ }
+ return this.noReturn ? 0 : []
+ }
+ throw new Error("Buffer was of incorrect sample length.")
+ }, l.prototype.bypassResampler = function(t) {
+ return this.noReturn ? (this.outputBuffer = t, t.length) : t
+ }, l.prototype.bufferSlice = function(t) {
+ if (this.noReturn) return t;
+ try {
+ return this.outputBuffer.subarray(0, t)
+ } catch (e) {
+ try {
+ return this.outputBuffer.length = t, this.outputBuffer
+ } catch (e) {
+ return this.outputBuffer.slice(0, t)
+ }
+ }
+ }, l.prototype.initializeBuffers = function(t) {
+ this.outputBufferSize = Math.ceil(t * this.toSampleRate / this.fromSampleRate);
+ try {
+ this.outputBuffer = new Float32Array(this.outputBufferSize), this.lastOutput = new Float32Array(this
+ .channels)
+ } catch (t) {
+ this.outputBuffer = [], this.lastOutput = []
+ }
+ };
+ var h = function(e) {
+ ! function(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError(
+ "Super expression must either be null or a function");
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ writable: !0,
+ configurable: !0
+ }
+ }), Object.defineProperty(t, "prototype", {
+ writable: !1
+ }), e && r(t, e)
+ }(h, e);
+ var n, i, o, u = s(h);
+
+ function h() {
+ var t;
+ ! function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, h);
+ var e = a(t = u.call(this));
+ return t.port.onmessage = function(t) {
+ var r = t.data,
+ n = r.type,
+ i = r.data;
+ if (console.log("type", n), "init" === n) {
+ var o = i.frameSize,
+ a = i.toSampleRate,
+ s = i.arrayBufferType,
+ f = i.fromSampleRate;
+ return e.frameSize = o * Math.floor(f / a), e.resampler = new l(f, a, 1), e
+ .frameBuffer = [], void(e.arrayBufferType = s),e.gain = i.gain || 1.0;
+ }
+ "stop" === n && (e.port.postMessage({
+ frameBuffer: e.transData(e.frameBuffer),
+ isLastFrame: !0
+ }), e.frameBuffer = [])
+ }, t
+ }
+ return n = h, (i = [{
+ key: "process",
+ value: function(t) {
+ var e, r = t[0][0];
+ return this.frameSize ? ((e = this.frameBuffer).push.apply(e, f(r)), this
+ .frameBuffer.length >= this.frameSize && (this.port.postMessage({
+ frameBuffer: this.transData(this.frameBuffer),
+ isLastFrame: !1
+ }), this.frameBuffer = []), !0) : (r && this.port.postMessage({
+ frameBuffer: this.transData(r),
+ isLastFrame: !1
+ }), !0)
+ }
+ }, {
+ key: "transData",
+ value: function(t) {
+ const gain = this.gain; // 增益系数,可根据实际需求修改
+ t = t.map(sample => sample * gain); // 对每个样本应用增益
+ return "short16" === this.arrayBufferType && (t = function(t) {
+ for (var e = new ArrayBuffer(2 * t.length), r = new DataView(e), n = 0,
+ i = 0; i < t.length; i += 1, n += 2) {
+ var o = Math.max(-1, Math.min(1, t[i]));
+ r.setInt16(n, o < 0 ? 32768 * o : 32767 * o, !0)
+ }
+ return r.buffer
+ }(t = this.resampler.resampler(t))), t
+ }
+ }]) && t(n.prototype, i), o && t(n, o), Object.defineProperty(n, "prototype", {
+ writable: !1
+ }), h
+ }(o(AudioWorkletProcessor));
+ registerProcessor("processor-worklet", h)
+}();
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/js/useMicrophone.js b/tra-app/src/pages/sparring/js/useMicrophone.js
deleted file mode 100644
index af6863c..0000000
--- a/tra-app/src/pages/sparring/js/useMicrophone.js
+++ /dev/null
@@ -1,149 +0,0 @@
-import {
- ref,
- onUnmounted,
- watch
-} from 'vue';
- import {
- ProtocolCodec,
- MessageType,
- SerializationType,
- CompressionType,
- ControlCommand,
- ProtocolConst
- } from './ProtocolCodec';
-/**
- * 麦克风操作Hook(封装开始/停止录音、状态管理)
- * @param {Object} options - 录音配置项
- * @param {number} options.duration - 最大录音时长(秒,默认60)
- * @param {string} options.format - 录音格式(mp3/wav/pcm,默认mp3)
- * @param {number} options.sampleRate - 采样率(默认16000)
- * @param {number} options.bitRate - 码率(默认16000)
- * @param {Function} options.onData - 实时音频数据回调(仅H5/PCM格式生效)
- * @param {Function} options.onStop - 结束回调
- * @param {Function} options.onError - 错误回调
- * @returns {Object} 录音控制方法+状态
- */
-export default function useMicrophone(options = {}) {
- console.log('options', options);
- const send = options.send
- const recordFrame = ref(null)
- const renderJSModule = ref(null)
-
- // 默认配置
- const defaultOptions = {
- duration: 60,
- format: 'mp3',
- sampleRate: 16000,
- bitRate: 16000,
- onData: () => {},
- onStop: () => {},
- onError: (err) => console.error('录音错误:', err)
- };
- const finalOptions = {
- ...defaultOptions,
- ...options
- };
-
- // 响应式状态
- const isRecording = ref(false); // 是否正在录音
- const recordTime = ref(0); // 录音时长(秒)
- const recordResult = ref(null); // 录音结果(临时文件路径/Blob)
- const recorderManager = ref(null); // 录音管理器实例(uniapp/小程序)
- const audioContext = ref(null); // AudioContext(H5)
- const mediaRecorder = ref(null); // MediaRecorder(H5)
- const timer = ref(null); // 录音时长定时器
-
- // 平台判断
- const platform = uni.getSystemInfoSync().platform;
-
- // ==================== 核心方法:开始录音 ====================
- const startRecording = async () => {
- // 防止重复点击
- if (isRecording.value) return;
-
- // 重置状态
- recordTime.value = 0;
- recordResult.value = null;
- console.log('开始', recordFrame.value);
- recordFrame.value.start({
- sampleRate: 16000,
- frameSize: 1024,
- gain: 1.0,
- onFrameRecorded: ({ isLastFrame, frameBuffer }) => {
- // console.log('录音返回', frameBuffer);
- const data = ProtocolCodec.pack(MessageType.AUDIO_DATA, frameBuffer)
- // console.log('录音返回', data);
- send(data)
- // try {
- // ws.value.send({
- // data: ProtocolCodec.pack(MessageType.AUDIO_DATA, frameBuffer)
- // });
- // } catch (e) {}
- },
- onDecibels: (decibels) => {
- // this.currentDecibels = decibels;
- }
- });
- // this.isRecording = true;
- // this.status = '录音中...';
- // isRecording.value = true;
-
- };
-
- // ==================== 核心方法:停止录音 ====================
- const stopRecord = () => {
- // if (!isRecording.value) return;
-
- // try {
- // if (isH5) {
- // mediaRecorder.value?.stop();
- // } else if (isMiniProgram || platform === 'app-plus') {
- // recorderManager.value?.stop();
- // }
- // isRecording.value = false;
- // clearInterval(timer.value);
- // } catch (err) {
- // finalOptions.onError(`停止录音失败:${err.message}`);
- // }
- };
-
- // ==================== 资源清理 ====================
- const cleanup = () => {
- // stopRecord();
- // // H5端额外清理
- // if (isH5) {
- // if (mediaRecorder.value) mediaRecorder.value = null;
- // if (audioContext.value) audioContext.value.close();
- // // 释放Blob URL
- // if (recordResult.value?.url) {
- // URL.revokeObjectURL(recordResult.value.url);
- // }
- // }
- // // 小程序/APP端清理
- // if (recorderManager.value) recorderManager.value = null;
- };
-
- // 组件卸载时自动清理
- // onUnmounted(() => {
- // cleanup();
- // });
-
- // 监听最大时长,自动停止
- // watch(
- // () => recordTime.value,
- // (val) => {
- // if (val >= finalOptions.duration) {
- // stopRecord();
- // }
- // }
- // );
-
- // 返回控制方法+状态
- return {
-
- isRecording,
- renderJSModule,
- startRecording,
- recordFrame
- };
-};
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/js/useSpeaker.js b/tra-app/src/pages/sparring/js/useSpeaker.js
deleted file mode 100644
index 568ca08..0000000
--- a/tra-app/src/pages/sparring/js/useSpeaker.js
+++ /dev/null
@@ -1,129 +0,0 @@
-import {
- ref,
- onUnmounted,
- watch
-} from 'vue';
-
-/**
- * 扬声器管理Hook(音频输出)
- * @param {Object} options - 播放配置
- * @param {number} options.sampleRate - 播放采样率(默认16000,需与音频源一致)
- * @param {number} options.volume - 初始音量(0~1,默认1)
- * @param {boolean} options.autoPlay - 是否自动播放(默认false,需用户交互触发)
- * @param {Function} options.onPlay - 播放开始回调
- * @param {Function} options.onError - 播放错误回调
- * @returns {Object} 播放控制方法+状态
- */
-export const useSpeaker = (options = {}) => {
- // 默认配置
- const defaultOptions = {
- sampleRate: 16000,
- volume: 1.0,
- autoPlay: false,
- onPlay: () => {},
- onError: (err) => console.error('扬声器播放错误:', err)
- };
- const finalOptions = {
- ...defaultOptions,
- ...options
- };
-
- // 响应式状态
- const isPlaying = ref(false); // 是否正在播放
- const volume = ref(finalOptions.volume); // 播放音量(0~1)
- const audioContext = ref(null); // 音频播放上下文(H5)
- const audioBufferSource = ref(null); // 音频缓冲源(播放PCM流)
- const audioElement = ref(null); // 音频元素(播放文件/URL)
- const playQueue = ref([]); // 音频数据播放队列(适配实时流)
-
- // 平台判断
- const isH5 = uni.getSystemInfoSync().platform === 'h5';
-
- // ==================== 初始化播放上下文 ====================
- const initAudioContext = () => {
-
- };
-
- // ==================== 核心方法:播放PCM音频流(实时) ====================
- /**
- * 播放PCM音频数据(适配WebSocket传输的实时流)
- * @param {ArrayBuffer} pcmData - PCM音频数据(16位单声道)
- */
- const playPCM = (pcmData) => {
-
-
-
- };
-
- // ==================== 控制方法:暂停/停止/调节音量 ====================
- const pausePlay = () => {
- if (!isPlaying.value) return;
-
- if (isH5) {
- if (audioBufferSource.value) {
- audioBufferSource.value.stop();
- audioBufferSource.value = null;
- }
- audioElement.value?.pause();
- } else {
- uni.createInnerAudioContext().pause();
- }
- isPlaying.value = false;
- };
-
- const stopPlay = () => {
- pausePlay();
- playQueue.value = []; // 清空播放队列
- if (audioContext.value) {
- audioContext.value.close().then(() => {
- audioContext.value = null;
- });
- }
- audioElement.value = null;
- };
-
- const setVolume = (val) => {
- if (val < 0) val = 0;
- if (val > 1) val = 1;
- volume.value = val;
-
- if (isH5) {
- audioContext.value?.destination.setVolume(val);
- audioElement.value.volume = val;
- } else {
- uni.createInnerAudioContext().volume = val;
- }
- };
-
- // ==================== 资源清理 ====================
- const cleanup = () => {
- stopPlay();
- isPlaying.value = false;
- volume.value = finalOptions.volume;
- playQueue.value = [];
- };
-
- // 组件卸载时自动清理
- onUnmounted(() => {
- cleanup();
- });
-
- // 监听音量变化,同步更新
- watch(volume, (newVal) => {
- setVolume(newVal);
- });
-
- // 返回控制方法+状态
- return {
- // 响应式状态
- isPlaying, // 是否正在播放
- volume, // 当前音量(0~1)
- // 核心方法
- playPCM, // 播放实时PCM音频流(适配WebSocket)
- playAudio, // 播放音频文件/URL
- pausePlay, // 暂停播放
- stopPlay, // 停止播放
- setVolume, // 调节音量(0~1)
- cleanup // 手动清理资源
- };
-};
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/js/useWebSocket.js b/tra-app/src/pages/sparring/js/useWebSocket.js
index c5d5d02..0b7cd92 100644
--- a/tra-app/src/pages/sparring/js/useWebSocket.js
+++ b/tra-app/src/pages/sparring/js/useWebSocket.js
@@ -22,8 +22,8 @@ const DEFAULT_AUTH_PARAMS = {
user_id: '1001', // 默认用户ID(可从缓存/全局状态取)
token: '', // 优先从缓存获取,避免硬编码
name: '测试用户',
- device_id: uni.getSystemInfoSync().deviceId || '', // 设备ID(补充)
- timestamp: Date.now() // 时间戳(防篡改)
+ // device_id: uni.getSystemInfoSync().deviceId || '', // 设备ID(补充)
+ // timestamp: Date.now() // 时间戳(防篡改)
};
// const wsUrl = 'ws://127.0.0.1:8000/ws/audio'
const url = '/trapractice/voiceCallSocket/voiceCall'
@@ -31,23 +31,27 @@ const _baseUrl = get_base_url(url).split('http').join('ws')
export default function useWebSocket(aaas = null, options = {}) {
const isRecording = ref(false) //是否接通
const ws = ref(null)
- const initConnection = (authParams = {}, onStartRecord, sssssss) => {
+ const initConnection = ({
+ authParams = {},
+ onStartRecord,
+ playPcmCallback,
+ setPlayNumber = () => {}, //设置当前播放的音频的id,用于播放完成回调
+ onError = () => {},
+ onClose = () => {},
+ }) => {
const wsUrl = _baseUrl + url + '?summary=' + getToken()
- console.log('wsUrl', wsUrl);
const finalAuthParams = {
...DEFAULT_AUTH_PARAMS,
...authParams,
};
+
ws.value = uni.connectSocket({
url: wsUrl,
fail: () => {
- console.log('fail');
+ // console.log('fail');
},
success: () => {
- console.log('web');
- },
- fail: () => {
- console.log('fail');
+ // console.log('web');
}
});
ws.value.onOpen((res) => {
@@ -55,12 +59,20 @@ export default function useWebSocket(aaas = null, options = {}) {
data: ProtocolCodec.pack(MessageType.IDENTITY, finalAuthParams)
});
});
+ ws.value.onError((err) => onError(err))
+
+ ws.value.onClose((err) => {
+ console.log('onClose', err);
+ onClose(err)
+ });
+
ws.value.onMessage((res) => {
const {
msgType,
body
} = ProtocolCodec.unpack(res.data);
switch (msgType) {
+
case MessageType.IDENTITY:
console.log('身份校验', body);
onStartRecord(body)
@@ -70,16 +82,41 @@ export default function useWebSocket(aaas = null, options = {}) {
if (buffer.byteLength < 2) break;
const uint8 = new Uint8Array(buffer);
const numArray = Array.from(uint8);
- // currentPCMChunk.value = numArray;
- sssssss(numArray)
- // console.log('音频消息', body);
+ playPcmCallback(numArray)
break;
case MessageType.ERROR:
+ switch (body.errCode) {
+ case 1:
+ // ASR或TTS初始化出错
+ console.log('后端返回的错误', body.errMsg);
- // this.handleErrorMessage(body);
+ case 4:
+ console.log('通话接通失败', body.errMsg);
+ // 通话接通失败,请稍后再试!
+ ws.value.close({
+ code: 4001,
+ reason: body.errMsg
+ })
+ break;
+ default:
+ // 其他错误码的默认处理(如果需要)
+ // ws.value.close({
+ // code: 1001,
+ // reason: body.errMsg
+ // })
+ break;
+ }
+ break;
+ case MessageType.CONTROL_CMD:
+ // 控制消息
+ console.log('控制消息', msgType, body);
+ if (body.type === 1) { // 开始播放,记录当前播放的语音id
+ console.log('开始播放,记录当前播放的语音id', body.lock);
+ setPlayNumber(body.lock)
+ }
break;
default:
- console.log('其他消息', body);
+ console.log('其他消息', msgType, body);
break;
}
});
@@ -89,6 +126,7 @@ export default function useWebSocket(aaas = null, options = {}) {
data
});
}
+
const close = () => {
ws.value.close({
code: 1000,
diff --git a/tra-app/src/pages/sparring/result.vue b/tra-app/src/pages/sparring/result.vue
index 7227ae3..5e5ea52 100644
--- a/tra-app/src/pages/sparring/result.vue
+++ b/tra-app/src/pages/sparring/result.vue
@@ -41,12 +41,12 @@
+ :activeVoiceId="activeVoiceTalkingItemId" @handleEvents="talkItemEvents" :showVoice="isTalking">
+ :activeVoiceId="activeVoiceTalkingItemId" @handleEvents="talkItemEvents" :showVoice="isTalking">
@@ -210,6 +210,7 @@
const negativeList = ref([]) // 劣质话术
const positiveList = ref([]) // 劣质话术
const isLoading = ref(false)
+ const isTalking = ref(true)
const getData = () => {
isLoading.value = true
partnerChatReport({
@@ -228,6 +229,7 @@
positiveList.value = res.body.positiveList || []
negativeList.value = res.body.negativeList || []
hitBanWords.value = res.body.traPartnerExecuteHisVo?.hitBanWords || ''
+ isTalking.value = res.body.traPartnerExecuteHisVo?.traInterTyp === '01'
let _evalDimens = res.body.traPartnerSettlement || []
evalDimens.value = _evalDimens.map((t, index) => {
return {
@@ -294,8 +296,7 @@
const isOver = ref(false)
const goBack = () => {
if (isOver.value) {
- console.log(3)
- common.navigateBack(3)
+ common.navigateBack(2)
} else {
common.navigateBack()
}
@@ -642,6 +643,7 @@
.item-cont {
font-size: 28rpx;
line-height: 50rpx;
+ white-space: pre-line;
}
}
@@ -671,7 +673,7 @@
font-size: 66rpx;
color: #06f;
font-family: Arial, Helvetica, sans-serif;
- marign-bottom: 20rpx;
+ // marign-bottom: 20rpx;
}
.static-desc {
@@ -698,5 +700,8 @@
:deep(.uv-tabs__wrapper__nav__item) {
padding: 0 20rpx !important;
}
+ :deep(.uv-tabs__wrapper__nav__item__text){
+ white-space: nowrap;
+ }
}
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/talk.vue b/tra-app/src/pages/sparring/talk.vue
index fcbeecb..5f22780 100644
--- a/tra-app/src/pages/sparring/talk.vue
+++ b/tra-app/src/pages/sparring/talk.vue
@@ -1,16 +1,18 @@
-
-
+
+
-
- 场景提示
-
+
+
+
+ {{ formattedTime }}
+ 正在接通中
-
- {{ dataInfo.userName }}
+
+ {{ dataInfo.chaName }}
{{ formattedTime }}
正在接通中
@@ -21,132 +23,253 @@
-
+
+
+
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/talk1.vue b/tra-app/src/pages/sparring/talk1.vue
deleted file mode 100644
index 913cc10..0000000
--- a/tra-app/src/pages/sparring/talk1.vue
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
-
-
-
- 预热
- 开始推流
- 暂停推流
- 恢复推流
- 停止推流
- 快照
- 开启摄像头预览
- 关闭摄像头预览
- 切换摄像头
-
-
-
-
-
diff --git a/tra-app/src/pages/sparring/talk3.vue b/tra-app/src/pages/sparring/talk3.vue
deleted file mode 100644
index e50d99b..0000000
--- a/tra-app/src/pages/sparring/talk3.vue
+++ /dev/null
@@ -1,182 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/tra-app/src/pages/sparring/talk4.vue b/tra-app/src/pages/sparring/talk4.vue
deleted file mode 100644
index ff6c494..0000000
--- a/tra-app/src/pages/sparring/talk4.vue
+++ /dev/null
@@ -1,492 +0,0 @@
-
-
-
-
-
-
- 场景提示
-
-
-
-
-
- {{ userInfo.userName }}
- {{ timeShow }}
- 正在接通中
-
-
-
- {{ sceneDesc }}
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tra-app/src/pages/sparring/talkCom.nvue b/tra-app/src/pages/sparring/talkCom.nvue
deleted file mode 100644
index ad0e5d1..0000000
--- a/tra-app/src/pages/sparring/talkCom.nvue
+++ /dev/null
@@ -1,158 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tra-app/src/pages/sparring/tip.vue b/tra-app/src/pages/sparring/tip.vue
index 3ccb531..590dc95 100644
--- a/tra-app/src/pages/sparring/tip.vue
+++ b/tra-app/src/pages/sparring/tip.vue
@@ -1,8 +1,7 @@
-
-
+
@@ -12,28 +11,38 @@
内容由AI生成
-
-
+
+
-
-
+
{{ detailInfo.chaName }}
{{ detailInfo.chaAge }}岁
-
-
-
-
+
+
- 预计时间: {{detailInfo.traStartLimit}} ~ {{detailInfo.traEndLimit}} 分钟
+
+ 预计时长: {{ detailInfo.traStartLimit }} ~ {{ detailInfo.traEndLimit }} 分钟
+
@@ -60,29 +69,52 @@
{{ detailInfo.sceneDesc }}
-
-
+ 陪练角色不具备主动终止场景陪练的功能,当用户完成预设陪练目标时,需由用户手动发起结束陪练操作。
+
+ -请点击下方按钮开始{{ detailInfo.traInterTypDesc }}
+
+
+
-
- 结束陪练
-
+ 结束陪练
-
+
-
-
+
+
- {{detailInfo.traInterTypDesc}}
+ {{ detailInfo.traInterTypDesc }}
@@ -93,92 +125,66 @@
@@ -689,7 +813,6 @@
width: 30rpx;
}
}
-
}
.role-desc {
@@ -755,7 +878,7 @@
.body-scene {
background: linear-gradient(209deg, #fefeff 0%, #d7dfff 100%);
- border: 2rpx solid rgba(255, 255, 255, .65);
+ border: 2rpx solid rgba(255, 255, 255, 0.65);
position: relative;
line-height: 42rpx;
font-size: 29rpx;
@@ -776,9 +899,20 @@
text-align: center;
}
}
-
+ .talking-desc{
+ // padding-top: 24rpx;
+ padding: 24rpx 20rpx 0;
+ font-size: 24rpx;
+ // text-align: center;
+ color: #999;
+ }
.talking-box {
padding-top: 24rpx;
+ .tip-text {
+ color: #7295cb;
+ text-align: center;
+ font-size: 29rpx;
+ }
}
}
@@ -842,4 +976,4 @@
}
}
}
-
\ No newline at end of file
+
diff --git a/tra-app/src/pages/test/CameraPreview.nvue b/tra-app/src/pages/test/CameraPreview.nvue
new file mode 100644
index 0000000..f1f4b3b
--- /dev/null
+++ b/tra-app/src/pages/test/CameraPreview.nvue
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tra-app/src/pages/test/CameraPreview1.vue b/tra-app/src/pages/test/CameraPreview1.vue
new file mode 100644
index 0000000..1fae4ee
--- /dev/null
+++ b/tra-app/src/pages/test/CameraPreview1.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tra-app/src/pages/test/index.vue b/tra-app/src/pages/test/index.vue
index 85bfd02..281077f 100644
--- a/tra-app/src/pages/test/index.vue
+++ b/tra-app/src/pages/test/index.vue
@@ -23,6 +23,7 @@
diff --git a/tra-app/src/pages/test/testChat.vue b/tra-app/src/pages/test/testChat.vue
index 02d0a00..336c20c 100644
--- a/tra-app/src/pages/test/testChat.vue
+++ b/tra-app/src/pages/test/testChat.vue
@@ -1,236 +1,38 @@
-
-
-
- {{ status }}
- 当前分贝:{{ currentDecibels }}
-
-
- xx
-
-
+
+
+
+
+
+
+
+
+
-
-
-
\ No newline at end of file
+
diff --git a/tra-app/src/pages/test/testChat2.vue b/tra-app/src/pages/test/testChat2.vue
deleted file mode 100644
index e250a7d..0000000
--- a/tra-app/src/pages/test/testChat2.vue
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
-
-
-
- 预热
- 开始推流
- 暂停推流
- 恢复推流
- 停止推流
- 快照
- 开启摄像头预览
- 关闭摄像头预览
- 切换摄像头
-
-
-
-
-
diff --git a/tra-app/src/pages/test/testChat2vue b/tra-app/src/pages/test/testChat2vue
new file mode 100644
index 0000000..6543709
--- /dev/null
+++ b/tra-app/src/pages/test/testChat2vue
@@ -0,0 +1,762 @@
+
+
+
+
+
+
+
+
+
+
+ 摄像头预览
+ ● 预览中
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 预览功能
+
+
+ 📷
+ 点击开始预览体验摄像头功能
+
+
+
+
+
+
+
+ 预览设置
+ ✕
+
+
+
+
+ 显示设置
+
+
+ 方向模式
+
+
+ {{ orientationOptions[orientationIndex] }}
+ ▼
+
+
+
+
+
+ 画面比例
+
+
+ {{ aspectOptions[aspectIndex] }}
+ ▼
+
+
+
+
+
+
+ 美化设置
+
+
+ 美颜等级: {{ beautyLevel }}
+
+
+
+
+ 美白等级: {{ whiteLevel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 💡 提示:预览功能仅用于查看摄像头画面,不会产生任何推流或录制
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tra-app/src/pages/test/testChat3.vue b/tra-app/src/pages/test/testChat3.vue
new file mode 100644
index 0000000..e69a2c2
--- /dev/null
+++ b/tra-app/src/pages/test/testChat3.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/tra-app/src/pagesOther.json b/tra-app/src/pagesOther.json
index 3b5f6d2..26d9972 100644
--- a/tra-app/src/pagesOther.json
+++ b/tra-app/src/pagesOther.json
@@ -103,6 +103,7 @@
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"navigationStyle": "custom",
+ "screenOrientation": "portrait",
"app-plus": {
"titleView": false,
"bounce": "none",
diff --git a/tra-app/src/static/js/processor.worklet.js b/tra-app/src/static/js/processor.worklet.js
new file mode 100644
index 0000000..05d2977
--- /dev/null
+++ b/tra-app/src/static/js/processor.worklet.js
@@ -0,0 +1,300 @@
+! function() {
+ "use strict";
+
+ function t(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object
+ .defineProperty(t, (i = n.key, o = void 0, "symbol" == typeof(o = function(t, e) {
+ if ("object" != typeof t || null === t) return t;
+ var r = t[Symbol.toPrimitive];
+ if (void 0 !== r) {
+ var n = r.call(t, e || "default");
+ if ("object" != typeof n) return n;
+ throw new TypeError("@@toPrimitive must return a primitive value.")
+ }
+ return ("string" === e ? String : Number)(t)
+ }(i, "string")) ? o : String(o)), n)
+ }
+ var i, o
+ }
+
+ function e(t) {
+ return e = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function(t) {
+ return t.__proto__ || Object.getPrototypeOf(t)
+ }, e(t)
+ }
+
+ function r(t, e) {
+ return r = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(t, e) {
+ return t.__proto__ = e, t
+ }, r(t, e)
+ }
+
+ function n() {
+ if ("undefined" == typeof Reflect || !Reflect.construct) return !1;
+ if (Reflect.construct.sham) return !1;
+ if ("function" == typeof Proxy) return !0;
+ try {
+ return Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], (function() {}))), !0
+ } catch (t) {
+ return !1
+ }
+ }
+
+ function i(t, e, o) {
+ return i = n() ? Reflect.construct.bind() : function(t, e, n) {
+ var i = [null];
+ i.push.apply(i, e);
+ var o = new(Function.bind.apply(t, i));
+ return n && r(o, n.prototype), o
+ }, i.apply(null, arguments)
+ }
+
+ function o(t) {
+ var n = "function" == typeof Map ? new Map : void 0;
+ return o = function(t) {
+ if (null === t || (o = t, -1 === Function.toString.call(o).indexOf("[native code]"))) return t;
+ var o;
+ if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
+ if (void 0 !== n) {
+ if (n.has(t)) return n.get(t);
+ n.set(t, a)
+ }
+
+ function a() {
+ return i(t, arguments, e(this).constructor)
+ }
+ return a.prototype = Object.create(t.prototype, {
+ constructor: {
+ value: a,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), r(a, t)
+ }, o(t)
+ }
+
+ function a(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t
+ }
+
+ function s(t) {
+ var r = n();
+ return function() {
+ var n, i = e(t);
+ if (r) {
+ var o = e(this).constructor;
+ n = Reflect.construct(i, arguments, o)
+ } else n = i.apply(this, arguments);
+ return function(t, e) {
+ if (e && ("object" == typeof e || "function" == typeof e)) return e;
+ if (void 0 !== e) throw new TypeError(
+ "Derived constructors may only return object or undefined");
+ return a(t)
+ }(this, n)
+ }
+ }
+
+ function f(t) {
+ return function(t) {
+ if (Array.isArray(t)) return u(t)
+ }(t) || function(t) {
+ if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"]) return Array
+ .from(t)
+ }(t) || function(t, e) {
+ if (!t) return;
+ if ("string" == typeof t) return u(t, e);
+ var r = Object.prototype.toString.call(t).slice(8, -1);
+ "Object" === r && t.constructor && (r = t.constructor.name);
+ if ("Map" === r || "Set" === r) return Array.from(t);
+ if ("Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)) return u(t, e)
+ }(t) || function() {
+ throw new TypeError(
+ "Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+ )
+ }()
+ }
+
+ function u(t, e) {
+ (null == e || e > t.length) && (e = t.length);
+ for (var r = 0, n = new Array(e); r < e; r++) n[r] = t[r];
+ return n
+ }
+
+ function l(t, e, r, n) {
+ this.fromSampleRate = t, this.toSampleRate = e, this.channels = 0 | r, this.noReturn = !!n, this.initialize()
+ }
+ l.prototype.initialize = function() {
+ if (!(this.fromSampleRate > 0 && this.toSampleRate > 0 && this.channels > 0)) throw new Error(
+ "Invalid settings specified for the resampler.");
+ this.fromSampleRate == this.toSampleRate ? (this.resampler = this.bypassResampler, this.ratioWeight = 1) : (
+ this.fromSampleRate < this.toSampleRate ? (this.lastWeight = 1, this.resampler = this
+ .compileLinearInterpolation) : (this.tailExists = !1, this.lastWeight = 0, this.resampler = this
+ .compileMultiTap), this.ratioWeight = this.fromSampleRate / this.toSampleRate)
+ }, l.prototype.compileLinearInterpolation = function(t) {
+ var e = t.length;
+ this.initializeBuffers(e);
+ var r, n, i = this.outputBufferSize,
+ o = this.ratioWeight,
+ a = this.lastWeight,
+ s = 0,
+ f = 0,
+ u = 0,
+ l = this.outputBuffer;
+ if (e % this.channels == 0) {
+ if (e > 0) {
+ for (; a < 1; a += o)
+ for (s = 1 - (f = a % 1), r = 0; r < this.channels; ++r) l[u++] = this.lastOutput[r] * s + t[
+ r] * f;
+ for (a--, e -= this.channels, n = Math.floor(a) * this.channels; u < i && n < e;) {
+ for (s = 1 - (f = a % 1), r = 0; r < this.channels; ++r) l[u++] = t[n + r] * s + t[n + this
+ .channels + r] * f;
+ a += o, n = Math.floor(a) * this.channels
+ }
+ for (r = 0; r < this.channels; ++r) this.lastOutput[r] = t[n++];
+ return this.lastWeight = a % 1, this.bufferSlice(u)
+ }
+ return this.noReturn ? 0 : []
+ }
+ throw new Error("Buffer was of incorrect sample length.")
+ }, l.prototype.compileMultiTap = function(t) {
+ var e = [],
+ r = t.length;
+ this.initializeBuffers(r);
+ var n = this.outputBufferSize;
+ if (r % this.channels == 0) {
+ if (r > 0) {
+ for (var i = this.ratioWeight, o = 0, a = 0; a < this.channels; ++a) e[a] = 0;
+ var s = 0,
+ f = 0,
+ u = !this.tailExists;
+ this.tailExists = !1;
+ var l = this.outputBuffer,
+ h = 0,
+ c = 0;
+ do {
+ if (u)
+ for (o = i, a = 0; a < this.channels; ++a) e[a] = 0;
+ else {
+ for (o = this.lastWeight, a = 0; a < this.channels; ++a) e[a] += this.lastOutput[a];
+ u = !0
+ }
+ for (; o > 0 && s < r;) {
+ if (!(o >= (f = 1 + s - c))) {
+ for (a = 0; a < this.channels; ++a) e[a] += t[s + a] * o;
+ c += o, o = 0;
+ break
+ }
+ for (a = 0; a < this.channels; ++a) e[a] += t[s++] * f;
+ c = s, o -= f
+ }
+ if (0 != o) {
+ for (this.lastWeight = o, a = 0; a < this.channels; ++a) this.lastOutput[a] = e[a];
+ this.tailExists = !0;
+ break
+ }
+ for (a = 0; a < this.channels; ++a) l[h++] = e[a] / i
+ } while (s < r && h < n);
+ return this.bufferSlice(h)
+ }
+ return this.noReturn ? 0 : []
+ }
+ throw new Error("Buffer was of incorrect sample length.")
+ }, l.prototype.bypassResampler = function(t) {
+ return this.noReturn ? (this.outputBuffer = t, t.length) : t
+ }, l.prototype.bufferSlice = function(t) {
+ if (this.noReturn) return t;
+ try {
+ return this.outputBuffer.subarray(0, t)
+ } catch (e) {
+ try {
+ return this.outputBuffer.length = t, this.outputBuffer
+ } catch (e) {
+ return this.outputBuffer.slice(0, t)
+ }
+ }
+ }, l.prototype.initializeBuffers = function(t) {
+ this.outputBufferSize = Math.ceil(t * this.toSampleRate / this.fromSampleRate);
+ try {
+ this.outputBuffer = new Float32Array(this.outputBufferSize), this.lastOutput = new Float32Array(this
+ .channels)
+ } catch (t) {
+ this.outputBuffer = [], this.lastOutput = []
+ }
+ };
+ var h = function(e) {
+ ! function(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError(
+ "Super expression must either be null or a function");
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ writable: !0,
+ configurable: !0
+ }
+ }), Object.defineProperty(t, "prototype", {
+ writable: !1
+ }), e && r(t, e)
+ }(h, e);
+ var n, i, o, u = s(h);
+
+ function h() {
+ var t;
+ ! function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, h);
+ var e = a(t = u.call(this));
+ return t.port.onmessage = function(t) {
+ var r = t.data,
+ n = r.type,
+ i = r.data;
+ if (console.log("type", n), "init" === n) {
+ var o = i.frameSize,
+ a = i.toSampleRate,
+ s = i.arrayBufferType,
+ f = i.fromSampleRate;
+ return e.frameSize = o * Math.floor(f / a), e.resampler = new l(f, a, 1), e
+ .frameBuffer = [], void(e.arrayBufferType = s),e.gain = i.gain || 1.0;
+ }
+ "stop" === n && (e.port.postMessage({
+ frameBuffer: e.transData(e.frameBuffer),
+ isLastFrame: !0
+ }), e.frameBuffer = [])
+ }, t
+ }
+ return n = h, (i = [{
+ key: "process",
+ value: function(t) {
+ var e, r = t[0][0];
+ return this.frameSize ? ((e = this.frameBuffer).push.apply(e, f(r)), this
+ .frameBuffer.length >= this.frameSize && (this.port.postMessage({
+ frameBuffer: this.transData(this.frameBuffer),
+ isLastFrame: !1
+ }), this.frameBuffer = []), !0) : (r && this.port.postMessage({
+ frameBuffer: this.transData(r),
+ isLastFrame: !1
+ }), !0)
+ }
+ }, {
+ key: "transData",
+ value: function(t) {
+ const gain = this.gain; // 增益系数,可根据实际需求修改
+ t = t.map(sample => sample * gain); // 对每个样本应用增益
+ return "short16" === this.arrayBufferType && (t = function(t) {
+ for (var e = new ArrayBuffer(2 * t.length), r = new DataView(e), n = 0,
+ i = 0; i < t.length; i += 1, n += 2) {
+ var o = Math.max(-1, Math.min(1, t[i]));
+ r.setInt16(n, o < 0 ? 32768 * o : 32767 * o, !0)
+ }
+ return r.buffer
+ }(t = this.resampler.resampler(t))), t
+ }
+ }]) && t(n.prototype, i), o && t(n, o), Object.defineProperty(n, "prototype", {
+ writable: !1
+ }), h
+ }(o(AudioWorkletProcessor));
+ registerProcessor("processor-worklet", h)
+}();
\ No newline at end of file
diff --git a/tra-app/vite.config.js b/tra-app/vite.config.js
deleted file mode 100644
index 08a24f3..0000000
--- a/tra-app/vite.config.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import {
- defineConfig
-} from 'vite'
-import uni from '@dcloudio/vite-plugin-uni'
-import path from 'path'
-export default defineConfig({
- plugins: [uni()],
- // 新增服务器配置,指定启动端口
- server: {
- port: 5174,
- strictPort: true, // 可选:端口被占用时直接报错(避免自动切换端口)
- open: false // 可选:启动后自动打开浏览器(按需开启)
- },
- base: './', // 关键:设置基础路径为相对路径
- build: {
- outDir: 'dist',
- assetsDir: 'assets' // 和打包后的目录一致
- }
-})
\ No newline at end of file
diff --git a/tra-app/上架信息/ios/新建文本文档.txt b/tra-app/上架信息/ios/新建文本文档.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/tra-app/上架信息/jax-prod-0.0.3-202510291539.apk b/tra-app/上架信息/jax-prod-0.0.3-202510291539.apk
deleted file mode 100644
index 6224794..0000000
Binary files a/tra-app/上架信息/jax-prod-0.0.3-202510291539.apk and /dev/null differ
diff --git a/tra-app/上架信息/logo/1024.png b/tra-app/上架信息/logo/1024.png
deleted file mode 100644
index e93a49e..0000000
Binary files a/tra-app/上架信息/logo/1024.png and /dev/null differ
diff --git a/tra-app/上架信息/logo/1024.zip b/tra-app/上架信息/logo/1024.zip
deleted file mode 100644
index 3a8a778..0000000
Binary files a/tra-app/上架信息/logo/1024.zip and /dev/null differ
diff --git a/tra-app/上架信息/logo/512.png b/tra-app/上架信息/logo/512.png
deleted file mode 100644
index d60aa96..0000000
Binary files a/tra-app/上架信息/logo/512.png and /dev/null differ
diff --git a/tra-app/上架信息/上架需要添加的信息.txt b/tra-app/上架信息/上架需要添加的信息.txt
deleted file mode 100644
index da16405..0000000
--- a/tra-app/上架信息/上架需要添加的信息.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-测试账号
- 账号:015169
- 密码:Aa111111
-
-隐私政策(URL):https://aits.jlbank.com.cn:7001/traapp/dfAgtInfo/queryValidDfAgtHtml
\ No newline at end of file
diff --git a/tra-app/上架信息/备案/ICP备案信息.xlsx b/tra-app/上架信息/备案/ICP备案信息.xlsx
deleted file mode 100644
index d01afea..0000000
Binary files a/tra-app/上架信息/备案/ICP备案信息.xlsx and /dev/null differ
diff --git a/tra-app/上架信息/备案/包名.txt b/tra-app/上架信息/备案/包名.txt
deleted file mode 100644
index 28f7ea9..0000000
--- a/tra-app/上架信息/备案/包名.txt
+++ /dev/null
@@ -1 +0,0 @@
-cn.com.jlbank.ai
\ No newline at end of file
diff --git a/tra-app/上架信息/备案/吉AI学APP签名MD5值与公钥信息.txt b/tra-app/上架信息/备案/吉AI学APP签名MD5值与公钥信息.txt
deleted file mode 100644
index e037751..0000000
--- a/tra-app/上架信息/备案/吉AI学APP签名MD5值与公钥信息.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-
-APP名称:吉AI学
-APP包名:cn.com.jlbank.ai
-versionName:0.0.5
-versionCode:5
-
-签名MD5值/证书MD5指纹(32位):
-d5dc64cddda525fe26b8ef248a2bb389
-
-公钥(十六进制 512位):
-9d972f990ca99f917a1f29b8e75ecab936f914a2577f867e401aab03661a00bdd50eb1e7f6cd48a6446eec5c26aaa121607b3bd81137178d696cb933835efc77d82b485309f0ddceb4673d0f8fe3b78b1e4b26767cf5a448ddfcba940f7ad1448d8406250dcc782a9b85d5c65c343e5d18bfc0bb15a53ec3a75d6ed07dabeee144a43f39924267a28c85749029b666dda9bfce8b9c026c9651c0ed41495de160ec394fdff8c9ec4b46d79238388c9aaef18c06a8b5fc5235eecea4e1a504105ef389ec9a99720d1d2695daa1f5eb020dc4a5072c1620edb2f5acd6c7c17813247fdcf4c9c22d3799e405a520768a85d0c198105d7955f19d15716c74251a862f
-
-公钥(十进制):
-19893966439922127693384889719938315036246244972917959385248316118565725143577774036887780362653488778541217930399876645058313599133123463497736546146477791544117358463680573389561564122662732863094890558191705481620786157835099824817072995429209906478607521681804646130325624863706603729124166653309099138828812936635381758248002921848461146778345641566513142267099505733743260834038131644946170268034014656863696128367747110259139002386246751925404899322985476977818658456537060869883795126190386613636784820986934886571172792850421551099690646290355407553479248915543674214152326021332306334646652057751589152785967
-
-SHA1值:
-de:f9:24:0c:b3:52:c1:8c:7b:af:12:00:2c:e3:89:f1:73:09:2c:8c
-
-
-以上信息来自,APP备案助手,下载链接 https://sj.qq.com/appdetail/cn.houapp.beian.zhushou,或者各大安卓应用市场搜索 APP备案助手 即可。
-
-
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqOBG7pYHgQ3wUf9pj6qA
-RvKSgNEnREQfZX58O5Zc6FhGO+CLX+GXXxgtLQ4b637YLHCS8KWQhlK3WIWjBOEP
-Kq3lVxjPrKqbBqFLMnvwR5DfWg3oEDn7pge+hDDuf+OjnqTzm+vCsivmKTrpyb/H
-9lbBfBU5+AqkNdqauAmJ/5Xx9f0Fj+xxSfgbHVxjcpiyjE6Bxa7ZGbzDzS2Gs0ND
-uhLKhCcM44Z9ht+1Pd9cd19vbfzfQOOcAkSXJd9k2SaoMW7Pq9/ftn+rdzkTjBty
-OO1F6wvtUQNgJferVWogsi4gVJY2wuqm36yO6ypw/TSWUMGOQnOVQsFzgelUUmdS
-sQIDAQAB
-
-
-
-keytool -exportcert -alias ai_jlyh_app -keystore ai_jlyh_app.keystore -file cert.cer
-
-
-
diff --git a/tra-app/上架信息/应用上架信息.xlsx b/tra-app/上架信息/应用上架信息.xlsx
deleted file mode 100644
index 134d12b..0000000
Binary files a/tra-app/上架信息/应用上架信息.xlsx and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 2.png b/tra-app/上架信息/应用截图/1242-2688/AI问答备份 2.png
deleted file mode 100644
index af50661..0000000
Binary files a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 2.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 3.png b/tra-app/上架信息/应用截图/1242-2688/AI问答备份 3.png
deleted file mode 100644
index c092573..0000000
Binary files a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 3.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 4.png b/tra-app/上架信息/应用截图/1242-2688/AI问答备份 4.png
deleted file mode 100644
index 4e8091b..0000000
Binary files a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 4.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 5.png b/tra-app/上架信息/应用截图/1242-2688/AI问答备份 5.png
deleted file mode 100644
index 7f063f1..0000000
Binary files a/tra-app/上架信息/应用截图/1242-2688/AI问答备份 5.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1242-2688/AI问答备份.png b/tra-app/上架信息/应用截图/1242-2688/AI问答备份.png
deleted file mode 100644
index df235d3..0000000
Binary files a/tra-app/上架信息/应用截图/1242-2688/AI问答备份.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1920-1080/1.png b/tra-app/上架信息/应用截图/1920-1080/1.png
deleted file mode 100644
index d54e2aa..0000000
Binary files a/tra-app/上架信息/应用截图/1920-1080/1.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1920-1080/2.png b/tra-app/上架信息/应用截图/1920-1080/2.png
deleted file mode 100644
index 1bc4e46..0000000
Binary files a/tra-app/上架信息/应用截图/1920-1080/2.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1920-1080/3.png b/tra-app/上架信息/应用截图/1920-1080/3.png
deleted file mode 100644
index dcdde04..0000000
Binary files a/tra-app/上架信息/应用截图/1920-1080/3.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1920-1080/4.png b/tra-app/上架信息/应用截图/1920-1080/4.png
deleted file mode 100644
index 40e909d..0000000
Binary files a/tra-app/上架信息/应用截图/1920-1080/4.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/1920-1080/5.png b/tra-app/上架信息/应用截图/1920-1080/5.png
deleted file mode 100644
index c2b5397..0000000
Binary files a/tra-app/上架信息/应用截图/1920-1080/5.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/2064-2752/1.png b/tra-app/上架信息/应用截图/2064-2752/1.png
deleted file mode 100644
index 6ed317c..0000000
Binary files a/tra-app/上架信息/应用截图/2064-2752/1.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/2064-2752/2.png b/tra-app/上架信息/应用截图/2064-2752/2.png
deleted file mode 100644
index 9bc1653..0000000
Binary files a/tra-app/上架信息/应用截图/2064-2752/2.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/2064-2752/3.png b/tra-app/上架信息/应用截图/2064-2752/3.png
deleted file mode 100644
index 3c7650d..0000000
Binary files a/tra-app/上架信息/应用截图/2064-2752/3.png and /dev/null differ
diff --git a/tra-app/上架信息/应用截图/2064-2752/4.png b/tra-app/上架信息/应用截图/2064-2752/4.png
deleted file mode 100644
index 40d858d..0000000
Binary files a/tra-app/上架信息/应用截图/2064-2752/4.png and /dev/null differ
diff --git a/tra-app/上架信息/软著/jax.jpg b/tra-app/上架信息/软著/jax.jpg
deleted file mode 100644
index fc0e67e..0000000
Binary files a/tra-app/上架信息/软著/jax.jpg and /dev/null differ
diff --git a/测试流式传输uniapp/js_sdk/gary-check/app-permission.js b/测试流式传输uniapp/js_sdk/gary-check/app-permission.js
new file mode 100644
index 0000000..954263c
--- /dev/null
+++ b/测试流式传输uniapp/js_sdk/gary-check/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/测试流式传输uniapp/js_sdk/gary-check/package.json b/测试流式传输uniapp/js_sdk/gary-check/package.json
new file mode 100644
index 0000000..7cc2afc
--- /dev/null
+++ b/测试流式传输uniapp/js_sdk/gary-check/package.json
@@ -0,0 +1,21 @@
+{
+ "id": "gary-check",
+ "name": "解决APP需要同步用户告知权限申请目的,导致安卓,华为,小米等上架被拒问题",
+ "displayName": "解决APP需要同步用户告知权限申请目的,导致安卓,华为,小米等上架被拒问题",
+ "version": "1.0.1",
+ "description": "超简单即可调用成功,JS单文件,解决APP需要同步用户告知权限申请目的,导致安卓,华为,小米等上架被拒问题",
+ "keywords": [
+ "华为,小米,上架,上架拒绝,拒绝,权限"
+ ],
+ "dcloudext": {
+ "type": "js_sdk",
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ }
+ }
+}
\ No newline at end of file