Bläddra i källkod

feat:ib-搜索组件修改

ljc 2 månader sedan
förälder
incheckning
8f05cdebb4
5 ändrade filer med 398 tillägg och 168 borttagningar
  1. 24 1
      components/cwg-complex-search.vue
  2. 42 22
      pages/ib/accountList.vue
  3. 93 40
      pages/ib/customer.vue
  4. 145 85
      pages/ib/report.vue
  5. 94 20
      pages/ib/subsList.vue

+ 24 - 1
components/cwg-complex-search.vue

@@ -23,6 +23,16 @@
                                 <uni-datetime-picker v-model="formData[field.key]" type="daterange"
                                     :placeholder="field.placeholder || '请选择日期范围'" @change="handleDateChange" />
                             </template>
+                            <template v-else-if="field.type === 'picker'">
+                                <uni-data-picker
+                                    v-model="formData[field.key]"
+                                    :localdata="field.options"
+                                    :popup-title="field.popupTitle || t('State.All')"
+                                    :map="field.map || { value: 'value', text: 'label' }"
+                                    @change="(e) => field.onChange?.(e)"
+                                    @nodeclick="(node) => field.onNodeClick?.(node)"
+                                />
+                            </template>
                             <template v-else-if="field.type === 'number'">
                                 <uni-easyinput v-model="formData[field.key]" type="number"
                                     :placeholder="field.placeholder || '请输入数字'" />
@@ -86,6 +96,16 @@
                             <uni-easyinput v-model="tempFormData[field.key]" type="number"
                                 :placeholder="field.placeholder || '请输入数字'" />
                         </template>
+                        <template v-else-if="field.type === 'picker'">
+                            <uni-data-picker
+                                v-model="tempFormData[field.key]"
+                                :localdata="field.options"
+                                :popup-title="field.popupTitle || t('State.All')"
+                                :map="field.map || { value: 'value', text: 'label' }"
+                                @change="(e) => field.onChange?.(e)"
+                                @nodeclick="(node) => field.onNodeClick?.(node)"
+                            />
+                        </template>
                     </view>
                 </view>
             </scroll-view>
@@ -221,6 +241,9 @@ const nonDateField = computed(() => {
                 otherFields.push(field)
             }
         }
+        else if (field.type === 'picker') {
+            priorityFields.push(field)
+        }
         else {
             otherFields.push(field)
         }
@@ -460,4 +483,4 @@ onMounted(() => {
         }
     }
 }
-</style>
+</style>

+ 42 - 22
pages/ib/accountList.vue

@@ -5,14 +5,8 @@
     <view class="account-content">
       <view class="search-content">
         <view class="search-bar">
-          <cwg-combox v-model:value="search.platform" :options="platformOptions"
-                      :placeholder="t('placeholder.choose')" />
-          <uni-easyinput v-model="search.login" :placeholder="t('Label.Login')" />
-          <uni-easyinput v-model="search.cId" placeholder="CID" />
-          <uni-datetime-picker type="daterange" v-model="search.date"
-                               :placeholder="t('placeholder.Start') + ' - ' + t('placeholder.End')" @change="handleDateChange"/>
+          <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
         </view>
-        <view />
       </view>
       <cwg-tabel
         ref="tableRef"
@@ -37,22 +31,18 @@
 
 <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 { lang } from '@/composables/config'
+  import { ref } from 'vue'
+  import { useI18n } from 'vue-i18n'
   import { ibApi } from '@/service/ib'
   import { useFilters } from '@/composables/useFilters'
 
-  const { numberFormat, numberDecimal } = useFilters()
+  const { numberFormat } = useFilters()
+  const { t } = useI18n()
 
