feat: 首页改版

This commit is contained in:
2026-08-25 17:52:05 +08:00
parent d65083aa51
commit d5253e3202
15 changed files with 1014 additions and 644 deletions
@@ -918,6 +918,187 @@ export default {
await this.pickAndUploadImage()
},
checkMicrophoneAuthorized() {
// #ifdef H5
return true
// #endif
// #ifdef MP-WEIXIN
return new Promise((resolve) => {
uni.getSetting({
success: (res) => {
resolve(res.authSetting['scope.record'] === true)
},
fail: () => resolve(false)
})
})
// #endif
// #ifdef APP-PLUS
return new Promise((resolve) => {
const platform = uni.getSystemInfoSync().platform
if (platform === 'android') {
try {
const main = plus.android.runtimeMainActivity()
const PackageManager = plus.android.importClass('android.content.pm.PackageManager')
const permission = main.checkSelfPermission('android.permission.RECORD_AUDIO')
resolve(permission === PackageManager.PERMISSION_GRANTED)
} catch (e) {
resolve(false)
}
} else if (platform === 'ios') {
try {
const avSession = plus.ios.importClass('AVAudioSession')
const audioSession = avSession.sharedInstance()
const permissionStatus = audioSession.recordPermission()
resolve(permissionStatus === 1970168948)
} catch (e) {
resolve(false)
}
} else {
resolve(true)
}
})
// #endif
},
async requestMicrophonePermission() {
// #ifdef H5
if (typeof navigator !== 'undefined' && navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === 'function') {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
stream.getTracks().forEach(track => track.stop())
return true
} catch (e) {
uni.showModal({
title: '麦克风权限提示',
content: '请允许浏览器访问麦克风以使用语音录制功能。',
showCancel: false
})
return false
}
}
return true
// #endif
// #ifdef MP-WEIXIN
return new Promise((resolve) => {
uni.getSetting({
success: (res) => {
const recordAuth = res.authSetting['scope.record']
if (recordAuth === true) {
resolve(true)
} else if (recordAuth === false) {
uni.showModal({
title: '麦克风权限未开启',
content: '需要访问您的麦克风发送语音消息,请前往设置开启权限。',
confirmText: '去设置',
success: (modalRes) => {
if (modalRes.confirm) {
uni.openSetting()
}
resolve(false)
}
})
} else {
uni.authorize({
scope: 'scope.record',
success: () => resolve(true),
fail: () => {
uni.showModal({
title: '授权提示',
content: '麦克风授权失败,无法使用语音功能。',
showCancel: false
})
resolve(false)
}
})
}
},
fail: () => resolve(true)
})
})
// #endif
// #ifdef APP-PLUS
return new Promise((resolve) => {
const platform = uni.getSystemInfoSync().platform
if (platform === 'android') {
try {
plus.android.requestPermissions(
['android.permission.RECORD_AUDIO'],
(result) => {
if (result.granted && result.granted.length > 0) {
resolve(true)
} else {
uni.showModal({
title: '麦克风权限未开启',
content: 'App 需要您的同意才能访问麦克风以发送语音消息。',
confirmText: '去设置',
success: (modalRes) => {
if (modalRes.confirm) {
const Intent = plus.android.importClass('android.content.Intent')
const Settings = plus.android.importClass('android.provider.Settings')
const Uri = plus.android.importClass('android.net.Uri')
const main = plus.android.runtimeMainActivity()
const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
const uri = Uri.fromParts('package', main.getPackageName(), null)
intent.setData(uri)
main.startActivity(intent)
}
resolve(false)
}
})
}
},
(error) => {
console.error('requestPermissions error:', error)
resolve(true)
}
)
} catch (e) {
resolve(true)
}
} else if (platform === 'ios') {
try {
const avSession = plus.ios.importClass('AVAudioSession')
const audioSession = avSession.sharedInstance()
const permissionStatus = audioSession.recordPermission()
if (permissionStatus === 1970168948) { // AVAudioSessionRecordPermissionGranted
resolve(true)
} else if (permissionStatus === 1970168947) { // AVAudioSessionRecordPermissionDenied
uni.showModal({
title: '麦克风权限未开启',
content: 'App 需要您的同意才能访问麦克风,请前往设置开启麦克风权限。',
confirmText: '去设置',
success: (modalRes) => {
if (modalRes.confirm) {
const UIApplication = plus.ios.importClass('UIApplication')
const NSURL = plus.ios.importClass('NSURL')
const app = UIApplication.sharedApplication()
const settingsUrl = NSURL.URLWithString('app-settings:')
if (app.canOpenURL(settingsUrl)) {
app.openURL(settingsUrl)
}
}
resolve(false)
}
})
} else { // Undetermined
audioSession.requestRecordPermission((granted) => {
resolve(granted)
})
}
} catch (e) {
resolve(true)
}
} else {
resolve(true)
}
})
// #endif
},
toggleVoiceMode() {
if (this.uploadingAttachment) return
if (this.recording) this.cancelVoiceRecording()
@@ -939,8 +1120,10 @@ export default {
this.voiceGestureActive = true
this.recordingCancelled = false
this.voiceStartY = this.voiceEventY(event)
await this.startVoiceRecording()
if (!this.voiceGestureActive && this.recording) this.cancelVoiceRecording()
const ok = await this.startVoiceRecording()
if (!ok || (!this.voiceGestureActive && this.recording)) {
this.cancelVoiceRecording()
}
},
handleVoicePressMove(event) {
@@ -28,13 +28,15 @@
/>
<view v-else-if="normalizedType === contentType.AUDIO" class="audio-block">
<button class="audio-message" @click.stop="toggleAudio">
<u-icon :name="audioPlaying ? 'pause-circle' : 'play-circle'" size="24" color="#7934f6" />
<text>{{ audioPlaying ? '正在播放' : '语音消息' }}</text>
<view class="audio-message__left">
<u-icon :name="audioPlaying ? 'pause-circle' : 'play-circle'" size="26" color="#7934f6" />
<text class="audio-message__title">{{ audioPlaying ? '正在播放' : '语音消息' }}</text>
</view>
<text class="audio-duration">{{ attachment.duration ? `${attachment.duration}″` : '' }}</text>
</button>
<text v-if="attachment.transcript" class="audio-transcript" selectable>{{ attachment.transcript }}</text>
<button v-else class="transcribe-button" :disabled="transcribing" @click.stop="$emit('transcribe', message)">
{{ transcribing ? '识别中…' : '转文字' }}
<text>{{ transcribing ? '识别中…' : '转文字' }}</text>
</button>
</view>
<button v-else-if="normalizedType === contentType.FILE" class="file-message" @click.stop="openFile">
@@ -513,44 +515,82 @@ export default {
border: 0;
}
.audio-duration {
margin-left: auto;
color: #777983;
font-size: 22rpx;
}
.audio-block {
display: flex;
min-width: 240rpx;
flex-direction: column;
min-width: 260rpx;
padding: 20rpx 26rpx;
box-sizing: border-box;
}
.audio-message {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
gap: 16rpx;
margin: 0;
padding: 0;
background: transparent;
color: #1f1f23;
text-align: left;
line-height: 1;
&::after {
border: 0;
}
}
.audio-message__left {
display: flex;
align-items: center;
gap: 10rpx;
}
.audio-transcript {
padding-top: 10rpx;
border-top: 1rpx solid rgba(121, 52, 246, 0.14);
color: #35343b;
.audio-message__title {
font-size: 27rpx;
font-weight: 500;
color: #1f1f23;
}
.audio-duration {
margin-left: auto;
color: #7934f6;
font-size: 25rpx;
font-weight: 600;
}
.audio-transcript {
margin-top: 14rpx;
padding-top: 12rpx;
border-top: 1rpx solid rgba(121, 52, 246, 0.15);
color: #27272c;
font-size: 26rpx;
line-height: 1.55;
white-space: normal;
}
.transcribe-button {
display: inline-flex;
align-items: center;
align-self: flex-start;
margin: 0;
padding: 0;
background: transparent;
color: #6730d7;
font-size: 23rpx;
line-height: 34rpx;
}
margin-top: 12rpx;
padding: 6rpx 16rpx;
border-radius: 12rpx;
background: rgba(121, 52, 246, 0.08);
color: #7934f6;
font-size: 22rpx;
font-weight: 500;
line-height: 1.4;
.transcribe-button::after {
border: 0;
}
&::after {
border: 0;
}
.transcribe-button[disabled] {
color: #8e8f96;
&[disabled] {
color: #8e8f96;
background: rgba(0, 0, 0, 0.04);
}
}
.file-message {