增加语音播放暂停功能

main
xushilin 3 months ago
parent 9fba96e374
commit 2e88029c58

@ -1,11 +1,38 @@
import request from '@/request'; import request from '@/request';
// 获取回复 // 获取回复
export const getAIResponse = (data) => request({ export const getAIResponse = (data) => request({
method : 'POST', method: 'POST',
url: '/api/chat', url: '/api/chat',
data data
}); });
export const getTextToAudio = (tex) => {
return new Promise(resolve => {
uni.request({
url: `https://tsn.baidu.com/text2audio`,
method: 'POST',
data : {
tex,
tok : '24.1c8cc30b5f7be445723b6d4b19a36152.2592000.1765094496.282335-120706844',
cuid : '17619124287472660978',
ctp : '1',
lan : 'zh',
spd : 5,
pit : 5,
vol : 5,
per : 0,
aue : 3
},
'headers': {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(res => {
console.log('res getBaiduToken ',res);
})
})
}

@ -1,25 +1,28 @@
import App from './App' import App from './App'
// #ifndef VUE3 // #ifndef VUE3
import Vue from 'vue' import Vue from 'vue'
import './uni.promisify.adaptor' import './uni.promisify.adaptor'
import store from './store' import store from './store'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$store = store Vue.prototype.$store = store;
App.mpType = 'app' App.mpType = 'app'
const app = new Vue({ const app = new Vue({
...App ...App
}) })
app.$mount() app.$mount()
// #endif // #endif
// #ifdef VUE3 // #ifdef VUE3
import { createSSRApp } from 'vue' import {
createSSRApp
} from 'vue'
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)
return { return {
app app
} }
} }
// #endif // #endif

@ -1,116 +1,116 @@
{ {
"name" : "萃星智能AI", "name": "萃星智能AI",
"appid" : "__UNI__5BDEDB4", "appid": "__UNI__5BDEDB4",
"description" : "", "description": "",
"versionName" : "1.0.1", "versionName": "1.0.1",
"versionCode" : 100, "versionCode": 100,
"transformPx" : false, "transformPx": false,
/* 5+App */ /* 5+App */
"app-plus" : { "app-plus": {
"usingComponents" : true, "usingComponents": true,
"nvueStyleCompiler" : "uni-app", "nvueStyleCompiler": "uni-app",
"compilerVersion" : 3, "compilerVersion": 3,
"splashscreen" : { "splashscreen": {
"alwaysShowBeforeRender" : true, "alwaysShowBeforeRender": true,
"waiting" : true, "waiting": true,
"autoclose" : true, "autoclose": true,
"delay" : 0 "delay": 0
}, },
"compatible": { "compatible": {
"ignoreVersion": true "ignoreVersion": true
}, },
/* */ /* */
"modules" : { "modules": {
"Record" : {} "Record": {}
}, },
/* */ /* */
"distribute" : { "distribute": {
/* android */ /* android */
"android" : { "android": {
"permissions" : [ "permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
], ],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ] "abiFilters": ["armeabi-v7a", "arm64-v8a", "x86"]
}, },
/* ios */ /* ios */
"ios" : { "ios": {
"dSYMs" : false "dSYMs": false
}, },
/* SDK */ /* SDK */
"sdkConfigs" : { "sdkConfigs": {
"ad" : {} "ad": {}
}, },
"icons" : { "icons": {
"android" : { "android": {
"hdpi" : "unpackage/res/icons/72x72.png", "hdpi": "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png", "xhdpi": "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png", "xxhdpi": "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png" "xxxhdpi": "unpackage/res/icons/192x192.png"
}, },
"ios" : { "ios": {
"appstore" : "unpackage/res/icons/1024x1024.png", "appstore": "unpackage/res/icons/1024x1024.png",
"ipad" : { "ipad": {
"app" : "unpackage/res/icons/76x76.png", "app": "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png", "app@2x": "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png", "notification": "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png", "notification@2x": "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png", "proapp@2x": "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png", "settings": "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png", "settings@2x": "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png", "spotlight": "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png" "spotlight@2x": "unpackage/res/icons/80x80.png"
}, },
"iphone" : { "iphone": {
"app@2x" : "unpackage/res/icons/120x120.png", "app@2x": "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png", "app@3x": "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png", "notification@2x": "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png", "notification@3x": "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png", "settings@2x": "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png", "settings@3x": "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png", "spotlight@2x": "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png" "spotlight@3x": "unpackage/res/icons/120x120.png"
} }
} }
} }
} }
}, },
/* */ /* */
"quickapp" : {}, "quickapp": {},
/* */ /* */
"mp-weixin" : { "mp-weixin": {
"appid" : "wxb86917d1487922b9", "appid": "wxb86917d1487922b9",
"setting" : { "setting": {
"urlCheck" : false, "urlCheck": false,
"postcss" : true, "postcss": true,
"minified" : true "minified": true
}, },
"usingComponents" : true "usingComponents": true
}, },
"mp-alipay" : { "mp-alipay": {
"usingComponents" : true "usingComponents": true
}, },
"mp-baidu" : { "mp-baidu": {
"usingComponents" : true "usingComponents": true
}, },
"mp-toutiao" : { "mp-toutiao": {
"usingComponents" : true "usingComponents": true
}, },
"uniStatistics" : { "uniStatistics": {
"enable" : false "enable": false
}, },
"vueVersion" : "2" "vueVersion": "2"
} }

6
node_modules/.package-lock.json generated vendored

