1226 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			1226 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			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/translate/css/public.css?v=4"> -->
 | ||
|     <link rel="stylesheet" href="static/css/layui.css" />
 | ||
|      <!-- <link rel="stylesheet" href="static/js/css/buefy.min.css"> -->
 | ||
|     
 | ||
|     <script src="static/js/jquery-1.11.0.min.js"></script>
 | ||
|     <script src="static/js/axios.min.js"></script>
 | ||
|     <script src="static/translate/js/echarts.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>
 | ||
|     <script src="https://cdn.jsdelivr.net/npm/qrcode@1.4.4/build/qrcode.min.js"></script>
 | ||
|     <script src="static/js/countdown.js"></script>
 | ||
|     
 | ||
|     <!-- <script src="static/js/buefy.min.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 id="main" class="public-header normal">
 | ||
|       <div class="container clearfix">
 | ||
|         <div class="left">
 | ||
|           <img
 | ||
|             src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/logo.png"
 | ||
|             alt=""
 | ||
|             class="logo default"
 | ||
|           /><img
 | ||
|             src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/logo1.png"
 | ||
|             alt=""
 | ||
|             class="logo1 default"
 | ||
|           /><img
 | ||
|             src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/logow.png"
 | ||
|             alt=""
 | ||
|             class="logo light"
 | ||
|           /><img
 | ||
|             src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/logo1w.png"
 | ||
|             alt=""
 | ||
|             class="logo1 light"
 | ||
|           />
 | ||
|           <div class="nav">
 | ||
|             <a class="" href="index.html"><span>首页</span></a
 | ||
|             ><a class="" href="onlineTranslation.html"><span>文本翻译</span></a
 | ||
|             ><a class="" href="voice.html"><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>
 | ||
|     <style>
 | ||
|       .page-console {
 | ||
|         height: auto !important;
 | ||
|         padding-bottom: 16px;
 | ||
|       }
 | ||
|       .range-picker {
 | ||
|         display: flex;
 | ||
|         align-items: center;
 | ||
|         justify-content: flex-end;
 | ||
|         margin: 40px auto 0;
 | ||
|       }
 | ||
| 
 | ||
|       .range-picker .col {
 | ||
|         margin-right: 16px;
 | ||
|         font-size: 16px;
 | ||
|         color: #333;
 | ||
|         cursor: pointer;
 | ||
|       }
 | ||
| 
 | ||
|       .range-picker .col.on {
 | ||
|         color: #2578ff;
 | ||
|       }
 | ||
|     </style>
 | ||
|     <div id="app" class="page-console" style="padding-top: 90px">
 | ||
|       <div class="id-container">
 | ||
|         <div class="user-id-container">
 | ||
|           <img
 | ||
|             src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/pay.png"
 | ||
|             class="user-id-icon"
 | ||
|           /><span class="user-id-text">用户ID : {{userInfo.userId}}</span>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|       <div class="tab-container">
 | ||
|         <!-- <div class="tabs">
 | ||
|           <div class="tab on">文本翻译</div>
 | ||
|           <div class="tab">语音翻译</div>
 | ||
|         </div> -->
 | ||
|         <div id="text-translation" class="w1200 transUserinfo">
 | ||
|           <h5>使用情况</h5>
 | ||
|           <div class="line"></div>
 | ||
|           <div class="table-row">
 | ||
|             <div class="col">
 | ||
|               <div class="cell"><span>翻译引擎</span></div>
 | ||
|               <div class="cell"><span>已使用字符数</span></div>
 | ||
|               <div class="cell"><span>剩余字符数</span></div>
 | ||
|               <div class="cell"><span>价格(U/百万字符)</span></div>
 | ||
|               <div class="cell"><span>操作</span></div>
 | ||
|             </div>
 | ||
|             <div
 | ||
|               class="col"
 | ||
|               v-for="(item,index) in translateInfos"
 | ||
|               :key="'platform_'+index"
 | ||
|             >
 | ||
|               <div class="cell"><span>{{item.name}}</span></div>
 | ||
|               <div class="cell"><span>{{item.useChars}}</span></div>
 | ||
|               <div class="cell">
 | ||
|                 <span>{{item.remainChars}}</span>
 | ||
|                 <img v-if="item.remainChars>0" class="btn-clock" @click="showRecord(item.platformId,index)" src="static/image/clock.png"/>
 | ||
|               </div>
 | ||
|               <div class="cell"><span>{{item.price}}</span></div>
 | ||
|               <div class="cell">
 | ||
|                 <div class="act">
 | ||
|                   <span class="recharge" @click="show(item)">充值</span
 | ||
|                   ><span class="view" @click="look(item.apiKey,index)"
 | ||
|                     >查看API密钥</span
 | ||
|                   >
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|           <div class="warn">备注:技术问题,请联系客服。</div>
 | ||
|           <div class="clearfix" style="height: 361px">
 | ||
|             <!-- <div class="range-picker">
 | ||
|               <div class="col on">近7天</div>
 | ||
|               <div class="col">近15天</div>
 | ||
|               <div class="col">近30天</div>
 | ||
|             </div> -->
 | ||
| 
 | ||
|             <div class="chart-container-wrapper">
 | ||
|               <!-- ECharts 图表将渲染到这个 div 中 -->
 | ||
|               <div id="mainEchart" class="echarts-chart-direct"></div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|         <div
 | ||
|           id="voice-translation"
 | ||
|           class="w1200 transUserinfo"
 | ||
|           style="display: none"
 | ||
|         >
 | ||
|           <div class="header-container">
 | ||
|             <div class="title-section">
 | ||
|               <h5>使用情况</h5>
 | ||
|               <div class="api-key">
 | ||
|                 <span>密钥:</span
 | ||