+  const searchParams = ref({})
   const search = ref({
     cId: '',
     login: '',
-    date: '',
     platform: 'MT4',
     startDate: '',
     endDate: '',
@@ -62,7 +52,41 @@
     { text: 'MT4', value: 'MT4' },
     { text: 'MT5', value: 'MT5' },
   ]
-  const { t, locale } = useI18n()
+
+  const filterFields = [
+    { key: 'platform', type: 'select', label: t('Label.Platform'), placeholder: t('placeholder.choose'), options: platformOptions, defaultValue: 'MT4', isSelect: true },
+    { key: 'login', type: 'input', label: t('Label.Login'), placeholder: t('Label.Login'), defaultValue: '' },
+    { key: 'cId', type: 'input', label: 'CID', placeholder: 'CID', defaultValue: '' },
+    { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' },
+  ]
+
+  const tableRef = ref<any>(null)
+
+  const handleSearch = (params: any) => {
+    const payload = { ...params }
+    if (payload.date && Array.isArray(payload.date) && payload.date.length === 2) {
+      payload.startDate = payload.date[0]
+      payload.endDate = payload.date[1]
+    } else {
+      payload.startDate = ''
+      payload.endDate = ''
+    }
+    delete payload.date
+
+    search.value = payload
+    tableRef.value?.refreshTable?.()
+  }
+
+  const handleReset = () => {
+    search.value = {
+      cId: '',
+      login: '',
+      platform: 'MT4',
+      startDate: '',
+      endDate: '',
+    }
+    tableRef.value?.refreshTable?.()
+  }
   // 表格列配置
   const columns = ref([
     {
@@ -154,10 +178,6 @@
 
 
   const listApi = ref(ibApi.accountSubs)
-  const handleDateChange = (val) => {
-    search.value.startDate = val[0]
-    search.value.endDate = val[1]
-  }
 </script>
 <style lang="scss" scoped>
   @import "@/uni.scss";
@@ -166,4 +186,4 @@
     display: flex;
     justify-content: space-between;
   }
-</style>
+</style>

+ 93 - 40
pages/ib/customer.vue

@@ -2,50 +2,52 @@
   <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
     <cwg-header :title="t('Home.page_ib.item2')" />
     <view class="info-card">
-      <view class="search-content">
-        <view class="search-bar">
-          <uni-easyinput v-model="search.cId" placeholder="CID" />
-          <uni-easyinput v-model="search.name" :placeholder="t('Ib.Custom.NameLabel')" />
-          <uni-easyinput v-model="search.email" :placeholder="t('Label.Email')" />
-        </view>
-        <view class="search-tabs">
-          <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 1 }" @click="chooseBelongsType(1)"
-          >
-            {{ t('Ib.Custom.Unverified') }}
-            <view
-              v-if="statistics.unverifiedNum !== undefined"
-              class="count-badge"
-            >({{ statistics.unverifiedNum }})
+      <!-- 移动端:分类标签在搜索组件上方 -->
+      <cwg-match-media :max-width="991">
+        <view class="search-content mobile-search-content">
+          <view class="search-tabs">
+            <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 1 }" @click="chooseBelongsType(1)">
+              {{ t('Ib.Custom.Unverified') }}
+              <view v-if="statistics.unverifiedNum !== undefined" class="count-badge">({{ statistics.unverifiedNum }})</view>
+            </view>
+            <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 2 }" @click="chooseBelongsType(2)">
+              {{ t('Ib.Custom.UnDeposit') }}
+              <view v-if="statistics.unDepositNum !== undefined" class="count-badge">({{ statistics.unDepositNum }})</view>
+            </view>
+            <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 3 }" @click="chooseBelongsType(3)">
+              {{ t('Ib.Custom.Deposited') }}
+              <view v-if="statistics.depositNum !== undefined" class="count-badge">({{ statistics.depositNum }})</view>
             </view>
           </view>
-          <view
-            class="crm-cursor tab-item"
-            :class="{ active: search.belongsType == 2 }"
-            @click="chooseBelongsType(2)"
-          >
-            {{ t('Ib.Custom.UnDeposit') }}
-            <view
-              v-if="statistics.unDepositNum !== undefined"
-              class="count-badge"
-            >({{ statistics.unDepositNum }})
-            </view
-            >
+          <view class="search-bar">
+            <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
           </view>