@ -0,0 +1,6 @@
{
"name": "AI-app",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

6
package-lock.json generated

@ -0,0 +1,6 @@
{
"name": "AI-app",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

@ -2,13 +2,27 @@
<view class="chat"> <view class="chat">
<view v-for="(m,index) in messages" :key="m.id" :id="'msg-' + m.id" :class="['msg', m.role]"> <view v-for="(m,index) in messages" :key="m.id" :id="'msg-' + m.id" :class="['msg', m.role]">
<view v-if="m.role === 'user'" class="bubble user-bubble"> <view v-if="m.role === 'user'" class="bubble user-bubble">
<text v-if="m.inputType === 'text'" @longpress.prevent="loadTool($event,m)" >{{ m.content }}</text> <text v-if="m.inputType === 'text'" @longpress.prevent="loadTool($event,m)">{{ m.content }}</text>
<view class="text-voice" v-if="m.inputType === 'voice'" @tap="playVoice(m)"> <view class="text-voice" v-if="m.inputType === 'voice'" @tap="playVoice(m)">
<text>{{ m.duration }}</text> <text>{{ m.duration }}</text>
<image class="voice-play" src="@/static/voice-play.png" mode="widthFix"></image> <image class="voice-play" src="@/static/voice-play.png" mode="widthFix"></image>
</view> </view>
</view> </view>
<view v-else class="bubble ai-bubble">
<view v-if="m.role !== 'user' && m.type !== 'card' && !m.loading " class="ai-voice" style="width: 100%;">
<view class="ai-voice-play" @tap="clickAiVocie(m.src)">
<image class="voice-play" :src="leftVoiceImgList[current].image" mode="widthFix"
v-if="playSrc === m.src">
</image>
<image class="voice-play" :src="leftVoiceImgList[2].image" mode="widthFix"
v-else>
</image>
<text
style="margin-left: 5px;font-size: 14px;">{{ m.duration ? Math.ceil( m.duration) : 0 }}"</text>
</view>
</view>
<view v-if="m.role !== 'user'" class="bubble ai-bubble">
<view v-if="m.type === 'card'" class="ai-card"> <view v-if="m.type === 'card'" class="ai-card">
<view class="ai-card-title">{{ m.title }}</view> <view class="ai-card-title">{{ m.title }}</view>
<view class="ai-card-body">{{ m.content }}</view> <view class="ai-card-body">{{ m.content }}</view>
@ -90,7 +104,9 @@
</template> </template>
<script> <script>
import {copyText} from '@/utils/utils.js' import {
copyText
} from '@/utils/utils.js'
export default { export default {
props: { props: {
messages: { messages: {
@ -102,21 +118,36 @@
isReplying: { isReplying: {
type: Boolean, type: Boolean,
default: false, default: false,
textTool: [] },
} isPalyingVoice: {
type: Boolean,
default: false,
},
playSrc : {
type: String,
default: '',
},
}, },
data() { data() {
return { return {
upvoteImage: require('@/static/upvote.png'), upvoteImage: require('@/static/upvote.png'),
upvoteHighLightImage: require('@/static/upvote-highlight.png'), upvoteHighLightImage: require('@/static/upvote-highlight.png'),
textToolList : [{ leftVoiceImgList: [{
id : 1, image: require('@/static/voice-play-left1.png')
text : '复制', }, {
imageUrl : require('@/static/copy.png') image: require('@/static/voice-play-left2.png')
},{ }, {
id : 2, image: require('@/static/voice-play-left3.png')
text : '修改', }],
imageUrl : require('@/static/edit.png') current: 2,
textToolList: [{
id: 1,
text: '复制',
imageUrl: require('@/static/copy.png')
}, {
id: 2,
text: '修改',
imageUrl: require('@/static/edit.png')
}], }],
isHighLight: false, isHighLight: false,
upvoteIndex: null, upvoteIndex: null,
@ -134,47 +165,69 @@
} }
], ],
askActive: null, askActive: null,
textToolStyle : {}, textToolStyle: {},
isOpenTextTool : false, isOpenTextTool: false,
showTool: false, showTool: false,
screenWidth : 0, screenWidth: 0,
selectText : '' selectText: '',
voiceTimer: null,
} }
}, },
mounted () { mounted() {
this.screenWidth = uni.getSystemInfoSync().screenWidth; this.screenWidth = uni.getSystemInfoSync().screenWidth;
},
watch: {
isPalyingVoice(val) {
if (val) {
this.voiceTimer = setInterval(() => {
if (this.current === 2) {
this.current = -1;
}
this.current += 1;
}, 500)
}else{
if (this.voiceTimer) {
clearInterval(this.voiceTimer)
};
this.current = 2;
}
},
}, },
methods: { methods: {
selectTextTool(id){ clickAiVocie(src) {
switch(id){ this.$emit('handleVoice', src)
},
selectTextTool(id) {
switch (id) {
case 1: case 1:
copyText(this.selectText) copyText(this.selectText)
break; break;
case 2: case 2:
this.$emit('changeInputText',this.selectText) this.$emit('changeInputText', this.selectText)
default: default:
break; break;
} }
this.closeTool(); this.closeTool();
}, },
closeTool(){ closeTool() {
this.showTool = false; this.showTool = false;
this.isOpenTextTool = false; this.isOpenTextTool = false;
this.$emit('changeShow', false) this.$emit('changeShow', false)
}, },
loadTool($event, m) { loadTool($event, m) {
this.selectText = m.content; this.selectText = m.content;
uni.createSelectorQuery().select(`#msg-${m.id}`).boundingClientRect((rect) => { uni.createSelectorQuery().select(`#msg-${m.id}`).boundingClientRect((rect) => {
let height = rect.height || 0; let height = rect.height || 0;
if($event.touches[0].pageX > (this.screenWidth / 2)){ if ($event.touches[0].pageX > (this.screenWidth / 2)) {
this.textToolStyle = { this.textToolStyle = {
top : $event.target.offsetTop + height - 10 + 'px', top: $event.target.offsetTop + height - 10 + 'px',
right : this.screenWidth - Math.ceil($event.touches[0].pageX) + 'px' right: this.screenWidth - Math.ceil($event.touches[0].pageX) + 'px'
} }
}else{ } else {
this.textToolStyle = { this.textToolStyle = {
top : $event.target.offsetTop + height - 10 + 'px', top: $event.target.offsetTop + height - 10 + 'px',
left : Math.ceil($event.touches[0].pageX) + 'px' left: Math.ceil($event.touches[0].pageX) + 'px'
} }
} }
this.isOpenTextTool = true; this.isOpenTextTool = true;
@ -422,7 +475,7 @@
transform: translateY(0) scale(1); transform: translateY(0) scale(1);
} }
.tool-item{ .tool-item {
display: flex; display: flex;
width: 160px; width: 160px;
padding: 10px; padding: 10px;
@ -435,11 +488,11 @@
animation: slideInItem 0.3s ease forwards; animation: slideInItem 0.3s ease forwards;
} }
.tool-item:last-child{ .tool-item:last-child {
border-bottom: 0px; border-bottom: 0px;
} }
.img{ .img {
width: 16px; width: 16px;
margin-right: 10px; margin-right: 10px;
} }
@ -450,6 +503,7 @@
opacity: 0; opacity: 0;
transform: translateX(-10px); transform: translateX(-10px);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateX(0); transform: translateX(0);
@ -523,7 +577,7 @@
} }
} }
.mark-layer{ .mark-layer {
position: fixed; position: fixed;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
@ -534,4 +588,14 @@
z-index: 9999; z-index: 9999;
opacity: 0; opacity: 0;
} }
.ai-voice-play {
width: 60px;
background-color: #fff;
margin-bottom: 10px;
padding: 10px 12px;
border-radius: 14px;
display: flex;
align-items: center;
}
</style> </style>

@ -5,23 +5,30 @@
<scroll-view class="content" :scroll-y="true" show-scrollbar="false" scroll-with-animation ref="scrollView"> <scroll-view class="content" :scroll-y="true" show-scrollbar="false" scroll-with-animation ref="scrollView">
<front @onSuggestionTap="onQuickAsk" /> <front @onSuggestionTap="onQuickAsk" />
<chat :messages="messages" @continueCreate="continueCreate" :isReplying="isReplying" @refresh="refresh" <chat :messages="messages" @continueCreate="continueCreate" :isReplying="isReplying" @refresh="refresh"
@changeShow="changeShow" @changeInputText="changeInputText"/> @changeShow="changeShow" @changeInputText="changeInputText" @handleVoice="handleVoice" :isPalyingVoice="isPalyingVoice" :playSrc="playSrc"/>
</scroll-view> </scroll-view>
<view :style="{height: marginBottom + 'px',backgroundColor : '#fff'}" /> <view :style="{ height: marginBottom + 'px', backgroundColor: '#fff' }" />
<leftDrawer :historyGroups="historyGroups" ref="popup" @changeShow="changeShow" <leftDrawer :historyGroups="historyGroups" ref="popup" @changeShow="changeShow"
@onHistoryItemTap="onHistoryItemTap" @removeFromHistory="removeFromHistory" @onHistoryItemTap="onHistoryItemTap" @removeFromHistory="removeFromHistory"
@clearAllHistory="clearAllHistory" /> @clearAllHistory="clearAllHistory" />
<search ref="searchRef" :inputText="inputText" @onSend="onSend" @onQuickAsk="onQuickAsk" <search ref="searchRef" :inputText="inputText" @onSend="onSend" @onQuickAsk="onQuickAsk"
@changeInputText="changeInputText" :isReplying="isReplying" @handleBreak="handleBreak" /> @changeInputText="changeInputText" :isReplying="isReplying" @handleBreak="handleBreak"
@changeShow="changeShow" />
</view> </view>
</template> </template>
<script> <script>
const HISTORY_KEY = "chat_history_groups"; const HISTORY_KEY = "chat_history_groups";
import { import {
getAIResponse getAIResponse,
} from "@/api/index.js"; } from "@/api/index.js";
import {
textToSpeech,
base64ToFile,
removeFile
} from '@/utils/utils.js'
import top from "./top/index.vue"; import top from "./top/index.vue";
import front from "./front/index.vue"; import front from "./front/index.vue";
import chat from "./chat/index.vue"; import chat from "./chat/index.vue";
@ -44,16 +51,17 @@
typewriterTimers: {}, typewriterTimers: {},
show: false, show: false,
marginBottom: 0, marginBottom: 0,
isReplying: false, isReplying: false, //
breakReplying: false, breakReplying: false, //
replyData: {}, replyData: {}, //
isRefresh: false isRefresh: false, //
audioContext: null,
isPalyingVoice : false, //
playSrc : ''
}; };
}, },
async mounted() { async mounted() {
this.loadChatHistory(); this.loadChatHistory();
// this.scrollToBottom();
let self = this;
uni.onKeyboardHeightChange((res) => { uni.onKeyboardHeightChange((res) => {
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: this.height + res.height, scrollTop: this.height + res.height,
@ -66,7 +74,8 @@
this.marginBottom = this.$refs.searchRef.getHeight() || 103; this.marginBottom = this.$refs.searchRef.getHeight() || 103;
}); });
// #endif // #endif
this.marginBottom = 103 this.marginBottom = 103;
this.initAudio();
}, },
beforeDestroy() { beforeDestroy() {
// //
@ -76,6 +85,82 @@
this.typewriterTimers = {}; this.typewriterTimers = {};
}, },
methods: { methods: {
handleVoice(src){
if(this.isReplying){
console.log('正在回复中');
return;
}
if(this.audioContext.src === src && this.isPalyingVoice){
this.isPalyingVoice = false;
this.audioContext.stop();
return;
};
if(this.audioContext.src === src && !this.isPalyingVoice){
this.isPalyingVoice = true;
this.audioContext.play();
return;
};
if(this.isPalyingVoice){
this.audioContext.stop();
};
this.isPalyingVoice = true;
this.audioContext.src = src;
this.playSrc = src;
this.audioContext.play();
},
initAudio() {
this.audioContext = uni.createInnerAudioContext()
this.audioContext.onCanplay((e) => {
console.log('src onCanplay',this.audioContext.src);
let items = this.messages.find(item => item.src && item.src === this.audioContext.src);
items.duration = this.audioContext.duration;
this.isPalyingVoice = true;
this.audioContext.play();
});
this.audioContext.onEnded(res => {
this.isPalyingVoice = false
// const platform = uni.getSystemInfoSync().uniPlatform;
// if(platform === 'web') return;
// removeFile(this.audioContext.src)
})
},
getSpeech(speechStr) {
let self = this;
return new Promise((resolve, reject) => {
textToSpeech(speechStr).then(audioData => {
const platform = uni.getSystemInfoSync().uniPlatform;
// H5
if (platform === 'web') {
const blob = new Blob([audioData], {
type: 'audio/mp3'
});
const url = URL.createObjectURL(blob);
this.playSrc = url;
console.log('赋值 h5');
this.audioContext.src = url;
resolve(true)
}
// App
else {
const base64Audio = uni.arrayBufferToBase64(audioData);
const base64WithPrefix = `data:audio/mp3;base64,${base64Audio}`;
const fileName = `_doc/${Date.now()}_numberPerson.mp3`;
base64ToFile(base64WithPrefix, fileName, (path) => {
console.log('赋值 plus');
this.playSrc = path;
self.audioContext.src = path;
resolve(true)
});
}
}).catch(err => {
resolve(true)
})
})
},
deleteSpeech() {
removeFile(this.audioContext.src)
},
// //
refresh() { refresh() {
this.messages.splice(this.messages.length - 1, 1); this.messages.splice(this.messages.length - 1, 1);
@ -252,10 +337,15 @@
this.isRefresh = false; this.isRefresh = false;
this.scrollToBottom(); this.scrollToBottom();
this.addToHistory(text); this.addToHistory(text);
if(this.isPalyingVoice){
this.audioContext.stop();
this.isPalyingVoice = false;
}
// 3. AI // 3. AI
const reply = await getAIResponse({ const reply = await getAIResponse({
message: text, message: text,
}); });
await this.getSpeech(reply);
this.replyData = reply; this.replyData = reply;
this.isLoading = false; this.isLoading = false;
if (this.breakReplying) { if (this.breakReplying) {
@ -276,6 +366,7 @@
if (loadingIdx > -1) this.messages.splice(loadingIdx, 1); if (loadingIdx > -1) this.messages.splice(loadingIdx, 1);
// 5. + // 5. +
const replyId = this.baseId + 1; const replyId = this.baseId + 1;
console.log('添加');
if (!isCreate) { if (!isCreate) {
this.messages.push({ this.messages.push({
id: replyId, id: replyId,
@ -283,9 +374,10 @@
type: "text", type: "text",
content, content,
displayText: "", displayText: "",
src : JSON.parse(JSON.stringify(this.audioContext.src)),
duration : null
}); });
} }
this.$nextTick(() => this.scrollToBottom()); this.$nextTick(() => this.scrollToBottom());
this.typewriter(replyId, content); this.typewriter(replyId, content);
}, },
@ -310,6 +402,8 @@
this.isReplying = false; this.isReplying = false;
this.breakReplying = false this.breakReplying = false
this.isLoading = false; this.isLoading = false;
this.isPalyingVoice =false;
this.audioContext.stop();
} }
if (index < fullText.length) { if (index < fullText.length) {
msg.displayText = fullText.substring(0, index + 1); msg.displayText = fullText.substring(0, index + 1);
@ -324,7 +418,7 @@
this.breakReplying = false; this.breakReplying = false;
this.$nextTick(() => { this.$nextTick(() => {
this.scrollToBottom(); this.scrollToBottom();
}) });
} }
}, speed); }, speed);
this.typewriterTimers[messageId] = timer; this.typewriterTimers[messageId] = timer;

