Kaynağa Gözat

feat:ib-申请代理

ljc 2 ay önce
ebeveyn
işleme
75cadbf19e

+ 8 - 0
components/cwg-combox.vue

@@ -129,6 +129,14 @@ const handleComboxChange = (text) => {
 }
 </script>
 <style lang="scss" scoped>
+.cwg-combox {
+    /* 穿透修改 uni-data-select 内部列表最大高度,使其可以滚动 */
+    :deep(.uni-select__selector-scroll) {
+        max-height: px2rpx(200); /* 限制最高约 200px (约 5~6 个选项的高度) */
+        overflow-y: auto;
+    }
+}
+
 .disabled-text {
     height: px2rpx(35);
     padding: 0 px2rpx(12);

+ 340 - 91
pages/ib/components/applyIbDialog.vue

@@ -1,7 +1,87 @@
 <template>
-  <cwg-popup :title="t('Ib.Custom.AccountAdjust')" :visible="visible" @close="closeDia" @confirm="confirmDia">
-    <view class="dia-content dialog-account-adjust-body">
+  <cwg-popup :title="t('Ib.Report.Title5')" :visible="visible" @close="closeDia" @confirm="confirmDia">
+    <view class="dia-content">
+      <uni-forms ref="formRef" labelWidth="200">
+        <uni-forms-item v-if="isFormApplyIb" :label="t('Ib.Custom.Manage3')+':'" prop="customerId">
+          <cwg-combox v-model:value="addAgentForm.customerId" :options="customerList"
+                      :placeholder="t('placeholder.choose')" filterable/>
+        </uni-forms-item>
+        <view class="commission-groups">
+          <view v-for="(group, gIndex) in commissionTemplateTableData" :key="gIndex" class="group-card">
+            <!-- 头部开关和标题 -->
+            <view class="group-header" @click="toggleGroup(group)">
+              <view class="group-title">
+                <text class="title-text">{{ group.accountGroup }}</text>
+              </view>
+              <view class="group-switch" @click.stop>
+                <switch :checked="group.isOpen" @change="(e) => onGroupSwitchChange(e, group)" color="#2b5aed" style="transform:scale(0.8)"/>
+              </view>
+            </view>
 
+            <!-- 展开的内容区 -->
+            <view v-show="group.isOpen" class="group-body">
+              <view v-for="(item, iIndex) in group.items" :key="iIndex" class="item-row">
+                <view class="item-title">
+                  <text class="type-badge">{{ item.dataType === 'rebates' ? 'Rebates' : 'Commissions' }}</text>
+                  <text class="type-text">{{ item.type }}</text>
+                </view>
+                
+                <view class="item-fields">
+                  <!-- METAL -->
+                  <view class="field-col">
+                    <text class="field-label">METAL</text>
+                    <cwg-combox 
+                      v-model:value="item.energy" 
+                      :options="formatOptions(item.energyOptions)" 
+                      :placeholder="t('placeholder.choose')" 
+                    />
+                  </view>
+                  
+                  <!-- FX -->
+                  <view class="field-col">
+                    <text class="field-label">FX</text>
+                    <cwg-combox 
+                      v-model:value="item.forex" 
+                      :options="formatOptions(item.forexOptions)" 
+                      :placeholder="t('placeholder.choose')" 
+                    />
+                  </view>
+                  
+                  <!-- ENERGY -->
+                  <view class="field-col">
+                    <text class="field-label">ENERGY</text>
+                    <cwg-combox 
+                      v-model:value="item.energy2" 
+                      :options="formatOptions(item.energy2Options)" 
+                      :placeholder="t('placeholder.choose')" 
+                    />
+                  </view>
+                  
+                  <!-- CFD -->
+                  <view class="field-col">
+                    <text class="field-label">CFD</text>
+                    <cwg-combox 
+                      v-model:value="item.index" 
+                      :options="formatOptions(item.indexOptions)" 
+                      :placeholder="t('placeholder.choose')" 
+                    />
+                  </view>
+                  
+                  <!-- INDEX -->
+                  <view class="field-col">
+                    <text class="field-label">INDEX</text>
+                    <cwg-combox 
+                      v-model:value="item.metal" 
+                      :options="formatOptions(item.metalOptions)" 
+                      :placeholder="t('placeholder.choose')" 
+                    />
+                  </view>
+                </view>
+              </view>
+            </view>
+          </view>
+        </view>
+      </uni-forms>
     </view>
   </cwg-popup>
 </template>
@@ -24,14 +104,19 @@
       default: false,
     },
     // 详情tableData