-          <view
-            class="crm-cursor tab-item"
-            :class="{ active: search.belongsType == 3 }"
-            @click="chooseBelongsType(3)"
-          >
-            {{ t('Ib.Custom.Deposited') }}
-            <view
-              v-if="statistics.depositNum !== undefined"
-              class="count-badge"
-            >({{ statistics.depositNum }})
-            </view
-            >
+        </view>
+      </cwg-match-media>
+
+      <!-- PC端:分类标签和搜索组件在同一行 (搜索在左,标签在右) -->
+      <cwg-match-media :min-width="992">
+        <view class="search-content pc-search-content">
+          <view class="search-bar">
+            <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
+          </view>
+          <view class="search-tabs">
+            <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 1 }" @click="chooseBelongsType(1)">
+              {{ t('Ib.Custom.Unverified') }}
+              <view v-if="statistics.unverifiedNum !== undefined" class="count-badge">({{ statistics.unverifiedNum }})</view>
+            </view>
+            <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 2 }" @click="chooseBelongsType(2)">
+              {{ t('Ib.Custom.UnDeposit') }}
+              <view v-if="statistics.unDepositNum !== undefined" class="count-badge">({{ statistics.unDepositNum }})</view>
+            </view>
+            <view class="crm-cursor tab-item" :class="{ active: search.belongsType == 3 }" @click="chooseBelongsType(3)">
+              {{ t('Ib.Custom.Deposited') }}
+              <view v-if="statistics.depositNum !== undefined" class="count-badge">({{ statistics.depositNum }})</view>
+            </view>
           </view>
         </view>
-      </view>
+      </cwg-match-media>
+
       <cwg-tabel
         ref="tableRef"
         :columns="columns"
@@ -84,6 +86,7 @@
   import DocumentaryDialog from '@/pages/ib/components/documentaryDialog.vue'
   import PointDialog from '@/pages/ib/components/pointDialog.vue'
   import ApplyIbDialog from '@/pages/ib/components/applyIbDialog.vue'
+  import { nextTick } from 'vue'
 
   const { Code } = Config
   const statistics = ref({
@@ -92,6 +95,7 @@
     depositNum: 0,
   })
 
+  const searchParams = ref({})
   const search = ref({
     'name': '',
     'email': '',
@@ -99,6 +103,12 @@
     // 1:未实名 2:未入金 3:已入金
     belongsType: null,
   })
+  
+  const filterFields = [
+    { key: 'cId', type: 'input', label: 'CID', placeholder: 'CID', defaultValue: '' },
+    { key: 'name', type: 'input', label: t('Ib.Custom.NameLabel'), placeholder: t('Ib.Custom.NameLabel'), defaultValue: '' },
+    { key: 'email', type: 'input', label: t('Label.Email'), placeholder: t('Label.Email'), defaultValue: '' }
+  ]
 
   const formInfoRow = ref({})
   const pointForm = ref({})
@@ -188,6 +198,30 @@
 
   const listApi = ref(null)
   listApi.value = ibApi.customerSubs