@ -40,7 +40,7 @@
<uni-popup ref="inputDialog" type="dialog" style="z-index: 10003;" > <uni-popup ref="inputDialog" type="dialog" style="z-index: 10003;" >
<uni-popup-dialog ref="inputClose" mode="input" title="添加快捷提问" v-model="dialogText" placeholder="请输入内容" <uni-popup-dialog ref="inputClose" mode="input" title="添加快捷提问" v-model="dialogText" placeholder="请输入内容"
@confirm="dialogInputConfirm" :maxlength="15" ></uni-popup-dialog> @confirm="dialogInputConfirm" :maxlength="15" @close='dialogInputClose'></uni-popup-dialog>
</uni-popup> </uni-popup>
<view v-if="isRecording" class="mask-layer"> </view> <view v-if="isRecording" class="mask-layer"> </view>
@ -118,11 +118,16 @@
} }
}) })
}, },
dialogInputClose(){
this.$emit('changeShow',false)
},
inputDialogToggle() { inputDialogToggle() {
this.dialogText = ''; this.dialogText = '';
this.$refs.inputDialog.open() this.$refs.inputDialog.open();
this.$emit('changeShow',true)
}, },
dialogInputConfirm() { dialogInputConfirm() {
this.$emit('changeShow',false)
if(!this.dialogText && !this.dialogText.trim()){ if(!this.dialogText && !this.dialogText.trim()){
uni.showToast({ uni.showToast({
title: '内容不能为空', title: '内容不能为空',
@ -175,6 +180,7 @@
if (this.recorder) { if (this.recorder) {
this.recorder.onStart(); this.recorder.onStart();
this.recorder.onStop(async (res) => { this.recorder.onStop(async (res) => {
this.$emit('changeShow',false)
const duration = Date.now() - this.recordStartTs; const duration = Date.now() - this.recordStartTs;
if (this.willCancel || duration < 700) { if (this.willCancel || duration < 700) {
uni.showToast({ uni.showToast({
@ -230,6 +236,7 @@
}) })
return return
} }
this.$emit('changeShow',true)
this.ensureRecorder(); this.ensureRecorder();
this.isRecording = true; this.isRecording = true;
this.willCancel = false; this.willCancel = false;
@ -421,6 +428,7 @@
top: 0; top: 0;
bottom: 0; bottom: 0;
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, 0.1);
z-index: 100004;
} }
.cancel { .cancel {

@ -1,217 +1,324 @@
<template> <template>
<view class="setting-page"> <view class="setting-page">
<uni-nav-bar left-icon="left" @clickLeft="$pageJumb.backJump()" title="设置" > <uni-nav-bar left-icon="left" @clickLeft="$pageJumb.backJump()" title="设置">
<template v-slot:left> <template v-slot:left>
<view ></view> <view></view>
</template> </template>
<template v-slot:right> <template v-slot:right>
<view class="close" @tap="onClose"></view> <view class="close" @tap="onClose"></view>
</template> </template>
</uni-nav-bar> </uni-nav-bar>
<view class="group" > <view class="group">
<view class="group-title">账户</view> <view class="group-title">账户</view>
<view class="card"> <view class="card">
<view class="item" @tap="onItem('账号管理')"> <view class="item" @tap="onItem('账号管理')">
<view class="left"> <view class="left">
<view class="icon-wrap"><uni-icons type="person" size="20" color="#3b3f45" /></view> <view class="icon-wrap"><uni-icons type="person" size="20" color="#3b3f45" /></view>
<text class="text">账号管理</text> <text class="text">账号管理</text>
</view> </view>
<text class="arrow"></text> <text class="arrow"></text>
</view> </view>
<view class="divider" /> <view class="divider" />
<view class="item" @tap="onItem('数据管理')"> <view class="item" @tap="onItem('数据管理')">
<view class="left"> <view class="left">
<view class="icon-wrap"> <view class="icon-wrap">
<image src="../../static/data-management.png" mode="widthFix" style="width: 20px;"></image> <image src="../../static/data-management.png" mode="widthFix" style="width: 18px;"></image>
</view> </view>
<text class="text">数据管理</text> <text class="text">数据管理</text>
</view> </view>
<text class="arrow"></text> <text class="arrow"></text>
</view> </view>
</view> </view>
</view> </view>
<view class="group"> <view class="group">
<view class="group-title">关于</view> <view class="group-title">应用</view>
<view class="card"> <view class="card">
<view class="item" @tap="onItem('检查更新')"> <view class="item" @tap="chatPattern">
<view class="left"> <view class="left">
<view class="icon-wrap"><uni-icons type="refreshempty" size="20" color="#3b3f45" /></view> <view class="icon-wrap"><uni-icons type="chat" size="20" color="#3b3f45" /></view>
<text class="text">检查更新</text> <text class="text">回复模式</text>
</view> </view>
<text class="arrow"></text> <text class="arrow"></text>
</view> </view>
<view class="divider" /> <view class="divider" />
<view class="item" @tap="onItem('服务协议')"> <view class="item" @tap="onItem('字体大小')">
<view class="left"> <view class="left">
<view class="icon-wrap"><uni-icons type="help" size="20" color="#3b3f45" /></view> <view class="icon-wrap"><uni-icons type="help" size="20" color="#3b3f45" /></view>
<text class="text">服务协议</text> <text class="text">字体大小</text>
</view> </view>
<text class="arrow"></text> <text class="arrow"></text>
</view> </view>
</view> </view>
</view> </view>
<view class="card single" style="margin-top: 30px;"> <view class="group">
<view class="item" @tap="onItem('联系我们')"> <view class="group-title">关于</view>
<view class="left"> <view class="card">
<view class="icon-wrap"><uni-icons type="phone" size="20" color="#3b3f45" /></view> <view class="item" @tap="onItem('检查更新')">
<text class="text">联系我们</text> <view class="left">
</view> <view class="icon-wrap"><uni-icons type="refreshempty" size="20" color="#3b3f45" /></view>
<text class="arrow"></text> <text class="text">检查更新</text>
</view> </view>
</view> <text class="arrow"></text>
</view>
<view class="card single"> <view class="divider" />
<view class="item danger" @tap="onLogout"> <view class="item" @tap="onItem('服务协议')">
<view class="left"> <view class="left">
<view class="icon-wrap"><image src="../../static/quit.png" mode="widthFix" style="width: 20px;"></image></view> <view class="icon-wrap"><uni-icons type="help" size="20" color="#3b3f45" /></view>
<text class="text danger">退出登录</text> <text class="text">服务协议</text>
</view> </view>
</view> <text class="arrow"></text>
</view> </view>
</view>
<view class="brand"> </view>
<view class="card single" style="margin-top: 30px;">
<view class="item" @tap="onItem('联系我们')">
<view class="left">
<view class="icon-wrap"><uni-icons type="phone" size="20" color="#3b3f45" /></view>
<text class="text">联系我们</text>
</view>
<text class="arrow"></text>
</view>
</view>
<view class="card single">
<view class="item danger" @tap="onLogout">
<view class="left">
<view class="icon-wrap">
<image src="../../static/quit.png" mode="widthFix" style="width: 16px;"></image>
</view>
<text class="text danger">退出登录</text>
</view>
</view>
</view>
<view class="brand">
<image src="../../static/cxlogo.png" mode="heightFix" style="height: 40px;"></image> <image src="../../static/cxlogo.png" mode="heightFix" style="height: 40px;"></image>
</view> </view>
</view>
<uni-popup ref="popup" class="popup" type="center" border-radius="10px 10px 0 0" :is-mask-click="false">
<view class="chat-box">
<view class="chat-title"> AI回复模式 </view>
<radio-group @change="radioChange">
<label v-for="(item, index) in items" :key="item.value" style="display: flex;margin-bottom: 10px;">
<view>
<radio :value="item.value" :checked="item.value === current" />
</view>
<view style="margin-left: 10px;">{{item.label}}</view>
</label>
</radio-group>
<view class="confirm" @tap="confirmPattern"></view>
</view>
</uni-popup>
</view>
</template> </template>
<script> <script>
export default { export default {
methods: { data() {
onClose() { return {
uni.navigateBack(); current : '0',
}, items : [{
onItem(name) { label : '文字回复',
uni.showToast({ title: name, icon: 'none' }) value : '0'
}, },{
onLogout() { label : '语音回复',
uni.showModal({ value : '1'
title: '提示', },{
content: '确认退出登录?', label : '文字 + 语音回复',
success: (res) => { value : '2'
if (res.confirm) { }]
uni.showToast({ title: '已退出', icon: 'none' }) }
} },
} mounted () {
}) this.current = this.$store.state.set.replyPattern;
} },
} methods: {
} onClose() {
uni.navigateBack();
},
onItem(name) {
uni.showToast({
title: name,
icon: 'none'
})
},
onLogout() {
uni.showModal({
title: '提示',
content: '确认退出登录?',
success: (res) => {
if (res.confirm) {
uni.showToast({
title: '已退出',
icon: 'none'
})
}
}
})
},
chatPattern() {
this.$refs.popup.open()
},
radioChange(e){
this.current = e.detail.value;
},
confirmPattern(){
this.$refs.popup.close();
this.$store.commit('set/SET_REPLY_PATTERN', this.current)
},
}
}
</script> </script>
<style scoped > <style scoped lang="scss">
.setting-page { .setting-page {
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: #eef1f4; background: #eef1f4;
} }
.header { .header {
height: 52px; height: 52px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative; position: relative;
background: #eef1f4; background: #eef1f4;
} }
.title { .title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #333; color: #333;
} }
.close { .close {
width: 28px; width: 28px;
height: 28px; height: 28px;
line-height: 28px; line-height: 28px;
text-align: center; text-align: center;
border-radius: 14px; border-radius: 14px;
background: #ffffff; background: #ffffff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
color: #666; color: #666;
} }
.content { .content {
flex: 1; flex: 1;
padding: 8px 14px 20px; padding: 8px 14px 20px;
} }
.group { .group {
width: 80vw; width: 80vw;
margin: 8px auto; margin: 8px auto;
} }
.group-title { .group-title {
font-size: 12px; font-size: 12px;
color: #9aa3b2; color: #9aa3b2;
margin: 10px 6px; margin: 10px 6px;
} }
.card { .card {
width: 80vw; width: 80vw;
margin: 0 auto; margin: 0 auto;
background: #fff; background: #fff;
border-radius: 12px; border-radius: 12px;
padding: 0 12px; padding: 0 12px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
box-sizing: border-box; box-sizing: border-box;
} }
.card.single { .card.single {
margin-top: 12px; margin-top: 12px;
} }
.item { .item {
height: 48px; height: 38px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.left { .left {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
} }
.icon-wrap { .icon-wrap {
width: 28px; width: 18px;
height: 28px; height: 18px;
border-radius: 14px; border-radius: 14px;
background: #f1f3f6; background: #f1f3f6;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.icon-wrap.danger { .icon-wrap.danger {
background: #fdecea; background: #fdecea;
} }
.text { .text {
font-size: 14px; font-size: 14px;
color: #333; color: #333;
} }
.arrow { .arrow {
color: #b3bac5; color: #b3bac5;
font-size: 18px; font-size: 18px;
} }
.divider { .divider {
height: 1px; height: 1px;
background: #eef0f3; background: #eef0f3;
} }
.brand { .brand {
position: absolute; position: absolute;
bottom: 20px; bottom: 20px;
left : 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
} }
.popup {
z-index: 99999;
}
.chat-box {
background-color: #fff;
width: 70vw;
border-radius: 10px;
padding: 0 20px;
box-sizing: border-box;
::v-deep uni-radio .uni-radio-input{
width: 16px !important;
height: 16px !important;
}
.chat-title {
text-align: center;
padding: 10px;
border-bottom: 1px solid #ddd;
margin-bottom: 10px;
}
.confirm {
color: #048bff;
text-align: center;
padding: 8px;
border-top: 1px solid #ddd;
}
}
</style> </style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -1,10 +1,12 @@
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex' import Vuex from 'vuex'
import permission from './module/permission' import permission from './module/permission'
import set from './module/set'
Vue.use(Vuex) Vue.use(Vuex)
export default new Vuex.Store({ export default new Vuex.Store({
modules : { modules : {
permission permission,
set
} }
}) })

@ -1,8 +1,12 @@
export default { export default {
namespaced : true,
state : { state : {
// microphoneAuthorized : uni.getAppAuthorizeSetting().microphoneAuthorized // microphoneAuthorized : uni.getAppAuthorizeSetting().microphoneAuthorized
}, },
mutations : { mutations : {
},
actions : {
} }
} }

@ -0,0 +1,15 @@
export default {
namespaced : true,
state : {
replyPattern : uni.getStorageSync('replyPattern') || '0'
},
mutations : {
SET_REPLY_PATTERN(state,value){
state.replyPattern = value;
uni.setStorageSync('replyPattern',value)
}
},
actions : {
}
}

@ -1,8 +1,8 @@
var isReady=false;var onReadyCallbacks=[]; var isReady=false;var onReadyCallbacks=[];
var isServiceReady=false;var onServiceReadyCallbacks=[]; var isServiceReady=false;var onServiceReadyCallbacks=[];
var __uniConfig = {"pages":["pages/index/index"],"window":{"navigationBarTextStyle":"black","navigationBarTitleText":"uni-app","navigationBarBackgroundColor":"#F8F8F8","backgroundColor":"#F8F8F8"},"darkmode":false,"nvueCompiler":"uni-app","nvueStyleCompiler":"uni-app","renderer":"auto","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":false},"appname":"漆包车间看板","compilerVersion":"4.29","entryPagePath":"pages/index/index","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000}}; var __uniConfig = {"pages":["pages/index/index","pages/setting/index"],"window":{"navigationBarTextStyle":"black","navigationBarTitleText":"uni-app","navigationBarBackgroundColor":"#F8F8F8","backgroundColor":"#F8F8F8"},"darkmode":false,"nvueCompiler":"uni-app","nvueStyleCompiler":"uni-app","renderer":"auto","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":false},"appname":"萃星智能AI","compilerVersion":"4.29","entryPagePath":"pages/index/index","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000}};
var __uniRoutes = [{"path":"/pages/index/index","meta":{"isQuit":true},"window":{"navigationStyle":"custom"}}]; var __uniRoutes = [{"path":"/pages/index/index","meta":{"isQuit":true},"window":{"navigationStyle":"custom","titleNView":false,"softinputMode":"adjustResize"}},{"path":"/pages/setting/index","meta":{},"window":{"navigationStyle":"custom"}}];
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}}); __uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
__uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}}); __uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:Math.round(f/20)})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes,global:void 0,window:void 0,document:void 0,frames:void 0,self:void 0,location:void 0,navigator:void 0,localStorage:void 0,history:void 0,Caches:void 0,screen:void 0,alert:void 0,confirm:void 0,prompt:void 0,fetch:void 0,XMLHttpRequest:void 0,WebSocket:void 0,webkit:void 0,print:void 0}}}}); service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:Math.round(f/20)})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes,global:void 0,window:void 0,document:void 0,frames:void 0,self:void 0,location:void 0,navigator:void 0,localStorage:void 0,history:void 0,Caches:void 0,screen:void 0,alert:void 0,confirm:void 0,prompt:void 0,fetch:void 0,XMLHttpRequest:void 0,WebSocket:void 0,webkit:void 0,print:void 0}}}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
{"@platforms":["android","iPhone","iPad"],"id":"__UNI__5BDEDB4","name":"漆包车间看板","version":{"name":"1.0.17","code":102},"description":"","launch_path":"__uniappview.html","developer":{"name":"","email":"","url":""},"permissions":{"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"autoclose":true,"delay":0,"target":"id:1","waiting":true},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F8F8F8"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"distribute":{"icons":{"android":{"hdpi":"icon-android-hdpi.png","xhdpi":"icon-android-xhdpi.png","xxhdpi":"icon-android-xxhdpi.png","xxxhdpi":"icon-android-xxxhdpi.png"},"ios":{"appstore":"unpackage/res/icons/1024x1024.png","ipad":{"app":"unpackage/res/icons/76x76.png","app@2x":"unpackage/res/icons/152x152.png","notification":"unpackage/res/icons/20x20.png","notification@2x":"unpackage/res/icons/40x40.png","proapp@2x":"unpackage/res/icons/167x167.png","settings":"unpackage/res/icons/29x29.png","settings@2x":"unpackage/res/icons/58x58.png","spotlight":"unpackage/res/icons/40x40.png","spotlight@2x":"unpackage/res/icons/80x80.png"},"iphone":{"app@2x":"unpackage/res/icons/120x120.png","app@3x":"unpackage/res/icons/180x180.png","notification@2x":"unpackage/res/icons/40x40.png","notification@3x":"unpackage/res/icons/60x60.png","settings@2x":"unpackage/res/icons/58x58.png","settings@3x":"unpackage/res/icons/87x87.png","spotlight@2x":"unpackage/res/icons/80x80.png","spotlight@3x":"unpackage/res/icons/120x120.png"},"prerendered":"false"}},"google":{"abiFilters":["armeabi-v7a","arm64-v8a","x86"],"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"],"packagename":"uni.UNI5BDEDB4","aliasname":"","password":"","keystore":"html5plus://test","custompermissions":true},"apple":{"dSYMs":false,"devices":"universal"},"plugins":{"ad":{},"audio":{"mp3":{"description":"Android平台录音支持MP3格式文件"}}},"orientation":"portrait-primary"},"uniStatistics":{"enable":false},"allowsInlineMediaPlayback":true,"uni-app":{"compilerVersion":"4.29","control":"uni-v3","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal"},"launch_path":"__uniappview.html","adid":"124076130506"}} {"@platforms":["android","iPhone","iPad"],"id":"__UNI__5BDEDB4","name":"萃星智能AI","version":{"name":"1.0.1","code":100},"description":"","launch_path":"__uniappview.html","developer":{"name":"","email":"","url":""},"permissions":{"Record":{},"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"autoclose":true,"delay":0,"target":"id:1","waiting":true},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F8F8F8"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"compatible":{"ignoreVersion":true},"distribute":{"icons":{"android":{"hdpi":"icon-android-hdpi.png","xhdpi":"icon-android-xhdpi.png","xxhdpi":"icon-android-xxhdpi.png","xxxhdpi":"icon-android-xxxhdpi.png"},"ios":{"appstore":"unpackage/res/icons/1024x1024.png","ipad":{"app":"unpackage/res/icons/76x76.png","app@2x":"unpackage/res/icons/152x152.png","notification":"unpackage/res/icons/20x20.png","notification@2x":"unpackage/res/icons/40x40.png","proapp@2x":"unpackage/res/icons/167x167.png","settings":"unpackage/res/icons/29x29.png","settings@2x":"unpackage/res/icons/58x58.png","spotlight":"unpackage/res/icons/40x40.png","spotlight@2x":"unpackage/res/icons/80x80.png"},"iphone":{"app@2x":"unpackage/res/icons/120x120.png","app@3x":"unpackage/res/icons/180x180.png","notification@2x":"unpackage/res/icons/40x40.png","notification@3x":"unpackage/res/icons/60x60.png","settings@2x":"unpackage/res/icons/58x58.png","settings@3x":"unpackage/res/icons/87x87.png","spotlight@2x":"unpackage/res/icons/80x80.png","spotlight@3x":"unpackage/res/icons/120x120.png"},"prerendered":"false"}},"google":{"abiFilters":["armeabi-v7a","arm64-v8a","x86"],"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"],"packagename":"uni.UNI5BDEDB4","custompermissions":true},"apple":{"dSYMs":false,"plistcmds":["Add :UIFileSharingEnabled bool true"],"devices":"universal"},"plugins":{"ad":{},"audio":{"mp3":{"description":"Android平台录音支持MP3格式文件"}}},"debug":true,"syncDebug":true,"orientation":"portrait-primary"},"uniStatistics":{"enable":false},"allowsInlineMediaPlayback":true,"uni-app":{"compilerVersion":"4.29","control":"uni-v3","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal"},"launch_path":"__uniappview.html","adid":"124076130506"}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

