From 982c97ab82f3beb1b4febcf014562eda34b9fc05 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期二, 29 九月 2026 17:59:41 +0800
Subject: [PATCH] feat(ui): 江苏商贸品牌视觉与首页/登录页改版

---
 src/views/_core/authentication/login.vue |  370 ++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 294 insertions(+), 76 deletions(-)

diff --git a/src/views/_core/authentication/login.vue b/src/views/_core/authentication/login.vue
index 9df6483..3e2356d 100644
--- a/src/views/_core/authentication/login.vue
+++ b/src/views/_core/authentication/login.vue
@@ -1,15 +1,15 @@
 <script lang="ts" setup>
-import type { VbenFormSchema } from '../../../packages/effects/common-ui/src';
+import type { VbenFormSchema } from '@vben/common-ui';
 
 import type { AuthApi } from '#/api/core/auth';
 
 import { computed, onMounted, ref } from 'vue';
-import { useRoute } from 'vue-router';
 
-import { AuthenticationLogin, Verification, z } from '../../../packages/effects/common-ui/src';
-import { isCaptchaEnable, isTenantEnable } from '../../../packages/effects/hooks/src';
-import { $t } from '../../../packages/locales/src';
-import { useAccessStore } from '../../../packages/stores/src';
+import { AuthenticationLogin, VbenButton, Verification, z } from '@vben/common-ui';
+import { isCaptchaEnable, isTenantEnable } from '@vben/hooks';
+import { SvgWeChatIcon } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { useAccessStore } from '@vben/stores';
 
 import {
   checkCaptcha,
@@ -22,7 +22,9 @@
 
 defineOptions({ name: 'Login' });
 
-const { query } = useRoute();
+// vite.config.ts 娉ㄥ叆鐨勫叕鍙� Logo 璺緞
+declare const __APP_LOGO__: string;
+
 const authStore = useAuthStore();
 const accessStore = useAccessStore();
 const tenantEnable = isTenantEnable();
@@ -33,35 +35,21 @@
 
 const captchaType = 'blockPuzzle'; // 楠岃瘉鐮佺被鍨嬶細'blockPuzzle' | 'clickWord'
 
-/** 鑾峰彇绉熸埛鍒楄〃锛屽苟榛樿閫変腑 */
+/** 搴旂敤鏍囬锛堢櫥褰曢〉鍝佺墝鏂囧瓧锛� */
+const appTitle = import.meta.env.VITE_APP_TITLE || '姹熻嫃鍟嗚锤';
+
+/** 鍝佺墝寰芥爣锛氬鐢� vite 娉ㄥ叆鐨勫叕鍙� Logo锛岀己鐪佸洖钀藉埌鍐呯疆鍥炬爣 */
+const brandLogo = __APP_LOGO__ || '/logos/JSSM.svg';
+
+/** 鑾峰彇绉熸埛鍒楄〃 */
 const tenantList = ref<AuthApi.TenantResult[]>([]); // 绉熸埛鍒楄〃
 async function fetchTenantList() {
   if (!tenantEnable) {
     return;
   }
   try {
-    // 鑾峰彇绉熸埛鍒楄〃銆佸煙鍚嶅搴旂鎴�
-    const websiteTenantPromise = getTenantByWebsite(window.location.hostname);
+    // 鑾峰彇绉熸埛鍒楄〃
     tenantList.value = await getTenantSimpleList();
-
-    // 閫変腑绉熸埛锛氬煙鍚� > store 涓殑绉熸埛 > 棣栦釜绉熸埛
-    let tenantId: null | number = null;
-    const websiteTenant = await websiteTenantPromise;
-    if (websiteTenant?.id) {
-      tenantId = websiteTenant.id;
-    }
-    // 濡傛灉娌℃湁浠庡煙鍚嶈幏鍙栧埌绉熸埛锛屽皾璇曚粠 store 涓幏鍙�
-    if (!tenantId && accessStore.tenantId) {
-      tenantId = accessStore.tenantId;
-    }
-    // 濡傛灉杩樻槸娌℃湁绉熸埛锛屼娇鐢ㄥ垪琛ㄤ腑鐨勭涓�涓�
-    if (!tenantId && tenantList.value?.[0]?.id) {
-      tenantId = tenantList.value[0].id;
-    }
-
-    // 璁剧疆閫変腑鐨勭鎴风紪鍙�
-    accessStore.setTenantId(tenantId);
-    loginRef.value.getFormApi().setFieldValue('tenantId', tenantId?.toString());
   } catch (error) {
     console.error('鑾峰彇绉熸埛鍒楄〃澶辫触:', error);
   }
@@ -90,57 +78,44 @@
   }
 }
 