+
+  const handleSearch = (params: any) => {
+    // 合并表单的过滤参数,同时保留当前的 belongsType 标签选中状态
+    search.value = {
+      ...params,
+      belongsType: search.value.belongsType
+    }
+    nextTick(() => {
+      tableRef.value.refreshTable()
+    })
+  }
+
+  const handleReset = () => {
+    search.value = {
+      name: '',
+      email: '',
+      cId: '',
+      belongsType: search.value.belongsType // 保持当前的分类标签选中
+    }
+    nextTick(() => {
+      tableRef.value.refreshTable()
+    })
+  }
+
   //选择belongsType(点击已选中的 tab 可反选取消)
   const chooseBelongsType = (belongsType) => {
     if (search.value.belongsType == belongsType) {
@@ -195,6 +229,10 @@
     } else {
       search.value.belongsType = belongsType
     }
+    // 切换 tab 时自动重新请求列表
+    nextTick(() => {
+      tableRef.value.refreshTable()
+    })
   }
   // 下拉菜单配置
   const menuList = (row) => {
@@ -291,8 +329,23 @@
   .search-content {
     display: flex;
     justify-content: space-between;
+    align-items: flex-start;
   }
 
+  .mobile-search-content {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: px2rpx(10);
+    .search-tabs{
+      padding: 0;
+      margin: 0;
+    }
+  }
+
+  .pc-search-content {
+    flex-direction: row;
+    align-items: flex-start;
+  }
 
   .search-bar {
     display: flex;
@@ -322,7 +375,7 @@
       min-width: px2rpx(100);
       border: 1px solid #F0F0F0;
       border-radius: px2rpx(4);
-      margin-left: px2rpx(5);
+      margin-right: px2rpx(5);
       height: px2rpx(33);
       line-height: px2rpx(33);
       justify-content: center;

+ 145 - 85
pages/ib/report.vue

@@ -5,49 +5,7 @@
     <view class="account-content">
       <view class="search-content">
         <view class="search-bar">
-          <cwg-combox v-model:value="search.reportType" :options="typeList"
-                      :placeholder="t('placeholder.choose')" />
-          <cwg-combox v-if="search.reportType == 3" v-model:value="search.detail_type" :options="detailTypeList"
-                      :placeholder="t('placeholder.choose')" />
-          <view v-if="[1,3,4,7,24].includes(search.reportType)" class="report-platform">
-            <view
-              v-for="(item,index) in platformOptions"
-              :key="index"
-              class="checklist-box"
-              :class="{
-                'active': item.value === search.platform,
-              }"
-              @click="changePlatformType(item.value)"
-            >
-              {{ item.text }}
-            </view>
-          </view>
-          <cwg-combox v-if="search.reportType == 24" v-model:value="search.customType" :options="customTypeList"
-                      :placeholder="t('placeholder.choose')" />
-
-          <uni-data-picker class="agent-select" v-model="search.agentId" :localdata="agentIdOpts"
-                           :popup-title="t('State.All')" @change="handleItemChange" @nodeclick="onnodeclick"
-                           :map="{value:'value',text:'label'}"></uni-data-picker>
-
-          <view class="search-input-box">
-            <uni-easyinput v-if="['1', '2', '3', '4', '7'].includes(String(search.reportType))"
-                           v-model.trim="search.login" :placeholder="t('Label.TradingAccount')" />
-          </view>
-
-          <view class="search-input-box" v-if="search.reportType == 7">
-            <uni-easyinput v-model.trim="search.cId" placeholder="CID" />
-          </view>
-
-          <cwg-combox v-if="search.reportType == 3 || search.reportType == 7" v-model:value="search.isShort"
-                      :options="isShortList" :placeholder="t('placeholder.choose')" />
-
-          <uni-datetime-picker type="daterange" v-model="search.date"
-                               :placeholder="t('placeholder.Start') + ' - ' + t('placeholder.End')"
-                               @change="handleDateChange" />
-          <button class="search-btn" @click="toSearch">{{ t('Ib.Report.Btn') }}</button>
-        </view>
-        <view>
-
+          <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
         </view>
       </view>
 
@@ -69,8 +27,7 @@
 
 <script setup lang="ts">
   // 报告
-  import { ref, reactive, computed, onMounted, watch } from 'vue'
-  import { onLoad } from '@dcloudio/uni-app'
+  import { ref, computed, onMounted, watch } from 'vue'
   import { useI18n } from 'vue-i18n'
   import Config from '@/config/index'
   import { ibApi } from '@/service/ib'
@@ -80,8 +37,7 @@
   import useUserStore from '@/stores/use-user-store'
 
   const { numberFormat } = useFilters()
-  const { t, locale } = useI18n()
-  const lang = locale.value
+  const { t } = useI18n()
   let { Code } = Config
   const { userInfo } = useUserStore()
   const tableRef = ref(null)
@@ -110,14 +66,31 @@
     { text: t('Ib.Report.item2'), value: 2 },
   ])
 
+  const now = new Date()
+  const year = now.getFullYear()
+  const month = String(now.getMonth() + 1).padStart(2, '0')
+  const day = String(now.getDate()).padStart(2, '0')
+  const defaultDateRange = [`${year}-${month}-01`, `${year}-${month}-${day}`]
+
+  const searchParams = ref<any>({
+    reportType: 1,
+    detail_type: null,
+    customType: 0,
+    platform: 'MT4',
+    agentId: '',
+    login: '',
+    cId: '',
+    isShort: 0,
+    date: defaultDateRange,
+  })
+
   const search = ref({
     reportType: 1,
     detail_type: null as number | null,
     customType: 0,
     platform: 'MT4',
-    date: [] as string[],
-    startDate: '',
-    endDate: '',
+    startDate: defaultDateRange[0],
+    endDate: defaultDateRange[1],
     agentId: '',
     login: '',
     cId: '',
@@ -136,12 +109,8 @@
       children: [],
     },
   ])