|                 ><button class="copy-btn" style="display: none">复制</button>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|             <div class="balance-section">
 | ||
|               <div class="balance">剩余金额:0元</div>
 | ||
|               <button class="recharge-btn">充值</button>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|           <div class="line"></div>
 | ||
|           <div class="table-container table-row">
 | ||
|             <div class="grid-header col">
 | ||
|               <div class="cell" style="width: 180px">翻译引擎</div>
 | ||
|               <div class="cell">服务类型</div>
 | ||
|               <div class="cell">已消耗时常/用量</div>
 | ||
|               <div class="cell">已消费金额(元)</div>
 | ||
|               <div class="cell">价格(元/小时)</div>
 | ||
|             </div>
 | ||
|             <div class="grid-body">
 | ||
|               <div class="vendor-cell" style="grid-row: span 3">
 | ||
|                 <span>微软</span>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|           <div class="warn">备注:技术问题,请联系客服。</div>
 | ||
|           <div class="clearfix" style="height: 361px">
 | ||
|             <div class="range-picker">
 | ||
|               <div class="col on">近7天</div>
 | ||
|               <div class="col">近15天</div>
 | ||
|               <div class="col">近30天</div>
 | ||
|             </div>
 | ||
|             <!-- <div
 | ||
|               id="chartDoms"
 | ||
|               style="width: 1200px; height: 300px; margin: 30px auto"
 | ||
|             ></div> -->
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|       <div class="public-customer">
 | ||
|         <div class="ctr">
 | ||
|           <div class="item">
 | ||
|             <img
 | ||
|               src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/p25.png"
 | ||
|               alt=""
 | ||
|             />
 | ||
|             <div>电报咨询</div>
 | ||
|             <div class="detail wechat">
 | ||
|               <h5>电报咨询</h5>
 | ||
|               <img
 | ||
|                 src="/static/picture/p23.jpg"
 | ||
|                 alt=""
 | ||
|               />
 | ||
|               <p>手机扫码加我电报</p>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|           <div class="line"></div>
 | ||
|           <div class="item">
 | ||
|             <img
 | ||
|               src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/p26.png"
 | ||
|               alt=""
 | ||
|             />
 | ||
|             <div>电话咨询</div>
 | ||
|             <div class="detail">
 | ||
|               <h5>电话咨询</h5>
 | ||
|               <div class="phone">+18435173355</div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|       <div class="modal-overlay" style="display: none">
 | ||
|           <div class="modal">
 | ||
|             <button class="close-btn" @click="close">×</button>
 | ||
|              <div
 | ||
|                 class="modal-content"
 | ||
|                 :style="loadingQr ? 'opacity: 0.4; pointer-events: none;' : ''"
 | ||
|               >
 | ||
|                 <h3 v-if="rechargeData.step === 1">Step 1: 输入购买数量</h3>
 | ||
|                 <h3 v-else>Step 2: 支付信息</h3>
 | ||
| 
 | ||
|                 <!-- Step 1 -->
 | ||
|                 <div v-if="rechargeData.step === 1" class="step">
 | ||
|                   <label>购买数量:</label>
 | ||
|                   <input type="number" v-model.number="rechargeData.count" min="1" />
 | ||
|                 </div>
 | ||
| 
 | ||
|                 <!-- Step 2 -->
 | ||
|                 <div v-else class="step">
 | ||
|                   <div class="qr-code">
 | ||
|                     <div id="qrcode"></div>
 | ||
|                     <!-- <div v-if="loadingQr" class="loading-spinner"></div> -->
 | ||
|                     <!-- <img v-else-if="qrCodeUrl" :src="qrCodeUrl" alt="二维码"
 | ||
|                         @load="onQrLoadSuccess" @error="onQrLoadError"
 | ||
|                         style="width: 100%; height: 100%; border-radius: 8px;" />
 | ||
|                     <span v-else style="font-size: 12px; color: #999;">加载失败</span> -->
 | ||
|                   </div>
 | ||
|                   <div class="wallet-info">
 | ||
|                     <p>主链:<strong>{{ rechargeData.blockChain }}</strong></p>
 | ||
|                     <p>钱包地址: <strong>{{ rechargeData.receiveAddress }}</strong></p>
 | ||
|                     <p>支付金额: <strong>{{ rechargeData.amount }} USDT</strong></p>
 | ||
|                     <div>
 | ||
|                       <countdown  :time="(rechargeData.expireUnix * 1000) - Date.now()"
 | ||
|                         v-if="rechargeData.status!==2&& rechargeData.expireUnix && (rechargeData.expireUnix * 1000) > Date.now()" >
 | ||
|                         <template slot-scope="props">
 | ||
|                           倒计时:
 | ||
|                           <span v-if="props.minutes>0||props.hours>0||props.days>0">{{ props.minutes }} 分</span>
 | ||
|                           <span v-if="props.seconds>0||props.minutes>0||props.hours>0||props.days>0">{{ props.seconds }} 秒</span>  
 | ||
|                           <span style="color: red;" v-if="props.days==0&&props.hours==0&&props.minutes==0&&props.seconds==0">订单已过期,请勿支付!</span>
 | ||
|                         </template>
 | ||
|                           
 | ||
|                         </countdown>
 | ||
|                        <div v-else-if="rechargeData.status===2" style="color: green">
 | ||
|                         充值成功,请勿重复支付!
 | ||
|                       </div>
 | ||
|                     </div>
 | ||
|                   </div>
 | ||
|                 </div>
 | ||
| 
 | ||
|             <div class="btn-group">
 | ||
|               <!-- <button class="btn btn-secondary" @click="close">关闭</button> -->
 | ||
|               <button class="btn btn-secondary" v-if="rechargeData.step === 2" @click="prevStep">上一步</button>
 | ||
