Forráskód Böngészése

feat:客户管理-开户调整

ljc 2 hónapja
szülő
commit
66a5f8ec79

+ 8 - 1
locale/cn.json

@@ -1751,7 +1751,14 @@
       "SaveFailed": "保存失败",
       "GetDataFailed": "获取数据失败",
       "SubmitSuccess": "提交成功",
-      "SubmitFailed": "提交失败"
+      "SubmitFailed": "提交失败",
+      "AccountAdjust": "开户调整",
+      "AccountAdjustNotesSection1Title": "生成开户链接注意事项",
+      "AccountAdjustNotesSection1Item1": "开户链接为一次性生成,生成后固定使用且不支持修改或删除,请创建前确认配置无误。",
+      "AccountAdjustNotesSection1Item2": "生成链接时,请明确选择可开通的账户类型并设置对应加点;未选择的账户类型将无法通过该链接开通。",
+      "AccountAdjustNotesSection2Title": "开户调整注意事项",
+      "AccountAdjustNotesSection2Item1": "修改单个CID任意一账户类型加点时,该CID下所有同类型账户将同步更新。如修改时任意账户存在持仓,则无法修改加点设置。",
+      "AccountAdjustNotesSection2Item2": "如需清理某账户类型加点(即禁止客户开通该类型账户),若客户已持有该类型账户,则无法操作。"
     },
     "Transfer": {
       "CommissionTransfer": "佣金内转",

+ 18 - 2
pages/ib/components/documentaryDialog.vue

@@ -75,7 +75,7 @@
     permissionDisplay: '',
     agree: '',
   })
