1171 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			1171 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | ||
| <html lang="en">
 | ||
|   <head>
 | ||
|     <meta charset="UTF-8" />
 | ||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | ||
|     <meta http-equiv="X-UA-Compatible" content="ie=edge" />
 | ||
|     <meta name="baidu-site-verification" content="codeva-bhaFvYlfgd" />
 | ||
|     <meta
 | ||
|       name="keywords"
 | ||
|       content="deepl、deepl翻译、百度翻译、谷歌翻译、腾讯翻译君"
 | ||
|     />
 | ||
|     <meta
 | ||
|       name="description"
 | ||
|       content="聚合翻译提供即时免费的中文、英语、日语、韩语、法语、德语、俄语、西班牙语、葡萄牙语、越南语、印尼语、意大利语、荷兰语、泰语全文翻译等服务。"
 | ||
|     />
 | ||
|     <meta name="baidu-site-verification" content="codeva-mXz3BqI9VN" />
 | ||
|     <link rel="stylesheet" href="static/css/public.css" />
 | ||
|     <link rel="stylesheet" href="static/css/layui.css" />
 | ||
|     <script src="static/js/jquery-1.11.0.min.js"></script>
 | ||
|     <script src="static/js/axios.min.js"></script>
 | ||
|     <script src="static/js/countUp.min.js"></script>
 | ||
|     <script src="static/js/vue.js"></script>
 | ||
|     <script src="static/js/lodash.min.js"></script>
 | ||
|     <script src="static/js/layui.all.js"></script>
 | ||
|     <script src="static/js/common.js"></script>
 | ||
|     <title>聚合翻译</title>
 | ||
|     <script>
 | ||
|       var _hmt = _hmt || [];
 | ||
|       (function () {
 | ||
|         var hm = document.createElement("script");
 | ||
|         hm.src = "https://hm.baidu.com/hm.js?c4e0dd6add63dd71fa52870120ca22cf";
 | ||
|         var s = document.getElementsByTagName("script")[0];
 | ||
|         s.parentNode.insertBefore(hm, s);
 | ||
|       })();
 | ||
|     </script>
 | ||
|   </head>
 | ||
|   <body>
 | ||
|     <div class="public-header normal" id="main">
 | ||
|       <div class="container clearfix">
 | ||
|         <div class="left">
 | ||
|           <img class="logo default" src="static/picture/logo.png" alt="" /><img
 | ||
|             class="logo1 default"
 | ||
|             src="static/picture/logo1.png"
 | ||
|             alt=""
 | ||
|           /><img class="logo light" src="static/picture/logow.png" alt="" /><img
 | ||
|             class="logo1 light"
 | ||
|             src="static/picture/logo1w.png"
 | ||
|             alt=""
 | ||
|           />
 | ||
|           <div class="nav">
 | ||
|             <a class="" href="index.html"><span>首页</span></a
 | ||
|             ><a class="" href="onlineTranslation.html"><span>文本翻译</span></a
 | ||
|             ><a class="active" href=""><span>语音翻译</span></a
 | ||
|             ><a class="" href="api.html"><span>API文档</span></a
 | ||
|             ><a class="" href="commonProblems.html"><span>常见问题</span></a>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|         <div v-if="userInfo!=undefined&&userInfo.userId>0" class="right">
 | ||
|           <a href="userinfo.html" class="console">控制台</a>
 | ||
|           <div class="user-info">
 | ||
|             <div class="phone">{{userInfo.name}}</div>
 | ||
|             <i></i>
 | ||
|             <div class="log-out" @click="logOut">退出</div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|         <div v-else class="right">
 | ||
|           <a class="unlogin" href="login.html">登录</a>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|       <div class="bg"></div>
 | ||
|     </div>
 | ||
|     <script type="text/javascript">
 | ||
