| {% extends "base.html" %}
|
|
|
| {% block title %}Token管理{% endblock %}
|
|
|
| {% block extra_css %}
|
| <style>
|
| .token-list {
|
| width: 100%;
|
| border-collapse: collapse;
|
| }
|
|
|
| .token-list th,
|
| .token-list td {
|
| border: 1px solid #e2e8f0;
|
| padding: 8px;
|
| text-align: left;
|
| }
|
|
|
| .token-list th {
|
| background-color: #f8fafc;
|
| }
|
|
|
| .token-list tr:nth-child(even) {
|
| background-color: #f1f5f9;
|
| }
|
|
|
| .truncate {
|
| max-width: 200px;
|
| white-space: nowrap;
|
| overflow: hidden;
|
| text-overflow: ellipsis;
|
| }
|
|
|
| h2 {
|
| position: relative;
|
| }
|
|
|
| #addTokenBtn {
|
| position: absolute;
|
| font-size: 1rem;
|
| right: 0;
|
| top: 50%;
|
| transform: translateY(-50%);
|
| }
|
|
|
| button:disabled {
|
| color: #ccc;
|
| background-color: #eee;
|
| border: none;
|
| cursor: not-allowed;
|
| }
|
|
|
| button:disabled:hover {
|
| color: #ccc;
|
| background-color: #eee;
|
| border: none;
|
| cursor: not-allowed;
|
| }
|
|
|
| @media (max-width: 770px) {
|
| body {
|
| font-size: 2.3vw;
|
| }
|
|
|
| h2 {
|
| font-size: 3.5vw !important;
|
| }
|
|
|
| #addTokenBtn {
|
| font-size: 2vw;
|
| line-height: 2vw;
|
| }
|
|
|
| .token-list {
|
| flex: 1;
|
| }
|
|
|
| .token-list thead {
|
| display: flex;
|
| flex-wrap: wrap;
|
| }
|
|
|
| .token-list #tokenTableBody {
|
| display: flex;
|
| flex-wrap: wrap;
|
| }
|
|
|
| .token-list tr {
|
| display: flex;
|
| }
|
|
|
| .token-list tr,
|
| .token-list th,
|
| .token-list td {
|
| flex: 1;
|
| }
|
| }
|
| </style>
|
| {% endblock %}
|
|
|
| {% block content %}
|
| <div class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
|
| <h2 class="text-2xl font-bold text-gray-800 mb-4">账号列表
|
| <button id="addTokenBtn"
|
| class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline transition duration-300 ease-in-out mr-2">
|
| 添加账号
|
| </button>
|
| </h2>
|
| <table class="token-list">
|
| <thead>
|
| <tr>
|
| <th>Email</th>
|
| <th>Sk Token</th>
|
| <th>状态</th>
|
| <th>操作</th>
|
| </tr>
|
| </thead>
|
| <tbody id="tokenTableBody">
|
|
|
| </tbody>
|
| </table>
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| </div>
|
|
|
| <div id="tokenModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden">
|
| <div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
|
| <div class="mt-3">
|
| <h3 class="text-lg font-medium text-gray-900 mb-4">账号信息</h3>
|
| <form id="tokenForm">
|
| <input type="hidden" id="id">
|
| <div class="mb-4">
|
| <label class="block text-gray-700 text-sm font-bold mb-2" for="email">
|
| 邮箱
|
| </label>
|
| <input
|
| class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
| id="email" type="text" required placeholder="仅用于标识">
|
| </div>
|
| <div class="mb-4">
|
| <label class="block text-gray-700 text-sm font-bold mb-2" for="skToken">
|
| skToken
|
| </label>
|
| <input
|
| class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
| id="skToken" type="text" placeholder="必填" required>
|
| </div>
|
| <div class="mb-4">
|
| <label class="block text-gray-700 text-sm font-bold mb-2" for="PLUS">
|
| PLUS
|
| </label>
|
| <select
|
| class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
| id="PLUS" required>
|
| <option value='false'>false</option>
|
| <option value='true'>true</option>
|
| </select>
|
| </div>
|
| <div class="flex items-center justify-end">
|
| <button type="button" onclick="closeModal()"
|
| class="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline mr-2">
|
| 取消
|
| </button>
|
| <button type="submit"
|
| class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
|
| 保存
|
| </button>
|
| </div>
|
| </form>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| </div>
|
| {% endblock %}
|
| {% block extra_js %}
|
|
|
| <script>
|
|
|
| function loadTokens() {
|
| fetch('/get_Claude')
|
| .then(response => response.json())
|
| .then(data => {
|
| tokens = data
|
| tokenTableBody.innerHTML = '';
|
| data.forEach(token => {
|
| let rt = '有'
|
| if (!token.skToken) {
|
| rt = '无'
|
| }
|
| let recolor = token.skToken ? ' style="color: rgb(6, 161, 6);"' : ' style="color: rgb(204, 28, 28);"'
|
| let color = token.status ? ' style="color: rgb(6, 161, 6);"' : ' style="color: rgb(204, 28, 28);"'
|
| const row = document.createElement('tr');
|
| row.innerHTML = `
|
| <td class="truncate">${token.email}</td>
|
| <td class="truncate" ${recolor}>${rt}</td>
|
| <td class="truncate" ${color}>${token.status ? '有效' : '失效'}</td>
|
| <td>
|
| <button onclick="editUser('${token.email}')" class="text-blue-600 hover:text-blue-900 mr-4">编辑</button>
|
| <button onclick="deleteUser('${token.email}')" class="text-red-600 hover:text-red-900">删除</button>
|
| </td>
|
| `;
|
| tokenTableBody.appendChild(row);
|
| });
|
| })
|
| .catch(error => {
|
| console.error('加载 Tokens 失败:', error);
|
| showStatus('加载 Tokens 失败', 'error');
|
| });
|
| }
|
|
|
| let tokens = []
|
| const modal = document.getElementById('tokenModal');
|
| const tokenForm = document.getElementById('tokenForm');
|
| const addTokenBtn = document.getElementById('addTokenBtn');
|
|
|
|
|
| function openModal(email = null) {
|
| const form = document.getElementById('tokenForm');
|
| if (email) {
|
| document.getElementById('id').value = 'id'
|
| document.getElementById('email').value = email.email;
|
| document.getElementById('skToken').value = email.skToken;
|
| document.getElementById('PLUS').value = email.PLUS;
|
| } else {
|
| form.reset();
|
| document.getElementById('id').value = ''
|
| }
|
| modal.classList.remove('hidden');
|
| }
|
|
|
|
|
| function closeModal() {
|
| modal.classList.add('hidden');
|
| }
|
|
|
|
|
| function editUser(email) {
|
| const tkemail = tokens.find(u => u.email === email);
|
| if (tkemail) {
|
| openModal(tkemail);
|
| }
|
| }
|
|
|
|
|
| function deleteUser(email) {
|
| if (confirm('确定要删除这个账户吗?')) {
|
| fetch(`/api/Claude/${email}`, {
|
| method: 'DELETE'
|
| })
|
| .then(response => response.json())
|
| .then(data => {
|
| if (data.success) {
|
| loadTokens();
|
| }
|
| })
|
| .catch(error => console.error('Error:', error));
|
| }
|
| }
|
|
|
|
|
| tokenForm.addEventListener('submit', function (e) {
|
| e.preventDefault();
|
| const Id = document.getElementById('id').value;
|
| const tkemail = document.getElementById('email').value
|
| const skToken = document.getElementById('skToken').value
|
| const plus = document.getElementById('PLUS').value
|
| const tkData = {
|
| email: document.getElementById('email').value,
|
| SkToken: skToken,
|
| PLUS: plus
|
| };
|
|
|
| const url = Id ? `/api/Claude/${tkemail}` : '/api/Claude';
|
| const method = Id ? 'PUT' : 'POST';
|
|
|
| fetch(url, {
|
| method: method,
|
| headers: {
|
| 'Content-Type': 'application/json'
|
| },
|
| body: JSON.stringify(tkData)
|
| })
|
| .then(response => response.json())
|
| .then(data => {
|
| if (data.success) {
|
| closeModal();
|
| loadTokens();
|
| }
|
| })
|
| .catch(error => console.error('Error:', error));
|
| });
|
|
|
|
|
| addTokenBtn.addEventListener('click', () => openModal());
|
| </script>
|
| <script>
|
| document.addEventListener('DOMContentLoaded', function () {
|
| const tokenTableBody = document.getElementById('tokenTableBody');
|
| const refreshBtn = document.getElementById('refreshBtn');
|
| const statusMessage = document.getElementById('statusMessage');
|
| const autoRefreshToggle = document.getElementById('autoRefreshToggle');
|
| const refreshInterval = document.getElementById('refreshInterval');
|
| const nextRefreshTime = document.getElementById('nextRefreshTime');
|
| const refreshHistory = document.getElementById('refreshHistory');
|
|
|
| function loadTokens() {
|
| fetch('/get_Claude')
|
| .then(response => response.json())
|
| .then(data => {
|
| tokens = data
|
| tokenTableBody.innerHTML = '';
|
| data.forEach(token => {
|
| let rt = '有'
|
| if (!token.skToken) {
|
| rt = '无'
|
| }
|
| let recolor = token.skToken ? ' style="color: rgb(6, 161, 6);"' : ' style="color: rgb(204, 28, 28);"'
|
| let color = token.status ? ' style="color: rgb(6, 161, 6);"' : ' style="color: rgb(204, 28, 28);"'
|
| const row = document.createElement('tr');
|
| row.innerHTML = `
|
| <td class="truncate">${token.email}</td>
|
| <td class="truncate" ${recolor}>${rt}</td>
|
| <td class="truncate" ${color}>${token.status ? '有效' : '失效'}</td>
|
| <td>
|
| <button onclick="editUser('${token.email}')" class="text-blue-600 hover:text-blue-900 mr-4">编辑</button>
|
| <button onclick="deleteUser('${token.email}')" class="text-red-600 hover:text-red-900">删除</button>
|
| </td>
|
| `;
|
| tokenTableBody.appendChild(row);
|
| });
|
| })
|
| .catch(error => {
|
| console.error('加载 Tokens 失败:', error);
|
| showStatus('加载 Tokens 失败', 'error');
|
| });
|
| }
|
|
|
|
|
| loadTokens();
|
| });
|
| </script>
|
| {% endblock %}
|
|
|