-  const toSearch = () => {
-    tableRef.value?.refreshTable()
-  }
 
-  const handleItemChange = (e: any) => {
-  }
+  const handleItemChange = (e: any) => {}
 
   const getSummaries = (param: any) => {
     const { columns, summaryData } = param
@@ -223,8 +192,55 @@
 
     return sums
   }
+
+  const normalizePickerValue = (val: any) => {
+    if (Array.isArray(val)) return val[val.length - 1]
+    return val
+  }
+
+  const handleSearch = (params: any) => {
+    const payload: any = { ...params }
+    if (payload.date && Array.isArray(payload.date) && payload.date.length === 2) {
+      payload.startDate = payload.date[0]
+      payload.endDate = payload.date[1]
+    } else {
+      payload.startDate = ''
+      payload.endDate = ''
+    }
+    delete payload.date
+
+    payload.agentId = normalizePickerValue(payload.agentId)
+
+    const type = Number(payload.reportType)
+    if (![1, 3, 4, 7, 24].includes(type)) payload.platform = ''
+    if (![1, 2, 3, 4, 7].includes(type)) payload.login = ''
+    if (type !== 7) payload.cId = ''
+    if (![3, 7].includes(type)) payload.isShort = 0
+    if (type !== 3) payload.detail_type = null
+    if (type !== 24) payload.customType = 0
+
+    search.value = {
+      reportType: payload.reportType,
+      detail_type: payload.detail_type,
+      customType: payload.customType,
+      platform: payload.platform,
+      startDate: payload.startDate,
+      endDate: payload.endDate,
+      agentId: payload.agentId,
+      login: payload.login,
+      cId: payload.cId,
+      isShort: payload.isShort,
+    }
+
+    tableRef.value?.refreshTable?.()
+  }
+
+  const handleReset = (emptyParams: any) => {
+    handleSearch(emptyParams)
+  }
+
   const initIbTree = async () => {
-    const res = await ibApi.ibTree({ pid: val })
+    const res = await ibApi.ibTree({ pid: 0 })
 
     if (res.code === Code.StatusOK) {
       if (res.data && res.data.length > 0) {
@@ -346,20 +362,6 @@
     }
   })
 
-  const handleDateChange = (val: any) => {
-    if (val && val.length === 2) {
-      search.value.startDate = val[0]
-      search.value.endDate = val[1]
-    } else {
-      search.value.startDate = ''
-      search.value.endDate = ''
-    }
-  }
-
-  const changePlatformType = (type: string) => {
-    search.value.platform = type
-  }
-
   const groupCurrency1 = (type: string) => {
     if (type == 'GBP') return '£'
     if (type == 'USD') return '$'
@@ -379,31 +381,89 @@
     return '--'
   }
 