|               <button class="btn btn-primary" v-if="rechargeData.step === 1" :disabled="!rechargeData.count" @click="nextStep">下一步</button>
 | ||
|             </div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
| 
 | ||
|           <!-- loading 遮罩层 -->
 | ||
|           <div class="modal-loading-overlay" v-if="loadingQr">
 | ||
|             <div class="spinner"></div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|         
 | ||
|       <div class="modal-overlay-record" style="display: none">
 | ||
|         <div class="service-modal">
 | ||
|           <div class="content-normal">
 | ||
|             <div class="close" @click="closeRecord"></div>
 | ||
|             <div v-for="(item,index) in rechargeList" :key="'record'+index" class="content-item">
 | ||
|              <div>订单号:{{item.orderNo}}</div> 
 | ||
|              <div>金额:{{item.amount}}</div>
 | ||
|              <div>总字符数:{{item.totalCharater}}</div>
 | ||
|              <div>可用字符数:{{item.remainCharater}}</div>
 | ||
|              <!-- <div>倒计时:{{item.expireUnix}}</div> -->
 | ||
|               <countdown  :time="(item.expireUnix * 1000) - Date.now()"
 | ||
|         v-if="item.expireUnix && (item.expireUnix * 1000) > Date.now()" >
 | ||
|               <template slot-scope="props">
 | ||
|                 倒计时:<span v-if="props.days > 0">{{ props.days }} 天</span> 
 | ||
|                 <span v-if="props.hours>0||props.days>0">{{ props.hours }} 时</span> 
 | ||
|                 <span v-if="props.minutes>0||props.hours>0||props.days>0">{{ props.minutes }} 分</span>
 | ||
|                 <span v-if="props.seconds>0||props.minutes>0||props.hours>0||props.days>0">{{ props.seconds }} 秒</span>  
 | ||
|               </template>
 | ||
|                 
 | ||
|               </countdown>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|     </div>
 | ||
|     <style>
 | ||
|        
 | ||
|     .modal-overlay {
 | ||
|       position: fixed;
 | ||
|       inset: 0;
 | ||
|       background: rgba(0, 0, 0, 0.4);
 | ||
|       display: flex;
 | ||
|       justify-content: center;
 | ||
|       align-items: center;
 | ||
|       z-index: 999;
 | ||
|     }
 | ||
| 
 | ||
|     .modal {
 | ||
|       background: #ffffff;
 | ||
|       border-radius: 12px;
 | ||
|       box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
 | ||
|       padding: 24px 28px;
 | ||
|       width: 400px;
 | ||
|       max-width: 90%;
 | ||
|       animation: fadeIn 0.3s ease;
 | ||
|       position:relative;
 | ||
|     }
 | ||
| 
 | ||
|     .modal-content {
 | ||
|       transition: opacity 0.2s;
 | ||
|     }
 | ||
| 
 | ||
|     .modal-loading-overlay {
 | ||
|       position: absolute;
 | ||
|       top: 0; left: 0; right: 0; bottom: 0;
 | ||
|       background-color: rgba(255, 255, 255, 0.6);
 | ||
|       display: flex;
 | ||
|       justify-content: center;
 | ||
|       align-items: center;
 | ||
|       z-index: 10;
 | ||
|       border-radius: 12px;
 | ||
|     }
 | ||
| 
 | ||
|     .spinner {
 | ||
|       border: 4px solid #f3f3f3;
 | ||
|       border-top: 4px solid #409eff;
 | ||
|       border-radius: 50%;
 | ||
|       width: 32px;
 | ||
|       height: 32px;
 | ||
|       animation: spin 0.8s linear infinite;
 | ||
|     }
 | ||
| 
 | ||
|     @keyframes fadeIn {
 | ||
|       from { opacity: 0; transform: translateY(-20px); }
 | ||
|       to { opacity: 1; transform: translateY(0); }
 | ||
|     }
 | ||
| 
 | ||
|     .modal h3 {
 | ||
|       margin-top: 0;
 | ||
|       font-size: 20px;
 | ||
|       color: #333;
 | ||
|     }
 | ||
| 
 | ||
|     input[type="number"] {
 | ||
|       width: 100%;
 | ||
|       padding: 10px 12px;
 | ||
|       font-size: 16px;
 | ||
|       margin-top: 8px;
 | ||
|       border: 1px solid #ccc;
 | ||
|       border-radius: 6px;
 | ||
|       transition: border-color 0.2s;
 | ||
|     }
 | ||
| 
 | ||
|     input[type="number"]:focus {
 | ||
|       border-color: #409eff;
 | ||
|       outline: none;
 | ||
|     }
 | ||
| 
 | ||
|     button{
 | ||
|       cursor: pointer;
 | ||
|     }
 | ||
| 
 | ||
|     .step {
 | ||
|       padding-top: 16px;
 | ||
|       margin-bottom: 16px;
 | ||
|     }
 | ||
| 
 | ||
|     .qr-code {
 | ||
|       width: 150px;
 | ||
|       height: 150px;
 | ||
|       background: #f8f8f8;
 | ||
|       border: 1px dashed #ccc;
 | ||
|       display: flex;
 | ||
|       align-items: center;
 | ||
|       justify-content: center;
 | ||
|       margin: 0 auto;
 | ||
|       border-radius: 8px;
 | ||
|     }
 | ||
| 
 | ||
|     .loading-spinner {
 | ||
|       border: 3px solid #f3f3f3;
 | ||
|       border-top: 3px solid #409eff;
 | ||
|       border-radius: 50%;
 | ||
|       width: 28px;
 | ||
|       height: 28px;
 | ||
|       animation: spin 0.8s linear infinite;
 | ||
|     }
 | ||