|       var vm = new Vue({
 | ||
|         el: "#main",
 | ||
|         data() {
 | ||
|           return {
 | ||
|             userInfo: {},
 | ||
|             token: "",
 | ||
|           };
 | ||
|         },
 | ||
|         created() {},
 | ||
|         mounted() {
 | ||
|           let token = localStorage.getItem("token");
 | ||
|           if (token) {
 | ||
|             this.token = token;
 | ||
|             this.getUserInfo(token);
 | ||
|           } else {
 | ||
|             // location.href = "login.html";
 | ||
|           }
 | ||
|         },
 | ||
|         methods: {
 | ||
|           logOut() {
 | ||
|             axios
 | ||
|               .post("/logout", {
 | ||
|                 headers: {
 | ||
|                   Authorization: `Bearer ${this.token}`,
 | ||
|                 },
 | ||
|               })
 | ||
|               .then((response) => {
 | ||
|                 localStorage.removeItem("token");
 | ||
|                 location.reload();
 | ||
|               });
 | ||
|           },
 | ||
| 
 | ||
|           getUserInfo(token) {
 | ||
|             let that = this;
 | ||
|             axios
 | ||
|               .get("/getinfo", {
 | ||
|                 headers: {
 | ||
|                   Authorization: `Bearer ${this.token}`,
 | ||
|                 },
 | ||
|               })
 | ||
|               .then((response) => {
 | ||
|                 if (response.data.code === 200) {
 | ||
|                   this.userInfo = response.data.data;
 | ||
|                   console.log("userinfo", this.userInfo);
 | ||
|                 } else {
 | ||
|                   localStorage.removeItem("token");
 | ||
|                   location.href = "login.html";
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|         },
 | ||
|       });
 | ||
|     </script>
 | ||
|     <div class="page-translation" id="app">
 | ||
|       <div class="w1200">
 | ||
|         <div class="translation-engine">
 | ||
|           <div
 | ||
|             v-for="item in engineType"
 | ||
|             :key="item.text"
 | ||
|             class="voiceitem"
 | ||
|             :class="{ on: engine.text == item.text }"
 | ||
|             @click="onSelectEngine(item)"
 | ||
|           >
 | ||
|             <img
 | ||
|               :src="engine.text == item.text ? item.icon :item.icon1 "
 | ||
|               alt=""
 | ||
|             /><span class="engine-name">{{ item.text }}</span>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|         <div
 | ||
|           class="translation-row"
 | ||
|           style="
 | ||
|             padding-top: 40px;
 | ||
|             padding-left: 62px;
 | ||
|             border: 1px solid #fff;
 | ||
|             padding-bottom: 40px;
 | ||
|             display: flex;
 | ||
|           "
 | ||
|         >
 | ||
|           <div class="left-side">
 | ||
|             <div class="title">
 | ||
|               {{ engine.text === '语音识别' ? '语音转文字,我们帮您一键识别!' :
 | ||
|               engine.text === '语音合成' ? '录入文字,我们帮你翻译并朗读!' :
 | ||
|               '说出中文,我们帮你语音翻译!' }}
 | ||
|             </div>
 | ||
|             <div class="subtitle">
 | ||
|               {{ engine.text === '语音识别' ?
 | ||
|               '识别结果(单次识别最长支持1分钟)' : engine.text === '语音合成' ?
 | ||
|               '文字录入(单次合成最长支持100字符)' :
 | ||
|               '识别结果(单次识别最长支持1分钟)' }}
 | ||
|             </div>
 | ||
|             <textarea
 | ||
|               class="transcription-box"
 | ||
|               :placeholder="engine.text === '语音识别' ? '这里实时显示语音识别结果' :
 | ||
|                               engine.text === '语音合成' ? '请输入要合成语音的文字内容' :
 | ||
|                               '这里实时显示翻译结果'"
 | ||
|               disabled
 | ||
|             ></textarea>
 | ||
|             <div class="action-button">
 | ||
|               <div class="sound-wave-container" v-show="soundShow">
 | ||
|                 <!-- First sound wave -->
 | ||
|                 <div class="sound-wave">
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                 </div>
 | ||
|                 <!-- Second sound wave -->
 | ||
|                 <div class="sound-wave">
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                 </div>
 | ||
|                 <!-- Third sound wave -->
 | ||
|                 <div class="sound-wave">
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                 </div>
 | ||
|                 <!-- Fourth sound wave -->
 | ||
|                 <div class="sound-wave">
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                 </div>
 | ||
|                 <!-- Fifth sound wave -->
 | ||
|                 <div class="sound-wave">
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                   <div class="sound-bar"></div>
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|             <div class="synthesis-options">
 | ||
|               <div class="synthesis-option" @click="start" v-show="!soundShow">
 | ||
|                 <img
 | ||
|                   src="static/picture/icon1.png"
 | ||
|                   alt="合成图标"
 | ||
|                   class="option-icon"
 | ||
|                 /><span
 | ||
|                   >{{ engine.text === '语音识别' ? '开始识别' : engine.text ===
 | ||
|                   '语音合成' ? '开始合成' : '开始翻译' }}</span
 | ||
|                 >
 | ||
|               </div>
 | ||
|               <div
 | ||
|                 class="synthesis-option"
 | ||
|                 @click="stop"
 | ||
|                 v-show="soundShow"
 | ||
|                 style="background-image: url('static/image/stopbj.png')"
 | ||
|               >
 | ||
|                 <img
 | ||
|                   src="static/picture/icon2.png"
 | ||
|                   alt="合成图标"
 | ||
|                   class="option-icon"
 | ||
|                 /><span
 | ||
|                   >{{ engine.text === '语音识别' ? '结束识别' : engine.text ===
 | ||
|                   '语音合成' ? '结束合成' : '结束翻译' }}</span
 | ||
|                 >
 | ||
|               </div>
 | ||
|             </div>
 | ||
|             <div class="balance-warning" v-show="errmsg!=''">
 | ||
|               <div class="balance-warnings">
 | ||
|                 <img
 | ||
|                   src="static/picture/warning-icon.png"
 | ||
|                   alt="警告"
 | ||
|                   class="warning-icon"
 | ||
|                 /><span v-show="errmsg == '余额'">
 | ||
|                   余额不足,请前往控制台充值</span
 | ||
|                 ><span v-show="errmsg == '登录'"> 请先登录</span>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|             <div style="height: 30px"></div>
 | ||
|           </div>
 | ||
|           <div class="right-side">
 | ||
|             <div class="voice-input-title">
 | ||
|               {{ engine.text === '语音识别' ? '语音录入' : engine.text ===
 | ||
|               '语音合成' ? '语音配置' : '语音配置' }}
 | ||
|             </div>
 | ||
|             <div
 | ||
|               class="language-row"
 | ||
|               v-show="engine.text === '语音识别'"
 | ||
|               style="margin-top: 48px"
 | ||
|             >
 | ||
|               <div class="original-language-text">原始语种:</div>
 | ||
|               <div class="language-selector-box">
 | ||
|                 <div
 | ||
|                   class="translation-language"
 | ||
|                   style="padding-left: 0; border-bottom: none; width: 100%"
 | ||
|                 >
 | ||
|                   <div
 | ||
|                     class="source language-selector"
 | ||
|                     @click="onShowLanguage('sourceLanguage')"
 | ||
|                     style="
 | ||
|                       width: 100%;
 | ||
|                       margin-right: 0;
 | ||
|                       justify-content: space-between;
 | ||
|                     "
 | ||
|                   >
 | ||
|                     {{ sourceLanguage.name }}
 | ||
|                     <div
 | ||
|                       class="icon select-icons"
 | ||
|                       :class="{ rotate: languageShow }"
 | ||
|                     ></div>
 | ||
|                   </div>
 | ||
|                   <div
 | ||
|                     class="language-row dropdown-menu"
 | ||
|                     :class="{ show: languageShow }"
 | ||
|                     :style="{ left: '-10px', top: '50px', width: '280px' }"
 | ||
|                   >
 | ||
|                     <div class="search">
 | ||
|                       <i class="icon"></i
 | ||
|                       ><input
 | ||
|                         type="text"
 | ||
|                         class="search-input"
 | ||
|                         v-model="serachKeywords"
 | ||
|                         placeholder="搜索你想要的"
 | ||
|                       />
 | ||
|                     </div>
 | ||
|                     <div class="row">
 | ||
|                       <div
 | ||
|                         class="cols"
 | ||
|                         v-for="(k, v) in languageCurrent"
 | ||
|                         :key="v"
 | ||
|                         :value="v"
 | ||
|                         @click="onSelectLanguage(v)"
 | ||
|                         :class="{ on: sourceLanguage.key == v}"
 | ||
|                         style="height: 34px; overflow-y: hidden"
 | ||
|                       >
 | ||
|                         <div class="cols"><span>{{ k }}</span></div>
 | ||
|                       </div>
 | ||
|                     </div>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|             <div
 | ||
|               v-show="engine.text === '语音翻译' || engine.text === '语音合成' "
 | ||
|             >
 | ||
|               <div class="language-row" style="margin-top: 30px">
 | ||
|                 <div class="target-language-text">翻译类型:</div>
 | ||
|                 <div class="language-selector-box">
 | ||
|                   <div
 | ||
|                     class="translation-language"
 | ||
|                     style="padding-left: 0; border-bottom: none; width: 100%"
 | ||
|                   >
 | ||
|                     <div
 | ||
|                       class="target language-selector"
 | ||
|                       @click="onShowLanguage('transTypeValue')"
 | ||
|                       style="
 | ||
|                         width: 100%;
 | ||
|                         margin-right: 0;
 | ||
|                         justify-content: space-between;
 | ||
|                         font-size: 16px;
 | ||
|                       "
 | ||
|                     >
 | ||
|                       {{ transTypeValue.value }}
 | ||
|                       <div
 | ||
|                         class="icon select-icons"
 | ||
|                         :class="{ rotate: transShow }"
 | ||
|                       ></div>
 | ||
|                     </div>
 | ||
|                     <transtype-dropdown
 | ||
|                       class="dropdown-menu"
 | ||
|                       :show="transShow"
 | ||
|                       :left="languageRowLeft"
 | ||
|                       :top="languageRowTop"
 | ||
|                       width="280px"
 | ||
|                       :current-key="transTypeValue.key"
 | ||
|                       :language-list="transType"
 | ||
|                       @select="onSelectTransType"
 | ||
|                     ></transtype-dropdown>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|               <div
 | ||
|                 class="language-row"
 | ||
|                 v-show="engine.text === '语音翻译' && transTypeValue.key == '1' "
 | ||
|                 style="margin-top: 30px"
 | ||
|               >
 | ||
|                 <div class="original-language-text">原始语种:</div>
 | ||
|                 <div class="language-selector-box">
 | ||
|                   <div
 | ||
|                     class="translation-language"
 | ||
|                     style="padding-left: 0; border-bottom: none; width: 100%"
 | ||
|                   >
 | ||
|                     <div
 | ||
|                       class="source"
 | ||
|                       @click="onShowLanguage('sourceLanguage')"
 | ||
|                       style="
 | ||
|                         width: 100%;
 | ||
|                         margin-right: 0;
 | ||
|                         justify-content: space-between;
 | ||
|                         font-size: 16px;
 | ||
|                       "
 | ||
|                     >
 | ||
|                       {{ sourceLanguage.name }}
 | ||
|                       <div
 | ||
|                         class="icon select-icons"
 | ||
|                         :class="{ rotate: languageShow }"
 | ||
|                       ></div>
 | ||
|                     </div>
 | ||
|                     <language-dropdown
 | ||
|                       class="dropdown-menu"
 | ||
|                       :show="languageShow"
 | ||
|                       :left="languageRowLeft"
 | ||
|                       :top="languageRowTop"
 | ||
|                       width="280px"
 | ||
|                       :current-key="sourceLanguage.key"
 | ||
|                       :language-list="languageCurrent"
 | ||
|                       @select="onSelectLanguage"
 | ||
|                     ></language-dropdown>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|               <div
 | ||
|                 class="language-row"
 | ||
|                 style="margin-top: 30px"
 | ||
|                 v-show="engine.text === '语音翻译' && transTypeValue.key == '1' "
 | ||
|               >
 | ||
|                 <div class="target-language-text">目标语种:</div>
 | ||
|                 <div class="language-selector-box">
 | ||
|                   <div
 | ||
|                     class="translation-language"
 | ||
|                     style="padding-left: 0; border-bottom: none; width: 100%"
 | ||
|                   >
 | ||
|                     <div
 | ||
|                       class="target"
 | ||
|                       @click="onShowLanguage('targetLanguage')"
 | ||
|                       style="
 | ||
|                         width: 100%;
 | ||
|                         margin-right: 0;
 | ||
|                         justify-content: space-between;
 | ||
|                         font-size: 16px;
 | ||
|                       "
 | ||
|                     >
 | ||
|                       {{ targetLanguage.name }}
 | ||
|                       <div
 | ||
|                         class="icon select-icons"
 | ||
|                         :class="{ rotate: languageShowTarget }"
 | ||
|                       ></div>
 | ||
|                     </div>
 | ||
|                     <language-dropdown
 | ||
|                       class="dropdown-menu"
 | ||
|                       :show="languageShowTarget"
 | ||
|                       :left="languageRowLeft"
 | ||
|                       :top="languageRowTop"
 | ||
|                       width="280px"
 | ||
|                       :current-key="targetLanguage.key"
 | ||
|                       :language-list="languageCurrent"
 | ||
|                       @select="onSelectLanguage"
 | ||
|                     ></language-dropdown>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|               <div
 | ||
|                 class="language-row"
 | ||
|                 style="margin-top: 30px"
 | ||
|                 v-show="engine.text === '语音翻译' && transTypeValue.key == '2' "
 | ||
|               >
 | ||
|                 <div class="language-selector-box">
 | ||
|                   <div
 | ||
|                     class="translation-language"
 | ||
|                     style="padding-left: 0; border-bottom: none; width: 100%"
 | ||
|                   >
 | ||
|                     <div
 | ||
|                       class="source"
 | ||
|                       @click="onShowLanguage('sourceLanguage')"
 | ||
|                       style="
 | ||
|                         width: 100%;
 | ||
|                         margin-right: 0;
 | ||
|                         justify-content: space-between;
 | ||
|                         font-size: 16px;
 | ||
|                       "
 | ||
|                     >
 | ||
|                       <div
 | ||
|                         style="
 | ||
|                           max-width: 143px;
 | ||
|                           white-space: nowrap;
 | ||
|                           overflow: hidden;
 | ||
|                           text-overflow: ellipsis;
 | ||
|                         "
 | ||
|                       >
 | ||
|                         {{ sourceLanguage.name }}
 | ||
|                       </div>
 | ||
|                       <div
 | ||
|                         class="icon select-icons"
 | ||
|                         :class="{ rotate: languageShow }"
 | ||
|                       ></div>
 | ||
|                     </div>
 | ||
|                     <language-dropdown
 | ||
|                       class="dropdown-menu"
 | ||
|                       :show="languageShow"
 | ||
|                       :left="languageRowLeft"
 | ||
|                       :top="languageRowTop"
 | ||
|                       :current-key="sourceLanguage.key"
 | ||
|                       :language-list="languageCurrent"
 | ||
|                       width="200px"
 | ||
|                       @select="onSelectLanguage"
 | ||
|                     ></language-dropdown>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
|                 <div
 | ||
|                   style="
 | ||
|                     cursor: pointer;
 | ||
|                     background: url(static/image/p14.png) no-repeat center;
 | ||
|                     background-size: 19px;
 | ||
|                     width: 40px;
 | ||
|                     height: 19px;
 | ||
|                   "
 | ||
|                   @click="onSwitch"
 | ||
|                 ></div>
 | ||
|                 <!-- 目标 -->
 | ||
|                 <div class="language-selector-box">
 | ||
|                   <div
 | ||
|                     class="translation-language"
 | ||
|                     style="padding-left: 0; border-bottom: none; width: 100%"
 | ||
|                   >
 | ||
|                     <div
 | ||
|                       class="target"
 | ||
|                       @click="onShowLanguage('targetLanguage')"
 | ||
|                       style="
 | ||
|                         width: 100%;
 | ||
|                         margin-right: 0;
 | ||
|                         justify-content: space-between;
 | ||
|                         font-size: 16px;
 | ||
|                       "
 | ||
|                     >
 | ||
|                       <div
 | ||
|                         style="
 | ||
|                           max-width: 143px;
 | ||
|                           white-space: nowrap;
 | ||
|                           overflow: hidden;
 | ||
|                           text-overflow: ellipsis;
 | ||
|                         "
 | ||
|                       >
 | ||
|                         {{ targetLanguage.name }}
 | ||
|                       </div>
 | ||
|                       <div
 | ||
|                         class="icon select-icons"
 | ||
|                         :class="{ rotate: languageShowTarget }"
 | ||
|                       ></div>
 | ||
|                     </div>
 | ||
|                     <language-dropdown
 | ||
|                       class="dropdown-menu"
 | ||
|                       :show="languageShowTarget"
 | ||
|                       :left="languageRowLeft"
 | ||
|                       :top="languageRowTop"
 | ||
|                       width="200px"
 | ||
|                       :current-key="targetLanguage.key"
 | ||
|                       :language-list="languageCurrent"
 | ||
|                       @select="onSelectLanguage"
 | ||
|                     ></language-dropdown>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
|                 <!-- 目标 -->
 | ||
|               </div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|     </div>
 | ||
|     <script type="text/x-template" id="transtype-dropdown">
 | ||
|       <div class="language-row" :class="{ show: show }"  :style="{ left: '-10px', top: '50px', width: '280px' }"  style="height: auto;" ><!--  <div class="search"><i class="icon"></i><input
 | ||
|                type="text"
 | ||
|                class="search-input"
 | ||
|                v-model="search"
 | ||
|                placeholder="搜索你想要的"
 | ||
|              /></div> --><div class="row cols"  v-for="item in filteredOptions"
 | ||
|                :key="item.key"  @click="select(item)"
 | ||
|                :class="{ on: currentKey === item.key }"><div
 | ||
|                class="cols"
 | ||
|              ><span>{{ item.value }}</span></div></div></div>
 | ||
|     </script>
 | ||
|     <script>
 | ||
|       Vue.component("transtype-dropdown", {
 | ||
|         name: "transtype-dropdown",
 | ||
|         template: "#transtype-dropdown",
 | ||
|         props: {
 | ||
|           show: Boolean,
 | ||
|           left: String,
 | ||
|           top: String,
 | ||
|           width: {
 | ||
|             type: String,
 | ||
|             default: "280px",
 | ||
|           },
 | ||
|           currentKey: String,
 | ||
|           languageList: {
 | ||
|             type: Array,
 | ||
|             default: () => [],
 | ||
|           },
 | ||
|         },
 | ||
|         data() {
 | ||
|           return {
 | ||
|             search: "",
 | ||
|           };
 | ||
|         },
 | ||
|         computed: {
 | ||
|           filteredOptions() {
 | ||
|             if (!this.search) return this.languageList;
 | ||
|             return this.languageList.filter((item) =>
 | ||
|               item.value.includes(this.search)
 | ||
|             );
 | ||
|           },
 | ||
|         },
 | ||
|         methods: {
 | ||
|           select(key) {
 | ||
|             this.$emit("update:modelValue", key);
 | ||
|             this.$emit("select", key);
 | ||
|           },
 | ||
|         },
 | ||
|       });
 | ||
|     </script>
 | ||
|     <script type="text/x-template" id="language-dropdown">
 | ||
|       <div class="language-row" :class="{ show: show }" :style="{ left, top, width }"  v-if="show"><div class="search"><i class="icon"></i><input
 | ||
|                 type="text"
 | ||
|                 class="search-input"
 | ||
|                 v-model="search"
 | ||
|                 placeholder="搜索你想要的"
 | ||
|               /></div><div class="row"><div class="cols" v-for="(k, v) in filteredLanguages"
 | ||
|                 :key="v"   @click="select(v)"
 | ||
|                 :class="{ on: currentKey === v }"
 | ||
|             style="height: 34px; overflow-y: hidden;"><div class="cols"><span>{{ k }}</span></div></div></div></div>
 | ||
|     </script>
 | ||
|     <script>
 | ||
|       Vue.component("language-dropdown", {
 | ||
|         template: "#language-dropdown",
 | ||
|         props: {
 | ||
|           show: Boolean,
 | ||
|           left: String,
 | ||
|           top: String,
 | ||
|           width: {
 | ||
|             type: String,
 | ||
|             default: "280px",
 | ||
|           },
 | ||
|           currentKey: String,
 | ||
|           languageList: Object,
 | ||
|         },
 | ||
|         data() {
 | ||
|           return {
 | ||
|             search: "",
 | ||
|           };
 | ||
|         },
 | ||
|         computed: {
 | ||
|           filteredLanguages() {
 | ||
|             if (!this.search) return this.languageList;
 | ||
|             const result = {};
 | ||
|             for (const key in this.languageList) {
 | ||
|               if (this.languageList[key].includes(this.search)) {
 | ||
|                 result[key] = this.languageList[key];
 | ||
|               }
 | ||
|             }
 | ||
|             return result;
 | ||
|           },
 | ||
|         },
 | ||
|         methods: {
 | ||
|           select(key) {
 | ||
|             this.$emit("select", key);
 | ||
|           },
 | ||
|         },
 | ||
|       });
 | ||
|     </script>
 | ||
|     <script type="text/javascript">
 | ||
|       const CancelToken = axios.CancelToken;
 | ||
|       let source = CancelToken.source();
 | ||
|       new Vue({
 | ||
|         el: "#app",
 | ||
|         data() {
 | ||
|           return {
 | ||
|             soundShow: false,
 | ||
|             engine: {},
 | ||
|             transType: [
 | ||
|               { key: "1", value: "指定翻译" },
 | ||
|               { key: "2", value: "双向翻译" },
 | ||
|             ],
 | ||
|             engineType: [
 | ||
|               {
 | ||
|                 key: "baidu",
 | ||
|                 value: 0,
 | ||
|                 icon: "/static/translate/img/identify.png",
 | ||
|                 icon1: "/static/translate/img/identify1.png",
 | ||
|                 text: "语音识别",
 | ||
|               },
 | ||
|               //        {
 | ||
|               //          key: 'baidu',
 | ||
|               //          value: 1,
 | ||
|               //          icon: '/static/translate/img/synthetic.png',
 | ||
|               // icon1: '/static/translate/img/synthetic1.png',
 | ||
|               // text:'语音合成',
 | ||
|               //        },
 | ||
|               {
 | ||
|                 key: "baidu",
 | ||
|                 value: 2,
 | ||
|                 icon: "/static/translate/img/translation.png",
 | ||
|                 icon1: "/static/translate/img/translation1.png",
 | ||
|                 text: "语音翻译",
 | ||
|               },
 | ||
|             ],
 | ||
|             sourceLanguage: {
 | ||
|               key: "zh-cn",
 | ||
|               name: "中文(普通话,简体)",
 | ||
|             },
 | ||
|             targetLanguage: {
 | ||
|               key: "en-US",
 | ||
|               name: "英语(美国)",
 | ||
|             },
 | ||
|             transTypeValue: {
 | ||
|               key: "1",
 | ||
|               value: "指定翻译",
 | ||
|             },
 | ||
|             sourceText: "",
 | ||
|             targetText: "",
 | ||
|             instance: {},
 | ||
|             serachKeywords: "",
 | ||
|             languageShow: false,
 | ||
|             languageShowTarget: false,
 | ||
|             transShow: false,
 | ||
|             languageRowLeft: "-10px",
 | ||
|             languageRowTop: "50px",
 | ||
|             languageTotalData: {},
 | ||
|             isLoading: false,
 | ||
|             selectedGender: "male",
 | ||
|             speedValue: 5,
 | ||
|             pitchValue: 5,
 | ||
|             mediaRecorder: null,
 | ||
|             audioContext: null,
 | ||
|             processor: null,
 | ||
|             source: null,
 | ||
|             socket: null,
 | ||
|             preSocket: null,
 | ||
|             autoCloseTimer: null,
 | ||
|             stream: null,
 | ||
|             errmsg: "",
 | ||
|             token: "",
 | ||
|             sampleRate: "16000",
 | ||
|           };
 | ||
|         },
 | ||
|         async created() {
 | ||
|           this.engine = this.engineType[0];
 | ||
|           this.getLanguage();
 | ||
|           this.getuserinfo();
 | ||
|           layui.use("layer", function () {
 | ||
|             window.layer = layui.layer;
 | ||
|           });
 | ||
|           const tempCtx = new (window.AudioContext ||
 | ||
|             window.webkitAudioContext)();
 | ||
|           const sampleRate = tempCtx.sampleRate;
 | ||
|           this.sampleRate = sampleRate;
 | ||
|           await tempCtx.close();
 | ||
|         },
 | ||
|         beforeUnmount() {
 | ||
|           this.stop();
 | ||
|         },
 | ||
|         mounted() {
 | ||
|           document.addEventListener("click", this.handleOutsideClick);
 | ||
|         },
 | ||
|         beforeDestroy() {
 | ||
|           document.removeEventListener("click", this.handleOutsideClick);
 | ||
|         },
 | ||
|         watch: {},
 | ||
|         computed: {
 | ||
|           languageCurrent() {
 | ||
|             const current = this.languageTotalData;
 | ||
|             const copyCurrent = {};
 | ||
|             if (this.serachKeywords) {
 | ||
|               Object.keys(current).forEach((key) => {
 | ||
|                 // console.log('current[key]', current[key])
 | ||
|                 if (current[key].indexOf(this.serachKeywords) > -1) {
 | ||
|                   copyCurrent[key] = current[key];
 | ||
|                 }
 | ||
|               });
 | ||
|               return copyCurrent;
 | ||
|             }
 | ||
|             return this.languageTotalData;
 | ||
|           },
 | ||
|         },
 | ||
|         methods: {
 | ||
|           handleOutsideClick(e) {
 | ||
|             const dropdownButtons = document.querySelectorAll(
 | ||
|               ".translation-language"
 | ||
|             );
 | ||
|             const dropdownMenus = document.querySelectorAll(".dropdown-menu");
 | ||
| 
 | ||
|             let clickedInside = false;
 | ||
| 
 | ||
|             dropdownButtons.forEach((button) => {
 | ||
|               if (button.contains(e.target)) {
 | ||
|                 clickedInside = true;
 | ||
|               }
 | ||
|             });
 | ||
| 
 | ||
|             dropdownMenus.forEach((menu) => {
 | ||
|               if (menu.contains(e.target)) {
 | ||
|                 clickedInside = true;
 | ||
|               }
 | ||
|             });
 | ||
| 
 | ||
|             if (!clickedInside) {
 | ||
|               this.languageShow = false;
 | ||
|               this.languageShowTarget = false;
 | ||
|               this.transShow = false;
 | ||
|             }
 | ||
|           },
 | ||
|           getuserinfo() {
 | ||
|             this.errmsg = "";
 | ||
|             axios.get("/api/voice/getAmount").then((res) => {
 | ||
|               if (res.data.code == 1) {
 | ||
|                 let result = res.data.data;
 | ||
|                 this.token = result.token;
 | ||
| 
 | ||
|                 if (
 | ||
|                   Number(result.total_amount) - Number(result.use_amount) <
 | ||
|                   0
 | ||
|                 ) {
 | ||
|                   this.errmsg = "余额";
 | ||
|                 }
 | ||
|               } else {
 | ||
|                 this.errmsg = "登录";
 | ||
|                 layer.msg(res.data.info);
 | ||
|               }
 | ||
|             });
 | ||
|           },
 | ||
|           convertFloat32ToInt16(buffer) {
 | ||
|             let l = buffer.length;
 | ||
|             const buf = new Int16Array(l);
 | ||
|             while (l--) {
 | ||
|               buf[l] = Math.min(1, buffer[l]) * 0x7fff;
 | ||
|             }
 | ||
|             return buf.buffer;
 | ||
|           },
 | ||
| 
 | ||
|           onSocketOpen() {
 | ||
|             console.log("WebSocket已连接");
 | ||
|             this.soundShow = true;
 | ||
|             this.autoCloseTimer = setTimeout(() => {
 | ||
|               this.stop();
 | ||
|             }, 60000);
 | ||
|           },
 | ||
|           async start() {
 | ||
|             if (this.errmsg != "") {
 | ||
|               return;
 | ||
|             }
 | ||
|             try {
 | ||
|               document.querySelector(".transcription-box").value = "";
 | ||
| 
 | ||
|               this.audioContext = new (window.AudioContext ||
 | ||
|                 window.webkitAudioContext)({ sampleRate: this.sampleRate });
 | ||
|               const sampleRate = this.audioContext.sampleRate;
 | ||
|               this.sampleRate = sampleRate;
 | ||
|               let url = "";
 | ||
|               if (this.engine.text === "语音识别") {
 | ||
|                 url = `wss://wss.trans-home.com/speech/ws?token=${this.token}&language=${this.sourceLanguage.key}&sampleRate=${sampleRate}`;
 | ||
|               } else {
 | ||
|                 url =
 | ||
|                   this.transTypeValue.key == "1"
 | ||
|                     ? `wss://wss.trans-home.com/speech/ws?token=${this.token}&language=${this.sourceLanguage.key}&transLanguage=${this.targetLanguage.key}&transType=1&sampleRate=${sampleRate}`
 | ||
|                     : `wss://wss.trans-home.com/speech/ws?token=${this.token}&language=${this.sourceLanguage.key},${this.targetLanguage.key}&transType=2&sampleRate=${sampleRate}`;
 | ||
|               }
 | ||
| 
 | ||
|               this.socket = new WebSocket(url);
 | ||
|               this.socket.onopen = () => {
 | ||
|                 this.onSocketOpen();
 | ||
|               };
 | ||
| 
 | ||
|               window.finalResult = "";
 | ||
|               this.socket.onmessage = (event) => {
 | ||
|                 try {
 | ||
|                   if (event.data == "recharge") {
 | ||
|                     this.stop();
 | ||
|                     return;
 | ||
|                   }
 | ||
| 
 | ||
|                   const msg = JSON.parse(event.data);
 | ||
|                   console.log("收到消息:", msg);
 | ||
| 
 | ||
|                   const outputBox =
 | ||
|                     document.querySelector(".transcription-box");
 | ||
|                   if (!outputBox) return;
 | ||
| 
 | ||
|                   let tempResult = "";
 | ||
| 
 | ||
|                   if (this.engine.text === "语音识别") {
 | ||
|                     if (msg.status == "recognizing") {
 | ||
|                       tempResult = msg.text;
 | ||
|                       outputBox.value =
 | ||
|                         finalResult +
 | ||
|                         (finalResult && tempResult ? " " : "") +
 | ||
|                         tempResult;
 | ||
|                     } else if (msg.status === "recognized") {
 | ||
|                       finalResult =
 | ||
|                         finalResult + (finalResult ? " " : "") + msg.text; // 修正这里
 | ||
|                       tempResult = "";
 | ||
|                       outputBox.value = finalResult;
 | ||
|                     }
 | ||
|                   } else {
 | ||
|                     if (msg.status == "recognizing") {
 | ||
|                       tempResult =
 | ||
|                         this.transTypeValue.key == "1"
 | ||
|                           ? Object.values(msg.target)[0] || ""
 | ||
|                           : this.getTranslatedText(msg) || "";
 | ||
|                       outputBox.value =
 | ||
|                         finalResult +
 | ||
|                         (finalResult && tempResult ? " " : "") +
 | ||
|                         tempResult;
 | ||
|                     } else if (msg.status === "recognized") {
 | ||
|                       let val =
 | ||
|                         this.transTypeValue.key == "1"
 | ||
|                           ? Object.values(msg.target)[0] || ""
 | ||
|                           : this.getTranslatedText(msg) || "";
 | ||
|                       finalResult =
 | ||
|                         finalResult + (finalResult ? " " : "") + val; // 修正这里
 | ||
|                       tempResult = "";
 | ||
|                       outputBox.value = finalResult;
 | ||
|                     }
 | ||
|                   }
 | ||
|                 } catch (err) {
 | ||
|                   console.error("消息处理错误:", err);
 | ||
|                 }
 | ||
|               };
 | ||
| 
 | ||
|               this.socket.onerror = (error) => {
 | ||
|                 console.error("WebSocket错误:", error);
 | ||
|                 this.stop();
 | ||
|               };
 | ||
| 
 | ||
|               this.socket.onclose = () => {
 | ||
|                 console.log("WebSocket已关闭");
 | ||
|                 this.cleanupResources();
 | ||
|               };
 | ||
| 
 | ||
|               // 初始化音频处理
 | ||
|               this.stream = this.stream
 | ||
|                 ? this.stream
 | ||
|                 : await navigator.mediaDevices.getUserMedia({ audio: true });
 | ||
|               this.source = this.audioContext.createMediaStreamSource(
 | ||
|                 this.stream
 | ||
|               );
 | ||
|               this.processor = this.audioContext.createScriptProcessor(
 | ||
|                 4096,
 | ||
|                 1,
 | ||
|                 1
 | ||
|               );
 | ||
| 
 | ||
|               // 安全发送数据函数
 | ||
|               const safeSend = (data) => {
 | ||
|                 if (this.socket && this.socket.readyState === WebSocket.OPEN) {
 | ||
|                   try {
 | ||
|                     this.socket.send(data);
 | ||
|                   } catch (err) {
 | ||
|                     console.error("发送数据失败:", err);
 | ||
|                     this.stop(); // 出错时自动停止
 | ||
|                   }
 | ||
|                 }
 | ||
|               };
 | ||
| 
 | ||
|               this.processor.onaudioprocess = (e) => {
 | ||
|                 if (!this.socket || this.socket.readyState !== WebSocket.OPEN)
 | ||
|                   return;
 | ||
| 
 | ||
|                 const input = e.inputBuffer.getChannelData(0);
 | ||
|                 const pcmData = this.convertFloat32ToInt16(input);
 | ||
|                 safeSend(pcmData);
 | ||
|               };
 | ||
| 
 | ||
|               this.source.connect(this.processor);
 | ||
|               this.processor.connect(this.audioContext.destination);
 | ||
|             } catch (err) {
 | ||
|               layer.msg("初始化错误");
 | ||
|               console.error("初始化错误:", err);
 | ||
|               this.stop();
 | ||
|             }
 | ||
|           },
 | ||
| 
 | ||
|           getTranslatedText(data) {
 | ||
|             const mainLang = data.language.split("-")[0];
 | ||
|             const entries = Object.entries(data.target);
 | ||
|             const nonMainLangEntry = entries.find(
 | ||
|               ([lang]) => !lang.startsWith(mainLang)
 | ||
|             );
 | ||
|             return nonMainLangEntry
 | ||
|               ? nonMainLangEntry[1]
 | ||
|               : entries[0]
 | ||
|               ? entries[0][1]
 | ||
|               : null;
 | ||
|           },
 | ||
| 
 | ||
|           stop() {
 | ||
|             console.log("停止");
 | ||
|             window.finalResult = "";
 | ||
|             // 关闭WebSocket
 | ||
|             if (this.socket) {
 | ||
|               if (
 | ||
|                 this.socket.readyState === WebSocket.OPEN ||
 | ||
|                 this.socket.readyState === WebSocket.CONNECTING
 | ||
|               ) {
 | ||
|                 this.socket.close();
 | ||
|               }
 | ||
| 
 | ||
|               this.socket = null;
 | ||
|             }
 | ||
| 
 | ||
|             // 清理音频资源
 | ||
|             this.cleanupResources();
 | ||
| 
 | ||
|             if (this.autoCloseTimer) {
 | ||
|               clearTimeout(this.autoCloseTimer);
 | ||
|               this.autoCloseTimer = null;
 | ||
|             }
 | ||
| 
 | ||
|             this.soundShow = false;
 | ||
| 
 | ||
|             //过一秒调用
 | ||
|             setTimeout(() => {
 | ||
|               this.getuserinfo();
 | ||
|             }, 1000);
 | ||
|           },
 | ||
| 
 | ||
|           // 清理音频资源
 | ||
|           cleanupResources() {
 | ||
|             if (this.processor) {
 | ||
|               this.processor.disconnect();
 | ||
|               this.processor = null;
 | ||
|             }
 | ||
| 
 | ||
|             if (this.source) {
 | ||
|               this.source.disconnect();
 | ||
|               this.source = null;
 | ||
|             }
 | ||
| 
 | ||
|             if (this.audioContext) {
 | ||
|               this.audioContext.close().catch((e) => {
 | ||
|                 console.error("关闭AudioContext失败:", e);
 | ||
|               });
 | ||
|               this.audioContext = null;
 | ||
|             }
 | ||
|           },
 | ||
|           copy() {
 | ||
|             navigator.clipboard
 | ||
|               .writeText(this.targetText)
 | ||
|               .then(() => {
 | ||
|                 window.alert("复制成功");
 | ||
|               })
 | ||
|               .catch((err) => {
 | ||
|                 window.alert("复制失败");
 | ||
|               });
 | ||
|           },
 | ||
|           onShowLanguage(key) {
 | ||
|             if (!this.soundShow) {
 | ||
|               if (key === "sourceLanguage") {
 | ||
|                 this.languageShow = !this.languageShow;
 | ||
|                 this.languageShowTarget = false;
 | ||
|                 this.transShow = false;
 | ||
|               } else if (key === "targetLanguage") {
 | ||
|                 this.languageShowTarget = !this.languageShowTarget;
 | ||
|                 this.languageShow = false;
 | ||
|                 this.transShow = false;
 | ||
|               } else if (key === "transTypeValue") {
 | ||
|                 this.transShow = !this.transShow;
 | ||
|                 this.languageShow = false;
 | ||
|                 this.languageShowTarget = false;
 | ||
|               }
 | ||
|             } else {
 | ||
|               layer.msg("目前识别中,不可修改!");
 | ||
|             }
 | ||
|             this.currentKey = key;
 | ||
|           },
 | ||
|           onSelectEngine(e) {
 | ||
|             if (this.soundShow) {
 | ||
|               layer.msg("目前识别中,不可修改!");
 | ||
|               return;
 | ||
|             }
 | ||
|             this.engine = e;
 | ||
|             (this.sourceLanguage = {
 | ||
|               key: "zh-cn",
 | ||
|               name: "中文(普通话,简体)",
 | ||
|             }),
 | ||
|               (this.targetLanguage = {
 | ||
|                 key: "en-US",
 | ||
|                 name: "英语(美国)",
 | ||
|               });
 | ||
|           },
 | ||
|           getLanguage() {
 | ||
|             axios.get("/api/voice/getLanguage").then((res) => {
 | ||
|               if (res.data.code == 1) {
 | ||
|                 this.languageTotalData = res.data.data;
 | ||
|                 console.log("res", this.languageTotalData);
 | ||
|               }
 | ||
|             });
 | ||
|           },
 | ||
|           onSelectTransType(e) {
 | ||
|             if (this.soundShow) {
 | ||
|               layer.msg("目前识别中,不可修改!");
 | ||
|               return;
 | ||
|             }
 | ||
|             this.transTypeValue = e;
 | ||
|             this.transShow = false;
 | ||
|           },
 | ||
|           onSelectLanguage(e) {
 | ||
|             console.log(this.currentKey);
 | ||
|             if (this.soundShow) {
 | ||
|               layer.msg("目前识别中,不可修改!");
 | ||
|               return;
 | ||
|             }
 | ||
|             this[this.currentKey] = {
 | ||
|               key: e,
 | ||
|               name: this.languageCurrent[e],
 | ||
|             };
 | ||
|             this.languageShow = false;
 | ||
|             this.languageShowTarget = false;
 | ||
|             console.log(this[this.currentKey]);
 | ||
|           },
 | ||
|           onSwitch() {
 | ||
|             if (this.soundShow) {
 | ||
|               layer.msg("目前识别中,不可修改!");
 | ||
|               return;
 | ||
|             }
 | ||
|             const copySource = JSON.parse(JSON.stringify(this.sourceLanguage));
 | ||
|             const copyTarget = JSON.parse(JSON.stringify(this.targetLanguage));
 | ||
|             this.targetLanguage = copySource;
 | ||
|             this.sourceLanguage = copyTarget;
 | ||
|           },
 | ||
|           onInput(e) {
 | ||
|             if (this.sourceText) {
 | ||
|               // _.debounce(this.translate, 500)
 | ||
|               // this.translate()
 | ||
|             } else {
 | ||
|               this.targetText = "";
 | ||
|             }
 | ||
|           },
 | ||
|         },
 | ||
|       });
 | ||
|     </script>
 | ||
|     <div class="public-footer">
 | ||
|       <div class="w1200">
 | ||
|         <div class="left"><img src="static/picture/logo.png" alt="" /></div>
 | ||
|         <div
 | ||
|           style="
 | ||
|             flex-direction: column;
 | ||
|             line-height: 23px;
 | ||
|             padding-left: 100px;
 | ||
|             color: #fff;
 | ||
|             font-size: 12px;
 | ||
|           "
 | ||
|         >
 | ||
|           <p style="color: #fff; font-size: 12px"><span>官方频道:@apiapl_news</span></p>
 | ||
|           <p style="color: #fff; font-size: 12px"><span>咨询客服:@apiapl</span></p>
 | ||
|             <span></span>
 | ||
|           </p>
 | ||
|         </div>
 | ||
|         <div class="right" style="white-space: nowrap">
 | ||
|           <p></p>
 | ||
| 
 | ||
|           <p><span>技术服务:@apiapl_sdk</span></p>
 | ||
|           <p><span>联系邮箱:info@apiapl.com</span></p>
 | ||
|           <p class=""><span>联系电话:+18435173355 </span></p>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|       <div class="copyright">
 | ||
|         <a href="https://beian.miit.gov.cn/" target="blank"
 | ||
|           ></a
 | ||
|         >
 | ||
|       </div>
 | ||
|     </div>
 | ||
|   </body>
 | ||
| </html>
 |