Procházet zdrojové kódy

feat:生成开户链接

ljc před 2 měsíci
rodič
revize
8a7befa3b6
5 změnil soubory, kde provedl 711 přidání a 18 odebrání
  1. 3 6
      components/cwg-popup.vue
  2. 27 2
      locale/cn.json
  3. 7 0
      pages.json
  4. 14 10
      pages/ib/index.vue
  5. 660 0
      pages/ib/linkList.vue

+ 3 - 6
components/cwg-popup.vue

@@ -34,7 +34,7 @@
                 <template v-else-if="footerType === 'single'">
                     <view class="btn-content">
                         <button class="single-btn" :class="singleBtnType" @click="handleSingleBtnClick">
-                            {{ singleBtnText || t('Common.Confirm') }}
+                            {{ singleBtnText || t('common.confirm') }}
                         </button>
                     </view>
                 </template>
@@ -43,10 +43,10 @@
                 <template v-else>
                     <view class="btn-content">
                         <button class="cancel-btn" @click="closeDialog">
-                            {{ cancelText || t('Common.Cancel') }}
+                            {{ cancelText || t('common.cancel') }}
                         </button>
                         <button class="confirm-btn" :class="confirmBtnType" @click="handleConfirm">
-                            {{ confirmText || t('Common.Confirm') }}
+                            {{ confirmText || t('common.confirm') }}
                         </button>
                     </view>
                 </template>
@@ -134,7 +134,6 @@ const props = defineProps({
         })
     }
 })
-console.log('props.showFooters:', props.showFooters)
 const emit = defineEmits(['update:visible', 'confirm', 'close', 'single-click'])
 
 // 弹窗引用