| 
 | ||
|     @keyframes spin {
 | ||
|       to { transform: rotate(360deg); }
 | ||
|     }
 | ||
| 
 | ||
|     .btn-group {
 | ||
|       display: flex;
 | ||
|       justify-content: flex-end;
 | ||
|       gap: 8px;
 | ||
|       margin-top: 16px;
 | ||
|     }
 | ||
| 
 | ||
|     .btn {
 | ||
|       padding: 8px 16px;
 | ||
|       border: none;
 | ||
|       border-radius: 6px;
 | ||
|       font-size: 14px;
 | ||
|       transition: background-color 0.2s ease;
 | ||
|     }
 | ||
| 
 | ||
|     .btn-primary {
 | ||
|       background-color: #409eff;
 | ||
|       color: #fff;
 | ||
|     }
 | ||
| 
 | ||
|     .btn-primary:disabled {
 | ||
|       background-color: #a0cfff;
 | ||
|       cursor: not-allowed;
 | ||
|     }
 | ||
| 
 | ||
|     .btn-secondary {
 | ||
|       background-color: #e0e0e0;
 | ||
|       color: #333;
 | ||
|     }
 | ||
| 
 | ||
|     .wallet-info {
 | ||
|       font-size: 14px;
 | ||
|       color: #555;
 | ||
|       text-align: center;
 | ||
|       margin-top: 12px;
 | ||
|     }
 | ||
| 
 | ||
|     .close-btn {
 | ||
|   position: absolute;
 | ||
|   top: 12px;
 | ||
|   right: 12px;
 | ||
|   background: transparent;
 | ||
|   border: none;
 | ||
|   font-size: 20px;
 | ||
|   color: #999;
 | ||
|   cursor: pointer;
 | ||
|   transition: color 0.2s ease;
 | ||
| }
 | ||
| .close-btn:hover {
 | ||
|   color: #333;
 | ||
| }
 | ||
|     </style>
 | ||
|     <script type="text/javascript">
 | ||
|       // 工具函数:将十六进制颜色转换为 RGBA 格式
 | ||
|       function hexToRgba(hex, alpha) {
 | ||
|         const r = parseInt(hex.slice(1, 3), 16);
 | ||
|         const g = parseInt(hex.slice(3, 5), 16);
 | ||
|         const b = parseInt(hex.slice(5, 7), 16);
 | ||
|         return `rgba(${r}, ${g}, ${b}, ${alpha})`;
 | ||
|       }
 | ||
| 
 | ||
|       
 | ||