-    tableData: { type: Array, default: () => ([]) },
+    detail: { type: Array, default: () => ([]) },
+    isFormApplyIb: {
+      type: Boolean,
+      default: true,
+    },
   })
   const { Code, Host80 } = Config
   const { t } = useI18n()
   const formRef = ref(null)
-  const dialogForm = ref({
-    cId: '123',
+  const addAgentForm = ref({
+    customerId: '',
   })
+  const customerList = ref([])
   const commissionAccountTypeSettings = ref({
     ecn: { selectedIndex: null, selectedItem: null, loginType: '2' },
     standard: { selectedIndex: null, selectedItem: null, loginType: '7' },
@@ -42,87 +127,12 @@
     standard: [],
     cent: [],
   })
+  const commissionTemplateTableData = ref<any[]>([])
   const emit = defineEmits(['close', 'confirm'])
 
   onMounted(() => {
-    console.log(props.visible)
+    initCommissionTemplateData(29634)
   })
-  // 佣金调整弹框:拉取点差/价格数据(与 ConsumerShareLink getCustomLinkTypes 一致)
-  const loadCommissionAccountTypes = async (ibId) => {
-    const params = ibId ? { ibId } : {}
-    let res = await ibApi.customLinkTypes(params)
-    if (res.code == Code.StatusOK) {
-      const data = res.data || []
-      commissionAccountTypeData.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',
-      })
-      commissionAccountTypeData.value = { ecn: [], standard: [], cent: [] }
-    }
-  }
-  const getAvailableSpreadsCommission = (loginType) => {
-    if (loginType === '2') return commissionAccountTypeData.value.ecn || []
-    if (loginType === '7')
-      return commissionAccountTypeData.value.standard || []
-    if (loginType === '8') return commissionAccountTypeData.value.cent || []
-    return []
-  }
-  // 佣金调整弹框:根据佣金查看(getLoginPoint)的当前值设置账户类型下拉默认选中
-  const setCommissionDefaultsFromLoginPoint = async (customerId) => {
-    if (!customerId) return
-    try {
-      const res = await ibApi.getLoginPoint({ id: customerId })
-      if (res.code !== Code.StatusOK || !Array.isArray(res.data)) return
-      const list = res.data || []
-      const norm = (v) =>
-        v === 2 || v === '2'
-          ? '2'
-          : v === 7 || v === '7'
-            ? '7'
-            : v === 8 || v === '8'
-              ? '8'
-              : null
-      const byType = { 2: [], 7: [], 8: [] }
-      list.forEach((d) => {
-        const t = norm(d.loginType)
-        if (t && d.groupName) byType[t].push(d.groupName)
-      });
-      ['2', '7', '8'].forEach((loginType) => {
-        const key =
-          loginType === '2' ? 'ecn' : loginType === '7' ? 'standard' : 'cent'
-        const currentGroupName = byType[loginType][0]
-        const options = getAvailableSpreadsCommission(loginType)
-        const idx =
-          currentGroupName == null
-            ? -1
-            : options.findIndex(
-              (item) => (item.groupName || '') === currentGroupName,
-            )
-        const setting = commissionAccountTypeSettings.value[key]
-        if (idx >= 0) {
-          setting.selectedIndex = idx
-          setting.selectedItem = options[idx]
-        } else {
-          setting.selectedIndex = null
-          setting.selectedItem = null
-        }
-      })
-    } catch (e) {
-      console.error('设置佣金调整默认值失败:', e)
-    }
-  }
 
   watch(() => props.detail, (val) => {
     if (val) {
@@ -130,13 +140,10 @@
       dialogForm.value = {
         cId, id, comPoint1, hide1,
       }
-      if (val.ibId) {
-        loadCommissionAccountTypes(val.ibId).then(
-          () => {
-            return setCommissionDefaultsFromLoginPoint(val.id)
-          },
-        )
-      }
+      initCommissionTemplateData(29634)
+      // if (val.id) {
+      //   initCommissionTemplateData(val.id)
+      // }
     }
   })
 
@@ -157,6 +164,161 @@
     }
   }
 
