handy пре 1 месец
родитељ
комит
97898abcb4
1 измењених фајлова са 176 додато и 1 уклоњено
  1. 176 1
      src/components/LoginModal.vue

+ 176 - 1
src/components/LoginModal.vue

@@ -112,8 +112,63 @@
             >
               {{ loading ? '登录中...' : '登录' }}
             </button>
+            <button
+              type="button"
+              class="btn-token"
+              :disabled="loading"
+              @click="openTokenModal"
+              title="使用 Token 登录"
+            >
+              <svg
+                viewBox="0 0 24 24"
+                aria-hidden="true"
+                class="btn-token-icon"
+              >
+                <path
+                  d="M3 7a4 4 0 1 1 7.8 1.3l9.2 3.54a3.5 3.5 0 1 1-1.1 2.74l-9.2-3.54A4 4 0 0 1 3 7zm4 2a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm13 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"
+                  fill="currentColor"
+                />
+              </svg>
+            </button>
           </div>
         </form>
+        <div
+          v-if="tokenModalVisible"
+          class="token-modal-overlay"
+          @click.self="closeTokenModal"
+        >
+          <div class="token-modal">
+            <div class="token-modal-header">Token 登录</div>
+            <div
+              v-if="tokenError"
+              class="error-message"
+            >
+              {{ tokenError }}
+            </div>
+            <input
+              v-model="tokenInput"
+              class="token-input"
+              type="text"
+              placeholder="请输入 Token"
+            >
+            <div class="token-modal-actions">
+              <button
+                type="button"
+                class="btn-secondary"
+                @click="closeTokenModal"
+              >
+                取消
+              </button>
+              <button
+                type="button"
+                class="btn-primary"
+                @click="confirmToken"
+              >
+                确认
+              </button>
+            </div>
+          </div>
+        </div>
       </div>
     </div>
   </div>
@@ -148,6 +203,9 @@ const loading = ref(false)
 const error = ref('')
 const showPassword = ref(false)
 const selectedEnvironment = ref(getApiEnvironment())
+const tokenModalVisible = ref(false)
+const tokenInput = ref('')
+const tokenError = ref('')
 
 watch(
   selectedEnvironment,
@@ -188,6 +246,29 @@ const handleSubmit = async () => {
   }
 }
 
+const openTokenModal = () => {
+  tokenInput.value = ''
+  tokenError.value = ''
+  tokenModalVisible.value = true
+}
+
+const closeTokenModal = () => {
+  tokenModalVisible.value = false
+  tokenError.value = ''
+}
+
+const confirmToken = () => {
+  const token = tokenInput.value.trim()
+  if (!token) {
+    tokenError.value = '请输入 Token'
+    return
+  }
+  setApiEnvironment(selectedEnvironment.value)
+  setToken(token)
+  tokenModalVisible.value = false
+  emit('success')
+}
+
 const handleCancel = () => {
   if (!loading.value) {
     emit('cancel')
@@ -216,6 +297,7 @@ const handleCancel = () => {
   width: 90%;
   max-width: 400px;
   box-shadow: 0 18px 48px rgba(0, 0, 0, 0.46);
+  position: relative;
 }
 
 .modal-header {
@@ -348,10 +430,12 @@ const handleCancel = () => {
 
 .form-actions {
   margin-top: 30px;
+  display: flex;
+  gap: 10px;
 }
 
 .btn-primary {
-  width: 100%;
+  flex: 1;
   padding: 12px;
   background: linear-gradient(180deg, #2f5fd7 0%, #244cb0 100%);
   border: 1px solid #325bbf;
@@ -372,4 +456,95 @@ const handleCancel = () => {
   opacity: 0.6;
   cursor: not-allowed;
 }
+
+.btn-secondary {
+  background: transparent;
+  border: 1px solid #2a2a2a;
+  color: #cfcfcf;
+  border-radius: 6px;
+  padding: 10px 16px;
+  font-size: 14px;
+  cursor: pointer;
+}
+
+.btn-secondary:hover {
+  border-color: #3a3a3a;
+  color: #f2f2f2;
+}
+
+.btn-token {
+  width: 44px;
+  height: 44px;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 6px;
+  border: 1px solid #2a2a2a;
+  background: rgba(255, 255, 255, 0.02);
+  color: #cfcfcf;
+  cursor: pointer;
+}
+
+.btn-token:hover {
+  border-color: #3a3a3a;
+  color: #ffffff;
+}
+
+.btn-token:disabled {
+  opacity: 0.6;
+  cursor: not-allowed;
+}
+
+.btn-token-icon {
+  width: 18px;
+  height: 18px;
+}
+
+.token-modal-overlay {
+  position: absolute;
+  inset: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 10px;
+}
+
+.token-modal {
+  width: 86%;
+  max-width: 320px;
+  background: #0d0d0d;
+  border: 1px solid #2a2a2a;
+  border-radius: 8px;
+  padding: 14px;
+  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.4);
+}
+
+.token-modal-header {
+  font-size: 14px;
+  color: #f2f2f2;
+  margin-bottom: 10px;
+}
+
+.token-input {
+  width: 100%;
+  padding: 10px 12px;
+  background: #121212;
+  border: 1px solid #2a2a2a;
+  color: #f2f2f2;
+  border-radius: 6px;
+  outline: none;
+  font-size: 13px;
+}
+
+.token-input:focus {
+  border-color: #2f8cff;
+}
+
+.token-modal-actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  margin-top: 12px;
+}
 </style>