2025-07-02 18:32:06 +08:00
|
|
|
|
<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" />
|
2025-07-07 19:03:16 +08:00
|
|
|
|
<!-- <link rel="stylesheet" href="static/js/css/buefy.min.css"> -->
|
|
|
|
|
|
|
2025-07-02 18:32:06 +08:00
|
|
|
|
<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>
|
2025-07-07 19:03:16 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- <script src="static/js/buefy.min.js"></script> -->
|
2025-07-02 18:32:06 +08:00
|
|
|
|
<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">
|
2025-07-07 19:03:16 +08:00
|
|
|
|
<span class="recharge" @click="show(item)">充值</span
|
2025-07-02 18:32:06 +08:00
|
|
|
|
><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">
|
2025-07-07 19:03:16 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
<countdown :time="(rechargeData.expireUnix * 1000) - Date.now()"
|
|
|
|
|
|
v-if="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 v-if="props.days==0&&props.hours==0&&props.minutes==0&&props.seconds==0">订单已过期,请勿支付!</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
</countdown>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</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>
|
2025-07-02 18:32:06 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-07-07 19:03:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- loading 遮罩层 -->
|
|
|
|
|
|
<div class="modal-loading-overlay" v-if="loadingQr">
|
|
|
|
|
|
<div class="spinner"></div>
|
2025-07-02 18:32:06 +08:00
|
|
|
|
</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>
|
2025-07-07 19:03:16 +08:00
|
|
|
|
|
2025-07-02 18:32:06 +08:00
|
|
|
|
</div>
|
2025-07-07 19:03:16 +08:00
|
|
|
|
<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>
|
2025-07-02 18:32:06 +08:00
|
|
|
|
<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: {},
|
2025-07-07 19:03:16 +08:00
|
|
|
|
activeStep:"2",
|
|
|
|
|
|
showRecharge:false,
|
|
|
|
|
|
loadingQr:false,
|
|
|
|
|
|
rechargeData:{
|
|
|
|
|
|
platformId:null,
|
|
|
|
|
|
name:null,
|
|
|
|
|
|
count:1,
|
|
|
|
|
|
amount:null,
|
|
|
|
|
|
receiveAddress:null,
|
|
|
|
|
|
step:1,
|
|
|
|
|
|
expireUnix:undefined
|
|
|
|
|
|
},
|
2025-07-02 18:32:06 +08:00
|
|
|
|
|
|
|
|
|
|
// ECharts 图表数据
|
|
|
|
|
|
myChart: null, // 用于存储 ECharts 实例
|
|
|
|
|
|
xAxisData: [],
|
|
|
|
|
|
seriesData: [],
|
|
|
|
|
|
receiveAddress: "",
|
|
|
|
|
|
rechargeList:[]
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
created() {
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
|
|
|
|
|
|
console.log(this.$refs.myCountdown)
|
|
|
|
|
|
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();
|
2025-07-07 19:03:16 +08:00
|
|
|
|
// this.getReceiveAddress();
|
2025-07-02 18:32:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2025-07-07 19:03:16 +08:00
|
|
|
|
// 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);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// });
|
|
|
|
|
|
// },
|
2025-07-02 18:32:06 +08:00
|
|
|
|
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) {
|
|
|
|
|
|
console.log("token", token);
|
|
|
|
|
|
let that = this;
|
|
|
|
|
|
axios
|
|
|
|
|
|
.get("/getinfo", {
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
Authorization: `Bearer ${token}`,
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((response) => {
|
|
|
|
|
|
console.log(response.data);
|
|
|
|
|
|
console.log("code", response.data.code);
|
|
|
|
|
|
if (response.data.code === 200) {
|
|
|
|
|
|
that.userInfo = response.data.data;
|
|
|
|
|
|
console.log("userinfo", that.userInfo);
|
|
|
|
|
|
} 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>',
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2025-07-07 19:03:16 +08:00
|
|
|
|
show(item) {
|
2025-07-02 18:32:06 +08:00
|
|
|
|
$(".modal-overlay").fadeIn();
|
2025-07-07 19:03:16 +08:00
|
|
|
|
this.rechargeData.platformId=item.platformId;
|
|
|
|
|
|
this.rechargeData.name=item.name;
|
2025-07-02 18:32:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
close() {
|
|
|
|
|
|
$(".modal-overlay").fadeOut();
|
2025-07-07 19:03:16 +08:00
|
|
|
|
this.rechargeData={
|
|
|
|
|
|
platformId:null,
|
|
|
|
|
|
name:null,
|
|
|
|
|
|
count:1,
|
|
|
|
|
|
amount:null,
|
|
|
|
|
|
receiveAddress:null,
|
|
|
|
|
|
step:1,
|
|
|
|
|
|
expireUnix:undefined
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
console.log(this.rechargeData);
|
|
|
|
|
|
},
|
|
|
|
|
|
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 => {
|
|
|
|
|
|
console.log("sss",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;
|
|
|
|
|
|
let _that=this;
|
|
|
|
|
|
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
_that.generateQRCode(_that.rechargeData.receiveAddress);
|
|
|
|
|
|
})
|
|
|
|
|
|
}else{
|
|
|
|
|
|
layer.msg(res.data.msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}).finally(() => {
|
|
|
|
|
|
this.loadingQr=false;
|
|
|
|
|
|
});
|
2025-07-02 18:32:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
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;
|
|
|
|
|
|
console.log("userinfo", this.userInfo);
|
|
|
|
|
|
} 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();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-07-07 19:03:16 +08:00
|
|
|
|
generateQRCode(qrString) {
|
|
|
|
|
|
const text = qrString.trim(); // 获取输入框内容并去除首尾空格
|
2025-07-02 18:32:06 +08:00
|
|
|
|
const qrcodeContainer = document.getElementById('qrcode');
|
|
|
|
|
|
|
|
|
|
|
|
if (text) {
|
2025-07-07 19:03:16 +08:00
|
|
|
|
console.log('container',qrcodeContainer)
|
2025-07-02 18:32:06 +08:00
|
|
|
|
// 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
|
2025-07-07 19:03:16 +08:00
|
|
|
|
width: 150, // 设置二维码宽度
|
2025-07-02 18:32:06 +08:00
|
|
|
|
color: {
|
|
|
|
|
|
dark: '#000000', // 二维码颜色
|
|
|
|
|
|
light:'#ffffff' // 背景颜色
|
|
|
|
|
|
}
|
|
|
|
|
|
}, (error) => {
|
|
|
|
|
|
if (error) {
|
|
|
|
|
|
qrcodeContainer.innerHTML = `<p class="text-red-500">获取地址失败请刷新</p>`; // 重新显示错误信息
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log('二维码生成成功!');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果输入为空,给出提示
|
|
|
|
|
|
qrcodeContainer.innerHTML = ''; // 清空可能存在的旧二维码
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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>
|