+  const generateOptions = (currentValue) => {
+    const options = [];
+    for (let i = 0; i <= currentValue; i++) {
+      options.push(i);
+    }
+    return options;
+  }
+
+  // 格式化 options 为 combox 期望的格式
+  const formatOptions = (opts) => {
+    if (!opts || !Array.isArray(opts)) return []
+    return opts.map(val => ({ text: String(val), value: val }))
+  }
+
+  const toggleGroup = (group) => {
+    group.isOpen = !group.isOpen
+  }
+
+  const onGroupSwitchChange = (e, group) => {
+    group.isOpen = e.detail.value
+  }
+
+  const initCommissionTemplateData = async (customId: string | number) => {
+    try {
+      const res = await ibApi.getVietnamPoints({ customId })
+
+      if (res.code == Code.StatusOK && res.data && Array.isArray(res.data)) {
+        const groupedData: Record<string, any[]> = {}
+
+        res.data.forEach((group: any) => {
+          const accountGroup = group.groupCategoryName || '--'
+          const valid = group.valid !== undefined ? group.valid : 1
+          
+          if (!groupedData[accountGroup]) {
+            groupedData[accountGroup] = []
+          }
+
+          const rebates = Array.isArray(group.rebates) ? group.rebates : []
+          const superRebates = Array.isArray(group.superRebates) ? group.superRebates : []
+          if (superRebates.length > 0) {
+            const rebateRow: any = {
+              accountGroup,
+              groupCategoryId: group.groupCategoryId,
+              dataType: 'rebates',
+              type: group.rebateTypeName || 'Point',
+              valid,
+              forex: 0,
+              index: 0,
+              metal: 0,
+              energy: 0,
+              energy2: 0,
+              energy2Max: 0,
+              forex1: 0,
+              index1: 0,
+              metal1: 0,
+              energy1: 0,
+            }
+
+            rebates.forEach((rebate: any) => {
+              if (rebate.symbolCategory === 1) rebateRow.forex = rebate.point || 0
+              else if (rebate.symbolCategory === 2) rebateRow.index = rebate.point || 0
+              else if (rebate.symbolCategory === 3) rebateRow.metal = rebate.point || 0
+              else if (rebate.symbolCategory === 4) rebateRow.energy = rebate.point || 0
+              else if (rebate.symbolCategory === 5) rebateRow.energy2 = rebate.point || 0
+            })
+
+            superRebates.forEach((rebate: any) => {
+              if (rebate.symbolCategory === 1) rebateRow.forex1 = rebate.point || 0
+              else if (rebate.symbolCategory === 2) rebateRow.index1 = rebate.point || 0
+              else if (rebate.symbolCategory === 3) rebateRow.metal1 = rebate.point || 0
+              else if (rebate.symbolCategory === 4) rebateRow.energy1 = rebate.point || 0
+              else if (rebate.symbolCategory === 5) rebateRow.energy2Max = rebate.point || 0
+            })
+
+            rebateRow.forexOptions = generateOptions(rebateRow.forex1)
+            rebateRow.indexOptions = generateOptions(rebateRow.index1)
+            rebateRow.metalOptions = generateOptions(rebateRow.metal1)
+            rebateRow.energyOptions = generateOptions(rebateRow.energy1)
+            rebateRow.energy2Options = generateOptions(rebateRow.energy2Max)
+
+            groupedData[accountGroup].push(rebateRow)
+          }
+
+          const commissions = Array.isArray(group.commissions) ? group.commissions : []
+          const superCommissions = Array.isArray(group.superCommissions) ? group.superCommissions : []
+          if (superCommissions.length > 0) {
+            const commissionRow: any = {
+              accountGroup,
+              groupCategoryId: group.groupCategoryId,
+              dataType: 'commissions',
+              type: group.commissionTypeName || 'Commission',
+              valid,
+              forex: 0,
+              index: 0,
+              metal: 0,
+              energy: 0,
+              energy2: 0,
+              energy2Max: 0,
+              forex1: 0,
+              index1: 0,
+              metal1: 0,
+              energy1: 0,
+            }
+
+            commissions.forEach((comm: any) => {
+              if (comm.symbolCategory === 1) commissionRow.forex = comm.point || 0
+              else if (comm.symbolCategory === 2) commissionRow.index = comm.point || 0
+              else if (comm.symbolCategory === 3) commissionRow.metal = comm.point || 0
+              else if (comm.symbolCategory === 4) commissionRow.energy = comm.point || 0
+              else if (comm.symbolCategory === 5) commissionRow.energy2 = comm.point || 0
+            })
+
+            superCommissions.forEach((comm: any) => {
+              if (comm.symbolCategory === 1) commissionRow.forex1 = comm.point || 0
+              else if (comm.symbolCategory === 2) commissionRow.index1 = comm.point || 0
+              else if (comm.symbolCategory === 3) commissionRow.metal1 = comm.point || 0
+              else if (comm.symbolCategory === 4) commissionRow.energy1 = comm.point || 0
+              else if (comm.symbolCategory === 5) commissionRow.energy2Max = comm.point || 0
+            })
+
+            commissionRow.forexOptions = generateOptions(commissionRow.forex1)
+            commissionRow.indexOptions = generateOptions(commissionRow.index1)
+            commissionRow.metalOptions = generateOptions(commissionRow.metal1)
+            commissionRow.energyOptions = generateOptions(commissionRow.energy1)
+            commissionRow.energy2Options = generateOptions(commissionRow.energy2Max)
+
+            groupedData[accountGroup].push(commissionRow)
+          }
+        })
+
+        // 将按 accountGroup 聚合后的对象转换为包含 accountGroup 和 items 数组的结构
+        const finalData = Object.keys(groupedData).map((accountGroup) => {
+          return {
+            accountGroup,
+            isOpen: false, // 默认不展开
+            items: groupedData[accountGroup],
+          }
+        })
+
+        console.log('tableData',finalData)
+        commissionTemplateTableData.value = finalData
+        return
+      }
+
+      commissionTemplateTableData.value = []
+      uni.showToast({
+        title: res.msg || t('Ib.Custom.GetDataFailed'),
+        icon: 'none',
+      })
+    } catch (error) {
+      commissionTemplateTableData.value = []
+      uni.showToast({ title: t('Ib.Custom.GetDataFailed'), icon: 'none' })
+    }
+  }
+
   const toVerified = () => {
     // 确认按钮点击事件
     emit('confirm')
@@ -188,7 +350,7 @@
       uni.showToast({
         title: t('Msg.ModifySuccess'),
       })
-      this.cancel()
+      cancel()
     } else {
       uni.showToast({
         title: res.msg,
@@ -201,6 +363,93 @@
 <style lang="scss" scoped>
   @import "@/uni.scss";
 
+  .commission-groups {
+    margin-top: px2rpx(10);
+    padding-bottom: px2rpx(150); /* 预留底部空间,防止最下面的下拉框被截断或遮挡 */
+  }
+
+  .group-card {
+    border: 1px solid #ebeef5;
+    border-radius: px2rpx(6);
+    margin-bottom: px2rpx(15);
+    background-color: #fff;
+    /* overflow: hidden; 移除此属性,防止下拉框被遮挡截断 */
+  }
+
+  .group-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: px2rpx(10) px2rpx(15);
+    background-color: #f5f7fa;
+    border-bottom: 1px solid #ebeef5;
+    border-top-left-radius: px2rpx(6);
+    border-top-right-radius: px2rpx(6);
+  }
+
+  .group-title {
+    font-size: px2rpx(14);
+    font-weight: bold;
+    color: #303133;
+  }
+
+  .group-body {
+    padding: px2rpx(15);
+  }
+
+  .item-row {
+    margin-bottom: px2rpx(15);
+    padding-bottom: px2rpx(15);
+    border-bottom: 1px dashed #ebeef5;
+
+    &:last-child {
+      margin-bottom: 0;
+      padding-bottom: 0;
+      border-bottom: none;
+    }
+  }
+
+  .item-title {
+    margin-bottom: px2rpx(10);
+    display: flex;
+    align-items: center;
+
+    .type-badge {
+      background-color: #e1f3d8;
+      color: #67c23a;
+      padding: px2rpx(2) px2rpx(8);
+      border-radius: px2rpx(4);
+      font-size: px2rpx(12);
+      margin-right: px2rpx(8);
+    }
+
+    .type-text {
+      font-size: px2rpx(13);
+      color: #606266;
+    }
+  }
+
+  .item-fields {
+    display: flex;
+    flex-wrap: wrap;
+    gap: px2rpx(10);
+    justify-content: flex-start;
+  }
+
+  .field-col {
+    flex: 0 0 calc(20% - px2rpx(10));
+    min-width: px2rpx(80);
+    max-width: px2rpx(120);
+    display: flex;
+    flex-direction: column;
+
+    .field-label {
+      font-size: px2rpx(12);
+      color: #909399;
+      margin-bottom: px2rpx(5);
+    }
+  }
+
   .dialog-account-adjust-body {
     padding: 20rpx;
   }
@@ -301,4 +550,4 @@
   .account-adjust-footer-buttons button {
     min-width: 120rpx;
   }
-</style>
+</style>

+ 1 - 0
pages/ib/customer.vue

@@ -255,6 +255,7 @@
     getStatistics()
     // docVisible.value =true
     // pointVisible.value =true
+    applyVisible.value =true
   })
 
   const closeDoc = () => {