@@ -143,8 +142,6 @@ const slots = useSlots()
 
 // 监听 visible 变化
 watch(() => props.visible, (val) => {
-
-    console.log(slots)
     if (val) {
         popupRef.value?.open()
     } else {

+ 27 - 2
locale/cn.json

@@ -1680,7 +1680,11 @@
       "Spread5": "请选择账户类型",
       "Spread6": "新加点",
       "Spread7": "旧加点",
-      "Spread8": "加点"
+      "Spread8": "加点",
+      "QrCode": "二维码",
+      "ViewQrCode": "查看二维码",
+      "CustomNum": "开户人数",
+      "LinkValue": "推荐码"
     },
     "NewAccount": {
       "TitleM": "新建MAM账户",
@@ -1722,7 +1726,28 @@
       "Tips1": "1. 当您选择“开启”时,客户可自主申请成为您名下代理",
       "Tips2": "2. 当您选择“关闭”时,名下客户将无法自主申请成为代理",
       "Tips3": "3. 当客户已经申请成为代理时,将无法操作“关闭”的设置",
-      "Tips4": "IB佣金转交易账户后,此笔金额只能在周五申请提款,其他日期申请,会拒绝处理。"
+      "Tips4": "IB佣金转交易账户后,此笔金额只能在周五申请提款,其他日期申请,会拒绝处理。",
+      "NameLabel": "名称",
+      "NameLabelColon": "名称:",
+      "AgentNum": "名下代理数量",
+      "CustomerNum": "名下客户数量",
+      "LastActiveTime": "上次活跃时间",
+      "Unverified": "未实名",
+      "UnDeposit": "未入金",
+      "Deposited": "已入金",
+      "CustomerStatus": "客户状态",
+      "ApplyAgent": "是否成为代理人",
+      "Yes": "是",
+      "No": "否",
+      "Status": "状态",
+      "PleaseSelectCustomer": "请先选择客户",
+      "CustomerNotExist": "客户信息不存在",
+      "CustomerNotFound": "未找到选中的客户信息",
+      "SaveSuccess": "保存成功",
+      "SaveFailed": "保存失败",
+      "GetDataFailed": "获取数据失败",
+      "SubmitSuccess": "提交成功",
+      "SubmitFailed": "提交失败"
     },
     "Transfer": {
       "CommissionTransfer": "佣金内转",

+ 7 - 0
pages.json

@@ -191,6 +191,13 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/ib/linkList",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/ib/report",
       "style": {

+ 14 - 10
pages/ib/index.vue

@@ -45,9 +45,9 @@
                 <button class="link-btn" @click="LinkActivity1">
                   {{ t('Ib.Index.CreateLink') }}
                 </button>
-                <button class="link-btn" @click="LinkActivity">
-                  {{ t('Ib.Index.CreateLinkActivity') }}
-                </button>
+<!--                <button class="link-btn" @click="LinkActivity">-->
+<!--                  {{ t('Ib.Index.CreateLinkActivity') }}-->
+<!--                </button>-->
               </view>
             </view>
           </view>
@@ -81,7 +81,7 @@
             </view>
           </view>
           <!-- 归属推荐码 -->
-          <view class="card code-card">
+<!--          <view class="card code-card">
             <view class="card-header">
               <view class="header-left">
                 <text class="header-title">{{ t('Tips.AttributionCode') }}</text>
@@ -99,13 +99,13 @@
               <uni-easyinput class="code-input" :disabled="true" v-model="getInfoId" :clearable="false"></uni-easyinput>
               <button class="link-btn">{{ t('Ib.Index.Copy') }}</button>
             </view>
-          </view>
+          </view>-->
         </view>
       </uni-col>
     </uni-row>
 
     <!-- 二维码弹窗 -->
-    <cwg-popup ref="linkPopup" type="center" :title="t('Ib.Index.CreateLink')" :showFooter="false" showFooterLine>
+    <cwg-popup ref="linkPopup" type="center" :title="t('Ib.Index.CreateLink')" :showFooters="false" showFooterLine>
       <view class="dia-content">
         <view class="content" style="font-size: 14px; text-align: left">
           <view class="label">{{ t('Ib.Index.Spread5') }} :</view>
@@ -193,7 +193,7 @@
       </view>
     </cwg-popup>
     <!-- 活动链接弹窗 -->
-    <cwg-popup ref="linkActivityPopup" type="center" :title="t('Ib.Index.CreateLinkActiv')" :showFooter="false" showFooterLine>
+    <cwg-popup ref="linkActivityPopup" type="center" :title="t('Ib.Index.CreateLinkActiv')" :showFooters="false" showFooterLine>
       <view class="dia-content">
         <view class="content" style="font-size: 14px; text-align: left">
           <view class="label">{{ t('Ib.Index.ChooseActiv') }}</view>
@@ -524,9 +524,13 @@
   // 生成开户链接
   const LinkActivity1 = async () => {
     // await loginTypeList()
-    await getAgentAccountSetting()
-    selectedSpreadId.value = ''
-    linkPopup.value.open()
+    // await getAgentAccountSetting()
+    // selectedSpreadId.value = ''
+    // linkPopup.value.open()
+    // 跳转到开户链接页面
+    uni.navigateTo({
+      url: '/pages/ib/linkList',
+    })
   }
   // 生成活动分享链接
   const LinkActivity = async () => {

+ 660 - 0
pages/ib/linkList.vue

@@ -0,0 +1,660 @@
+<template>
+  <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+    <cwg-header :title="t('Ib.Index.CreateLink')" />
+    <view class="account-section">
+      <view class="add-link" @click="addLink">
+        <view class="add-link-content" @click="addLink">
+          <cwg-icon name="icon_add" :size="18" color="#fff"></cwg-icon>
+          {{ t('Ib.Index.CreateLink') }}
+        </view>
+      </view>
+      <cwg-tabel ref="tableRef" :columns="columns" :mobilePrimaryFields="mobilePrimaryFields"
+                 :api="listApi" :show-operation="false" :showPagination="true">
+        <template #link="{ row }">
+          <view class="link-cell">
+            <uni-easyinput class="read-input" disabled v-model.trim="row.link"></uni-easyinput>
+            <view class="qr-code-icon" @click.stop="showQrCodeDialog(row.link)">
+              <svg style="width: 18px; height: 18px; fill: #409eff; vertical-align: middle;" viewBox="0 0 24 24"
+                   xmlns="http://www.w3.org/2000/svg">
+                <path
+                  d="M3 3h8v8H3V3zm2 2v4h4V5H5zm8-2h8v8h-8V3zm2 2v4h4V5h-4zM3 13h8v8H3v-8zm2 2v4h4v-4H5zm13-2h3v2h-3v-2zm0 4h3v2h-3v-2zm-4-4h2v6h-2v-6zm4-8h2v2h-2V3zm0 4h2v2h-2V7zm-4 0h2v2h-2V7z" />
+              </svg>
+            </view>
+            <view class="copy" @click.stop="CopyLink(row.link)">
+              {{ t('Ib.Index.Copy') }}
+            </view>
+          </view>
+        </template>
+        <template #linkValue="{ row }">
+          <view class="link-cell">
+            <uni-easyinput class="read-input" disabled v-model.trim="row.linkValue"></uni-easyinput>
+            <view class="copy" @click.stop="CopyLink(row.linkValue)">
+              {{ t('Ib.Index.Copy') }}
+            </view>
+          </view>
+        </template>
+      </cwg-tabel>
+      <cwg-popup ref="linkPopup" :visible="dialogLink" type="center" :title="t('Ib.Index.CreateLink')" showFooterLine @close="dialogLink = false" @confirm="saveLink">
+        <view class="dia-content">
+          <view class="content" style="font-size: 14px; text-align: left">
+            <view class="label">{{ t('Ib.Custom.NameLabelColon') }} </view>
+            <uni-easyinput
+              v-model="linkName"
+              :placeholder="t('Ib.Custom.NameLabel')"
+            />
+
+            <view class="label-tit">{{ t('Ib.Index.Spread5') }} :</view>
+            <!--标准账户-->
+            <view class="label">{{ t('AccountType.StandardAccount') }} :</view>
+            <cwg-combox
+              v-model:value="accountTypeSettings.standard.selectedIndex"
+              :options="getAvailableSpreads('7')"
+              @change="(val)=>handleAccountTypeChange('standard', '7',val)"
+              :placeholder="t('placeholder.choose')"
+            />
+
+            <view class="label">{{ t('AccountType.SeniorAccount') }}</view>
+            <cwg-combox
+              v-model:value="accountTypeSettings.ecn.selectedIndex"
+              :options="getAvailableSpreads('2')"
+              @change="(val)=>handleAccountTypeChange('ecn', '2',val)"
+              :placeholder="t('placeholder.choose')"
+            />
+
+            <view class="label">{{ t('AccountType.CentAccount') }}</view>
+            <cwg-combox
+              v-model:value="accountTypeSettings.cent.selectedIndex"
+              :options="getAvailableSpreads('8')"
+              @change="(val)=>handleAccountTypeChange('cent', '8',val)"
+              :placeholder="t('placeholder.choose')"
+            />
+
+            <view class="btn">
+              <button
+                class="crm-cursor"
+                @click="CreateLink"
+              >{{ t('Ib.Index.CreateLink') }}
+              </button>
+            </view>
+            <view class="link qrCode" v-if="link">
+              <QrCode
+                ref="qrCode"
+                :text="link"
+                :width="200"
+                :height="200"
+              />
+              <view class="btn">
+                <button
+                  class="crm-cursor"
+                  @click="downloadQrCode()"
+                >{{ t('Btn.item9') }}
+                </button>
+              </view>
+            </view>
+            <view class="link" v-if="link">
+              <uni-easyinput
+                disabled
+                v-model="link"
+              />
+              <button class="btn" @click="CopyLink(link)">
+                {{ t('Ib.Index.Copy') }}
+              </button>
+            </view>
+          </view>
+        </view>
+      </cwg-popup>
+      <cwg-popup :visible="qrCodeDialogVisible" type="center" :title="t('Ib.Index.QrCode')" showFooterLine @singleClick="qrCodeDialogVisible = false" :singleBtnText="t('Btn.Cancel')" :footerType="'single'">
+        <view class="qr-code-dialog-content">
+          <QrCode
+            ref="dialogQrCode"
+            v-if="currentQrCodeLink"
+            :text="currentQrCodeLink"
+            :width="300"
+            :height="300"
+          ></QrCode>
+          <view v-if="currentQrCodeLink" class="qr-code-btn">
+            <button @click="downloadDialogQrCode">
+              {{ t('Btn.item9') }}
+            </button>
+          </view>
+        </view>
+      </cwg-popup>
+    </view>
+  </cwg-page-wrapper>
+</template>
+
+<script setup lang="ts">
+  import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
+  import { onLoad } from '@dcloudio/uni-app'
+  import { useI18n } from 'vue-i18n' // uni-app 中已集成,但需配置
+  import { customApi } from '@/service/custom'
+  import { financialApi } from '@/service/financial'
+  import Config from '@/config/index'
+  import PaymentMethodsList from './components/PaymentMethodsList.vue'
+  import { ibApi } from '@/service/ib'
+  import useUserStore from '@/stores/use-user-store'
+  import QrCode from '@/components/QrCode.vue'
+
+  const { Code, Host80 } = Config
+  const { t, locale } = useI18n()
+  // 列表数据
+  const tableData = ref([])
+  const loading = ref(false)
+  const listApi = ref(null)
+  const currentQrCodeLink = ref('')
+  const qrCodeDialogVisible = ref(false)
+  // 按账户类型分组的数据
+  const accountTypeData = ref({
+    ecn: [], // loginType = 2
+    standard: [], // loginType = 7
+    cent: [], // loginType = 8
+  })
+  const tableRef = ref(null)
+  // 弹窗中的二维码组件
+  const dialogQrCode = ref(null)
+  const excludeList = ref([])
+  const excludeLists = ref([])
+  const excludeListVN = ref([])
+  const excludeShowLoginTypes = ref([])
+  // 账户类型设置:每个账户类型对应一个点差设置
+  const accountTypeSettings = ref({
+    // ECN账户,存储选中的完整对象
+    ecn: { selectedIndex: null, selectedItem: null, loginType: '2' },
+    // 标准账户
+    standard: { selectedIndex: null, selectedItem: null, loginType: '7' },
+    // 美分账户
+    cent: { selectedIndex: null, selectedItem: null, loginType: '8' },
+  })
+
+  const selectedSpreadId = ref('')
+  const linkName = ref('')
+  const loginTypes = ref('')
+  const link = ref('')
+  const linkValue = ref('')
+  const ibInvalid = ref('B0')
+  const dialogLink = ref(false)
+  const qrCode = ref(null)
+
+  const { userInfo } = useUserStore()
+
+  const country = computed(() => {
+    return userInfo.customInfo.country
+  })
+  const agentAccountSetting = computed(() => {
+    return userInfo.ibInfo.agentAccountSetting ||
+      0
+  })
+  const getInfoId = computed(() => {
+    console.log(userInfo.ibInfo.id, 'userInfo.ibInfo.id')
+    return userInfo.ibInfo.id ||
+      0
+  })
+
+  listApi.value = ibApi.customLinkSearchList
+
+  const columns = ref([
+    {
+      prop: 'name',
+      label: t('Ib.Custom.NameLabel'),
+      align: 'center',
+    },
+    {
+      prop: 'link',
+      label: t('Ib.Index.Link'),
+      align: 'center',
+      slot: 'link',
+      width: 450,
+    },
+    {
+      prop: 'linkValue',
+      label: t('Ib.Index.LinkValue'),
+      align: 'center',
+      slot: 'linkValue',
+    },
+    {
+      prop: 'customNum',
+      label: t('Ib.Index.CustomNum'),
+      align: 'center',
+    },
+    {
+      prop: 'comPoint',
+      label: t('AccountType.StandardAccount'),
+      align: 'center',
+      formatter: ({ row }) => getGroupNameByLoginType(row.loginConfig, 7),
+    },
+    {
+      prop: 'hide',
+      label: 'ECN',
+      align: 'center',
+      formatter: ({ row }) => getGroupNameByLoginType(row.loginConfig, 2),
+
+    },
+    {
+      prop: 'loginTypes',
+      label: t('AccountType.CentAccount'),
+      align: 'center',
+      formatter: ({ row }) => getGroupNameByLoginType(row.loginConfig, 8),
+    },
+  ])
+
+  const mobilePrimaryFields = ref([
+    {
+      prop: 'name',
+      label: t('Ib.Custom.NameLabel'),
+      align: 'center',
+    },
+    {
+      prop: 'customNum',
+      label: t('Ib.Index.CustomNum'),
+      align: 'center',
+    },
+    {
+      prop: 'more',
+      type: 'more',
+      width: 20,
+      align: 'right',
+    },
+  ])
+
+  const getGroupNameByLoginType = (loginConfig, loginType) => {
+    if (!loginConfig) return ''
+
+    // 如果 loginConfig 是字符串,尝试解析为数组
+    let config = loginConfig
+    if (typeof loginConfig === 'string') {
+      try {
+        config = JSON.parse(loginConfig)
+      } catch (e) {
+        return ''
+      }
+    }
+
+    // 确保是数组
+    if (!Array.isArray(config)) {
+      return ''
+    }
+
+    // 查找匹配的 loginType
+    const matchedItem = config.find(item => {
+      // 支持数字和字符串类型的比较
+      return item.loginType === loginType ||
+        item.loginType === String(loginType) ||
+        String(item.loginType) === String(loginType)
+    })
+
+    return matchedItem ? (matchedItem.groupName || '') : ''
+  }
+
+  const CopyLink = (link) => {
+    uni.setClipboardData({
+      data: link,
+      success: () => {
+        uni.showToast({
+          title: t('card.Msg.m8'),
+          icon: 'success',
+        })
+      },
+    })
+  }
+  const showQrCodeDialog = (link) => {
+    if (!link) return
+    currentQrCodeLink.value = link
+    qrCodeDialogVisible.value = true
+  }
+  // 获取开户链接账户类型列表
+  const getCustomLinkTypes = async () => {
+    let res = await ibApi.customLinkTypes()
+    if (res.code == Code.StatusOK) {
+      // 按 loginType 分组数据
+      const data = res.data || []
+      console.log(data, '123')
+      accountTypeData.value = {
+        ecn: data.filter(item => item.loginType === 2 || item.loginType === '2'),
+        standard: data.filter(item => item.loginType === 7 || item.loginType === '7'),
+        cent: data.filter(item => item.loginType === 8 || item.loginType === '8'),
+      }
+    } else {
+      uni.showToast({
+        title: res.msg,
+        icon: 'none',
+      })
+      accountTypeData.value = {
+        ecn: [],
+        standard: [],
+        cent: [],
+      }
+    }
+  }
+
+  // 获取账户类型设置
+  const getAgentAccountSetting = () => {
+    // 如果是越南账户,显示标准账户、美分账户和ECN账户
+    if (country.value === 'VN') {
+      const standardAccount = excludeLists.value.find(
+        (item) => item.value === '7',
+      )
+      const centAccount = excludeLists.value.find(
+        (item) => item.value === '8',
+      )
+      const ecnAccount = excludeLists.value.find(
+        (item) => item.value === '2',
+      )
+      excludeListVN.value = [standardAccount, centAccount, ecnAccount].filter(
+        Boolean,
+      )
+      excludeShowLoginTypes.value = []
+    } else {
+      if (agentAccountSetting.value == 0) {
+        const excludeValues = userInfo
+          .customInfo.excludeShowLoginTypes
+        try {
+          const excludeList = excludeLists.value.filter(
+            (item) => !excludeValues.includes(item.value),
+          )
+          excludeList.value = excludeList
+          excludeShowLoginTypes.value = []
+        } catch (error) {
+          excludeShowLoginTypes.value = []
+          excludeList.value = excludeLists.value
+        }
+      } else {
+        excludeShowLoginTypes.value = []
+        excludeList.value = excludeLists.value
+
+      }
+    }
+  }
+  // add
+  const addLink = async () => {
+    console.log(getInfoId.value, 'getInfo.id')
+    await getCustomLinkTypes()
+    getAgentAccountSetting()
+    // 重置所有表单字段
+    selectedSpreadId.value = ''
+    linkName.value = ''
+    loginTypes.value = ''
+    linkValue.value = ''
+    // 重置账户类型设置
+    accountTypeSettings.value = {
+      ecn: { selectedIndex: null, selectedItem: null, loginType: '2' },
+      standard: { selectedIndex: null, selectedItem: null, loginType: '7' },
+      cent: { selectedIndex: null, selectedItem: null, loginType: '8' },
+    }
+    dialogLink.value = true
+  }
+  const onNameChange = (e)=>{
+    console.log(e)
+  }
+  // 账户类型选择变化处理
+  const handleAccountTypeChange = (type, loginType,val) => {
+    console.log(type, loginType,val,'221')
+    const setting = accountTypeSettings.value[type]
+    const availableSpreads = getAvailableSpreads(loginType)
+    if (setting.selectedIndex !== null && setting.selectedIndex !== undefined) {
+      accountTypeSettings.value[type].selectedItem = availableSpreads[setting.selectedIndex] || null
+    } else {
+      accountTypeSettings.value[type].selectedItem = null
+    }
+  }
+  // 获取指定账户类型可用的点差设置
+  const getAvailableSpreads = (loginType) => {
+    // 根据 loginType 返回对应的数据
+    if (loginType === '2') {
+      return accountTypeData.value.ecn?.map((item,index) => ({ ...item,value:index, text: item.groupName })) || []
+    } else if (loginType === '7') {
+      return accountTypeData.value.standard?.map((item,index) => ({ ...item,value:index, text: item.groupName })) || []
+    } else if (loginType === '8') {
+      return accountTypeData.value.cent?.map((item,index) => ({ ...item,value:index, text: item.groupName })) || []
+    }
+    return []
+  }
+  // 获取链接值
+  const getLink1 = async () => {
+    // 收集所有选中的账户类型和对应的点差设置
+    const selectedAccountTypes = []
+    const loginConfig = []
+
+    // 检查每个账户类型是否已选择点差设置
+    Object.keys(accountTypeSettings.value).forEach((key) => {
+      const setting = accountTypeSettings.value[key]
+      if (setting.selectedItem) {
+        selectedAccountTypes.push(setting.loginType)
+        // 将选中的整个对象添加到 loginConfig 数组
+        loginConfig.push(setting.selectedItem)
+      }
+    })
+
+    if (selectedAccountTypes.length === 0) {
+      uni.showToast({
+        title: t('Ib.Index.Spread5'),
+        icon: 'none',
+      })
+      link.value = ''
+      return
+    }
+
+    // 构建请求参数
+    const validList = {
+      loginConfig: loginConfig,
+    }
+
+    // 直接调用接口生成链接
+    const res = await ibApi.customLinkCode(validList)
+    if (res.code === Code.StatusOK) {
+      uni.showToast({
+        title: res.msg,
+        icon: 'none',
+      })
+      return res.data
+    } else {
+      uni.showToast({
+        title: res.msg,
+        icon: 'error',
+      })
+      return ''
+    }
+  }
+
+  const saveLink = async () => {
+    if (!linkName.value) {
+      uni.showToast({
+        title: t("Ib.Custom.NameLabel"),
+        icon: 'none',
+      })
+      return;
+    }
+    if (!link.value) {
+      uni.showToast({
+        title: t("Ib.Index.CreateLink"),
+        icon: 'none',
+      })
+      return;
+    }
+
+    // 收集所有选中的账户类型配置
+    const loginConfig = [];
+
+    Object.keys(accountTypeSettings.value).forEach((key) => {
+      const setting = accountTypeSettings.value[key];
+      if (setting.selectedItem) {
+        // 将选中的整个对象添加到 loginConfig 数组
+        loginConfig.push(setting.selectedItem);
+      }
+    });
+
+    if (loginConfig.length === 0) {
+      uni.showToast({
+        title: t("Ib.Index.Spread5"),
+        icon: 'none',
+      })
+      return;
+    }
+
+    // 调用保存接口
+    const res = await ibApi.customLinkAdd({
+      name: linkName.value,
+      link: link.value,
+      linkValue: linkValue.value,
+      loginConfig: loginConfig,
+    });
+
+    if (res.code === Code.StatusOK) {
+      uni.showToast({
+        title: res.msg,
+        icon: 'none',
+      })
+      dialogLink.value = false;
+      // 重置表单
+      linkName.value = "";
+      link.value = "";
+      linkValue.value = "";
+      excludeShowLoginTypes.value = [];
+      selectedSpreadId.value = "";
+      accountTypeSettings.value = {
+        ecn: { selectedIndex: null, selectedItem: null, loginType: "2" },
+        standard: { selectedIndex: null, selectedItem: null, loginType: "7" },
+        cent: { selectedIndex: null, selectedItem: null, loginType: "8" },
+      };
+      tableRef.value.refreshTable()
+    } else {
+      uni.showToast({
+        title: res.msg,
+        icon: 'error',
+      })
+    }
+  }
+  // 生成链接(不保存)
+  const CreateLink = async () => {
+    console.log(linkName.value)
+    if (!linkName.value) {
+      uni.showToast({
+        title: t('Ib.Custom.NameLabel'),
+        icon: 'none',
+      })
+      return
+    }
+    const value = await getLink1()
+    if (!value) return
+    link.value = `${Host80}/#/signup/${getInfoId.value}/${value}/${ibInvalid.value}`
+  }
+
+  const downloadQrCode = (type = 0) => {
+      qrCode.value.download()
+  }
+  // 下载弹窗中的二维码
+  const downloadDialogQrCode = (type = 0) => {
+      dialogQrCode.value.download()
+  }
+</script>
+<style lang="scss" scoped>
+  @import "@/uni.scss";
+
+  .add-link {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+
+    .add-link-content {
+      cursor: pointer;
+      display: flex;
+      align-items: center;
+      color: #fff;
+      padding: 0 px2rpx(10);
+      background-color: #ffde02;
+      font-size: px2rpx(16);
+      font-weight: bold;
+      line-height: px2rpx(26);
+      border-radius: px2rpx(5);
+    }
+  }
+
+  .link-cell {
+    width: 100%;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    gap: 10px;
+    white-space: nowrap;
+
+    .read-input {
+      max-width: px2rpx(400);
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      flex: 1;
+    }
+
+    .copy {
+      cursor: pointer;
+      line-height: px2rpx(28);
+    }
+  }
+
+  .qr-code-icon {
+    cursor: pointer;
+    user-select: none;
+    transition: opacity 0.3s;
+    white-space: nowrap;
+    line-height: 28px;
+    display: flex;
+    align-items: center;
+    padding: 0 8px;
+
+    &:hover {
+      opacity: 0.7;
+    }
+  }
+  .dia-content {
+    padding: 20rpx;
+  }
+
+  .content {
+    display: flex;
+    flex-direction: column;
+    gap: 20rpx;
+  }
+  .label-tit{
+    font-weight: 500;
+    margin-bottom: 8rpx;
+  }
+
+  .label {
+    font-weight: 400;
+    margin-bottom: 8rpx;
+  }
+
+  .btn {
+    margin-top: px2rpx(16);
+    text-align: center;
+  }
+  .link {
+    display: flex;
+    margin-top: px2rpx(20);
+
+    .btn {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      height: px2rpx(35);
+      margin: 0 px2rpx(10);
+    }
+  }
+
+  .qrCode {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: px2rpx(16);
+  }
+  .qr-code-dialog-content {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    padding: px2rpx(20) 0;
+    .qr-code-btn{
+      margin-top: px2rpx(16);
+    }
+  }
+</style>