@ -1,8 +1,8 @@
var isReady=false;var onReadyCallbacks=[]; var isReady=false;var onReadyCallbacks=[];
var isServiceReady=false;var onServiceReadyCallbacks=[]; var isServiceReady=false;var onServiceReadyCallbacks=[];
var __uniConfig = {"pages":["pages/index/index"],"window":{"navigationBarTextStyle":"black","navigationBarTitleText":"uni-app","navigationBarBackgroundColor":"#F8F8F8","backgroundColor":"#F8F8F8"},"darkmode":false,"nvueCompiler":"uni-app","nvueStyleCompiler":"uni-app","renderer":"auto","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":false},"appname":"漆包车间看板","compilerVersion":"4.29","entryPagePath":"pages/index/index","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000}}; var __uniConfig = {"pages":["pages/index/index","pages/setting/index"],"window":{"navigationBarTextStyle":"black","navigationBarTitleText":"uni-app","navigationBarBackgroundColor":"#F8F8F8","backgroundColor":"#F8F8F8"},"darkmode":false,"nvueCompiler":"uni-app","nvueStyleCompiler":"uni-app","renderer":"auto","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":false},"appname":"萃星智能AI","compilerVersion":"4.29","entryPagePath":"pages/index/index","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000}};
var __uniRoutes = [{"path":"/pages/index/index","meta":{"isQuit":true},"window":{"navigationStyle":"custom"}}]; var __uniRoutes = [{"path":"/pages/index/index","meta":{"isQuit":true},"window":{"navigationStyle":"custom","titleNView":false,"softinputMode":"adjustResize"}},{"path":"/pages/setting/index","meta":{},"window":{"navigationStyle":"custom"}}];
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}}); __uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
__uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}}); __uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:Math.round(f/20)})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes,global:void 0,window:void 0,document:void 0,frames:void 0,self:void 0,location:void 0,navigator:void 0,localStorage:void 0,history:void 0,Caches:void 0,screen:void 0,alert:void 0,confirm:void 0,prompt:void 0,fetch:void 0,XMLHttpRequest:void 0,WebSocket:void 0,webkit:void 0,print:void 0}}}}); service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:Math.round(f/20)})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes,global:void 0,window:void 0,document:void 0,frames:void 0,self:void 0,location:void 0,navigator:void 0,localStorage:void 0,history:void 0,Caches:void 0,screen:void 0,alert:void 0,confirm:void 0,prompt:void 0,fetch:void 0,XMLHttpRequest:void 0,WebSocket:void 0,webkit:void 0,print:void 0}}}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
{"@platforms":["android","iPhone","iPad"],"id":"__UNI__5BDEDB4","name":"漆包车间看板","version":{"name":"1.0.17","code":102},"description":"","launch_path":"__uniappview.html","developer":{"name":"","email":"","url":""},"permissions":{"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"target":"id:1","autoclose":true,"waiting":true,"delay":0},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F8F8F8"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"distribute":{"icons":{"android":{"hdpi":"unpackage/res/icons/72x72.png","xhdpi":"unpackage/res/icons/96x96.png","xxhdpi":"unpackage/res/icons/144x144.png","xxxhdpi":"unpackage/res/icons/192x192.png"},"ios":{"appstore":"unpackage/res/icons/1024x1024.png","ipad":{"app":"unpackage/res/icons/76x76.png","app@2x":"unpackage/res/icons/152x152.png","notification":"unpackage/res/icons/20x20.png","notification@2x":"unpackage/res/icons/40x40.png","proapp@2x":"unpackage/res/icons/167x167.png","settings":"unpackage/res/icons/29x29.png","settings@2x":"unpackage/res/icons/58x58.png","spotlight":"unpackage/res/icons/40x40.png","spotlight@2x":"unpackage/res/icons/80x80.png"},"iphone":{"app@2x":"unpackage/res/icons/120x120.png","app@3x":"unpackage/res/icons/180x180.png","notification@2x":"unpackage/res/icons/40x40.png","notification@3x":"unpackage/res/icons/60x60.png","settings@2x":"unpackage/res/icons/58x58.png","settings@3x":"unpackage/res/icons/87x87.png","spotlight@2x":"unpackage/res/icons/80x80.png","spotlight@3x":"unpackage/res/icons/120x120.png"}}},"google":{"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"],"abiFilters":["armeabi-v7a","arm64-v8a","x86"]},"apple":{"dSYMs":false},"plugins":{"ad":{},"audio":{"mp3":{"description":"Android平台录音支持MP3格式文件"}}}},"uniStatistics":{"enable":false},"allowsInlineMediaPlayback":true,"uni-app":{"compilerVersion":"4.29","control":"uni-v3","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal"},"launch_path":"__uniappview.html"}} {"@platforms":["android","iPhone","iPad"],"id":"__UNI__5BDEDB4","name":"萃星智能AI","version":{"name":"1.0.1","code":100},"description":"","launch_path":"__uniappview.html","developer":{"name":"","email":"","url":""},"permissions":{"Record":{},"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"target":"id:1","autoclose":true,"waiting":true,"delay":0},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F8F8F8"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"compatible":{"ignoreVersion":true},"distribute":{"icons":{"android":{"hdpi":"unpackage/res/icons/72x72.png","xhdpi":"unpackage/res/icons/96x96.png","xxhdpi":"unpackage/res/icons/144x144.png","xxxhdpi":"unpackage/res/icons/192x192.png"},"ios":{"appstore":"unpackage/res/icons/1024x1024.png","ipad":{"app":"unpackage/res/icons/76x76.png","app@2x":"unpackage/res/icons/152x152.png","notification":"unpackage/res/icons/20x20.png","notification@2x":"unpackage/res/icons/40x40.png","proapp@2x":"unpackage/res/icons/167x167.png","settings":"unpackage/res/icons/29x29.png","settings@2x":"unpackage/res/icons/58x58.png","spotlight":"unpackage/res/icons/40x40.png","spotlight@2x":"unpackage/res/icons/80x80.png"},"iphone":{"app@2x":"unpackage/res/icons/120x120.png","app@3x":"unpackage/res/icons/180x180.png","notification@2x":"unpackage/res/icons/40x40.png","notification@3x":"unpackage/res/icons/60x60.png","settings@2x":"unpackage/res/icons/58x58.png","settings@3x":"unpackage/res/icons/87x87.png","spotlight@2x":"unpackage/res/icons/80x80.png","spotlight@3x":"unpackage/res/icons/120x120.png"}}},"google":{"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"],"abiFilters":["armeabi-v7a","arm64-v8a","x86"]},"apple":{"dSYMs":false},"plugins":{"ad":{},"audio":{"mp3":{"description":"Android平台录音支持MP3格式文件"}}}},"uniStatistics":{"enable":false},"allowsInlineMediaPlayback":true,"uni-app":{"compilerVersion":"4.29","control":"uni-v3","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal"},"launch_path":"__uniappview.html"}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,134 @@
// base64.ts
export const Base64 = {
keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
const utf8Input = this.utf8Encode(input);
while (i < utf8Input.length) {
chr1 = utf8Input.charCodeAt(i);
chr2 = utf8Input.charCodeAt(i + 1);
chr3 = utf8Input.charCodeAt(i + 2);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output =
output +
this.keyStr.charAt(enc1) +
this.keyStr.charAt(enc2) +
this.keyStr.charAt(enc3) +
this.keyStr.charAt(enc4);
i += 3;
}
return output;
},
decode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
const base64Input = input.replace(/[^A-Za-z0-9+/=]/g, '');
while (i < base64Input.length) {
enc1 = this.keyStr.indexOf(base64Input.charAt(i));
enc2 = this.keyStr.indexOf(base64Input.charAt(i + 1));
enc3 = this.keyStr.indexOf(base64Input.charAt(i + 2));
enc4 = this.keyStr.indexOf(base64Input.charAt(i + 3));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output += String.fromCharCode(chr1);
if (enc3 !== 64) {
output += String.fromCharCode(chr2);
}
if (enc4 !== 64) {
output += String.fromCharCode(chr3);
}
i += 4;
}
return this.utf8Decode(output);
},
utf8Encode(string) {
let utftext = '';
let c;
for (let n = 0; n < string.length; n += 1) {
c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c < 2048) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
utf8Decode(utftext) {
let string = '';
let i = 0;
let c = 0;
let c1 = 0;
let c2 = 0;
// const c3 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i += 1;
} else if (c < 224) {
c1 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i + 1);
c2 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
}
};