-  watch(() => search.value.reportType, (val) => {
-    if (val == 24) {
+  watch(() => searchParams.value.reportType, (val) => {
+    const type = Number(val)
+    search.value.reportType = type
+    if (type === 24) {
+      searchParams.value.customType = 0
+      searchParams.value.detail_type = null
       search.value.customType = 0
       search.value.detail_type = null
-    } else if (val == 3) {
-      search.value.detail_type = 1
+    } else if (type === 3) {
+      if (searchParams.value.detail_type == null) searchParams.value.detail_type = 1
+      if (search.value.detail_type == null) search.value.detail_type = 1
     } else {
+      searchParams.value.detail_type = null
       search.value.detail_type = null
+      searchParams.value.customType = 0
+      search.value.customType = 0
     }
+  }, { immediate: true })
+
+  watch(() => searchParams.value.detail_type, (val) => {
+    search.value.detail_type = val == null ? null : Number(val)
+  })
+
+  watch(() => searchParams.value.platform, (val) => {
+    search.value.platform = val
+  })
+
+  watch(() => searchParams.value.customType, (val) => {
+    search.value.customType = val
+  })
+
+  watch(() => searchParams.value.isShort, (val) => {
+    search.value.isShort = val
   })
 
   onMounted(() => {
     initIbTree()
+  })
+
+  const filterFields = computed(() => {
+    const type = Number(searchParams.value.reportType ?? 1)
+    const fields: any[] = [
+      { key: 'reportType', type: 'select', label: t('Home.page_ib.item3'), placeholder: t('placeholder.choose'), options: typeList.value, defaultValue: 1, isSelect: true },
+    ]
 
-    // 默认当月时间
-    const now = new Date()
-    const year = now.getFullYear()
-    let month: string | number = now.getMonth() + 1
-    if (month < 10) month = '0' + month
-    const day = now.getDate()
-    let dayStr = day < 10 ? '0' + day : day.toString()
-    search.value.date = [`${year}-${month}-01`, `${year}-${month}-${dayStr}`]
-    search.value.startDate = search.value.date[0]
-    search.value.endDate = search.value.date[1]
+    if (type === 3) {
+      fields.push({ key: 'detail_type', type: 'select', label: t('placeholder.choose'), placeholder: t('placeholder.choose'), options: detailTypeList.value, defaultValue: 1, isSelect: true })
+    }
+
+    if ([1, 3, 4, 7, 24].includes(type)) {
+      fields.push({ key: 'platform', type: 'select', label: t('Label.Platform'), placeholder: t('placeholder.choose'), options: platformOptions, defaultValue: 'MT4' })
+    }
+
+    if (type === 24) {
+      fields.push({ key: 'customType', type: 'select', label: t('placeholder.choose'), placeholder: t('placeholder.choose'), options: customTypeList, defaultValue: 0, isSelect: true })
+    }
+
+    fields.push({
+      key: 'agentId',
+      type: 'picker',
+      label: t('State.All'),
+      options: agentIdOpts.value,
+      popupTitle: t('State.All'),
+      map: { value: 'value', text: 'label' },
+      onChange: handleItemChange,
+      onNodeClick: onnodeclick,
+      defaultValue: '',
+    })
+
+    if ([1, 2, 3, 4, 7].includes(type)) {
+      fields.push({ key: 'login', type: 'input', label: t('Label.TradingAccount'), placeholder: t('Label.TradingAccount'), defaultValue: '' })
+    }
+
+    if (type === 7) {
+      fields.push({ key: 'cId', type: 'input', label: 'CID', placeholder: 'CID', defaultValue: '' })
+    }
+
+    if ([3, 7].includes(type)) {
+      fields.push({ key: 'isShort', type: 'select', label: t('placeholder.choose'), placeholder: t('placeholder.choose'), options: isShortList.value, defaultValue: 0, isSelect: true })
+    }
 
+    fields.push({ key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' })
+    return fields
   })
 </script>
 
@@ -460,4 +520,4 @@
     line-height: px2rpx(36);
     margin: 0;
   }
-</style>
+</style>

+ 94 - 20
pages/ib/subsList.vue

@@ -3,21 +3,36 @@
     <cwg-header :title="t('Ib.Custom.Manage2')" />
 
     <view class="account-content">
-      <view class="search-content">
-        <view class="search-bar">
-          <uni-easyinput v-model="search.ibNo" :placeholder="t('Label.IbAccount')" />
-          <uni-easyinput v-model="search.name" :placeholder="t('Ib.Custom.NameLabel')" />
-          <uni-easyinput v-model="search.cId" placeholder="CID" />
-          <uni-datetime-picker type="daterange" v-model="search.date"
-                               :placeholder="t('placeholder.Start') + ' - ' + t('placeholder.End')" @change="handleDateChange"/>
+      <!-- 移动端:按钮在筛选上方 -->
+      <cwg-match-media :max-width="991">
+        <view class="search-content mobile-search-content">
+          <view class="search-bar mobile-add-btn-wrap">
+            <button type="primary" class="search-button" @click="addSub">
+              <cwg-icon name="icon_add" :size="18" color="#fff"></cwg-icon>
+              {{t('Ib.Report.Title5')}}
+            </button>
+          </view>
+          <view class="search-bar">
+            <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
+          </view>
         </view>
-        <view class="search-bar">
-          <button type="primary" class="search-button" @click="addSub">
-            <cwg-icon name="icon_add" :size="18" color="#fff"></cwg-icon>
-            {{t('Ib.Report.Title5')}}
-          </button>
+      </cwg-match-media>
+
+      <!-- PC端:按钮和筛选在同一行 -->
+      <cwg-match-media :min-width="991">
+        <view class="search-content pc-search-content">
+          <view class="search-bar">
+            <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
+          </view>
+          <view class="search-bar">
+            <button type="primary" class="search-button" @click="addSub">
+              <cwg-icon name="icon_add" :size="18" color="#fff"></cwg-icon>
+              {{t('Ib.Report.Title5')}}
+            </button>
+          </view>
         </view>
-      </view>
+      </cwg-match-media>
+      
       <cwg-tabel
         ref="tableRef"
         :columns="columns"
@@ -72,17 +87,27 @@
   import { ibApi } from '@/service/ib'
   import { useFilters } from '@/composables/useFilters'
   import ApplyIbDialog from '@/pages/ib/components/applyIbDialog.vue'
+  import { nextTick } from 'vue'
 
   const { numberFormat, numberDecimal } = useFilters()
+  const { t, locale } = useI18n()
+  const { Code } = Config
 
+  const searchParams = ref({})
   const search = ref({
     ibNo: '',
     name: '',
-    date: '',
     cId: '',
     startDate: '',
     endDate: '',
   })
+  
+  const filterFields = [
+    { key: 'ibNo', type: 'input', label: t('Label.IbAccount'), placeholder: t('Label.IbAccount'), defaultValue: '' },
+    { key: 'name', type: 'input', label: t('Ib.Custom.NameLabel'), placeholder: t('Ib.Custom.NameLabel'), defaultValue: '' },
+    { key: 'cId', type: 'input', label: 'CID', placeholder: 'CID', defaultValue: '' },
+    { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
+  ]
   const tableRef = ref(null)
   const applyIbDialogRef = ref(null)
   const applyVisible = ref(false)
@@ -97,8 +122,6 @@
     pointOptions: [],
   })
   const exclusiveRow = ref<any>(null)
-  const { t, locale } = useI18n()
-  const { Code } = Config
   // 表格列配置
   const columns = ref([
     {
@@ -170,13 +193,40 @@
 
 
   const listApi = ref(ibApi.IbSubs)
-  const handleDateChange = (val) => {
-    search.value.startDate = val[0]
-    search.value.endDate = val[1]
+
+  const handleSearch = (params: any) => {
+    // 拦截处理 daterange,将 date 拆分为 startDate 和 endDate
+    const payload = { ...params }
+    if (payload.date && payload.date.length === 2) {
+      payload.startDate = payload.date[0]
+      payload.endDate = payload.date[1]
+    } else {
+      payload.startDate = ''
+      payload.endDate = ''
+    }
+    delete payload.date
+
+    search.value = payload
+    nextTick(() => {
+      tableRef.value.refreshTable()
+    })
+  }
+
+  const handleReset = () => {
+    search.value = {
+      ibNo: '',
+      name: '',
+      cId: '',
+      startDate: '',
+      endDate: '',
+    }
+    nextTick(() => {
+      tableRef.value.refreshTable()
+    })
   }
 
   onMounted(()=>{
-    applyVisible.value = true
+    // applyVisible.value = true
   })
   // 下拉菜单配置
   const menuList = (row) => {
@@ -259,8 +309,32 @@
 
   .search-content {
     display: flex;
+  }
+
+  /* PC 端对齐方式 */
+  .pc-search-content {
     justify-content: space-between;
+    align-items: flex-start;
+    margin-bottom: px2rpx(10);
+  }
+
+  /* 移动端排版方式 */
+  .mobile-search-content {
+    flex-direction: column;
+    margin-bottom: px2rpx(10);
+    
+    .mobile-add-btn-wrap {
+      display: flex;
+      justify-content: flex-end;
+      width: 100%;
+      margin-bottom: px2rpx(10);
+
+      .search-button {
+        margin: 0 0 0 auto; /* 强制按钮靠右且消除其它 margin */
+      }
+    }
   }
+
   .search-button{
     display: flex;
     align-items: center;