|       var vm = new Vue({
 | ||
|         el: "#app",
 | ||
|         components:{
 | ||
|           countdown: window.VueCountdown,
 | ||
|         },
 | ||
|         data() {
 | ||
|           return {
 | ||
|             translateInfo: [],
 | ||
|             translateInfos: [],
 | ||
|             isShow: false,
 | ||
|             dateType: 0,
 | ||
|             pageChart: null,
 | ||
|             tabShow: "text",
 | ||
|             token: "",
 | ||
|             userMoney: 0,
 | ||
|             userInfo: {},
 | ||
|             activeStep:"2",
 | ||
|             showRecharge:false,
 | ||
|             loadingQr:false,
 | ||
|             rechargeData:{
 | ||
|               platformId:null,
 | ||
|               orderNo:undefined,
 | ||
|               name:null,
 | ||
|               count:1,
 | ||
|               amount:null,
 | ||
|               receiveAddress:null,
 | ||
|               step:1,
 | ||
|               expireUnix:undefined,
 | ||
|               status:undefined,
 | ||
|             },
 | ||
| 
 | ||
|             // ECharts 图表数据
 | ||
|             myChart: null, // 用于存储 ECharts 实例
 | ||
|             xAxisData: [],
 | ||
|             seriesData: [],
 | ||
|             receiveAddress: "",
 | ||
|             rechargeList:[],
 | ||
|             checkOrderTimer: null,
 | ||
|           };
 | ||
|         },
 | ||
|         created() {
 | ||
|         },
 | ||
|         mounted() {
 | ||
|           
 | ||
|           let token = localStorage.getItem("token");
 | ||
|           if (token) {
 | ||
|             this.token = token;
 | ||
|             this.getUserInfo(token);
 | ||
|           } else {
 | ||
|             location.href = "login.html";
 | ||
|           }
 | ||
| 
 | ||
|           // === 直接在主 Vue 实例的 mounted 钩子中初始化 ECharts ===
 | ||
|           // 确保在 DOM 更新周期之后再初始化 ECharts
 | ||
|           this.$nextTick(() => {
 | ||
|             setTimeout(() => {
 | ||
|               this.initECharts();
 | ||
|             }, 100); // 增加一个短暂的延迟
 | ||
|           });
 | ||
|           // 监听窗口大小变化,使图表自适应
 | ||
|           window.addEventListener("resize", this.resizeECharts);
 | ||
| 
 | ||
|           this.getUserPlatforms();
 | ||
|           this.getStatistics();
 | ||
|           // this.getReceiveAddress();
 | ||
|         },
 | ||
|         beforeDestroy() {
 | ||
|           // 销毁 ECharts 实例并移除事件监听器
 | ||
|           if (this.myChart) {
 | ||
|             this.myChart.dispose();
 | ||
|           }
 | ||
|           window.removeEventListener("resize", this.resizeECharts);
 | ||
|         },
 | ||
|         watch: {
 | ||
|           dateType() {
 | ||
|             if (this.tabShow == "voice") {
 | ||
|               this.getVoicestatistics();
 | ||
|             } else {
 | ||
|               this.getStatistics();
 | ||
|             }
 | ||
|           },
 | ||
|           // 监听数据变化,重新渲染图表
 | ||
|           seriesData: {
 | ||
|             deep: true,
 | ||
|             handler() {
 | ||
|               this.updateECharts();
 | ||
|             },
 | ||
|           },
 | ||
|           xAxisData: {
 | ||
|             deep: true,
 | ||
|             handler() {
 | ||
|               this.updateECharts();
 | ||
|             },
 | ||
|           },
 | ||
|         },
 | ||
|         methods: {
 | ||
|           getUserPlatforms() {
 | ||
|             axios
 | ||
|               .get("/tm-member/platforms", {
 | ||
|                 headers: { Authorization: `Bearer ${this.token}` },
 | ||
|               })
 | ||
|               .then((res) => {
 | ||
|                 if (res.data.code == 200) {
 | ||
|                   let result = res.data.data;
 | ||
|                   this.translateInfos = result;
 | ||
|                 } else {
 | ||
|                   layer.msg(response.data.msg);
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|           // getReceiveAddress() {
 | ||
|           //   axios
 | ||
|           //     .get("/configKey/trx_receive_address", {
 | ||
|           //       headers: { Authorization: `Bearer ${this.token}` },
 | ||
|           //     })
 | ||
|           //     .then((res) => {
 | ||
|           //       if (res.data.code == 200) {
 | ||
|           //         this.receiveAddress = res.data.data.configValue;
 | ||
|           //         this.generateQRCode();
 | ||
|           //       } else {
 | ||
|           //         layer.msg(response.data.msg);
 | ||
|           //       }
 | ||
|           //     });
 | ||
|           // },
 | ||
|           getMemberAdvent(platformId){
 | ||
|             axios
 | ||
|               .get("/tm-member/member-advent", {
 | ||
|                 headers: { Authorization: `Bearer ${this.token}` },
 | ||
|                 params:{platformId}
 | ||
|               })
 | ||
|               .then((res) => {
 | ||
|                 if (res.data.code == 200) {
 | ||
|                   let result = res.data.data;
 | ||
|                   this.rechargeList = result;
 | ||
|                 } else {
 | ||
|                   layer.msg(response.data.msg);
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|           getUserInfo(token) {
 | ||
|             let that = this;
 | ||
|             axios
 | ||
|               .get("/getinfo", {
 | ||
|                 headers: {
 | ||
|                   Authorization: `Bearer ${token}`,
 | ||
|                 },
 | ||
|               })
 | ||
|               .then((response) => {
 | ||
|                 if (response.data.code === 200) {
 | ||
|                   that.userInfo = response.data.data;
 | ||
|                 } else {
 | ||
|                   localStorage.removeItem("token");
 | ||
|                   location.href = "login.html";
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|           getStatistics() {
 | ||
|             const that = this;
 | ||
|             axios
 | ||
|               .get("/tm-member-platform/statistics", {
 | ||
|                 headers: { Authorization: `Bearer ${this.token}` },
 | ||
|               })
 | ||
|               .then((response) => {
 | ||
|                 if (response.data.code == 200) {
 | ||
|                   this.xAxisData = response.data.data.xAxis;
 | ||
|                   this.seriesData = response.data.data.data || [];
 | ||
|                 } else {
 | ||
|                   layer.msg(response.data.msg);
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|           look(apiKey, index) {
 | ||
|             var layer = layui.layer;
 | ||
|             // layer.open({
 | ||
|             //     content: token,
 | ||
|             //     // shade: 0.8
 | ||
|             //     shade: ["0.4"]
 | ||
|             //     // shade: false
 | ||
|             // })
 | ||
|             layer.open({
 | ||
|               type: 1,
 | ||
|               title: "API密钥",
 | ||
|               closeBtn: 1,
 | ||
|               shadeClose: true,
 | ||
|               skin: "11",
 | ||
|               content:
 | ||
|                 '<div class="secret-key"><div class="secret"><span>' +
 | ||
|                 apiKey +
 | ||
|                 '</span><i class="copy" data="' +
 | ||
|                 apiKey +
 | ||
|                 '" >复制</i></div></div>',
 | ||
|             });
 | ||
|           },
 | ||
|           show(item) {
 | ||
|             $(".modal-overlay").fadeIn();
 | ||
|             this.rechargeData.platformId=item.platformId;
 | ||
|             this.rechargeData.name=item.name;
 | ||
|           },
 | ||
|           close() {
 | ||
|             $(".modal-overlay").fadeOut();
 | ||
|             this.rechargeData={
 | ||
|               platformId:null,
 | ||
|               name:null,
 | ||
|               count:1,
 | ||
|               amount:null,
 | ||
|               receiveAddress:null,
 | ||
|               step:1,
 | ||
|               expireUnix:undefined,
 | ||
|               status:undefined,
 | ||
|             };
 | ||
| 
 | ||
|             this.cleanCheckOrderTimer();
 | ||
|             
 | ||
|           },
 | ||
|           prevStep(){
 | ||
|      
 | ||
|             this.rechargeData.step=1;
 | ||
|             
 | ||
|           },
 | ||
|           nextStep(){
 | ||
|             if(this.rechargeData.count<=0){
 | ||
|                layer.msg("数量不能小于0");
 | ||
|                return;
 | ||
|             }
 | ||
|             this.loadingQr=true;
 | ||
| 
 | ||
|             axios.post("/tm-member/recharge",this.rechargeData,{headers: { Authorization: `Bearer ${this.token}` }})
 | ||
|             .then(res => {
 | ||
|               
 | ||
|               if(res.data.code===200){
 | ||
|                 this.rechargeData.step=2;
 | ||
|                 this.rechargeData.amount=res.data.data.amount;
 | ||
|                 this.rechargeData.receiveAddress=res.data.data.receiveAddress;
 | ||
|                 this.rechargeData.blockChain=res.data.data.blockChain;
 | ||
|                 this.rechargeData.expireUnix=res.data.data.expireUnix;
 | ||
|                 this.rechargeData.orderNo=res.data.data.orderNo;
 | ||
|                 let _that=this;
 | ||
| 
 | ||
|                 this.$nextTick(() => {
 | ||
|                   _that.generateQRCode(_that.rechargeData.receiveAddress);
 | ||
|                 })
 | ||
|                 _that.createCheckOrderTimer();
 | ||
|               }else{
 | ||
|                 layer.msg(res.data.msg);
 | ||
|               }
 | ||
|             }).finally(() => {
 | ||
|               this.loadingQr=false;
 | ||
|               });
 | ||
|           },
 | ||
|           showRecord(platformId){
 | ||
|             $(".modal-overlay-record").fadeIn();
 | ||
|             this.getMemberAdvent(platformId);
 | ||
|           },
 | ||
|           closeRecord(){
 | ||
|             $(".modal-overlay-record").fadeOut();
 | ||
|           },
 | ||
|           tabClick(val) {
 | ||
|             this.tabShow = val;
 | ||
|             this.pageChart = null;
 | ||
|             if (val == "voice") {
 | ||
|               this.getVoicestatistics();
 | ||
|               this.getuserinfo();
 | ||
|               this.getUsersDuration();
 | ||
|             }
 | ||
|           },
 | ||
|           copy() {
 | ||
|             const apiKey = this.token;
 | ||
|             navigator.clipboard.writeText(apiKey).then(() => {
 | ||
|               console.log("已复制");
 | ||
|               layer.msg("复制成功");
 | ||
|             });
 | ||
|           },
 | ||
| 
 | ||
|           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;
 | ||
|                   
 | ||
|                 } else {
 | ||
|                   location.href = "login.html";
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|           // 模拟更新图表数据的方法
 | ||
|           updateRandomChartData() {
 | ||
|             // 直接调用 fetchChartData 来模拟数据更新
 | ||
|             this.fetchChartData();
 | ||
|             layer.msg("图表数据已更新!");
 | ||
|           },
 | ||
|           // === ECharts 初始化和更新方法 ===
 | ||
|           initECharts() {
 | ||
|             // 在这里添加一个检查,确保 echarts 对象是存在的
 | ||
|             if (typeof echarts === "undefined") {
 | ||
|               console.error("ECharts 库未加载!");
 | ||
|               return;
 | ||
|             }
 | ||
|             const chartDom = document.getElementById("mainEchart");
 | ||
|             if (!chartDom) {
 | ||
|               console.error("ECharts 图表容器 DOM 元素 #mainEchart 未找到!");
 | ||
|               return;
 | ||
|             }
 | ||
| 
 | ||
|             // 初始化 ECharts 实例
 | ||
|             this.myChart = echarts.init(chartDom);
 | ||
|             this.updateECharts(); // 首次加载数据
 | ||
|           },
 | ||
|           updateECharts() {
 | ||
|             if (!this.myChart) {
 | ||
|               console.error("ECharts 实例未创建!无法更新图表。");
 | ||
|               return;
 | ||
|             }
 | ||
| 
 | ||
|             // 动态生成 series 配置
 | ||
|             const series = this.seriesData.map((item, index) => {
 | ||
|               // 使用 this.seriesData
 | ||
|               const colors = [
 | ||
|                 "#3c8dbc",
 | ||
|                 "#00a65a",
 | ||
|                 "#f39c12",
 | ||
|                 "#724a9c",
 | ||
|                 "#e74c3c",
 | ||
|                 "#1abc9c",
 | ||
|               ];
 | ||
|               const color = colors[index % colors.length];
 | ||
| 
 | ||
|               return {
 | ||
|                 name: item.platformName, // 使用 platformName
 | ||
|                 type: "line",
 | ||
|                 // stack: '总量', // 如果不需要堆叠,请注释或移除此行
 | ||
|                 smooth: true,
 | ||
|                 lineStyle: {
 | ||
|                   width: 3,
 | ||
|                 },
 | ||
|                 itemStyle: {
 | ||
|                   borderColor: color,
 | ||
|                   borderWidth: 2,
 | ||
|                 },
 | ||
|                 emphasis: {
 | ||
|                   focus: "series",
 | ||
|                 },
 | ||
|                 data: item.data, // 使用 item.data
 | ||
|                 areaStyle: {
 | ||
|                   opacity: 0.8,
 | ||
|                   // 确保 echarts.graphic 存在
 | ||
|                   color:
 | ||
|                     typeof echarts !== "undefined" && echarts.graphic
 | ||
|                       ? new echarts.graphic.LinearGradient(0, 0, 0, 1, [
 | ||
|                           {
 | ||
|                             offset: 0,
 | ||
|                             color: hexToRgba(color, 0.3),
 | ||
|                           },
 | ||
|                           {
 | ||
|                             offset: 1,
 | ||
|                             color: hexToRgba(color, 0),
 | ||
|                           },
 | ||
|                         ])
 | ||
|                       : color, // Fallback to solid color if graphic is not available
 | ||
|                 },
 | ||
|               };
 | ||
|             });
 | ||
| 
 | ||
|             // 动态生成 legend data
 | ||
|             const legendData = (this.seriesData || []).map(
 | ||
|               (item) => item.platformName
 | ||
|             ); // 使用 platformName
 | ||
| 
 | ||
|             const option = {
 | ||
|               title: {
 | ||
|                 text: "字符消耗统计", // 标题可以直接在主实例中定义
 | ||
|                 left: "center",
 | ||
|                 textStyle: {
 | ||
|                   color: "#333",
 | ||
|                   fontSize: 18,
 | ||
|                   fontWeight: "bold",
 | ||
|                 },
 | ||
|               },
 | ||
|               tooltip: {
 | ||
|                 trigger: "axis",
 | ||
|                 axisPointer: {
 | ||
|                   type: "cross",
 | ||
|                   label: {
 | ||
|                     backgroundColor: "#6a7985",
 | ||
|                   },
 | ||
|                 },
 | ||
|                 formatter: function (params) {
 | ||
|                   var result = params[0].name + "<br/>";
 | ||
|                   params.forEach(function (item) {
 | ||
|                     if (
 | ||
|                       item.data !== null &&
 | ||
|                       item.seriesName &&
 | ||
|                       item.value !== undefined
 | ||
|                     ) {
 | ||
|                       result +=
 | ||
|                         '<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:' +
 | ||
|                         item.color +
 | ||
|                         ';"></span>' +
 | ||
|                         item.seriesName +
 | ||
|                         ": " +
 | ||
|                         item.value +
 | ||
|                         "<br/>";
 | ||
|                     }
 | ||
|                   });
 | ||
|                   return result;
 | ||
|                 },
 | ||
|               },
 | ||
|               legend: {
 | ||
|                 data: legendData,
 | ||
|                 top: "bottom",
 | ||
|                 textStyle: {
 | ||
|                   color: "#666",
 | ||
|                 },
 | ||
|                 padding: [10, 0, 0, 0],
 | ||
|               },
 | ||
|               grid: {
 | ||
|                 left: "3%",
 | ||
|                 right: "4%",
 | ||
|                 bottom: "10%",
 | ||
|                 containLabel: true,
 | ||
|               },
 | ||
|               xAxis: {
 | ||
|                 type: "category",
 | ||
|                 boundaryGap: false,
 | ||
|                 data: this.xAxisData, // 直接使用 xAxisData
 | ||
|                 axisLabel: {
 | ||
|                   color: "#555",
 | ||
|                 },
 | ||
|                 axisLine: {
 | ||
|                   lineStyle: {
 | ||
|                     color: "#ccc",
 | ||
|                   },
 | ||
|                 },
 | ||
|               },
 | ||
|               yAxis: {
 | ||
|                 type: "value",
 | ||
|                 name: "字符数", // Y轴名称可以直接在主实例中定义
 | ||
|                 nameTextStyle: {
 | ||
|                   color: "#555",
 | ||
|                   padding: [0, 0, 10, 0],
 | ||
|                 },
 | ||
|                 axisLabel: {
 | ||
|                   formatter: "{value} ",
 | ||
|                   color: "#555",
 | ||
|                 },
 | ||
|                 axisLine: {
 | ||
|                   lineStyle: {
 | ||
|                     color: "#ccc",
 | ||
|                   },
 | ||
|                 },
 | ||
|                 splitLine: {
 | ||
|                   lineStyle: {
 | ||
|                     type: "dashed",
 | ||
|                     color: "#e0e0e0",
 | ||
|                   },
 | ||
|                 },
 | ||
|               },
 | ||
|               series: series,
 | ||
|             };
 | ||
| 
 | ||
|             this.myChart.setOption(option);
 | ||
|             // 确保在设置选项后也调整图表大小
 | ||
|             setTimeout(() => {
 | ||
|               if (this.myChart) {
 | ||
|                 this.myChart.resize();
 | ||
|               }
 | ||
|             }, 50); // 增加一个短暂的延迟
 | ||
|           },
 | ||
|           resizeECharts() {
 | ||
|             // 更改方法名以与组件内的 resizeChart 区分
 | ||
|             if (this.myChart) {
 | ||
|               const chartDom = document.getElementById("mainEchart");
 | ||
|               if (chartDom) {
 | ||
|               }
 | ||
|               this.myChart.resize();
 | ||
|             }
 | ||
|           },
 | ||
|            generateQRCode(qrString) {
 | ||
|             const text = qrString.trim(); // 获取输入框内容并去除首尾空格
 | ||
|             const qrcodeContainer = document.getElementById('qrcode');
 | ||
| 
 | ||
|             if (text) {
 | ||
|               console.log('container',qrcodeContainer)
 | ||
|               // 1. 清空容器内的所有内容,包括旧的二维码或提示信息
 | ||
|               qrcodeContainer.innerHTML = ''; 
 | ||
|               this.showPlaceholder = false;
 | ||
|               this.qrError = null;
 | ||
| 
 | ||
|               // 2. 创建一个新的 canvas 元素
 | ||
|               const canvasElement = document.createElement('canvas');
 | ||
|               // 可以给 canvas 设置一个 ID 或者类名,如果需要后续引用或样式控制
 | ||
|               // canvasElement.id = 'qrCanvas'; 
 | ||
|               qrcodeContainer.appendChild(canvasElement); // 将 canvas 添加到容器中
 | ||
| 
 | ||
|               // 3. 使用 QRCode.toCanvas 在新创建的 canvas 上生成二维码
 | ||
|               QRCode.toCanvas(canvasElement, text, { // 将 canvasElement 传递给 toCanvas
 | ||
|                 width: 150, // 设置二维码宽度
 | ||
|                 color: {
 | ||
|                   dark: '#000000',  // 二维码颜色
 | ||
|                   light:'#ffffff' // 背景颜色
 | ||
|                 }
 | ||
|               }, (error) => {
 | ||
|                 if (error) {
 | ||
|                   qrcodeContainer.innerHTML = `<p class="text-red-500">获取地址失败请刷新</p>`; // 重新显示错误信息
 | ||
|                 } else {
 | ||
|                   console.log('二维码生成成功!');
 | ||
|                 }
 | ||
|               });
 | ||
|             } else {
 | ||
|               // 如果输入为空,给出提示
 | ||
|               qrcodeContainer.innerHTML = ''; // 清空可能存在的旧二维码
 | ||
|             }
 | ||
|           },
 | ||
|           getOrderStatus(orderNo){
 | ||
|             let that=this;
 | ||
|             let params={orderNo}
 | ||
|             
 | ||
|              axios
 | ||
|               .get("/tm-member/order", {
 | ||
|                 headers: {
 | ||
|                   Authorization: `Bearer ${this.token}`,
 | ||
|                 },
 | ||
|                 params:{orderNo}
 | ||
|               })
 | ||
|               .then((response) => {
 | ||
|                 if (response.data.code === 200) {
 | ||
|                   if(that.rechargeData.orderNo===response.data.data.orderNo && response.data.data.status===2){
 | ||
|                     that.rechargeData.status=response.data.data.status;
 | ||
|                     
 | ||
|                     that.cleanCheckOrderTimer();
 | ||
|                   }
 | ||
|                 } else {
 | ||
|                   // location.href = "login.html";
 | ||
|                 }
 | ||
|               });
 | ||
|           },
 | ||
|           //定时检查订单状态
 | ||
|           createCheckOrderTimer() {
 | ||
|             if (this.checkOrderTimer) {
 | ||
|               clearInterval(this.checkOrderTimer);
 | ||
|             }
 | ||
|             
 | ||
|               console.log("createCheckOrderTimer")
 | ||
|               this.checkOrderTimer = setInterval(() => {
 | ||
|                 this.getOrderStatus(this.rechargeData.orderNo);
 | ||
|               }, 10000);
 | ||
|           },
 | ||
|           cleanCheckOrderTimer() {
 | ||
|             if (this.checkOrderTimer) {
 | ||
|               clearInterval(this.checkOrderTimer);
 | ||
|             }
 | ||
|           },
 | ||
|         }
 | ||
|       });
 | ||
| 
 | ||
|       function copy(val) {
 | ||
|         var layer = layui.layer;
 | ||
|         const jsonStr = JSON.stringify(val);
 | ||
|         // 模拟 输入框
 | ||
|         var cInput = document.createElement("input");
 | ||
|         cInput.value = jsonStr;
 | ||
|         document.body.appendChild(cInput);
 | ||
|         cInput.select(); // 选取文本框内容
 | ||
| 
 | ||
|         // 执行浏览器复制命令
 | ||
|         // 复制命令会将当前选中的内容复制到剪切板中(这里就是创建的input标签)
 | ||
|         // Input要在正常的编辑状态下原生复制方法才会生效
 | ||
| 
 | ||
|         document.execCommand("copy");
 | ||
|         layer.msg("复制成功");
 | ||
|         // 复制成功后再将构造的标签 移除
 | ||
|         document.body.removeChild(cInput);
 | ||
|       }
 | ||
|       $("body").on("click", ".copy", function () {
 | ||
|         console.log($(this).attr("data"));
 | ||
|         copy($(this).attr("data"));
 | ||
|       });
 | ||
|       // $('body .copy').click(function() {
 | ||
|       //     console.log($(this).attr('data'))
 | ||
|       //     copy($(this).attr('data'))
 | ||
|       // })
 | ||
|     </script>
 | ||
|     <div class="public-footer">
 | ||
|       <div class="w1200">
 | ||
|         <div class="left">
 | ||
|           <img
 | ||
|             src="https://codeai.oss-cn-hangzhou.aliyuncs.com/img/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>
 | ||
|           <p></p>
 | ||
|         </div>
 | ||
|       </div>
 | ||
|       <div class="copyright">
 | ||
|         <a href="https://beian.miit.gov.cn/" target="blank"></a>
 | ||
|       </div>
 | ||
|     </div>
 | ||
|     <div class="layui-layer-move" style="cursor: move; display: none"></div>
 | ||
|     <style>
 | ||
|       .btn-clock{
 | ||
|         width: 15px;
 | ||
|         cursor: pointer;
 | ||
|       }
 | ||
| 
 | ||
|       .chart-container-wrapper {
 | ||
|         width: 100%;
 | ||
|         max-width: 900px; /* 最大宽度 */
 | ||
| 
 | ||
|         background-color: #ffffff;
 | ||
|         border-radius: 12px; /* 圆角 */
 | ||
|         box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); /* 阴影 */
 | ||
|         padding: 20px;
 | ||
|         box-sizing: border-box;
 | ||
|         display: flex;
 | ||
|         flex-direction: column;
 | ||
|         justify-content: center;
 | ||
|         align-items: center;
 | ||
|         margin: 20px auto; /* 居中显示 */
 | ||
|       }
 | ||
|       .echarts-chart-direct {
 | ||
|         /* 更改类名以区分,这里是直接渲染的div */
 | ||
|         width: 100%;
 | ||
|         height: 300px; /* === 移除此行,高度由内联样式直接控制 === */
 | ||
|         /* === 调试用样式:添加边框和背景色 === */
 | ||
|         /* ==================================== */
 | ||
|       }
 | ||
|       /* 响应式调整图表高度 */
 | ||
|       @media (max-width: 768px) {
 | ||
|         .chart-container-wrapper {
 | ||
|           height: 350px !important; /* 响应式也添加 !important */
 | ||
|           padding: 15px;
 | ||
|         }
 | ||
|       }
 | ||
|       @media (max-width: 480px) {
 | ||
|         .chart-container-wrapper {
 | ||
|           height: 300px !important; /* 响应式也添加 !important */
 | ||
|           padding: 10px;
 | ||
|         }
 | ||
|       }
 | ||
|     </style>
 | ||
|   </body>
 | ||
| </html>
 |