@ -36,4 +36,131 @@ export function copyText(text) {
}); });
} }
}); });
};
export const removeFile = (filePath) => {
plus.io.resolveLocalFileSystemURL(
filePath,
(entry) => {
entry.remove(
() => console.log("删除成功"), // 成功回调
(error) => console.log(`删除失败:${error.message}`) // 失败回调
);
},
(error) => console.log(`文件不存在:${error.message}`)
);
}
export const base64ToFile = (base64Strs, fileName, callback) => {
let index = base64Strs.indexOf(',');
let base64Str = base64Strs.slice(index + 1, base64Strs.length);
plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) {
fs.root.getFile(fileName, {
create: true
}, function(entry) {
let fullPath = entry.fullPath;
let platform = uni.getSystemInfoSync().platform;
if (platform == 'android') {
let Base64 = plus.android.importClass("android.util.Base64");
let FileOutputStream = plus.android.importClass("java.io.FileOutputStream");
try {
let out = new FileOutputStream(fullPath);
let bytes = Base64.decode(base64Str, Base64.DEFAULT);
out.write(bytes);
out.close();
callback && callback(entry.toLocalURL());
} catch (e) {
console.log(e.message);
}
} else if (platform == 'ios') {
let NSData = plus.ios.importClass('NSData');
let nsData = new NSData();
nsData = nsData.initWithBase64EncodedStringoptions(base64Str, 0);
if (nsData) {
nsData.plusCallMethod({
writeToFile: fullPath,
atomically: true
});
plus.ios.deleteObject(nsData);
}
callback && callback(entry.toLocalURL());
}
});
});
};
export function textToSpeech(text, options = {}) {
return new Promise((resolve, reject) => {
const {
token = '24.1c8cc30b5f7be445723b6d4b19a36152.2592000.1765094496.282335-120706844',
tex = text,
cuid = 'uni-app-demo',
ctp = 1,
lan = 'zh',
spd = 5,
pit = 5,
vol = 5,
per = 0
} = options
const url = 'https://tsn.baidu.com/text2audio'
const params = {
tex: encodeURIComponent(tex),
cuid,
ctp,
lan,
spd,
pit,
vol,
per,
tok: token
}
// 构建查询字符串
const queryString = Object.keys(params).map(key => {
return `${key}=${params[key]}`
}).join('&')
uni.request({
url: `${url}?${queryString}`,
method: 'GET',
responseType: 'arraybuffer',
success: (res) => {
// 检查响应状态
if (res.statusCode === 200) {
// 检查是否是音频数据MP3格式通常以特定字节开头
if (res.data && res.data.byteLength > 0) {
// 检查是否是JSON错误响应百度API错误时返回JSON
try {
const textDecoder = new TextDecoder('utf-8')
const text = textDecoder.decode(new Uint8Array(res.data.slice(0, 100)))
if (text.startsWith('{') || text.startsWith('[')) {
// 是JSON响应说明是错误
const errorData = JSON.parse(text)
console.error('TTS API Error:', errorData)
reject(new Error(errorData.err_msg || 'TTS请求失败'))
return
}
} catch (e) {
// 不是JSON应该是音频数据
}
resolve(res.data)
} else {
reject(new Error('返回数据为空'))
}
} else {
reject(new Error(`请求失败,状态码: ${res.statusCode}`))
}
},
fail: (err) => {
console.error('TTS Request Error:', err)
reject(new Error(err.errMsg || '网络请求失败'))
}
})
})
} }
Loading…
Cancel
Save