-/** 澶勭悊绗笁鏂圭櫥褰� */
-const redirect = query?.redirect;
-async function handleThirdLogin(type: number) {
-  if (type <= 0) {
-    return;
-  }
-  try {
-    // 璁$畻 redirectUri
-    // tricky: type銆乺edirect 闇�瑕佸厛 encode 涓�娆★紝鍚﹀垯閽夐拤鍥炶皟浼氫涪澶便�傞厤鍚� social-login.vue#getUrlValue() 浣跨敤
-    const redirectUri = `${
-      location.origin
-    }/auth/social-login?${encodeURIComponent(
-      `type=${type}&redirect=${redirect || '/'}`,
-    )}`;
-
-    // 杩涜璺宠浆
-    window.location.href = await socialAuthRedirect(type, redirectUri);
-  } catch (error) {
-    console.error('绗笁鏂圭櫥褰曞鐞嗗け璐�:', error);
-  }
-}
-
 /** 缁勪欢鎸傝浇鏃惰幏鍙栫鎴蜂俊鎭� */
 onMounted(() => {
   fetchTenantList();
 });
 
+// ========== 浼佷笟寰俊鐧诲綍 ==========
+
+/** 浼佷笟寰俊鐨勭ぞ浜ょ被鍨嬶紝瀵瑰簲鍚庣 SocialTypeEnum.WECHAT_ENTERPRISE */
+const WXCP_SOCIAL_TYPE = 30;
+
+const wxcpLoading = ref(false);
+
+/**
+ * 浼佷笟寰俊鎵爜鐧诲綍
+ *
+ * 娴佺▼锛氬彇鎺堟潈鍦板潃 -> 鏁撮〉璺宠浆鍒颁紒涓氬井淇℃壂鐮侀〉 -> 鎵爜鍚庝紒涓氬井淇″甫 code/state
+ * 鍥炶烦鍒� social-login 椤甸潰 -> 璇ラ〉闈㈣皟鐢� /system/auth/social-login 鎹㈠彇浠ょ墝
+ */
+async function handleWxcpLogin() {
+  try {
+    wxcpLoading.value = true;
+    // 娉ㄦ剰锛歵ype 闇�瑕佸厛 encode 涓�娆★紝閰嶅悎 social-login 椤甸潰鐨� getUrlValue() 浣跨敤锛�
+    // 鍚﹀垯浼佷笟寰俊鍥炶烦鍚� type 鍙傛暟浼氳鍚炴帀锛屽鑷存棤娉曡瘑鍒ぞ浜ょ被鍨�
+    const redirectUri = `${location.origin}/auth/social-login?${encodeURIComponent(
+      `type=${WXCP_SOCIAL_TYPE}`,
+    )}`;
+    window.location.href = await socialAuthRedirect(
+      WXCP_SOCIAL_TYPE,
+      redirectUri,
+    );
+  } catch (error) {
+    console.error('浼佷笟寰俊鐧诲綍澶辫触:', error);
+    wxcpLoading.value = false;
+  }
+}
+
 const formSchema = computed((): VbenFormSchema[] => {
   return [
-    {
-      component: 'VbenSelect',
-      componentProps: {
-        options: tenantList.value.map((item) => ({
-          label: item.name,
-          value: item.id.toString(),
-        })),
-        placeholder: $t('authentication.tenantTip'),
-      },
-      fieldName: 'tenantId',
-      label: $t('authentication.tenant'),
-      rules: z.string().min(1, { message: $t('authentication.tenantTip') }),
-      dependencies: {
-        triggerFields: ['tenantId'],
-        if: tenantEnable,
-        trigger(values) {
-          if (values.tenantId) {
-            accessStore.setTenantId(Number(values.tenantId));
-          }
-        },
-      },
-    },
     {
       component: 'VbenInput',
       componentProps: {
@@ -170,14 +145,57 @@
 </script>
 
 <template>
-  <div>
+  <div class="academic-login-wrapper">
+    <!-- 椤堕儴鍝佺墝鏍囪瘑锛氬窘鏍� + 骞冲彴鍚� + 閲戣壊鍒嗛殧绾� -->
+    <div class="academic-login-header">
+      <img :alt="appTitle" :src="brandLogo" class="academic-brand-logo" />
+      <h2 class="academic-brand-name">{{ appTitle }}</h2>
+      <div class="academic-decoration-line"></div>
+    </div>
+
     <AuthenticationLogin
       ref="loginRef"
       :form-schema="formSchema"
       :loading="authStore.loginLoading"
+      :show-code-login="false"
+      :show-qrcode-login="false"
+      :show-third-party-login="false"
+      :show-register="false"
+      :show-forget-password="false"
+      :show-doc-link="false"
+      class="academic-login-form"
       @submit="handleLogin"
-      @third-login="handleThirdLogin"
-    />
+    >
+      <!-- 鑷畾涔夋爣棰橈細瑕嗙洊娆㈣繋璇� -->
+      <template #title>
+        <div class="academic-title-area">
+          <h3 class="academic-title">璐﹀彿鐧诲綍</h3>
+          <p class="academic-subtitle">{{ $t('authentication.loginSubtitle') }}</p>
+        </div>
+      </template>
+
+      <!-- 绗笁鏂圭櫥褰� -->
+      <template #third-party-login>
+        <div class="academic-third-party">
+          <div class="academic-divider">
+            <span class="academic-divider-line"></span>
+            <span class="academic-divider-text">鍏朵粬鐧诲綍鏂瑰紡</span>
+            <span class="academic-divider-line"></span>
+          </div>
+          <VbenButton
+            class="academic-wxcp-btn"
+            variant="outline"
+            :loading="wxcpLoading"
+            @click="handleWxcpLogin"
+          >
+            <SvgWeChatIcon class="mr-2 size-4" />
+            浼佷笟寰俊鐧诲綍
+          </VbenButton>
+        </div>
+      </template>
+    </AuthenticationLogin>
+
+    <!-- 楠岃瘉鐮侊紙婊戝潡鎷煎浘锛夛紝captchaEnable 鏃跺惎鐢� -->
     <Verification
       ref="verifyRef"
       v-if="captchaEnable"
@@ -190,3 +208,203 @@
     />
   </div>
 </template>
+
+<style scoped>
+/* ========== 瀛︽湳绉戠爺椋庢牸鐧诲綍椤垫牱寮� ========== */
+.academic-login-wrapper {
+  @apply relative flex flex-col w-full;
+  min-height: 460px;
+}
+
+/* ---- 椤堕儴鍝佺墝鏍囪瘑 ---- */
+.academic-login-header {
+  @apply flex flex-col items-center mb-8;
+}
+
+.academic-brand-logo {
+  width: 52px;
+  height: 52px;
+  margin-bottom: 16px;
+  filter: drop-shadow(0 3px 10px rgba(15, 36, 64, 0.14));
+}
+
+.academic-brand-name {
+  font-size: 19px;
+  font-weight: 600;
+  letter-spacing: 5px;
+  /* 鏈瓧鍙充晶浼氬鍑轰竴浠藉瓧璺濓紝鐢ㄧ瓑閲忕缉杩涙姷娑堬紝瑙嗚鎵嶇湡姝e眳涓� */
+  text-indent: 5px;
+  color: #0f2440;
+  margin: 0 0 14px;
+}
+
+.academic-decoration-line {
+  position: relative;
+  width: 58px;
+  height: 2px;
+  background: linear-gradient(
+    90deg,
+    transparent,
+    #d4af37 32%,
+    #d4af37 68%,
+    transparent
+  );
+  border-radius: 2px;
+}
+
+/* 閲戠嚎涓ぎ鐨勮彵褰㈢偣缂� */
+.academic-decoration-line::after {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 6px;
+  height: 6px;
+  background: #d4af37;
+  border-radius: 1px;
+  transform: translate(-50%, -50%) rotate(45deg);
+}
+
+/* ---- 鑷畾涔夋爣棰� ---- */
+.academic-title-area {
+  @apply text-left mb-6;
+}
+
+.academic-title {
+  font-size: 26px;
+  font-weight: 600;
+  color: #0f2440;
+  letter-spacing: 2px;
+  margin: 0 0 8px 0;
+  line-height: 1.35;
+}
+
+.academic-subtitle {
+  font-size: 13.5px;
+  color: #8a94a6;
+  margin: 0;
+  letter-spacing: 0.3px;
+}
+
+/* ---- 瑕嗙洊榛樿鏍囬 ---- */
+:deep(.academic-login-form .mb-7) {
+  display: none;
+}
+
+/* ---- 杈撳叆妗嗭細鏆栫櫧搴� + 閲戣壊鑱氱劍 ---- */
+:deep(.academic-login-form .vben-input) {
+  border-radius: 8px;
+  border-color: #e6e2d8;
+  background: #fdfcfa;
+  transition: all 0.25s ease;
+  height: 48px;
+}
+
+:deep(.academic-login-form .vben-input:hover) {
+  border-color: #c9b77a;
+}
+
+:deep(.academic-login-form .vben-input:focus-within) {
+  border-color: #d4af37;
+  background: #fff;
+  box-shadow: 0 0 0 3px rgba(212, 175, 55, 0.13);
+}
+
+/* ---- 鐧诲綍鎸夐挳锛氳棌闈掓笎鍙� + 閲戣壊鎻忚竟涓庢枃瀛� ---- */
+:deep(.academic-login-form .w-full > button),
+:deep(.academic-login-form button[aria-label="login"]) {
+  height: 48px;
+  border-radius: 8px;
+  background: linear-gradient(135deg, #1e4571, #0f2440) !important;
+  border: 1px solid rgba(212, 175, 55, 0.45) !important;
+  font-size: 15px;
+  font-weight: 600;
+  letter-spacing: 6px;
+  text-indent: 6px;
+  box-shadow: 0 6px 18px rgba(15, 36, 64, 0.22);
+  transition: all 0.3s ease;
+  color: #f5e7c0 !important;
+}
+
+/* 鎮仠鍙姞娣辨弿杈逛笌鎶曞奖锛屼笉鍋氫綅绉伙紝淇濇寔鍏嬪埗 */
+:deep(.academic-login-form .w-full > button:hover),
+:deep(.academic-login-form button[aria-label="login"]:hover) {
+  box-shadow:
+    0 8px 22px rgba(15, 36, 64, 0.26),
+    0 0 0 1px rgba(212, 175, 55, 0.6);
+}
+
+:deep(.academic-login-form .w-full > button:active),
+:deep(.academic-login-form button[aria-label="login"]:active) {
+  box-shadow: 0 3px 12px rgba(15, 36, 64, 0.24);
+}
+
+/* ---- 璁颁綇璐﹀彿 / 蹇樿瀵嗙爜 ---- */
+:deep(.academic-login-form .vben-link) {
+  color: #b8901f;
+  font-weight: 500;
+  transition: color 0.2s;
+}
+
+:deep(.academic-login-form .vben-link:hover) {
+  color: #8a6a12;
+}
+
+/* ---- 绗笁鏂圭櫥褰� ---- */
+.academic-third-party {
+  @apply mt-5;
+}
+
+.academic-divider {
+  @apply flex items-center gap-3 mb-4;
+}
+
+.academic-divider-line {
+  flex: 1;
+  height: 1px;
+  background: linear-gradient(90deg, transparent, #e2e8f0, transparent);
+}
+
+.academic-divider-text {
+  @apply text-xs;
+  color: #94a3b8;
+  white-space: nowrap;
+  letter-spacing: 0.5px;
+}
+
+.academic-wxcp-btn {
+  @apply w-full rounded-lg;
+  height: 44px;
+  border-color: #e6e2d8;
+  color: #44546a;
+  font-weight: 500;
+  transition: all 0.3s;
+}
+
+.academic-wxcp-btn:hover {
+  border-color: #d4af37;
+  color: #0f2440;
+  background: rgba(212, 175, 55, 0.06);
+}
+
+/* ---- 鏆楄壊閫傞厤 ---- */
+:root.dark .academic-title {
+  color: #f0ead8;
+}
+
+:root.dark .academic-brand-name {
+  color: #f0ead8;
+}
+
+:root.dark .academic-subtitle {
+  color: #8a94a6;
+}
+
+:root.dark .academic-decoration-line {
+  background: linear-gradient(90deg, #8bb4f0, #4a7ad4);
+}
+
+:root.dark .academic-footer-text {
+  color: #64748b;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3