Преглед изворни кода

feat: 个人信息页支持绑定 Telegram 账号

urban пре 3 недеља
родитељ
комит
d1e2920698
3 измењених фајлова са 92 додато и 4 уклоњено
  1. 1 1
      src/api/user.ts
  2. 64 2
      src/views/profile/edit.vue
  3. 27 1
      src/views/profile/index.vue

+ 1 - 1
src/api/user.ts

@@ -93,7 +93,7 @@ export function requestGetSocialList(): Promise<CommonResponse<SocialAccount[]>>
 }
 
 // 绑定社交账号
-export function requestBindSocial(data: { type: string; account: string }): Promise<CommonResponse> {
+export function requestBindSocial(data: { platform: string; account: string; nickname?: string }): Promise<CommonResponse> {
   return http.request({
     url: "/api/v1/dt/social/bind",
     method: "post",

+ 64 - 2
src/views/profile/edit.vue

@@ -77,6 +77,31 @@
       </div>
     </div>
 
+    <!-- Telegram 绑定 -->
+    <div class="edit-section" v-if="type === 'telegram'">
+      <div class="telegram-header">
+        <svg viewBox="0 0 24 24" width="48" height="48" style="margin: 0 auto 12px; display: block;">
+          <circle cx="12" cy="12" r="12" fill="#0088cc"/>
+          <path fill="#fff" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5.46 7.12l-1.67 6.14c-.13.46-.47.58-.95.36l-2.62-1.93-1.26 1.22c-.14.14-.26.26-.53.26l.19-2.67 4.84-4.37c.21-.19-.05-.29-.32-.12l-5.99 3.78-2.58-.81c-.56-.17-.57-.56.12-.83l10.1-3.9c.46-.17.87.11.67.87z"/>
+        </svg>
+        <p class="telegram-tip">Enter your Telegram username to bind your account</p>
+      </div>
+      <van-field
+        v-model="telegramUsername"
+        placeholder="@username"
+        maxlength="50"
+        class="edit-input"
+      >
+        <template #left-icon>
+          <span style="color: var(--text-secondary, rgba(255,255,255,0.5)); font-size: 16px;">@</span>
+        </template>
+      </van-field>
+      <div class="tips">
+        <p>* Open Telegram → Settings → Username to find your username</p>
+        <p>* Binding Telegram enables you to participate in red packet events</p>
+      </div>
+    </div>
+
     <!-- 地区编辑 -->
     <div class="edit-section" v-if="type === 'region'">
       <van-field
@@ -146,7 +171,7 @@ import { useRouter, useRoute } from "vue-router";
 import { useI18n } from "vue-i18n";
 import { showToast } from "vant";
 import { useUserStore } from "@/store/modules/userStore";
-import { requestUpdateUserInfo, requestBindPhone, requestBindEmail, requestVerifyRealName } from "@/api/user";
+import { requestUpdateUserInfo, requestBindPhone, requestBindEmail, requestVerifyRealName, requestBindSocial, requestGetSocialList } from "@/api/user";
 import { requestSendCode } from "@/api/auth";
 
 const { t } = useI18n();
@@ -166,6 +191,7 @@ const age = ref(userInfo.value?.age ? String(userInfo.value.age) : '');
 const gender = ref(userInfo.value?.gender || 0);
 const realName = ref('');
 const idCard = ref('');
+const telegramUsername = ref('');
 const countdown = ref(0);
 let timer: NodeJS.Timer | null = null;
 
@@ -174,6 +200,7 @@ const getTitle = () => {
     nickname: t('user.nickname'),
     phone: t('user.bindPhone'),
     email: t('user.bindEmail'),
+    telegram: 'Bind Telegram',
     region: t('user.region'),
     age: t('user.age'),
     gender: t('user.gender'),
@@ -245,6 +272,15 @@ const handleSave = async () => {
         res = await requestBindEmail({ email: email.value, code: code.value });
         break;
 
+      case 'telegram':
+        const tgAccount = telegramUsername.value.trim().replace(/^@/, '');
+        if (!tgAccount) {
+          showToast('Please enter your Telegram username');
+          return;
+        }
+        res = await requestBindSocial({ platform: 'telegram', account: tgAccount });
+        break;
+
       case 'region':
         if (!region.value.trim()) {
           showToast(t('user.region'));
@@ -295,13 +331,28 @@ const goBack = () => {
   router.back();
 };
 
-onMounted(() => {
+onMounted(async () => {
   if (userInfo.value) {
     nickname.value = userInfo.value.nickname || '';
     region.value = userInfo.value.region || '';
     age.value = userInfo.value.age ? String(userInfo.value.age) : '';
     gender.value = userInfo.value.gender || 0;
   }
+
+  // 加载已绑定的 Telegram 用户名
+  if (type.value === 'telegram') {
+    try {
+      const res = await requestGetSocialList();
+      if (res.code === 200 && res.data) {
+        const tg = (res.data as any[]).find((item: any) => item.platform === 'telegram');
+        if (tg && tg.account) {
+          telegramUsername.value = tg.account;
+        }
+      }
+    } catch (e) {
+      // ignore
+    }
+  }
 });
 </script>
 
@@ -398,6 +449,17 @@ onMounted(() => {
     }
   }
 
+  .telegram-header {
+    text-align: center;
+    margin-bottom: 20px;
+
+    .telegram-tip {
+      font-size: 13px;
+      color: var(--text-secondary, rgba(255, 255, 255, 0.6));
+      line-height: 1.5;
+    }
+  }
+
   .tips {
     margin-top: 16px;
     padding: 12px;

+ 27 - 1
src/views/profile/index.vue

@@ -45,6 +45,15 @@
         </div>
       </div>
 
+      <!-- 绑定 Telegram -->
+      <div class="info-item" @click="goEdit('telegram')">
+        <span class="label">Bind Telegram</span>
+        <div class="value">
+          <span>{{ telegramAccount || $t('common.no') }}</span>
+          <van-icon name="arrow" />
+        </div>
+      </div>
+
       <!-- 地区 -->
       <div class="info-item" @click="goEdit('region')">
         <span class="label">{{ $t('user.region') }}</span>
@@ -117,10 +126,12 @@ import { useRouter } from "vue-router";
 import { useI18n } from "vue-i18n";
 import { showToast } from "vant";
 import { useUserStore } from "@/store/modules/userStore";
-import { requestUpdateUserInfo } from "@/api/user";
+import { requestUpdateUserInfo, requestGetSocialList } from "@/api/user";
 import { uploadFileToOss } from "@/api/upload";
 import defaultAvatar from "@/assets/images/common/icon_avatar.svg";
 
+const telegramAccount = ref('');
+
 const { t } = useI18n();
 const router = useRouter();
 const userStore = useUserStore();
@@ -189,8 +200,23 @@ const goPaymentAccount = () => {
   router.push('/payment-account');
 };
 
+const loadTelegramBind = async () => {
+  try {
+    const res = await requestGetSocialList();
+    if (res.code === 200 && res.data) {
+      const tg = (res.data as any[]).find((item: any) => item.platform === 'telegram');
+      if (tg) {
+        telegramAccount.value = tg.account || '';
+      }
+    }
+  } catch (e) {
+    // ignore
+  }
+};
+
 onMounted(() => {
   userStore.fetchUserInfo();
+  loadTelegramBind();
 });
 </script>