diff --git a/config.js b/config.js
index 74e3c87..c4a6092 100644
--- a/config.js
+++ b/config.js
@@ -4,10 +4,11 @@ export default {
// baseUrl: 'http://192.168.3.29:8081',
// baseUrl: 'http://10.213.6.207:19010/api',
// 语音转文字
- // vioceBaseURl: 'ws://39.98.44.136:8080/speech-recognition',
- vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/speech-recognition',
+ // vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/speech-recognition',
+ vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/system/asr/connect', // 自定义
// 语音合成
speechSynthesis: 'wss://qd.zhaopinzao8dian.com/api/speech-synthesis',
+ speechSynthesis2: 'wss://resource.zhuoson.com/synthesis/',
// indexedDB
DBversion: 2,
// 只使用本地缓寸的数据
diff --git a/hook/useRealtimeRecorder.js b/hook/useRealtimeRecorder.js
index a74b635..1cc6fde 100644
--- a/hook/useRealtimeRecorder.js
+++ b/hook/useRealtimeRecorder.js
@@ -9,6 +9,7 @@ import {
import config from '@/config'
+// Alibaba Cloud
export function useAudioRecorder() {
const isRecording = ref(false)
const isStopping = ref(false)
diff --git a/hook/useRealtimeRecorder2.js b/hook/useRealtimeRecorder2.js
new file mode 100644
index 0000000..4901226
--- /dev/null
+++ b/hook/useRealtimeRecorder2.js
@@ -0,0 +1,348 @@
+import {
+ ref,
+ onUnmounted
+} from 'vue'
+import {
+ $api
+} from '../common/globalFunction'; // 你的请求封装
+import config from '@/config'
+
+// 开源
+export function useAudioRecorder() {
+ // --- 状态定义 ---
+ const isRecording = ref(false)
+ const isSocketConnected = ref(false)
+ const recordingDuration = ref(0)
+ const volumeLevel = ref(0) // 0-100
+ const recognizedText = ref('')
+
+ // --- 内部变量 ---
+ let socketTask = null
+ let durationTimer = null
+
+ // --- APP/小程序 变量 ---
+ let recorderManager = null;
+
+ // --- H5 变量 ---
+ let audioContext = null;
+ let scriptProcessor = null;
+ let mediaStreamSource = null;
+ let h5Stream = null;
+
+ // --- 配置项 ---
+ const RECORD_CONFIG = {
+ duration: 600000,
+ sampleRate: 16000,
+ numberOfChannels: 1,
+ format: 'pcm',
+ frameSize: 4096
+ }
+
+ /**
+ * 获取 WebSocket 地址 (含 Token)
+ */
+ const getWsUrl = async () => {
+ let wsUrl = config.vioceBaseURl
+
+ // 拼接 Token
+ const token = uni.getStorageSync('token') || '';
+ if (token) {
+ const separator = wsUrl.includes('?') ? '&' : '?';
+ wsUrl = `${wsUrl}${separator}token=${encodeURIComponent(token)}`;
+ }
+ return wsUrl;
+ }
+
+ /**
+ * 开始录音 (入口)
+ */
+ const startRecording = async () => {
+ if (isRecording.value) return
+
+ try {
+ recognizedText.value = ''
+ volumeLevel.value = 0
+
+ // #ifdef H5
+ if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
+ uni.showToast({
+ title: 'H5录音需要HTTPS环境',
+ icon: 'none'
+ });
+ return;
+ }
+ // #endif
+
+ const url = await getWsUrl()
+ console.log('正在连接 ASR:', url)
+
+ await connectSocket(url);
+
+ } catch (err) {
+ console.error('启动失败:', err);
+ uni.showToast({
+ title: '启动失败: ' + (err.message || ''),
+ icon: 'none'
+ });
+ cleanup();
+ }
+ }
+
+ /**
+ * 连接 WebSocket
+ */
+ const connectSocket = (url) => {
+ return new Promise((resolve, reject) => {
+ socketTask = uni.connectSocket({
+ url: url,
+ success: () => console.log('Socket 连接请求发送'),
+ fail: (err) => reject(err)
+ });
+
+ socketTask.onOpen((res) => {
+ console.log('WebSocket 已连接');
+ isSocketConnected.value = true;
+
+ // #ifdef H5
+ startH5Recording().then(() => resolve()).catch(err => {
+ socketTask.close();
+ reject(err);
+ });
+ // #endif
+
+ // #ifndef H5
+ startAppRecording();
+ resolve();
+ // #endif
+ });
+
+ socketTask.onMessage((res) => {
+ // 接收文本结果
+ if (res.data) {
+ recognizedText.value = res.data;
+ }
+ });
+
+ socketTask.onError((err) => {
+ console.error('Socket 错误:', err);
+ isSocketConnected.value = false;
+ stopRecording();
+ });
+
+ socketTask.onClose(() => {
+ isSocketConnected.value = false;
+ console.log('Socket 已关闭');
+ });
+ })
+ }
+
+ const startH5Recording = async () => {
+ try {
+ // 1. 获取麦克风流
+ const stream = await navigator.mediaDevices.getUserMedia({
+ audio: true
+ });
+ h5Stream = stream;
+
+ // 2. 创建 AudioContext
+ const AudioContext = window.AudioContext || window.webkitAudioContext;
+ audioContext = new AudioContext({
+ sampleRate: 16000
+ });
+
+ mediaStreamSource = audioContext.createMediaStreamSource(stream);
+ scriptProcessor = audioContext.createScriptProcessor(4096, 1, 1);
+
+ scriptProcessor.onaudioprocess = (event) => {
+ if (!isSocketConnected.value || !socketTask) return;
+
+ const inputData = event.inputBuffer.getChannelData(0);
+
+ calculateVolume(inputData, true);
+
+ const buffer = new ArrayBuffer(inputData.length * 2);
+ const view = new DataView(buffer);
+ for (let i = 0; i < inputData.length; i++) {
+ let s = Math.max(-1, Math.min(1, inputData[i]));
+ view.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
+ }
+
+ socketTask.send({
+ data: buffer,
+ fail: (e) => console.error('发送音频失败', e)
+ });
+ };
+
+ mediaStreamSource.connect(scriptProcessor);
+ scriptProcessor.connect(audioContext.destination);
+
+ isRecording.value = true;
+ recordingDuration.value = 0;
+ durationTimer = setInterval(() => recordingDuration.value++, 1000);
+
+ console.log('H5 录音已启动');
+
+ } catch (err) {
+ console.error('H5 录音启动失败:', err);
+ throw err;
+ }
+ }
+
+ const stopH5Resources = () => {
+ if (scriptProcessor) scriptProcessor.disconnect();
+ if (mediaStreamSource) mediaStreamSource.disconnect();
+ if (audioContext) audioContext.close();
+ if (h5Stream) h5Stream.getTracks().forEach(track => track.stop());
+
+ scriptProcessor = null;
+ mediaStreamSource = null;
+ audioContext = null;
+ h5Stream = null;
+ }
+
+ const startAppRecording = () => {
+ recorderManager = uni.getRecorderManager();
+
+ recorderManager.onFrameRecorded((res) => {
+ const {
+ frameBuffer
+ } = res;
+
+ calculateVolume(frameBuffer, false);
+
+ if (isSocketConnected.value && socketTask) {
+ socketTask.send({
+ data: frameBuffer
+ });
+ }
+ });
+
+ recorderManager.onStart(() => {
+ console.log('APP 录音已开始');
+ isRecording.value = true;
+ recordingDuration.value = 0;
+ durationTimer = setInterval(() => recordingDuration.value++, 1000);
+ });
+
+ recorderManager.onError((err) => {
+ console.error('APP 录音报错:', err);
+ cleanup();
+ });
+
+ recorderManager.start(RECORD_CONFIG);
+ }
+ const stopHardwareResource = () => {
+ // APP/小程序停止
+ if (recorderManager) {
+ recorderManager.stop();
+ }
+
+ // H5停止
+ // #ifdef H5
+ if (scriptProcessor) scriptProcessor.disconnect();
+ if (mediaStreamSource) mediaStreamSource.disconnect();
+ if (audioContext) audioContext.close();
+ if (h5Stream) h5Stream.getTracks().forEach(track => track.stop());
+
+ scriptProcessor = null;
+ mediaStreamSource = null;
+ audioContext = null;
+ h5Stream = null;
+ // #endif
+ }
+
+ /**
+ * 停止录音 (通用)
+ */
+ const stopRecording = () => {
+ // 停止 APP 录音
+ if (recorderManager) {
+ recorderManager.stop();
+ }
+
+ // 停止 H5 录音资源
+ // #ifdef H5
+ stopH5Resources();
+ // #endif
+
+ // 关闭 Socket
+ if (socketTask) {
+ socketTask.close();
+ }
+
+ cleanup();
+ }
+
+ const cancelRecording = () => {
+ if (!isRecording.value) return;
+
+ console.log('取消录音 - 丢弃结果');
+
+ // 1. 停止硬件录音
+ stopHardwareResource();
+
+ // 2. 强制关闭 Socket
+ if (socketTask) {
+ socketTask.close();
+ }
+
+ // 3. 关键:清空已识别的文本
+ recognizedText.value = '';
+
+ // 4. 清理资源
+ cleanup();
+ }
+
+ /**
+ * 清理状态
+ */
+ const cleanup = () => {
+ clearInterval(durationTimer);
+ isRecording.value = false;
+ isSocketConnected.value = false;
+ socketTask = null;
+ recorderManager = null;
+ volumeLevel.value = 0;
+ }
+
+ /**
+ * 计算音量 (兼容 Float32 和 Int16/ArrayBuffer)
+ */
+ const calculateVolume = (data, isFloat32) => {
+ let sum = 0;
+ let length = 0;
+
+ if (isFloat32) {
+ length = data.length;
+ for (let i = 0; i < length; i += 10) {
+ sum += Math.abs(data[i]);
+ }
+ volumeLevel.value = Math.min(100, Math.floor((sum / (length / 10)) * 100 * 3));
+ } else {
+ const int16Data = new Int16Array(data);
+ length = int16Data.length;
+ for (let i = 0; i < length; i += 10) {
+ sum += Math.abs(int16Data[i]);
+ }
+ const avg = sum / (length / 10);
+ volumeLevel.value = Math.min(100, Math.floor((avg / 10000) * 100));
+ }
+ }
+
+ onUnmounted(() => {
+ if (isRecording.value) {
+ stopRecording();
+ }
+ })
+
+ return {
+ isRecording,
+ isSocketConnected,
+ recordingDuration,
+ volumeLevel,
+ recognizedText,
+ startRecording,
+ stopRecording,
+ cancelRecording
+ }
+}
\ No newline at end of file
diff --git a/hook/useTTSPlayer.js b/hook/useTTSPlayer.js
index b969236..bfc6e00 100644
--- a/hook/useTTSPlayer.js
+++ b/hook/useTTSPlayer.js
@@ -9,8 +9,9 @@ import {
onUnload
} from '@dcloudio/uni-app'
import WavDecoder from '@/lib/wav-decoder@1.3.0.js'
+import config from '@/config'
-export function useTTSPlayer(wsUrl) {
+export function useTTSPlayer() {
const isSpeaking = ref(false)
const isPaused = ref(false)
const isComplete = ref(false)
@@ -89,12 +90,13 @@ export function useTTSPlayer(wsUrl) {
const initWebSocket = () => {
const thisPlayId = currentPlayId
- socket = new WebSocket(wsUrl)
+ socket = new WebSocket(config.speechSynthesis)
socket.binaryType = 'arraybuffer'
socket.onopen = () => {
if (pendingText && thisPlayId === activePlayId) {
const seepdText = extractSpeechText(pendingText)
+ console.log(seepdText)
socket.send(seepdText)
pendingText = null
}
diff --git a/hook/useTTSPlayer2.js b/hook/useTTSPlayer2.js
new file mode 100644
index 0000000..131e9c7
--- /dev/null
+++ b/hook/useTTSPlayer2.js
@@ -0,0 +1,333 @@
+import {
+ ref,
+ onUnmounted,
+ onMounted
+} from 'vue'
+// 如果是 uni-app 环境,保留这些导入;如果是纯 Web Vue3,可以移除
+import {
+ onHide,
+ onUnload
+} from '@dcloudio/uni-app'
+import config from '@/config'
+
+/**
+ * Piper TTS 播放钩子 (WebSocket MSE 流式版 - 含 cancelAudio)
+ * 依赖: 后端必须去除 MP3 ID3 标签 (-map_metadata -1)
+ */
+export function useTTSPlayer() {
+ // 状态管理
+ const isSpeaking = ref(false)
+ const isPaused = ref(false)
+ const isLoading = ref(false)
+
+ // 核心对象
+ let audio = null
+ let mediaSource = null
+ let sourceBuffer = null
+ let ws = null
+
+ // 缓冲队列管理
+ let bufferQueue = []
+ let isAppending = false
+ let isStreamEnded = false
+
+ // 初始化 Audio 监听器 (只运行一次)
+ const initAudioElement = () => {
+ if (!audio && typeof window !== 'undefined') {
+ audio = new Audio()
+
+ // 错误监听
+ audio.addEventListener('error', (e) => {
+ // 如果是手动停止导致的 error (src 被置空),忽略
+ if (!audio.src) return
+ console.error('Audio Player Error:', e)
+ resetState()
+ })
+
+ // 播放结束监听
+ audio.addEventListener('ended', () => {
+ resetState()
+ })
+ }
+ }
+
+ /**
+ * 核心朗读方法 (WebSocket)
+ * @param {string} text - 要朗读的文本
+ */
+ const speak = async (text) => {
+ if (!text) return
+
+ // 1. 提取文本
+ const processedText = extractSpeechText(text)
+ if (!processedText) return
+
+ // 2. 彻底清理旧状态
+ cancelAudio()
+ initAudioElement()
+
+ isLoading.value = true
+ isSpeaking.value = true
+ isPaused.value = false
+ isStreamEnded = false
+
+ // 3. 检查环境
+ if (!window.MediaSource || !window.WebSocket) {
+ console.error('当前环境不支持 MediaSource 或 WebSocket')
+ resetState()
+ return
+ }
+
+ try {
+ // 4. 初始化 MSE
+ mediaSource = new MediaSource()
+ // 绑定 MSE 到 Audio
+ audio.src = URL.createObjectURL(mediaSource)
+
+ // 监听 MSE 打开事件
+ mediaSource.addEventListener('sourceopen', () => {
+ // 防止多次触发
+ if (mediaSource.sourceBuffers.length > 0) return
+ startWebSocketStream(processedText)
+ })
+
+ // 尝试播放 (处理浏览器自动播放策略)
+ const playPromise = audio.play()
+ if (playPromise !== undefined) {
+ playPromise.catch(e => {
+ console.warn('自动播放被拦截 (需用户交互):', e)
+ // 保持 isSpeaking 为 true,UI 显示播放按钮,用户点击后调用 resume() 即可
+ })
+ }
+
+ } catch (err) {
+ console.error('TTS Initialization Failed:', err)
+ cancelAudio()
+ }
+ }
+
+ // 启动 WebSocket 流程
+ const startWebSocketStream = (text) => {
+ const mime = 'audio/mpeg'
+
+ // 4.1 创建 SourceBuffer
+ try {
+ sourceBuffer = mediaSource.addSourceBuffer(mime)
+ sourceBuffer.addEventListener('updateend', () => {
+ isAppending = false
+ processQueue()
+ })
+ } catch (e) {
+ console.error('SourceBuffer Create Failed:', e)
+ return
+ }
+
+ // 4.2 计算 WebSocket 地址
+ let baseUrl = config.speechSynthesis2 || ''
+ baseUrl = baseUrl.replace(/\/$/, '')
+ const wsUrl = baseUrl.replace(/^http/, 'ws') + '/ws/synthesize'
+
+ // 4.3 建立连接
+ ws = new WebSocket(wsUrl)
+ ws.binaryType = 'arraybuffer' // 关键
+
+ ws.onopen = () => {
+ // console.log('WS Open')
+ ws.send(JSON.stringify({
+ text: text,
+ speaker_id: 0,
+ length_scale: 1.0,
+ noise_scale: 0.667
+ }))
+ isLoading.value = false
+ }
+
+ ws.onmessage = (event) => {
+ if (event.data instanceof ArrayBuffer) {
+ bufferQueue.push(event.data)
+ processQueue()
+ }
+ }
+
+ ws.onerror = (e) => {
+ console.error('WS Error:', e)
+ cancelAudio()
+ }
+
+ ws.onclose = () => {
+ // console.log('WS Closed')
+ isStreamEnded = true
+ // 检查是否需要结束 MSE 流
+ checkEndOfStream()
+ }
+ }
+
+ // 处理缓冲队列
+ const processQueue = () => {
+ if (!sourceBuffer || sourceBuffer.updating || bufferQueue.length === 0) {
+ // 如果队列空了,且流已结束,尝试结束 MSE
+ if (bufferQueue.length === 0 && isStreamEnded && !sourceBuffer.updating) {
+ checkEndOfStream()
+ }
+ return
+ }
+
+ isAppending = true
+ const chunk = bufferQueue.shift()
+
+ try {
+ sourceBuffer.appendBuffer(chunk)
+ } catch (e) {
+ // console.error('AppendBuffer Error:', e)
+ isAppending = false
+ }
+ }
+
+ // 结束 MSE 流
+ const checkEndOfStream = () => {
+ if (mediaSource && mediaSource.readyState === 'open' && bufferQueue.length === 0 && !sourceBuffer
+ ?.updating) {
+ try {
+ mediaSource.endOfStream()
+ } catch (e) {}
+ }
+ }
+
+ const pause = () => {
+ if (audio && !audio.paused) {
+ audio.pause()
+ isPaused.value = true
+ isSpeaking.value = false
+ }
+ }
+
+ const resume = () => {
+ if (audio && audio.paused) {
+ audio.play()
+ isPaused.value = false
+ isSpeaking.value = true
+ }
+ }
+
+ // === 新增/核心方法:取消并停止 ===
+ const cancelAudio = () => {
+ // 1. 断开 WebSocket (停止数据接收)
+ if (ws) {
+ // 移除监听器防止报错
+ ws.onclose = null
+ ws.onerror = null
+ ws.onmessage = null
+ ws.close()
+ ws = null
+ }
+
+ // 2. 停止音频播放
+ if (audio) {
+ audio.pause()
+ // 释放 Blob URL 内存
+ if (audio.src) {
+ URL.revokeObjectURL(audio.src)
+ audio.removeAttribute('src')
+ }
+ audio.currentTime = 0
+ }
+
+ // 3. 清理 MSE 对象
+ if (mediaSource) {
+ try {
+ if (mediaSource.readyState === 'open') {
+ mediaSource.endOfStream()
+ }
+ } catch (e) {}
+ mediaSource = null
+ }
+
+ sourceBuffer = null
+ bufferQueue = []
+ isAppending = false
+ isStreamEnded = false
+
+ // 4. 重置 UI 状态
+ resetState()
+ }
+
+ // 只是重置 UI 变量的辅助函数
+ const resetState = () => {
+ isSpeaking.value = false
+ isPaused.value = false
+ isLoading.value = false
+ }
+
+ // 别名 stop -> cancelAudio (保持兼容性)
+ const stop = cancelAudio
+
+ // === 生命周期 ===
+ onMounted(() => {
+ initAudioElement()
+ })
+
+ onUnmounted(() => {
+ cancelAudio()
+ audio = null
+ })
+
+ if (typeof onHide === 'function') onHide(cancelAudio)
+ if (typeof onUnload === 'function') onUnload(cancelAudio)
+
+ return {
+ speak,
+ pause,
+ resume,
+ stop,
+ cancelAudio, // 新增导出
+ isSpeaking,
+ isPaused,
+ isLoading
+ }
+}
+
+/**
+ * 提取文本逻辑
+ */
+function extractSpeechText(markdown) {
+ if (!markdown || markdown.indexOf('job-json') === -1) {
+ return markdown;
+ }
+
+ const jobRegex = /``` job-json\s*({[\s\S]*?})\s*```/g;
+ const jobs = [];
+ let match;
+ let lastJobEndIndex = 0;
+ let firstJobStartIndex = -1;
+
+ while ((match = jobRegex.exec(markdown)) !== null) {
+ const jobStr = match[1];
+ try {
+ const job = JSON.parse(jobStr);
+ jobs.push(job);
+ if (firstJobStartIndex === -1) {
+ firstJobStartIndex = match.index;
+ }
+ lastJobEndIndex = jobRegex.lastIndex;
+ } catch (e) {
+ console.warn('JSON 解析失败', e);
+ }
+ }
+
+ const guideText = firstJobStartIndex > 0 ?
+ markdown.slice(0, firstJobStartIndex).trim() : '';
+
+ const endingText = lastJobEndIndex < markdown.length ?
+ markdown.slice(lastJobEndIndex).trim() : '';
+
+ const jobTexts = jobs.map((job, index) => {
+ return `第 ${index + 1} 个岗位,岗位名称是:${job.jobTitle},公司是:${job.companyName},薪资:${job.salary},地点:${job.location},学历要求:${job.education},经验要求:${job.experience}。`;
+ });
+
+ const finalTextParts = [];
+ if (guideText) finalTextParts.push(guideText);
+ finalTextParts.push(...jobTexts);
+ if (endingText) finalTextParts.push(endingText);
+
+ return finalTextParts.join('\n');
+}
\ No newline at end of file
diff --git a/index.html b/index.html
index f5958b8..3f577f2 100644
--- a/index.html
+++ b/index.html
@@ -22,11 +22,11 @@
-->
-
+
diff --git a/packageA/pages/exhibitors/exhibitors.vue b/packageA/pages/exhibitors/exhibitors.vue
index 0a8659a..9dfc573 100644
--- a/packageA/pages/exhibitors/exhibitors.vue
+++ b/packageA/pages/exhibitors/exhibitors.vue
@@ -121,7 +121,7 @@ const pageState = reactive({
maxPage: 1,
pageSize: 10,
});
-const hasnext = ref(true);
+const hasnext = ref(false);
const zphId = ref('');
const pageOptions = ref({});
diff --git a/packageA/pages/myResume/myResume.vue b/packageA/pages/myResume/myResume.vue
index 4ee9721..642c6d4 100644
--- a/packageA/pages/myResume/myResume.vue
+++ b/packageA/pages/myResume/myResume.vue
@@ -186,7 +186,8 @@ function uploadResume(tempFilePath, loading) {
header['Authorization'] = encodeURIComponent(Authorization);
return new Promise((resolve, reject) => {
uni.uploadFile({
- url: config.baseUrl + '/app/oss/uploadToObs',
+ url: config.baseUrl + '/app/user/resume/recognition',
+ // url: config.baseUrl + '/app/oss/uploadToObs',
filePath: tempFilePath,
name: 'file',
header,
diff --git a/pages/chat/components/ai-paging.vue b/pages/chat/components/ai-paging.vue
index 3db1b13..dd08347 100644
--- a/pages/chat/components/ai-paging.vue
+++ b/pages/chat/components/ai-paging.vue
@@ -240,7 +240,7 @@
-
+
@@ -268,9 +268,9 @@ import WaveDisplay from './WaveDisplay.vue';
import FileIcon from './fileIcon.vue';
import FileText from './fileText.vue';
// 系统功能hook和阿里云hook
-import { useAudioRecorder } from '@/hook/useRealtimeRecorder.js';
+import { useAudioRecorder } from '@/hook/useRealtimeRecorder2.js';
// import { useAudioRecorder } from '@/hook/useSystemSpeechReader.js';
-import { useTTSPlayer } from '@/hook/useTTSPlayer.js';
+import { useTTSPlayer } from '@/hook/useTTSPlayer2.js';
// import { useTTSPlayer } from '@/hook/useSystemPlayer.js';
// 全局
const { $api, navTo, throttle } = inject('globalFunction');
@@ -612,17 +612,23 @@ function userGoodFeedback(msg) {
// $api.msg('该功能正在开发中,敬请期待后续更新!');
feeback.value?.open();
feebackData.value = msg;
+ uni.hideTabBar()
}
function confirmFeeBack(value) {
useChatGroupDBStore()
.badFeedback(feebackData.value, value)
.then(() => {
+ uni.showTabBar()
feeback.value?.close();
feeBackTips.value?.open();
});
}
+function colseFeeBack() {
+ uni.showTabBar()
+}
+
function readMarkdown(value, index) {
speechIndex.value = index;
if (speechIndex.value !== index) {
diff --git a/pages/chat/components/popupbadFeeback.vue b/pages/chat/components/popupbadFeeback.vue
index ebdc864..1d99f01 100644
--- a/pages/chat/components/popupbadFeeback.vue
+++ b/pages/chat/components/popupbadFeeback.vue
@@ -1,5 +1,5 @@
-
+
反馈
针对问题
@@ -38,7 +38,7 @@