-  const emit = defineEmits(['close','showQrCode'])
+  const emit = defineEmits(['close','confirm'])
 
   onMounted(() => {
     console.log(props.visible)
@@ -93,9 +93,25 @@
   const closeDia = () => {
     emit('close')
   }
-  const confirmDia = () => {
+  const confirmDia = async () => {
     console.log(formData.value)
     // emit('close')
+    const res = await ibApi.customUpdateFollowPermissionDisplay({
+      id: formData.value.id,
+      permissionDisplay: formData.value.permissionDisplay,
+    })
+    if (res.Code = Code.StatusOK) {
+      emit('confirm')
+      uni.showToast({
+        title:t("Msg.Success"),
+        icon: 'none'
+      })
+    }else {
+      uni.showToast({
+        title:res.msg,
+        icon: 'none'
+      })
+    }
   }
 </script>
 <style lang="scss" scoped>

+ 377 - 0
pages/ib/components/pointDialog.vue

@@ -0,0 +1,377 @@
+<template>
+  <cwg-popup :title="t('Ib.Custom.AccountAdjust')" :visible="visible" @close="closeDia" @confirm="confirmDia">
+    <view class="dia-content dialog-account-adjust-body">
+      <view class="account-adjust-cid-row">
+        <text class="account-adjust-cid-label">{{ t('Label.CidAccount') }}:</text>
+        <text class="account-adjust-cid-value">{{ dialogForm.cId || '--' }}</text>
+      </view>
+      <uni-forms :model="dialogForm" ref="formRef" label-width="0" class="dialogCheck_form dialog-account-adjust-form">
+        <view class="form-section form-section-commission">
+          <view class="section-title">
+            <cwg-icon name="crm-option" :size="24"></cwg-icon>
+            {{ t('Ib.Index.Spread5') }}
+          </view>
+          <view class="account-type-grid">
+            <view class="account-type-card">
+              <view class="account-type-label">
+                {{ t('AccountType.StandardAccount') }}
+              </view>
+              <cwg-combox
+                v-model:value="commissionAccountTypeSettings.standard.selectedIndex"
+                :options="getAvailableSpreadsCommission('7').map((item, index) => ({
+                  text: getSpreadLabelCommission(item),
+                  value: index
+                }))"
+                :placeholder="t('placeholder.choose')"
+                class="account-select"
+                @change="(value) => handleCommissionAccountTypeChange('standard', '7', value)"
+              />
+            </view>
+            <view class="account-type-card">
+              <view class="account-type-label">
+                {{ t('AccountType.SeniorAccount') }}
+              </view>
+              <cwg-combox
+                v-model:value="commissionAccountTypeSettings.ecn.selectedIndex"
+                :options="getAvailableSpreadsCommission('2').map((item, index) => ({
+                  text: getSpreadLabelCommission(item),
+                  value: index
+                }))"
+                :placeholder="t('placeholder.choose')"
+                class="account-select"
+                @change="(value) => handleCommissionAccountTypeChange('ecn', '2', value)"
+              />
+            </view>
+            <view class="account-type-card">
+              <view class="account-type-label">
+                {{ t('AccountType.CentAccount') }}
+              </view>
+              <cwg-combox
+                v-model:value="commissionAccountTypeSettings.cent.selectedIndex"
+                :options="getAvailableSpreadsCommission('8').map((item, index) => ({
+                  text: getSpreadLabelCommission(item),
+                  value: index
+                }))"
+                :placeholder="t('placeholder.choose')"
+                class="account-select"
+                @change="(value) => handleCommissionAccountTypeChange('cent', '8', value)"
+              />
+            </view>
+          </view>
+        </view>
+      </uni-forms>
+    </view>
+    <view class="dialog-footer dialog-account-adjust-footer">
+      <view class="account-adjust-notes-panel">
+        <view class="account-adjust-notes-section">
+          <view class="account-adjust-notes-title">
+            <cwg-icon name="gy" :size="20" class="account-adjust-notes-title-icon"></cwg-icon>
+            <span class="account-adjust-notes-title-text">{{ t('Ib.Custom.AccountAdjustNotesSection2Title') }}</span>
+          </view>
+          <view class="account-adjust-notes-list">
+            <view class="list">{{ t('Ib.Custom.AccountAdjustNotesSection2Item1') }}</view>
+            <view class="list">{{ t('Ib.Custom.AccountAdjustNotesSection2Item2') }}</view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </cwg-popup>
+</template>
+
+<script setup lang="ts">
+  import { ref, reactive, computed, onMounted, onUnmounted, watch } 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 { lang } from '@/composables/config'
+
+  const props = defineProps({
+    // 是否显示弹窗
+    visible: {
+      type: Boolean,
+      default: false,
+    },
+    // 详情formData
+    detail: { type: Object, default: () => ({}) },
+  })
+  const { Code, Host80 } = Config
+  const { t } = useI18n()
+  const formRef = ref(null)
+  const dialogForm = ref({
+    cId: '123',
+  })
+  const commissionAccountTypeSettings = ref({
+    ecn: { selectedIndex: null, selectedItem: null, loginType: '2' },
+    standard: { selectedIndex: null, selectedItem: null, loginType: '7' },
+    cent: { selectedIndex: null, selectedItem: null, loginType: '8' },
+  })
+  const commissionAccountTypeData = ref({
+    ecn: [],
+    standard: [],
+    cent: [],
+  })
+  const emit = defineEmits(['close', 'confirm'])
+
+  onMounted(() => {
+    console.log(props.visible)
+  })
+  // 佣金调整弹框:拉取点差/价格数据(与 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) {
+      const { cId, id, comPoint1, hide1 } = val
+      dialogForm.value = {
+        cId, id, comPoint1, hide1,
+      }
+      if (val.ibId) {
+        loadCommissionAccountTypes(val.ibId).then(
+          () => {
+            return setCommissionDefaultsFromLoginPoint(val.id)
+          },
+        )
+      }
+    }
+  })
+
+  const getSpreadLabelCommission = (item) => {
+    return item.groupName || ''
+  }
+
+  const handleCommissionAccountTypeChange = (type, loginType) => {
+    const setting = commissionAccountTypeSettings.value[type]
+    const availableSpreads = getAvailableSpreadsCommission(loginType)
+    if (
+      setting.selectedIndex !== null &&
+      setting.selectedIndex !== undefined
+    ) {
+      setting.selectedItem = availableSpreads[setting.selectedIndex] || null
+    } else {
+      setting.selectedItem = null
+    }
+  }
+
+  const toVerified = () => {
+    // 确认按钮点击事件
+    emit('confirm')
+  }
+
+  const cancel = () => {
+    // 取消按钮点击事件
+    emit('close')
+  }
+
+  const closeDia = () => {
+    emit('close')
+  }
+
+  const confirmDia = async () => {
+    // 确认按钮点击事件
+    const loginConfig = []
+    Object.keys(commissionAccountTypeSettings.value).forEach((key) => {
+      const setting = commissionAccountTypeSettings.value[key]
+      if (setting.selectedItem) {
+        loginConfig.push(setting.selectedItem)
+      }
+    })
+    let res = await ibApi.customCommissionPoint({
+      id: dialogForm.value.id,
+      loginConfig,
+    })
+    if (res.code == Code.StatusOK) {
+      uni.showToast({
+        title: t('Msg.ModifySuccess'),
+      })
+      this.cancel()
+    } else {
+      uni.showToast({
+        title: res.msg,
+        icon: 'none',
+      })
+    }
+    emit('confirm')
+  }
+</script>
+<style lang="scss" scoped>
+  @import "@/uni.scss";
+
+  .dialog-account-adjust-body {
+    padding: 20rpx;
+  }
+
+  .account-adjust-cid-row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 20rpx;
+  }
+
+  .account-adjust-cid-label {
+    color: #606266;
+    margin-right: px2rpx(5);
+  }
+
+  .account-adjust-cid-value {
+    font-weight: bold;
+    color: #303133;
+  }
+
+  .form-section {
+    margin-bottom: 20rpx;
+  }
+
+  .section-title {
+    display: flex;
+    align-items: center;
+    margin-bottom: px2rpx(15);
+    font-weight: bold;
+    font-size: px2rpx(14);
+  }
+
+  .section-title i {
+    margin-right: 10rpx;
+  }
+
+  .account-type-grid {
+  }
+
+  .account-type-card {
+    display: flex;
+    flex-direction: column;
+    margin-bottom: px2rpx(20);
+  }
+
+  .account-type-label {
+    margin-bottom: 10rpx;
+    font-size: 14rpx;
+  }
+
+  .account-select {
+    width: 100%;
+  }
+
+  .dialog-account-adjust-footer {
+    padding: 20rpx;
+  }
+
+  .account-adjust-notes-panel {
+    margin-bottom: 20rpx;
+  }
+
+  .account-adjust-notes-section {
+    background-color: #f5f7fa;
+    padding: 15rpx;
+    border-radius: 8rpx;
+  }
+
+  .account-adjust-notes-title {
+    display: flex;
+    align-items: center;
+    margin-bottom: px2rpx(10);
+    font-weight: bold;
+    font-size: px2rpx(13);
+  }
+
+  .account-adjust-notes-title-icon {
+    margin-right: px2rpx(10);
+  }
+
+  .account-adjust-notes-list {
+    margin-left: px2rpx(20);
+    color: #606266;
+    font-size: px2rpx(13);
+  }
+
+  .account-adjust-notes-list .list {
+    margin-bottom: px2rpx(5);
+    margin-left: px2rpx(10);
+  }
+
+  .account-adjust-footer-buttons {
+    display: flex;
+    justify-content: flex-end;
+    gap: 15rpx;
+  }
+
+  .account-adjust-footer-buttons button {
+    min-width: 120rpx;
+  }
+</style>

