yangyin
2024-07-19 eb12c4bc2af08b457f4282174626b067ba01f215
Merge branch 'master' of http://47.103.154.90:83/r/WI/Web.V1.0
已修改7个文件
已添加1个文件
370 ■■■■ 文件已修改
customer_list/ch/static/fonts/ywiconfont/iconfont.css 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
customer_list/ch/static/fonts/ywiconfont/iconfont.ttf 补丁 | 查看 | 原始文档 | blame | 历史
customer_list/ch/static/fonts/ywiconfont/iconfont.woff 补丁 | 查看 | 原始文档 | blame | 历史
customer_list/ch/static/fonts/ywiconfont/iconfont.woff2 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/components/FeedbackPanel.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/components/playBar/PlayBar.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/components/playBar/voicePage/VoicePage.vue 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
customer_list/ch/static/fonts/ywiconfont/iconfont.css
@@ -1,8 +1,8 @@
@font-face {
  font-family: "ywicon"; /* Project id 4499025 */
  src: url('iconfont.woff2?t=1720078869685') format('woff2'),
       url('iconfont.woff?t=1720078869685') format('woff'),
       url('iconfont.ttf?t=1720078869685') format('truetype');
  src: url('iconfont.woff2?t=1721375418093') format('woff2'),
       url('iconfont.woff?t=1721375418093') format('woff'),
       url('iconfont.ttf?t=1721375418093') format('truetype');
}
.ywicon {
@@ -11,6 +11,46 @@
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.icon-maikefeng-filled:before {
  content: "\e621";
}
.icon-gengduo:before {
  content: "\e73a";
}
.icon-maikefeng:before {
  content: "\e607";
}
.icon-wentifankui:before {
  content: "\e614";
}
.icon-zuoyoujiantou:before {
  content: "\e673";
}
.icon-zuoyoujiantou1:before {
  content: "\e602";
}
.icon-cedian:before {
  content: "\e65a";
}
.icon-shuzhuangtu:before {
  content: "\e600";
}
.icon-tubiao-zhexiantu:before {
  content: "\eb96";
}
.icon-sandiantu:before {
  content: "\e927";
}
.icon-gongzuozongjie:before {
@@ -129,7 +169,7 @@
  content: "\e61d";
}
.icon-ai23:before {
.icon-bofang:before {
  content: "\e68a";
}
customer_list/ch/static/fonts/ywiconfont/iconfont.ttf
Binary files differ
customer_list/ch/static/fonts/ywiconfont/iconfont.woff
Binary files differ
customer_list/ch/static/fonts/ywiconfont/iconfont.woff2
Binary files differ
src/components/chat/components/FeedbackPanel.vue
@@ -4,10 +4,10 @@
        :style="{ left: position.x + 'px', top: position.y + 'px' }"
    >
        <div class="flex justify-between">
            <h3>你的反馈将<br />帮助 WI æ°´åŠ¡ä¼˜åŒ–è¿›æ­¥</h3>
            <h3 class="text-base">你的反馈将<br />帮助 WI æ°´åŠ¡ä¼˜åŒ–è¿›æ­¥</h3>
            <i class="ywicon icon-guanbi right-0 top-0 !text-[20px] text-gray-500 cursor-pointer" @click="closeClick"></i>
        </div>
        <div class="mt-6 flex-col flex">
        <div class="mt-4 flex-col flex">
            <el-input v-model="content" resize="none" class="" type="textarea" :rows="3"></el-input>
            <el-button :disabled="!content" color="#1d86ff" class="m-auto mt-3" type="primary" @click="submitFeedback">提 äº¤</el-button>
        </div>
src/components/chat/components/playBar/PlayBar.vue
@@ -35,22 +35,20 @@
                </div>
            </div>
        </div>
        <VoicePage v-model:isShow="voicePageIsShow" v-show="voicePageIsShow" />
    </div>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus';
import { ref } from 'vue';
import VoicePage from './voicePage/VoicePage.vue';
const emits = defineEmits(['sendClick']);
const props = defineProps(['isTalking']);
const voicePageIsShow = ref(false);
const inputValue = defineModel({
    type: String,
});
const isListening = ref(false);
const enterInput = (e) => {
    if (props.isTalking) return;
@@ -63,41 +61,7 @@
    }
};
const audioChangeWord = () => {
    inputValue.value = '';
    // åˆ›å»ºSpeechRecognition对象
    // eslint-disable-next-line no-undef
    var recognition = new webkitSpeechRecognition();
    if (!recognition) {
        // eslint-disable-next-line no-undef
        recognition = new SpeechRecognition();
    }
    console.log('recognition2', recognition);
    console.log(11);
    // è®¾ç½®è¯­è¨€
    recognition.lang = 'zh-CN';
    console.log(22);
    // å¼€å§‹è¯­éŸ³è¯†åˆ«
    recognition.start();
    isListening.value = true;
    console.log(33);
    // ç›‘听识别结果
    recognition.onresult = function (event) {
        var result = event.results[0][0].transcript;
        console.log('监听结果:', result);
        inputValue.value = result;
    };
    // ç›‘听错误事件
    recognition.onerror = function (event) {
        isListening.value = false;
        ElMessage.error('监听语音失败');
        console.error(event.error);
    };
    // ç›‘听结束事件(包括识别成功、识别错误和用户停止)
    recognition.onend = function () {
        isListening.value = false;
        console.log('语音识别停止');
    };
    voicePageIsShow.value = true;
};
</script>
<style scoped lang="scss">
src/components/chat/components/playBar/voicePage/VoicePage.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,272 @@
<template>
    <div class="fixed top-0 left-0 w-screen h-screen bg-[rgb(0,0,0,.8)] backdrop-blur-[20px] z-10">
        <div
            class="absolute w-[414px] h-[752px] bg-black left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl text-white flex flex-col"
        >
            <div class="mx-auto text-lg text-gray-300 mt-4 flex-0">Chat-4.0</div>
            <div class="flex flex-col flex-auto relative items-center">
                <div class="chat mt-[130px] mb-[110px]">
                    <span :style="{ 'animation-play-state': animationPlayState }"
                        ><i :style="{ 'animation-play-state': animationPlayState }"></i
                        ><i :style="{ 'animation-play-state': animationPlayState }"></i
                        ><i :style="{ 'animation-play-state': animationPlayState }"></i
                    ></span>
                    <div class="chatPop size-72" :style="{ 'animation-play-state': animationPlayState }">
                        <span class="size-32" :style="{ 'animation-play-state': animationPlayState }"></span>
                    </div>
                </div>
                <div class="flex items-center">
                    <div class="sound-animate relative">
                        <i class="ywicon icon-maikefeng-filled !text-[26px] absolute -left-10 top-[5px]"></i>
                        <span :style="{ 'animation-play-state': animationPlayState }"></span
                        ><span :style="{ 'animation-play-state': animationPlayState }"></span
                        ><span :style="{ 'animation-play-state': animationPlayState }"></span
                        ><span :style="{ 'animation-play-state': animationPlayState }"></span>
                    </div>
                </div>
                <div class="mt-5">请开始说话</div>
                <div class="flex items-center justify-between bottom-16 absolute left-1/2 -translate-x-1/2 space-x-16">
                    <div class="size-[35px] flex items-center justify-center bg-[#292929] rounded-full cursor-pointer" @click="togglePlayClick">
                        <i class="ywicon !text-[16px]" :class="playIcon"></i>
                    </div>
                    <div class="size-[56px] flex items-center justify-center bg-red-500 rounded-full cursor-pointer" @click="closeClick">
                        <i class="ywicon icon-guanbi !text-[26px]"></i>
                    </div>
                    <div class="size-[35px] flex items-center justify-center bg-[#292929] rounded-full cursor-pointer">
                        <i class="ywicon icon-gengduo !text-[23px]"></i>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
const animationPlayState = ref<'paused' | 'running'>('running');
const playIcon = computed(() => (animationPlayState.value === 'running' ? 'icon-zanting' : 'icon-bofang'));
const togglePlayClick = () => {
    animationPlayState.value = animationPlayState.value === 'running' ? 'paused' : 'running';
};
const isShow = defineModel('isShow', {
    type: Boolean,
});
const isListening = ref(false);
const inputValue = ref('');
const closeClick = () => {
    isShow.value = false;
};
const audioChangeWord = () => {
    inputValue.value = '';
    // åˆ›å»ºSpeechRecognition对象
    // eslint-disable-next-line no-undef
    var recognition = new webkitSpeechRecognition();
    if (!recognition) {
        // eslint-disable-next-line no-undef
        recognition = new SpeechRecognition();
    }
    console.log('recognition2', recognition);
    console.log(11);
    // è®¾ç½®è¯­è¨€
    recognition.lang = 'zh-CN';
    console.log(22);
    // å¼€å§‹è¯­éŸ³è¯†åˆ«
    recognition.start();
    isListening.value = true;
    console.log(33);
    // ç›‘听识别结果
    recognition.onresult = function (event) {
        var result = event.results[0][0].transcript;
        console.log('监听结果:', result);
        inputValue.value = result;
    };
    // ç›‘听错误事件
    recognition.onerror = function (event) {
        isListening.value = false;
        ElMessage.error('监听语音失败');
        console.error(event.error);
    };
    // ç›‘听结束事件(包括识别成功、识别错误和用户停止)
    recognition.onend = function () {
        isListening.value = false;
        console.log('语音识别停止');
    };
};
const resetStatus = () => {
    animationPlayState.value = 'running';
};
watch(
    () => isShow.value,
    (val) => {
        if (!val) {
            resetStatus();
        }
    }
);
</script>
<style scoped lang="scss">
@keyframes balls {
    0% {
        top: 0;
        left: 0;
    }
    to {
        opacity: 0;
        top: 0;
        left: 100%;
    }
}
@keyframes chat-voices {
    0% {
        opacity: 1;
        -webkit-transform: scale(1);
        transform: scale(1);
    }
    50% {
        opacity: 1;
        -webkit-transform: scale(1.5);
        transform: scale(1.5);
    }
    to {
        opacity: 1;
        -webkit-transform: scale(1);
        transform: scale(1);
    }
}
@keyframes change-size {
    0% {
        -webkit-transform: scale(1);
        transform: scale(1);
    }
    50% {
        -webkit-transform: scale(1.2);
        transform: scale(1.2);
    }
    to {
        -webkit-transform: scale(1);
        transform: scale(1);
    }
}
.chat {
    position: relative;
    width: 100%;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    > span {
        width: 50%;
        position: absolute;
        left: 0;
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        -webkit-box-align: center;
        -ms-flex-align: center;
        align-items: center;
        top: 50%;
        -webkit-transform: translateY(-50%);
        -ms-transform: translateY(-50%);
        transform: translateY(-50%);
    }
}
.chatPop {
    border-radius: 50%;
    background-color: #fff;
    -webkit-animation: chat-voice-ad71603e 1s ease 0.5s forwards;
    animation: chat-voice-ad71603e 1s ease 0.5s forwards;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    > span {
        border-radius: 50%;
        opacity: 0;
        background-color: #000;
        -webkit-animation: chat-voices 1.5s linear 0.9s infinite;
        animation: chat-voices 1.5s linear 0.9s infinite;
        > i[data-v-ad71603e]:first-of-type {
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background-color: #fff;
            position: relative;
            -webkit-animation: balls 1s ease 0.3s forwards;
            animation: balls 1s ease 0.3s forwards;
            margin-left: 23px;
        }
        > i[data-v-ad71603e]:nth-of-type(2) {
            width: 23px;
            height: 23px;
            border-radius: 50%;
            background-color: #fff;
            position: relative;
            -webkit-animation: balles-ad71603e 1s ease 0.3s forwards;
            animation: balles-ad71603e 1s ease 0.3s forwards;
            margin-left: 7px;
        }
        > i[data-v-ad71603e]:nth-of-type(3) {
            width: 38px;
            height: 38px;
            border-radius: 50%;
            background-color: #fff;
            position: relative;
            -webkit-animation: ball-ad71603e 1s ease 0.3s forwards;
            animation: ball-ad71603e 1s ease 0.3s forwards;
            margin-left: 7px;
        }
    }
}
.sound-animate > span {
    -webkit-box-sizing: content-box;
    box-sizing: content-box;
    display: inline-block;
    width: 27px;
    height: 27px;
    border-radius: 50%;
    background-color: #fff;
    -webkit-animation: change-size var(--animation-duration) linear infinite alternate;
    animation: change-size var(--animation-duration) linear infinite alternate;
}
.sound-animate span:first-child {
    --animation-duration: 1s;
}
.sound-animate span:nth-child(2) {
    --animation-duration: 1.2s;
}
.sound-animate span:nth-child(3) {
    --animation-duration: 0.8s;
}
.sound-animate span:nth-child(4) {
    --animation-duration: 1.4s;
}
</style>
vite.config.ts
@@ -35,7 +35,7 @@
            host: '0.0.0.0',
            port: env.VITE_PORT as unknown as number,
            open: JSON.parse(env.VITE_OPEN),
            hmr: false,
            hmr: true,
        },
        build: {
            // outDir: 'dist/' + mode.mode,