123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- <template>
- <div class="ai_career_interview_chat">
- <div class="left-box">
- <div class="profile">
- <img src="@/assets/images/environment/ai-career-profile.png" alt="404">
- </div>
- <div class="introduce-text">
- 在生涯访谈中,通过与不同职业人物对话,可以了解不同职业的发展前景、职业要求,为尽早规划职业发展 xxxx
- <p>访谈时你可以提出以下问题:</p>
- </div>
- <div class="question-list">
- <p class="question-list-item">您为什么要选择这一职业?</p>
- <p class="question-list-item">这项职业每天的核心任务是什么?</p>
- <p class="question-list-item">这项职业的工作环境如何?(室内/室外,办公室/工厂,团队工作/独自工作等)</p>
- <p class="question-list-item">从事这项职业需要哪些学历、证书、经验或关键能力?</p>
- <p class="question-list-item">这项职业在招聘或晋升时,更看重哪些个人特质或阶段特征?</p>
- <p class="question-list-item">大学里哪些专业与这项职业直接相关?</p>
- <p class="question-list-item">为了从事这项职业,在校期间应做哪些具体准备?</p>
- <p class="question-list-item">请分享一个最有成就感的项目/瞬间,以及一次印象深刻的挫折,您从中学到的关键经验是什么?</p>
- <p class="question-list-item">这项职业未来的发展前景如何?</p>
- <p class="question-list-item">这项职业进一步提升的途径有哪些?(培训、证书、项目、学历等)</p>
- <p class="question-list-item">如果未来的我将选择从事该职业,您会给我哪些具体建议?</p>
- <p class="question-list-item">请用时间轴描述一个典型工作日从上班到下班的详细流程?</p>
- </div>
- </div>
- <div class="center-box">
- <div class="center-header">
- <div style="margin-left: 30px"></div>
- <div>小新老师</div>
- <div class="header-exit-btn">退出</div>
- </div>
- <div v-loading="loadingHistoryRecord" class="chat-container">
- <div class="message-list" ref="chatContainerRef">
- <div v-for="(item, index) in chatRecordList" :key="item.id">
- <div v-if="item.isUser == 1" class="user-message">
- <img src="@/assets/images/common/ai/user.png" alt="icon" style="margin-left: 4px"/>
- <span class="user-message-content">{{item.content}}</span>
- </div>
- <div v-else class="bot-message">
- <img src="@/assets/images/common/ai/system.png" alt="icon" style="margin-left: 4px"/>
- <div style="margin-left: 4px;">
- <div class="bot-message-content">
- <div v-if="index === chatRecordList.length-1">
- <div v-if="item.isTyping">
- <div v-html="item.content"></div>
- <span class="loading-dots" style="display: flex;justify-content: center">
- <span class="dot"></span>
- <span class="dot"></span>
- </span>
- </div>
- <div v-else>
- <div v-html="item.content"></div>
- </div>
- </div>
- <div v-else>
- <div v-show="!expandIndexList.includes(index)" v-html="item.content.substring(0, 80)"></div>
- <div v-show="expandIndexList.includes(index)" v-html="item.content"></div>
- </div>
- </div>
- <div style="margin: 4px">
- <el-text>{{item.createTime}}</el-text>
- </div>
- </div>
- <div v-if="index !== chatRecordList.length-1">
- <el-button v-if="item.content.length>80" style="margin-left: 4px"
- @click="foldOrExpandMessage(index, expandIndexList.includes(index))">
- {{expandIndexList.includes(index)?'折叠':'展开'}}
- </el-button>
- </div>
- <el-button @click="ttsStartPlay(item.content, index)">{{playActiveIndex === index && playButtonFlag ?'停止':'播放'}}</el-button>
- </div>
- </div>
- </div>
- </div>
- <div class="input-container">
- <el-input
- v-model="inputMessage"
- type="textarea"
- placeholder="请输入消息"
- @keyup.enter="sendMessage"
- ></el-input>
- <el-button @click="sendMessage" :disabled="isSending" type="primary">发送</el-button>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import headComponent from '@/views/xjc-integratedmachine/components/head_component.vue'
- import Drag_component from "@/views/xjc-integratedmachine/components/drag_component.vue";
- import {onMounted, ref, nextTick} from "vue";
- import { getToken } from '@/utils/auth'
- // md转换为html
- import { marked } from 'marked'
- // 语音识别
- import CryptoJS from 'crypto-js';
- import * as RecorderManager from "/public/ai/iat/dist/index.umd.js"
- // 语音播放
- import {Base64} from 'js-base64'
- import * as AudioPlayer from "/public/ai/tts/dist/index.umd.js"
- const router = useRouter()
- const route = useRoute()
- const param = route.query
- const loadingHistoryRecord = ref(false)
- // 聊天记录
- let chatRecordList = ref([])
- // md流式数据
- const streamMarkdownData = ref('');
- // html流式数据
- let streamHtmlData = ref('');
- // 流式加载状态
- const isLoading = ref(false);
- // 读取器实例
- let reader = null;
- // AbortController用于中止请求
- let controller = null;
- // 输入的问题
- let inputMessage = ref('')
- // 发送标识
- let isSending = ref(false)
- // 选中的消息,用于展开折叠
- let expandIndexList = ref([])
- // 播放按钮状态
- let playActiveIndex = ref(0)
- let playButtonFlag = ref(false)
- // 查看所有聊天记录
- function list() {
- loadingHistoryRecord.value = true
- let queryForm = {
- pageNum: 1,
- pageSize: 10000
- }
- aiChatRecordList(queryForm).then(resp =>{
- chatRecordList.value = resp.rows;
- loadingHistoryRecord.value = false
- setTimeout(()=>{
- scrollToBottom();
- }, 100);
- if(resp.total == 0){
- sayHi();
- }
- })
- }
- function addRecord(content) {
- let queryForm = {
- content: content,
- isUser: 0
- }
- aiChatRecordAdd(queryForm).then(resp =>{
- console.log(resp)
- })
- }
- function sayHi() {
- const botMsg = {
- isUser: false,
- content: '你好,我是来帮助你进行学习规划、选科辅导以及志愿填报的生涯教育专家。如果你有关于这些方面的问题,欢迎随时向我咨询!', // 增量填充
- isTyping: false, // 显示加载动画
- }
- chatRecordList.value.push(botMsg)
- }
- const sendMessage = () => {
- if (inputMessage.value.trim()) {
- sendRequest(inputMessage.value.trim())
- inputMessage.value = ''
- }
- }
- const sendRequest = async(message) => {
- // 用户信息
- const userMessage = {
- isUser: true,
- content: message,
- isTyping: false
- }
- // 消息加入聊天记录
- chatRecordList.value.push(userMessage)
- const botMsg = {
- isUser: false,
- content: '', // 增量填充
- isTyping: true, // 显示加载动画
- }
- chatRecordList.value.push(botMsg)
- const lastMsg = chatRecordList.value[chatRecordList.value.length - 1]
- try{
- isLoading.value = true;
- streamMarkdownData.value = ''; // 清空之前的数据
- // 创建AbortController以便可以中止请求
- controller = new AbortController();
- // 请求体
- let form = {
- "content": message? message: "你是谁?"
- }
- // 发送fetch请求
- const response = await fetch('/dev-api/ai/chat/record/stream', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': 'Bearer ' + getToken()
- },
- body: JSON.stringify(form)
- });
- // 获取可读流的读取器
- reader = response.body.getReader();
- const decoder = new TextDecoder('utf-8');
- // 循环读取流数据
- while (true) {
- const { done, value } = await reader.read();
- if (done) break; // 如果流读取完成则退出循环
- // 解码并追加数据
- let chunk = decoder.decode(value, { stream: true });
- chunk = chunk.replace(/\n\n/g, '').replace(/data:/g, '')
- streamMarkdownData.value += chunk;
- streamHtmlData.value = marked(streamMarkdownData.value)
- lastMsg.content = marked(streamMarkdownData.value)
- }
- }catch (error) {
- // 如果是手动中止,不显示错误
- if (error.name !== 'AbortError') {
- console.error('流式读取失败:', error);
- streamHtmlData.value = 'Error: ' + error.message;
- }
- } finally {
- isLoading.value = false;
- let htmlData = marked(streamMarkdownData.value);
- addRecord(htmlData);
- streamHtmlData.value = htmlData;
- lastMsg.content = marked(streamMarkdownData.value)
- lastMsg.isTyping = false
- // 组件挂载后自动滚动到底部
- scrollToBottom();
- }
- }
- const stopMessage = () => {
- if (reader) {
- // 取消读取
- reader.cancel().catch(() => {});
- reader = null;
- }
- if (controller) {
- // 中止请求
- controller.abort();
- controller = null;
- }
- isLoading.value = false;
- }
- function foldOrExpandMessage(index, flag){
- if(flag){
- expandIndexList.value = expandIndexList.value.filter((item)=>{
- return item !== index;
- })
- }else{
- expandIndexList.value.push(index)
- }
- }
- /* 语音识别 ↓*/
- // 控制录音弹窗
- let iatVoiceOpen = false
- // 是否开始录音
- let iatStartVoiceStatus = false
- // 识别中状态
- let iatIdentifyStatus = false
- // 录音对象
- let iatRecorder = null
- let iatTranscription = ''
- let iatBtnStatus = ''
- let iatResultText = ''
- let iatResultTextTemp = ''
- let iatCountdownInterval = null
- let iatWS = null
- let iatRecognition = null
- let iatButtonDisabled = true
- let iatLoading = false
- let xfIatKeys = {
- APPID: '5a2643f4',
- APISecret: 'MTg4MWIzY2VmYTg2YTEwMjliMDY1N2Iz',
- APIKey: '8b1a53486bec887eb817b4410aa743ed',
- }
- // 初始化语音识别
- function initSpeechRecognition(){
- // 初始化录音
- iatRecorder = new window.RecorderManager('/ai/iat/dist');
- // 开始录音
- iatRecorder.onStart = () => {
- iatChangeBtnStatus('OPEN');
- };
- iatRecorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => {
- if (iatWS.readyState === iatWS.OPEN) {
- iatWS.send(
- JSON.stringify({
- data: {
- status: isLastFrame ? 2 : 1,
- format: 'audio/L16;rate=16000',
- encoding: 'raw',
- audio: toBase64(frameBuffer),
- },
- }),
- );
- if (isLastFrame) {
- iatChangeBtnStatus('CLOSING');
- }
- }
- };
- iatRecorder.onStop = () => {
- console.log('录音结束,停止定时器');
- clearInterval(iatCountdownInterval);
- iatStartVoiceStatus = false;
- };
- }
- async function iatStartVoice() {
- if (iatLoading) {
- return;
- }
- iatVoiceOpen = true;
- await iatPlayIatVoice();
- }
- async function iatPlayIatVoice() {
- if (iatLoading) {
- return;
- }
- iatStartVoiceStatus = !iatStartVoiceStatus;
- // 浏览器自带的识别
- if (iatRecognition) {
- if (iatStartVoiceStatus) {
- iatRecognition.start();
- } else {
- iatRecognition.stop();
- }
- return;
- }
- if (iatStartVoiceStatus) {
- iatConnectWebSocket();
- } else {
- iatRecorder.stop();
- }
- }
- /**
- * 关闭录音弹窗
- */
- function iatCloseVoiceOpen() {
- iatVoiceOpen = false;
- iatStartVoiceStatus = false;
- if (iatRecorder) {
- iatRecorder.stop();
- }
- if (iatRecognition) {
- iatRecognition.stop();
- }
- iatTranscription = '';
- }
- function iatRenderResult(resultData) {
- // 识别结束
- const jsonData = JSON.parse(resultData);
- if (jsonData.data && jsonData.data.result) {
- const data = jsonData.data.result;
- let str = '';
- const { ws } = data;
- for (let i = 0; i < ws.length; i += 1) {
- str += ws[i].cw[0].w;
- }
- // 开启wpgs会有此字段(前提:在控制台开通动态修正功能)
- // 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段
- if (data.pgs) {
- if (data.pgs === 'apd') {
- // 将resultTextTemp同步给resultText
- iatResultText = iatResultTextTemp;
- }
- // 将结果存储在resultTextTemp中
- iatResultTextTemp = iatResultText + str;
- } else {
- iatResultText += str;
- }
- inputMessage.value = iatResultTextTemp || iatResultText || '';
- }
- if (jsonData.code === 0 && jsonData.data.status === 2) {
- iatWS.close();
- }
- if (jsonData.code !== 0) {
- iatWS.close();
- console.error(jsonData);
- }
- }
- function iatConnectWebSocket() {
- const websocketUrl = iatGetWebSocketUrl();
- if ('WebSocket' in window) {
- iatWS = new window.WebSocket(websocketUrl);
- } else if ('MozWebSocket' in window) {
- iatWS = new window.MozWebSocket(websocketUrl);
- } else {
- message.error('浏览器不支持WebSocket');
- return;
- }
- iatChangeBtnStatus('CONNECTING');
- iatWS.onopen = e => {
- console.log('iatWS.onopen', e);
- // 开始录音
- iatRecorder.start({
- sampleRate: 16000,
- frameSize: 1280,
- });
- const params = {
- common: {
- app_id: xfIatKeys.APPID,
- },
- business: {
- language: 'zh_cn',
- domain: 'iat',
- accent: 'mandarin',
- vad_eos: 5000,
- dwa: 'wpgs',
- nbest: 1,
- wbest: 1,
- },
- data: {
- status: 0,
- format: 'audio/L16;rate=16000',
- encoding: 'raw',
- },
- };
- iatWS.send(JSON.stringify(params));
- };
- iatWS.onmessage = e => {
- iatRenderResult(e.data);
- };
- iatWS.onerror = e => {
- console.error(e);
- iatRecorder.stop();
- iatChangeBtnStatus('CLOSED');
- };
- iatWS.onclose = e => {
- console.log(e);
- iatRecorder.stop();
- iatChangeBtnStatus('CLOSED');
- };
- }
- function iatGetWebSocketUrl() {
- const { APIKey, APISecret } = xfIatKeys;
- if (!APIKey) {
- message.error('语音识别配置未生效');
- return null;
- }
- // 请求地址根据语种不同变化
- let url = 'wss://iat-api.xfyun.cn/v2/iat';
- const host = 'iat-api.xfyun.cn';
- const apiKey = APIKey;
- const apiSecret = APISecret;
- const date = new Date().toGMTString();
- const algorithm = 'hmac-sha256';
- const headers = 'host date request-line';
- const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`;
- const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
- const signature = CryptoJS.enc.Base64.stringify(signatureSha);
- const authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
- const authorization = btoa(authorizationOrigin);
- url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
- return url;
- }
- function iatCountdown() {
- let seconds = 60;
- console.log(`录音中(${seconds}s)`);
- iatCountdownInterval = setInterval(() => {
- seconds -= 1;
- if (seconds <= 0) {
- clearInterval(iatCountdownInterval);
- iatRecorder.stop();
- } else {
- console.log(`录音中(${seconds}s)`);
- }
- }, 1000);
- }
- function iatChangeBtnStatus(status) {
- iatBtnStatus = status;
- if (status === 'CONNECTING') {
- console.log('建立连接中');
- iatResultText = '';
- iatResultTextTemp = '';
- } else if (status === 'OPEN') {
- if (iatRecorder) {
- iatCountdown();
- }
- } else if (status === 'CLOSING') {
- console.log('关闭连接中');
- } else if (status === 'CLOSED') {
- console.log('开始录音');
- }
- }
- function toBase64(buffer) {
- let binary = '';
- const bytes = new Uint8Array(buffer);
- const len = bytes.byteLength;
- for (let i = 0; i < len; i += 1) {
- binary += String.fromCharCode(bytes[i]);
- }
- return window.btoa(binary);
- }
- /* 语音识别 ↑*/
- /*语音合成 ↓*/
- // 合成对象
- let audioPlayer = null
- // 按钮状态:"UNDEFINED" "CONNECTING" "PLAY" "STOP"
- let btnStatus = "UNDEFINED";
- //
- let ttsWS = null;
- function initSpeechSynthesis(){
- // 初始化语音播放
- audioPlayer = new window.AudioPlayer("/ai/tts/dist");
- // 开始播放
- audioPlayer.onPlay = () => {
- changeBtnStatus("PLAY");
- };
- audioPlayer.onStop = (audioDatas) => {
- console.log('停止播放');
- // 修改为undefined,下次播放重头开始
- btnStatus === "PLAY" && changeBtnStatus("UNDEFINED");
- };
- }
- function changeBtnStatus(status) {
- btnStatus = status;
- if (status === "UNDEFINED") {
- console.log("立即合成");
- } else if (status === "CONNECTING") {
- console.log("正在合成");
- } else if (status === "PLAY") {
- console.log("停止播放");
- } else if (status === "STOP") {
- console.log("重新播放");
- }
- }
- function getWebSocketUrl() {
- const { APIKey, APISecret } = xfIatKeys;
- if (!APIKey) {
- message.error('语音合成配置未生效');
- return null;
- }
- let url = "wss://tts-api.xfyun.cn/v2/tts";
- let host = "tts-api.xfyun.cn";
- const apiKey = APIKey;
- const apiSecret = APISecret;
- let date = new Date().toGMTString();
- let algorithm = "hmac-sha256";
- let headers = "host date request-line";
- let signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`;
- let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
- let signature = CryptoJS.enc.Base64.stringify(signatureSha);
- let authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
- let authorization = btoa(authorizationOrigin);
- url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
- return url;
- }
- function encodeText(text, type) {
- if (type === "unicode") {
- let buf = new ArrayBuffer(text.length * 4);
- let bufView = new Uint16Array(buf);
- for (let i = 0, strlen = text.length; i < strlen; i++) {
- bufView[i] = text.charCodeAt(i);
- }
- let binary = "";
- let bytes = new Uint8Array(buf);
- let len = bytes.byteLength;
- for (let i = 0; i < len; i++) {
- binary += String.fromCharCode(bytes[i]);
- }
- return window.btoa(binary);
- } else {
- return Base64.encode(text);
- }
- }
- function ttsStartPlay(text, index) {
- playActiveIndex.value = index
- playButtonFlag.value = !playButtonFlag.value;
- if (btnStatus === "UNDEFINED") {
- // 开始合成
- connectWebSocket(text.replace(/<\/?.+?\/?>/g,''));
- } else if (btnStatus === "CONNECTING") {
- // 停止合成
- changeBtnStatus("UNDEFINED");
- ttsWS?.close();
- audioPlayer.reset();
- return;
- } else if (btnStatus === "PLAY") {
- audioPlayer.stop();
- } else if (btnStatus === "STOP") {
- audioPlayer.play();
- }
- };
- function connectWebSocket(text) {
- const url = getWebSocketUrl();
- if ("WebSocket" in window) {
- ttsWS = new WebSocket(url);
- } else if ("MozWebSocket" in window) {
- ttsWS = new MozWebSocket(url);
- } else {
- alert("浏览器不支持WebSocket");
- return;
- }
- changeBtnStatus("CONNECTING");
- ttsWS.onopen = (e) => {
- audioPlayer.start({
- autoPlay: true,
- sampleRate: 16000,
- resumePlayDuration: 1000
- });
- changeBtnStatus("PLAY");
- let tte = "UTF8";
- let params = {
- common: {
- app_id: xfIatKeys.APPID,
- },
- business: {
- aue: "raw",
- auf: "audio/L16;rate=16000",
- vcn: "xiaoyan",
- // vcn: "aisbabyxu",
- // vcn: "aisjinger",
- // vcn: "aisxping",
- // vcn: "aisjinger",
- // vcn: "x4_lingxiaoyao_em",
- // vcn: "x4_lingxiaoyao_en",
- speed: +50,
- volume: +50,
- pitch: +50,
- bgs: 1,
- tte,
- },
- data: {
- status: 2,
- text: encodeText(text, tte),
- },
- };
- ttsWS.send(JSON.stringify(params));
- };
- ttsWS.onmessage = (e) => {
- let jsonData = JSON.parse(e.data);
- // 合成失败
- if (jsonData.code !== 0) {
- console.error(jsonData);
- changeBtnStatus("UNDEFINED");
- return;
- }
- audioPlayer.postMessage({
- type: "base64",
- data: jsonData.data.audio,
- isLastData: jsonData.data.status === 2,
- });
- if (jsonData.code === 0 && jsonData.data.status === 2) {
- ttsWS.close();
- }
- };
- ttsWS.onerror = (e) => {
- console.error(e);
- };
- ttsWS.onclose = (e) => {
- // console.log(e);
- };
- }
- /*语音合成 ↑*/
- let chatContainerRef = ref(null)
- function scrollToBottom(){
- if(chatContainerRef.value.scrollHeight){
- chatContainerRef.value.scrollTop = chatContainerRef.value.scrollHeight+20;
- }
- }
- onMounted(()=>{
- nextTick(()=>{
- initSpeechRecognition();
- initSpeechSynthesis();
- list();
- })
- })
- </script>
- <style scoped lang="scss">
- p{
- margin: 0;
- padding: 0;
- }
- .ai_career_interview_chat{
- background: url('@/assets/images/environment/ai-career-background.png') no-repeat;
- background-size: 1920px 1080px;
- z-index:10;
- width: 100%;
- height: 1080px;
- display: flex;
- .left-box{
- /*position: absolute;*/
- margin-top: 18px;
- margin-left: 44px;
- width: 428px;
- height: 1044px;
- background: rgba(255,255,255,0.4);
- border-radius: 10px 10px 10px 10px;
- .profile {
- img{
- width: 117px;
- height: 136px;
- margin-top: 48px;
- margin-left: 145px;
- }
- }
- .introduce-text{
- width: 392px;
- margin-left: 14px;
- font-weight: 400;
- font-size: 28px;
- color: #7D7C7C;
- line-height: 40px;
- text-align: left;
- font-style: normal;
- text-transform: none;
- }
- .question-list{
- width: 392px;
- height: 500px;
- overflow: auto;
- margin-left: 14px;
- font-weight: 400;
- font-size: 28px;
- color: #7D7C7C;
- line-height: 40px;
- text-align: left;
- font-style: normal;
- text-transform: none;
- .question-list-item{
- cursor: pointer;
- }
- }
- }
- .center-box{
- width: 1390px;
- height: 1044px;
- margin-top: 18px;
- margin-left: 14px;
- background: rgba(255,255,255,0.2);
- border-radius: 10px 10px 10px 10px;
- .center-header{
- width: 1390px;
- height: 95px;
- background: #D8F9F2;
- border-radius: 10px 10px 0px 0px;
- font-weight: bold;
- font-size: 30px;
- color: #333333;
- line-height: 52px;
- letter-spacing: 3px;
- text-align: left;
- font-style: normal;
- text-transform: none;
- display: flex;
- justify-content: space-between;
- align-items: center;
- .header-exit-btn{
- width: 136px;
- height: 74px;
- background: #FB5451;
- border-radius: 10px 10px 10px 10px;
- font-weight: 400;
- font-size: 24px;
- color: #FFFFFF;
- /*text-align: center;*/
- font-style: normal;
- text-transform: none;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 30px;
- }
- }
- }
- }
- </style>
|