+ 33 - 1
pages/ib/customer.vue

@@ -63,7 +63,10 @@
           </cwg-dropdown>
         </template>
       </cwg-tabel>
-      <DocumentaryDialog :visible="docVisible" @close="close" />
+      <!-- 跟单全局设置     -->
+      <DocumentaryDialog :visible="docVisible" :detail="formInfoRow" @close="closeDoc" @confirm="confirmDoc" />
+      <!-- 开户调整     -->
+      <PointDialog :visible="pointVisible" @close="closePoint" @confirm="confirmPoint" />
     </view>
   </cwg-page-wrapper>
 </template>
@@ -78,6 +81,7 @@
   import { lang } from '@/composables/config'
   import { ibApi } from '@/service/ib'
   import DocumentaryDialog from '@/pages/ib/components/documentaryDialog.vue'
+  import PointDialog from '@/pages/ib/components/pointDialog.vue'
 
   const { Code } = Config
   const statistics = ref({
@@ -96,6 +100,10 @@
 
   const formInfoRow = ref({})
   const docVisible = ref(false)
+  const pointVisible = ref(false)
+  const applyVisible = ref(false)
+  const tableRef = ref(null)
+
 
   // 表格列配置
   const columns = ref([
@@ -240,8 +248,32 @@
   onMounted(() => {
     getStatistics()
     // docVisible.value =true
+    // pointVisible.value =true
   })
 
+  const closeDoc = () => {
+    docVisible.value = false
+  }
+  const closeApply = () => {
+    applyVisible.value = false
+  }
+  const closePoint = () => {
+    pointVisible.value = false
+  }
+
+  const confirmDoc = () => {
+    docVisible.value = false
+    tableRef.value.refreshTable()
+  }
+  const confirmPoint = () => {
+    pointVisible.value = false
+    tableRef.value.refreshTable()
+  }
+  const confirmApply = () => {
+    applyVisible.value = false
+    tableRef.value.refreshTable()
+  }
+
 
 </script>
 

+ 2 - 0
service/ib.ts

@@ -197,4 +197,6 @@ export const ibApi = {
   customLinkTypes: (params = {}) => post('/custom/register/link/types', params, 'Host90'),
   /** 新增代理申请(带佣金模板) */
   agentApplyAddPoint: (params = {}) => post('/agent/apply/add/point', params, 'Host80'),
+  /** 获取外佣点数据 */
+  getLoginPoint: (params = {}) => post('/custom/info/login/point', params, 'Host90'),
 };

+ 1 - 0
static/icons/crm-option.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M96 128C78.3 128 64 142.3 64 160C64 177.7 78.3 192 96 192L182.7 192C195 220.3 223.2 240 256 240C288.8 240 317 220.3 329.3 192L544 192C561.7 192 576 177.7 576 160C576 142.3 561.7 128 544 128L329.3 128C317 99.7 288.8 80 256 80C223.2 80 195 99.7 182.7 128L96 128zM96 288C78.3 288 64 302.3 64 320C64 337.7 78.3 352 96 352L342.7 352C355 380.3 383.2 400 416 400C448.8 400 477 380.3 489.3 352L544 352C561.7 352 576 337.7 576 320C576 302.3 561.7 288 544 288L489.3 288C477 259.7 448.8 240 416 240C383.2 240 355 259.7 342.7 288L96 288zM96 448C78.3 448 64 462.3 64 480C64 497.7 78.3 512 96 512L150.7 512C163 540.3 191.2 560 224 560C256.8 560 285 540.3 297.3 512L544 512C561.7 512 576 497.7 576 480C576 462.3 561.7 448 544 448L297.3 448C285 419.7 256.8 400 224 400C191.2 400 163 419.7 150.7 448L96 448z"/></svg>