Explorar o código

feat:跟单首页

ljc hai 1 mes
pai
achega
008e391a07
Modificáronse 2 ficheiros con 1241 adicións e 0 borrados
  1. 7 0
      pages.json
  2. 1234 0
      pages/follow/index.vue

+ 7 - 0
pages.json

@@ -379,6 +379,13 @@
         "navigationBarTitleText": "",
         "navigationStyle": "custom"
       }
+    },
+    {
+      "path": "pages/follow/index",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "follow"
+      }
     }
   ],
   "tabBar": {

+ 1234 - 0
pages/follow/index.vue

@@ -0,0 +1,1234 @@
+<template>
+  <cwg-page-wrapper class="create-page" :isHeaderFixed="true" :bgColor="'#f8f9f9'">
+    <cwg-header :title="t('Home.page_ib.item1')" :showBack="false" />
+    <uni-loading v-if="loading" />
+    <uni-row v-else class="demo-uni-row uni-row1" :gutter="20">
+      <uni-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" class="uni-col-left">
+        <view class="dashboard-container">
+          <!-- 余额卡片 -->
+          <view class="card balance-card">
+            <view class="card-header">
+              <view class="header-left">
+                <cwg-icon name="qbye" :size="24" color="#000" />
+                <text class="header-title">{{ t('news_add_field.Label.Balance') }}</text>
+              </view>
+              <view class="header-right">
+                <cwg-dropdown :menu-list="menuList" @menuClick="handleMenuClick">
+                  <view class="pc-header-btn">
+                    <cwg-icon name="crm-ellipsis" :size="24" color="#000" />
+                  </view>
+                </cwg-dropdown>
+              </view>
+            </view>
+            <view class="balance-content">
+              <view class="balance-main">
+                <text class="balance-currency">$</text>
+                <text class="balance-amount">{{ balanceInt }}</text>
+                <text class="balance-decimal">.{{ balanceDecimal }}</text>
+              </view>
+              <view class="total-earnings">
+                <text class="total-label">{{ t('Ib.Index.TotalRevenue') }}</text>
+                <text class="total-value">${{ numberFormat(ibData.all || '0') }}</text>
+              </view>
+            </view>
+          </view>
+
+          <!-- 开户链接 -->
+          <view class="card partner-card">
+            <view class="card-header">
+              <view class="header-left">
+                <cwg-icon name="crm-share-nodes" :size="24" color="#000" />
+                <text class="header-title">{{ t('Ib.Index.Link') }}</text>
+              </view>
+            </view>
+            <view class="partner-content">
+              <view class="link-area">
+                <button class="link-btn" @click="LinkActivity1">
+                  {{ t('Ib.Index.CreateLink') }}
+                </button>
+                <!--                <button class="link-btn" @click="LinkActivity">-->
+                <!--                  {{ t('Ib.Index.CreateLinkActivity') }}-->
+                <!--                </button>-->
+              </view>
+            </view>
+          </view>
+
+
+          <!-- 名下客户 -->
+          <view class="card custom-card">
+            <view class="card-header">
+              <view class="header-left">
+                <cwg-icon name="crm-custom" :size="24" color="#000" />
+                <text class="header-title">{{ t('Ib.Index.NameCustom') }}</text>
+              </view>
+            </view>
+            <view class="custom-content">
+              <view class="con" @click="toCustomManagement">
+                <view class="num">
+                  {{ ibData.customAmount || '0' }}
+                </view>
+                <view class="des">
+                  {{ t('Ib.Index.Custom') }}
+                </view>
+              </view>
+              <view class="con" @click="toIbManagement">
+                <view class="num">
+                  {{ ibData.ibAmount || '0' }}
+                </view>
+                <view class="des">
+                  {{ t('Ib.Index.Agent') }}
+                </view>
+              </view>
+            </view>
+          </view>
+          <!-- 归属推荐码 -->
+          <!--          <view class="card code-card">
+                      <view class="card-header">
+                        <view class="header-left">
+                          <text class="header-title">{{ t('Tips.AttributionCode') }}</text>
+                          <uni-tooltip placement="top">
+                            <text class="icon-tip">?</text>
+                            <template v-slot:content>
+                              <view style="width: 100px;">
+                                {{ t('Tips.tips') }}
+                              </view>
+                            </template>
+                          </uni-tooltip>
+                        </view>
+                      </view>
+                      <view class="code-content">
+                        <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>
+      </uni-col>
+      <uni-col :xs="24" :sm="24" :md="16" :lg="16" :xl="16" class="uni-col-right">
+        <view class="dashboard-container">
+          <view class="card mam-card">
+            <view class="card-header">
+              <view class="header-left">
+                <text class="header-title">{{ t('Ib.Index.MAMList') }}</text>
+              </view>
+              <view class="header-right" v-if="showAddMamAccount">
+                <cwg-dropdown :menu-list="addMamAccountMenus" @menuClick="handleAddMamAccountMenuClick">
+                  <button type="primary" class="add-mam-btn">
+                    <cwg-icon name="icon_add" :size="18" color="#fff" />
+                    <text class="btn-text">{{ t('Custom.Index.AddAccount') }}</text>
+                  </button>
+                </cwg-dropdown>
+              </view>
+            </view>
+
+            <cwg-tabel
+              ref="mamTableRef"
+              :columns="mamColumns"
+              :mobilePrimaryFields="mamMobilePrimaryFields"
+              :queryParams="mamSearch"
+              :api="mamListApi"
+              :show-operation="false"
+              :showPagination="true"
+            >
+              <template #mamAccount="{ row }">
+                <view v-if="row.type == 1 || row.type == 2">
+                  <text>{{ row.login || '-' }}</text>
+                </view>
+                <view v-else-if="row.type == 3">
+                  <view class="mam-line">
+                    <text>{{ t('Ib.PammManager.ownerId') }}:</text>
+                    <text>{{ row.ownerId || '--' }}</text>
+                  </view>
+                  <view class="mam-line">
+                    <text>{{ t('Ib.PammManager.accountId') }}:</text>
+                    <text>{{ row.accountId || '--' }}</text>
+                  </view>
+                  <view class="mam-line">
+                    <text>{{ t('Ib.PammManager.percent') }}:</text>
+                    <text>{{ (row.percent ?? '--') + '%' }}</text>
+                  </view>
+                </view>
+              </template>
+
+              <template #mamType="{ row }">
+                <text>{{ formatMamType(row.type) }}</text>
+              </template>
+
+              <template #loginType="{ row }">
+                <text>{{ formatAccountType(row.accountType) }}</text>
+              </template>
+
+              <template #leverage="{ row }">
+                <text>{{ row.leverage ? '1:' + row.leverage : '-' }}</text>
+              </template>
+
+              <template #balance="{ row }">
+                <text>{{ numberFormat(row.balance || 0) }}</text>
+              </template>
+
+              <template #equity="{ row }">
+                <text>{{ numberFormat(row.equity || 0) }}</text>
+              </template>
+
+              <template #operation="{ row }">
+                <view class="mam-ops">
+                  <view v-if="row.type == 1 || row.type == 2" class="mam-op" @click.stop="toSettings(row)">
+                    <text>{{ t('Ib.Index.Settings') }}</text>
+                  </view>
+                  <view v-if="row.type == 3" class="mam-op" @click.stop="toSettings(row)">
+                    <text>{{ t('Ib.PammManager.btn1') }}</text>
+                  </view>
+                  <view v-if="row.type == 3" class="mam-op" @click.stop="toDialogPercent(row)">
+                    <text>{{ t('Ib.PammManager.percent') }}</text>
+                  </view>
+                  <view class="mam-op" @click.stop="toDialogSubs(row)">
+                    <text>{{ t('blockchain.item1') }}</text>
+                  </view>
+                </view>
+              </template>
+            </cwg-tabel>
+          </view>
+        </view>
+      </uni-col>
+    </uni-row>
+
+    <!-- 二维码弹窗 -->
+    <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>
+          <cwg-combox
+            v-model="excludeShowLoginTypes"
+            :multiple="true"
+            :options="excludeList"
+            :placeholder="t('placeholder.choose')"
+            @change="handleChange"
+          />
+
+          <view class="label">{{ t('Ib.Index.Spread4') }} :</view>
+          <cwg-combox
+            v-model:value="selectedSpreadId"
+            :options="spreadList.map(item => ({
+          value: item.id,
+          text: t('Ib.Index.Commission') + ':' + item.comPoint +
+            (levelNum === 1 ? '-' + t('Ib.Index.Hide') + ':' + item.hide :
+            (fixedHide === 1 ? '' : '-' + t('Ib.Index.Hide') + ':' + item.hide))
+        }))"
+            :placeholder="t('placeholder.choose')"
+          />
+
+          <view class="label">{{ t('Ib.Index.IbInvalid') }}</view>
+          <cwg-combox
+            v-model:value="ibInvalid"
+            :options="[
+          { value: 'B0', text: t('Ib.Custom.Allow') },
+          { value: 'B1', text: t('Ib.Custom.NotAllow') }
+        ]"
+            :placeholder="t('placeholder.choose')"
+          />
+
+          <view>
+            <text style="line-height: 1.5">{{ t('ApplicationDialog.item1') }}</text>
+          </view>
+
+          <view>
+            <text style="line-height: 1.5">{{ t('ApplicationDialog.item2') }}</text>
+            <a
+              :href="country == 'NG' || country == 'TH' || country == 'LA'
+            ? `pdf/pdf6/all/Account Type Allocation Table - ${lang}.pdf`
+            : `pdf/pdf6/no/Account Type Allocation Table-${lang}.pdf`"
+              target="_blank"
+            >
+              {{ t('ApplicationDialog.item3') }}
+            </a>
+          </view>
+
+          <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"
+                style="height: 16px"
+                @click="downloadQrCode()"
+              >{{ t('Btn.item9') }}
+              </button>
+            </view>
+          </view>
+
+          <view class="link">
+            <uni-easyinput
+              disabled
+              v-model="link"
+            />
+            <button class="btn" @click="CopyShareLink(link)">
+              {{ t('Ib.Index.Copy') }}
+            </button>
+          </view>
+        </view>
+      </view>
+    </cwg-popup>
+    <!-- 活动链接弹窗 -->
+    <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>
+          <cwg-combox
+            v-model:value="activityLing"
+            :options="agentLinkList.map(item => ({ value: item.link, text: item.name }))"
+            :placeholder="t('Ib.Index.ChooseActiv')"
+          />
+
+          <view class="label">{{ t('Ib.Index.Spread5') }} :</view>
+          <cwg-combox
+            v-model:value="excludeShowLoginTypes"
+            :multiple="true"
+            :options="excludeList"
+            :placeholder="t('placeholder.choose')"
+            @change="handleChange"
+          />
+
+          <view class="label">{{ t('Ib.Index.Spread4') }} :</view>
+          <cwg-combox
+            v-model:value="selectedSpreadId"
+            :options="spreadList.map(item => ({
+          value: item.id,
+          text: t('Ib.Index.Commission') + ':' + item.comPoint +
+            (levelNum === 1 ? '-' + t('Ib.Index.Hide') + ':' + item.hide :
+            (fixedHide === 1 ? '' : '-' + t('Ib.Index.Hide') + ':' + item.hide))
+        }))"
+            :placeholder="t('placeholder.choose')"
+          />
+
+          <view class="label">{{ t('Ib.Index.IbInvalid') }}</view>
+          <cwg-combox
+            v-model:value="ibInvalid"
+            :options="[
+          { value: 'B0', text: t('Ib.Custom.Allow') },
+          { value: 'B1', text: t('Ib.Custom.NotAllow') }
+        ]"
+            :placeholder="t('placeholder.choose')"
+          />
+
+          <view>
+            <text style="line-height: 1.5">{{ t('ApplicationDialog.item1') }}</text>
+          </view>
+
+          <view>
+            <text style="line-height: 1.5">{{ t('ApplicationDialog.item2') }}</text>
+            <a
+              :href="country == 'NG' || country == 'TH' || country == 'LA' || isAfterJuly7()
+            ? `pdf/pdf6/all/Account Type Allocation Table - ${lang}.pdf`
+            : `pdf/pdf6/no/Account Type Allocation Table-${lang}.pdf`"
+              target="_blank"
+            >
+              {{ t('ApplicationDialog.item3') }}
+            </a>
+          </view>
+
+          <view class="btn">
+            <button
+              class="crm-cursor"
+              @click="CreateActivityLink"
+            >{{ t('Ib.Index.CreateLinkActivity') }}
+            </button>
+          </view>
+
+          <view class="link qrCode" v-if="linkActivity">
+            <QrCode
+              ref="qrCode1"
+              :text="linkActivity"
+              :width="200"
+              :height="200"
+            />
+            <view class="btn">
+              <button
+                class="crm-cursor"
+                @click="downloadQrCode(1)"
+              >{{ t('Btn.item9') }}
+              </button>
+            </view>
+          </view>
+        </view>
+      </view>
+    </cwg-popup>
+    <!-- 调整收益分成弹窗 -->
+    <cwg-popup
+      :visible="dialogPercent"
+      :title="t('Ib.PammManager.percent')"
+      @close="closeDialogPercent"
+      @confirm="applyPercent"
+    >
+      <view class="dia-content custom-dialog-content">
+        <uni-forms :model="dialogPercentData" label-width="150" label-position="left">
+          <uni-forms-item :label="t('Ib.PammManager.ownerId') + ':'">
+            <text class="info-text">{{ dialogPercentData.oldOwnerId || '--' }}</text>
+          </uni-forms-item>
+          <uni-forms-item :label="t('Ib.PammManager.accountId') + ':'">
+            <text class="info-text">{{ dialogPercentData.oldAccountId || '--' }}</text>
+          </uni-forms-item>
+          <uni-forms-item :label="t('Ib.PammManager.percent') + ':'">
+            <text class="info-text">{{ dialogPercentData.oldPercent }}%</text>
+          </uni-forms-item>
+          <uni-forms-item :label="t('Ib.PammManager.percentNew') + ':'" name="percent" required>
+            <uni-easyinput
+              v-model="dialogPercentData.percent"
+              :placeholder="t('placeholder.input')"
+            />
+          </uni-forms-item>
+        </uni-forms>
+      </view>
+    </cwg-popup>
+
+  </cwg-page-wrapper>
+</template>
+
+<script setup>
+  import { ref, computed, watch, onMounted } from 'vue'
+  import { useI18n } from 'vue-i18n'
+  import useRouter from '@/hooks/useRouter'
+  import { ibApi } from '@/service/ib'
+  import config from '@/config/index'
+  import useUserStore from '@/stores/use-user-store'
+  import { useStorage } from '@/hooks/useStorage'
+  import QrCode from '@/components/QrCode.vue'
+  import { useFilters } from '@/composables/useFilters'
+  import { isAfterJuly28 } from '@/utils/dateUtils'
+
+  const { t } = useI18n()
+  const loading = ref(false)
+  const router = useRouter()
+  const { Code } = config
+  const { userInfo } = useUserStore()
+  const { numberFormat } = useFilters()
+  // 数据
+  const totalEarnings = ref(0.00)
+  const partnerLink = ref('https://one.exnessonelink.com/a/plokue4yj3')
+  const partnerCode = ref('PLOKUE4YJ3')
+  const activeTab = ref('link') // 'link' 或 'code'
+
+  const ibData = ref({
+      customAmount: 0,
+      ibAmount: 0,
+    },
+  )
+  const selectedSpreadId = ref('')
+  const spreadList = ref([])
+  const excludeShowLoginTypes = ref([])
+  const pammManagerValid = ref()
+  const dialogPercent = ref(false)
+  const dialogPercentData = ref({
+    oldPercent: '',
+    mamListId: '',
+    oldOwnerId: '',
+    oldAccountId: '',
+    percent: '',
+  })
+  const isActionLoading = ref(false)
+  const menuList = computed(() => [
+    { label: t('Custom.Index.Withdrawals'), type: 1 },
+    { label: t('Home.page_ib.item4'), type: 2 },
+    { label: t('Ib.Transfer.CommissionIssue'), type: 3 },
+  ])
+  const excludeList = ref([])
+  const excludeLists = ref([
+    { text: t('AccountType.SeniorAccount'), value: '2' },
+    // {text: t('AccountType.SeniorAccount'),value: '3'},
+    { text: t('AccountType.StandardAccount'), value: '7' },
+    { text: t('AccountType.CentAccount'), value: '8' },
+  ])
+  const link = ref('')
+  const loginTypes = ref('')
+  const ibInvalid = ref('B0')
+  const qrCode = ref(null)
+  const qrCode1 = ref(null)
+
+  // 语言
+  const lang = useStorage('lang')
+  const flag = ref(false)
+  const agentLinkList = ref([])
+  const activityLing = ref('')
+  const linkActivity = ref('')
+  const commission = ref('')
+  const linkActivityPopup = ref(null)
+
+  // 开户链接
+  const linkPopup = ref(null)
+  const qrSize = ref(200)
+
+  const levelNum = computed(() => {
+    return userInfo.ibInfo.levelNum
+  })
+  const fixedHide = computed(() => {
+    return userInfo.ibInfo.fixedHide
+  })
+  const getInfoId = computed(() => {
+    return userInfo.ibInfo.id
+  })
+
+  const balanceInt = computed(() => {
+    return numberFormat(ibData.value?.balance || 0, true)[0]
+  })
+  const balanceDecimal = computed(() => {
+    return numberFormat(ibData.value?.balance || 0, true)[1] || '00'
+  })
+
+  // 国家
+  const country = computed(() => {
+    console.log(userInfo.customInfo.country, '2')
+    return userInfo.customInfo.country
+  })
+  // 修改多选
+  const handleChange = (val) => {
+    excludeShowLoginTypes.value = val
+  }
+  const isAfterJuly7 = () => {
+    const currentDate = new Date()
+    const july7 = new Date(currentDate.getFullYear(), 6, 7) // 月份从0开始,6表示7月
+    return currentDate >= july7
+  }
+
+  const getValidAccountTypes = (selectedExcludeValues, selectedSpreadId) => {
+    const spread = spreadList.value.find(
+      (item) => item.id === selectedSpreadId,
+    )
+    let data = {
+      hide: '',
+      commission: '',
+      excludeShowLoginTypes: [],
+    }
+    if (!spread) return data
+    const validValues = selectedExcludeValues.filter((value) =>
+      spread.loginTypes.includes(value),
+    )
+    const invalidValues = selectedExcludeValues.filter(
+      (value) => !spread.loginTypes.includes(value),
+    )
+
+    const invalidLabels = excludeList.value
+      .filter((item) => invalidValues.includes(item.value))
+      .map((item) => item.label)
+
+    const excludeTypes = excludeLists.value
+      .filter((item) => !validValues.includes(item.value))
+      .map((item) => item.value)
+
+    loginTypes.value = invalidLabels.join('、')
+
+    return {
+      hide: spread.hide,
+      commission: spread.comPoint,
+      excludeShowLoginTypes: excludeTypes,
+      invalidLabels,
+      invalidValues,
+    }
+  }
+
+  const downloadQrCode = (type = 0) => {
+    if (type === 1) {
+      qrCode1.value.download()
+    } else {
+      qrCode.value.download()
+    }
+  }
+  // 复制
+  const CopyShareLink = (value) => {
+    uni.setClipboardData({ data: value })
+  }
+
+  const getLink1 = async () => {
+    console.log(excludeShowLoginTypes.value, 2)
+    if (excludeShowLoginTypes.value.length == 0) {
+      uni.showToast({
+        title: t('Ib.Index.Spread5'), icon: 'none',
+      })
+      link.value = ''
+      return
+    }
+    if (!selectedSpreadId.value.length) {
+      uni.showToast({
+        title: t('Ib.Index.Spread4'), icon: 'none',
+      })
+      link.value = ''
+      return
+    }
+    const validList = getValidAccountTypes(
+      excludeShowLoginTypes.value,
+      selectedSpreadId.value,
+    )
+    if (validList.invalidLabels.length > 0) {
+      return new Promise((resolve) => {
+        uni.showModal({
+          title: t('Msg.SystemPrompt'),
+          content: `${t('Ib.Index.Spread1')}${
+            loginTypes.value
+          }${t('')}`,
+          confirmText: t('Btn.Confirm'),
+          cancelText: t('Btn.Cancel'),
+          success: async (res) => {
+            if (res.confirm) {
+              const res = await ibApi.customLink(validList)
+              if (res.code === Code.StatusOK) {
+                uni.showToast({
+                  title: res.msg,
+                  icon: 'none',
+                })
+                resolve(res.data)
+              } else {
+                uni.showToast({
+                  title: res.msg,
+                  icon: 'none',
+                })
+                resolve('')
+              }
+            }
+          },
+          fail: () => resolve(''),
+        })
+      })
+    } else {
+      const res = await ibApi.customLink(validList)
+      if (res.code === Code.StatusOK) {
+        uni.showToast({
+          title: res.msg,
+          icon: 'none',
+        })
+        return res.data
+      } else {
+        uni.showToast({
+          title: res.msg,
+          icon: 'none',
+        })
+        return ''
+      }
+    }
+
+  }
+  const CreateLink = async () => {
+    const linkValue = await getLink1()
+    if (!linkValue) return
+    link.value = `${Host80}/#/signup/${getInfoId.value}/${linkValue}/${ibInvalid.value}`
+  }
+
+  const loginTypeList = async () => {
+    const res = await ibApi.loginTypeList(
+      {
+        page: {
+          current: 1,
+          row: 100,
+        },
+      },
+    )
+    if (res.code === Code.StatusOK) {
+      spreadList.value = res.data
+    } else {
+      uni.showToast({ title: res.msg, icon: 'none' })
+    }
+  }
+  const getAgentAccountSetting = async () => {
+    const { agentAccountSetting = '' } = userInfo.ibInfo ?? {}
+    if (agentAccountSetting === 0) {
+      const excludeValues = userInfo.customInfo.excludeShowLoginTypes
+      try {
+        excludeList.value = excludeLists.value.filter(
+          (item) => !excludeValues.includes(item.value),
+        )
+        excludeShowLoginTypes.value = []
+      } catch (e) {
+        excludeShowLoginTypes.value = []
+        excludeList.value = excludeLists.value
+      }
+    } else {
+      excludeShowLoginTypes.value = []
+      excludeList.value = excludeLists.value
+    }
+  }
+  // 生成开户链接
+  const LinkActivity1 = async () => {
+    // 跳转到开户链接页面
+    uni.navigateTo({
+      url: '/pages/ib/linkList',
+    })
+  }
+  // 生成活动分享链接
+  const LinkActivity = async () => {
+    if (flag.value) {
+
+    } else {
+      flag.value = true
+    }
+    let res = await ibApi.marketAgentLinkList({})
+    if (res.code === Code.StatusOK) {
+      agentLinkList.value = res.data ?? []
+      loginTypeList()
+      getAgentAccountSetting()
+      activityLing.value = ''
+      linkActivity.value = ''
+      commission.value = 0
+      ibInvalid.value = 'B0'
+      linkActivityPopup.value.open()
+      flag.value = false
+    }
+  }
+
+  const CreateActivityLink = async () => {
+    if (!activityLing.value) {
+      uni.showToast({ title: t('Ib.Index.ChooseActiv'), icon: 'error' })
+      return
+    }
+    const linkValue = await getLink1()
+    if (!linkValue) return
+    if (activityLing.value.indexOf('http') > -1) {
+      if (activityLing.value.indexOf('?') > -1) {
+        linkActivity.value =
+          activityLing.value +
+          '&mmdi=' +
+          getInfoId.value +
+          '&mmF=' +
+          linkValue +
+          '&mmB=' +
+          ibInvalid.value
+      } else {
+        linkActivity.value =
+          activityLing.value +
+          '?mmdi=' +
+          getInfoId.value +
+          '&mmF=' +
+          linkValue +
+          '&mmB=' +
+          ibInvalid.value
+      }
+    } else {
+      if (activityLing.value.indexOf('?') > -1) {
+        linkActivity.value =
+          Host80 +
+          '/' +
+          activityLing.value +
+          '&mmdi=' +
+          getInfoId.value +
+          '&mmF=' +
+          linkValue +
+          '&mmB=' +
+          ibInvalid.value
+      } else {
+        linkActivity.value =
+          Host80 +
+          '/' +
+          activityLing.value +
+          '?mmdi=' +
+          getInfoId.value +
+          '&mmF=' +
+          linkValue +
+          '&mmB=' +
+          ibInvalid.value
+      }
+    }
+  }
+  const handleMenuClick = ({ value }) => {
+    console.log(value.type)
+    if (value.type === 1) {
+      toWithdraw()
+    } else if (value.type === 2) {
+      toTransfer()
+    } else {
+      toTransfer(2)
+    }
+  }
+
+  const toWithdraw = () => {
+    router.push({
+        path: '/pages/ib/withdraw-select',
+      },
+    )
+  }
+  const toTransfer = (tab = 1) => {
+    router.push({
+        path: '/pages/ib/transfer',
+        query: { tab },
+      },
+    )
+  }
+  const toCustomManagement = () => {
+    router.push({
+        path: '/pages/ib/customer',
+        query: { type: 3 },
+      },
+    )
+  }
+  const toIbManagement = () => {
+    router.push({
+        path: '/pages/ib/subsList',
+        query: { type: 2 },
+      },
+    )
+  }
+  const getIbData = async () => {
+    const res = await ibApi.IbData()
+    if (res.code === Code.StatusOK) {
+      if (res.data != null)
+        ibData.value = res.data
+    } else {
+      uni.showToast({ title: res.msg, icon: 'none' })
+    }
+  }
+  const getPammManagerValid = async () => {
+    // 没有ib状态不调用
+    if (!userInfo.ibInfo) {
+      return
+    }
+    const res = await ibApi.mamApplyPammManagerValid()
+    if (res.code === Code.StatusOK) {
+      if (res.data != null)
+        pammManagerValid.value = res.data
+    } else {
+      uni.showToast({ title: res.msg, icon: 'none' })
+    }
+  }
+
+  const mamTableRef = ref(null)
+  const mamSearch = ref({})
+  const mamListApi = computed(() => {
+    // 模拟,没有ib不调用接口
+    if (!userInfo.ibInfo) {
+      return (params) => new Promise(resolve => {
+        resolve({
+          code: 200,
+          data: [],
+        })
+      })
+    }
+    return (params) => ibApi.MamList(params)
+  })
+
+  const showAddMamAccount = computed(() => {
+    return !!(
+      pammManagerValid.value?.mamValid ||
+      pammManagerValid.value?.pammValid ||
+      pammManagerValid.value?.pammManagerValid
+    )
+  })
+
+  const addMamAccountMenus = computed(() => {
+    const list = []
+    if (pammManagerValid.value?.mamValid) list.push({ label: 'MAM', type: 1 })
+    if (pammManagerValid.value?.pammValid) list.push({ label: 'Money Manager', type: 2 })
+    if (pammManagerValid.value?.pammManagerValid) list.push({ label: t('Ib.PammManager.title'), type: 3 })
+    return list
+  })
+
+  const handleAddMamAccountMenuClick = ({ value }) => {
+    toNewAccount(value.type)
+  }
+
+  const formatMamType = (type) => {
+    if (type == 1) return 'MAM'
+    if (type == 2) return 'Money Manager'
+    if (type == 3) return t('Ib.PammManager.title1')
+    return '--'
+  }
+
+  const formatAccountType = (accountType) => {
+    if (accountType == 1) return t('AccountType.ClassicAccount')
+    if (accountType == 2) return t('AccountType.SeniorAccount')
+    if (accountType == 3 && !isAfterJuly28()) return t('AccountType.AgencyAccount')
+    if (accountType == 5) return t('AccountType.SpeedAccount')
+    if (accountType == 6) return t('AccountType.SpeedAccount')
+    if (accountType == 7) return t('AccountType.StandardAccount')
+    if (accountType == 8) return t('AccountType.CentAccount')
+    return '--'
+  }
+
+  const mamColumns = computed(() => [
+    { prop: 'mamAccount', label: t('Ib.Index.MAMAccount'), align: 'center', slot: 'mamAccount' },
+    { prop: 'type', label: t('Label.Type'), align: 'center', slot: 'mamType' },
+    { prop: 'accountType', label: t('Ib.Index.LoginType'), align: 'center', slot: 'loginType' },
+    { prop: 'platform', label: t('Ib.Index.Platform'), align: 'center' },
+    { prop: 'currency', label: t('Ib.Index.Currency'), align: 'center' },
+    { prop: 'leverage', label: t('Ib.Index.Leverage'), align: 'center', slot: 'leverage' },
+    { prop: 'balance', label: t('Ib.Index.Balance'), align: 'center', slot: 'balance' },
+    { prop: 'equity', label: t('Ib.Index.Equity'), align: 'center', slot: 'equity' },
+    { prop: 'commission', label: t('Ib.Index.Commission'), align: 'center' },
+    { prop: 'operation', label: t('Ib.Index.Operation'), align: 'center', slot: 'operation' },
+  ])
+
+  const mamMobilePrimaryFields = computed(() => [
+    { prop: 'mamAccount', label: t('Ib.Index.MAMAccount'), align: 'center', slot: 'mamAccount' },
+    { prop: 'type', label: t('Label.Type'), align: 'center', slot: 'mamType' },
+    { prop: 'platform', label: t('Ib.Index.Platform'), align: 'center' },
+    { prop: 'more', type: 'more', width: 20, align: 'right' },
+  ])
+
+  const toNewAccount = (type) => {
+    if (type == 3) {
+      router.push({
+        path: '/pages/ib/openPammManager',
+        query: {
+          type: type,
+        },
+      })
+    } else {
+      router.push({
+        path: '/pages/ib/openAccount',
+        query: {
+          type: type,
+        },
+      })
+    }
+  }
+
+  const toSettings = (row) => {
+    router.push({
+      path: '/pages/ib/settingPammManager',
+      query: { login: row.accountId, id: row.id },
+    })
+  }
+
+  const toDialogPercent = (row) => {
+    dialogPercentData.value.oldPercent = row.percent
+    dialogPercentData.value.mamListId = row.id
+    dialogPercentData.value.oldOwnerId = row.ownerId
+    dialogPercentData.value.oldAccountId = row.accountId
+    dialogPercentData.value.percent = ''
+    dialogPercent.value = true
+  }
+
+  const closeDialogPercent = () => {
+    dialogPercent.value = false
+  }
+
+  const applyPercent = async () => {
+    if (isActionLoading.value) return
+
+    if (!dialogPercentData.value.percent) {
+      uni.showToast({ title: t('placeholder.input'), icon: 'none' })
+      return
+    }
+
+    isActionLoading.value = true
+    try {
+      const res = await ibApi.applyPercent({
+        mamListId: dialogPercentData.value.mamListId,
+        percent: dialogPercentData.value.percent,
+      })
+      if (res.code === Code.StatusOK) {
+        uni.showToast({ title: res.msg, icon: 'success' })
+        dialogPercent.value = false
+        // Refresh MAM list
+        mamTableRef.value?.refreshTable()
+      } else {
+        uni.showToast({ title: res.msg, icon: 'none' })
+      }
+    } catch (error) {
+      uni.showToast({ title: t('Msg.Fail'), icon: 'none' })
+    } finally {
+      isActionLoading.value = false
+    }
+  }
+
+  const toDialogSubs = (row) => {
+    if (row?.type == 3) {
+      router.push({
+        path: '/pages/ib/transfer',
+        query: { tab: 'pammSubs', id: row.id },
+      })
+      return
+    }
+    router.push({
+      path: '/pages/ib/transfer',
+      query: { tab: 'mamSubs', id: row.id },
+    })
+  }
+
+  onMounted(async () => {
+    loading.value = true
+    // 初始化数据
+    await getIbData()
+    await getPammManagerValid()
+    loading.value = false
+  })
+
+</script>
+
+<style lang="scss" scoped>
+  @import "@/uni.scss";
+
+  .demo-uni-row {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: stretch;
+  }
+
+  .uni-col-left {
+    display: flex;
+    flex-direction: column;
+  }
+
+  .uni-col-right {
+    display: flex;
+    flex-direction: column;
+  }
+
+  .dashboard-container {
+    min-height: 10vh;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+  }
+
+  .mam-card {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
+
+  /* 卡片通用样式 */
+  .card {
+    background: var(--color-white);
+    color: #333;
+    padding: px2rpx(12) px2rpx(16);
+    border-radius: 4px;
+    margin-bottom: px2rpx(20);
+    box-shadow: 0 px2rpx(4) px2rpx(12) rgba(0, 0, 0, 0.2);
+  }
+
+  .custom-dialog-content {
+    padding: px2rpx(20);
+
+    .info-text {
+      color: #333;
+      font-size: px2rpx(14);
+      line-height: px2rpx(36);
+    }
+  }
+
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: px2rpx(12);
+  }
+
+  .header-left {
+    display: flex;
+    align-items: center;
+    gap: 12rpx;
+  }
+
+  .header-title {
+    font-size: px2rpx(14);
+    font-weight: 600;
+  }
+
+  .header-right {
+    display: flex;
+    align-items: center;
+  }
+
+  .action-btn {
+    background: #ffde02;
+    border: none;
+    border-radius: 50%;
+    width: px2rpx(32);
+    height: px2rpx(32);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 0;
+    margin: 0;
+
+    &:after {
+      border: none;
+    }
+  }
+
+  /* 余额区域 */
+  .balance-content {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: 16rpx;
+  }
+
+  .balance-main {
+    display: flex;
+    align-items: baseline;
+    flex-wrap: wrap;
+  }
+
+  .balance-amount {
+    font-size: px2rpx(20);
+    font-weight: 700;
+    line-height: 1;
+  }
+
+  .balance-decimal {
+    font-size: px2rpx(16);
+    font-weight: 500;
+    line-height: 1;
+  }
+
+  .balance-currency {
+    font-size: px2rpx(16);
+    font-weight: 500;
+  }
+
+  .total-earnings {
+    display: flex;
+    align-items: center;
+    gap: 5px;
+    color: rgba(20, 29, 34, 0.6);
+    font-size: px2rpx(12);
+  }
+
+  .total-value {
+    align-self: flex-end;
+  }
+
+  /* 合作伙伴卡片 */
+  .partner-content {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+  }
+
+  .link-area {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-around;
+    align-items: center;
+    gap: 12px;
+  }
+
+  .link-btn {
+    height: px2rpx(32);
+    background-color: rgb(108, 133, 149);
+    line-height: px2rpx(32);
+    color: var(--color-white);
+    border-radius: px2rpx(16);
+    font-size: px2rpx(14);
+    margin: 0;
+  }
+
+  .code-content {
+    display: flex;
+    justify-content: center;
+  }
+
+  .code-input {
+    width: 50%;
+    max-width: px2rpx(178);
+    margin-right: px2rpx(20);
+  }
+
+  .custom-content {
+    display: flex;
+    justify-content: space-around;
+    flex-wrap: wrap;
+
+    .con {
+      cursor: pointer;
+      text-align: center;
+      font-size: px2rpx(16);
+      margin: 5px;
+    }
+
+    .num {
+      font-weight: bold;
+    }
+
+    .des {
+      margin-top: px2rpx(5);
+
+    }
+  }
+
+  .dia-content {
+    padding: 20rpx;
+  }
+
+  .content {
+    display: flex;
+    flex-direction: column;
+    gap: 20rpx;
+  }
+
+  .label {
+    font-weight: 500;
+    margin-bottom: 8rpx;
+  }
+
+  .btn {
+    margin-top: 16rpx;
+    text-align: center;
+  }
+
+  .crm-cursor {
+    cursor: pointer;
+  }
+
+  .link {
+    display: flex;
+    margin-top: 20rpx;
+
+    .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: 16rpx;
+  }
+
+  .mam-card {
+    .add-mam-btn {
+      display: flex;
+      background-color: var(--color-error);
+      align-items: center;
+      gap: 8rpx;
+      height: px2rpx(32);
+      line-height: px2rpx(32);
+      padding: 0 px2rpx(12);
+      margin: 0;
+    }
+  }
+
+  .mam-line {
+    display: flex;
+    justify-content: center;
+    gap: 6rpx;
+    line-height: 1.5;
+  }
+
+  .mam-ops {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: center;
+    gap: 10rpx;
+  }
+
+  .mam-op {
+    color: #2b5aed;
+    font-size: px2rpx(12);
+    line-height: 1.4;
+  }
+</style>