Procházet zdrojové kódy

feat:页面loading,table操作按钮修改。

ljc před 2 měsíci
rodič
revize
6e057f9063

+ 36 - 2
components/cwg-detail-popup.vue

@@ -11,7 +11,15 @@
                     <cwg-label-line-value v-for="(item, index) in columns" :key="index" :label="item.label">
                         <template #operation1>
                             <slot :name="`cell-${item.prop}`" :row="row" :column="item" :index="index">
-                                <text>{{ formatCellValue(row[item.prop], item, row) }}</text>
+                                <view v-if="item.type === 'action'" class="action-list">
+                                    <template v-for="(actionItem, idx) in getVisibleActions(item.menuList, row)" :key="idx">
+                                        <text class="action-btn" 
+                                              @click.stop="actionItem.btnClick && actionItem.btnClick(row)">
+                                            {{ actionItem.label || actionItem.text || actionItem.name }}
+                                        </text>
+                                    </template>
+                                </view>
+                                <text v-else>{{ formatCellValue(row[item.prop], item, row) }}</text>
                             </slot>
                         </template>
 
@@ -49,7 +57,16 @@ const visible = computed({
     get: () => props.visible,
     set: (value) => emit('update:visible', value)
 });
-// 格式化单元格值(与表格组件保持一致的逻辑,可以提取成公共工具函数)
+// 过滤并获取允许显示的 action 按钮
+const getVisibleActions = (menuList, rowData) => {
+    if (!menuList) return []
+    return menuList.filter(item => {
+        if (typeof item.show === 'function') {
+            return item.show(rowData) !== false
+        }
+        return item.show !== false
+    })
+}
 const formatCellValue = (value, column, row) => {
     if (column.formatter) {
         return column.formatter({ value, row })
@@ -85,6 +102,23 @@ const formatDate = (date, format) => {
 <style scoped lang="scss">
 @import "@/uni.scss";
 
+.action-list {
+    display: flex;
+    flex-direction: column;
+    flex-wrap: wrap;
+    gap: 6px 10px;
+    align-items: flex-end;
+    justify-content: flex-end;
+}
+
+.action-btn {
+    color: var(--color-primary);
+    text-decoration: underline;
+    cursor: pointer;
+    font-size: 14px;
+    white-space: nowrap;
+}
+
 :deep(.uni-popup) {
     z-index: 101;
 }

+ 2 - 2
components/cwg-dropdown.vue

@@ -17,8 +17,8 @@
                 </slot>
             </view>
         </view>
-        <view class="cwg-dropdown-mask" :class="{ 'cwg-dropdown-mask-show': maskShow }" @touchmove.prevent="() => { }"
-            @click="close" />
+        <view class="cwg-dropdown-mask" :class="{ 'cwg-dropdown-mask-show': maskShow }"
+            @click.stop="close" />
     </view>
 </template>
 

+ 128 - 22
components/cwg-tabel.vue

@@ -38,6 +38,22 @@
                             <view v-else-if="column.type === 'note'">
                                 <text>{{ getNoteText(row, locale, userStore) }}</text>
                             </view>
+                            <view v-else-if="column.type === 'action'" class="action-wrapper">
+                                <view class="action-list">
+                                    <template v-for="(item, idx) in getVisibleActions(column.menuList, row)" :key="idx">
+                                        <text v-if="actionExpanded[`${rowIndex}-${column.prop}`] || idx < 2"
+                                              class="action-btn"
+                                              @click.stop="item.btnClick && item.btnClick(row)">
+                                            {{ item.label || item.text || item.name }}
+                                        </text>
+                                    </template>
+                                    <text v-if="getVisibleActions(column.menuList, row).length > 2"
+                                          class="action-toggle-btn"
+                                          @click.stop="toggleAction(rowIndex, column.prop)">
+                                        {{ actionExpanded[`${rowIndex}-${column.prop}`] ? '隐藏' : '更多' }}
+                                    </text>
+                                </view>
+                            </view>
                             <cwg-icon v-else-if="column.type === 'more'" name="crm-chevron-down"
                                 class="crm-chevron-down" :size="16" color="#007" />
                             <template v-else>
@@ -58,7 +74,7 @@
                 </template>
 
                 <!-- 总计行 -->
-                <uni-tr v-if="showSummary" class="summary-row">
+                <uni-tr v-if="showSummary &&tableData.length !== 0" class="summary-row">
                     <uni-td v-for="(column, index) in displayColumns" :key="'summary-' + column.prop"
                         :align="column.align || 'center'" class="summary-cell"
                         :style="getCellStyle(column, currentSummaryData)">
@@ -96,10 +112,10 @@
         <view class="table-loading-mask">
             <uni-loading v-if="loading" />
         </view>
-        <!-- 空状态 -->
-        <view v-if="!loading && tableData.length === 0">
-            <cwg-empty-state />
-        </view>
+      <!-- 空状态 -->
+      <view v-if="!loading && tableData.length === 0" style="width: 100%;">
+        <cwg-empty-state />
+      </view>
         <!-- 分页 -->
         <view class="pagination-container" v-if="showPagination && tableData.length > 0">
             <!-- <view class="pagination-info">
@@ -168,6 +184,7 @@ const props = defineProps({
      * - 'file': 使用 cwg-file 渲染
      * - 'more': 展示“更多”图标(用于移动端点击查看详情等)
      * - 'date': 日期格式化(搭配 dateFormat)
+     * - 'action': 操作按钮
      * - tagMap: 标签映射对象
      * - tagTypeMap: 标签类型映射对象
      * - dateFormat: 日期格式
@@ -264,6 +281,22 @@ const isMobile = ref(false)
 // 排序状态
 const sortState = ref({ prop: '', order: '' }) // order: 'asc' | 'desc' | ''
 
+// action 列的状态
+const actionExpanded = ref({})
+const getVisibleActions = (menuList, row) => {
+    if (!menuList) return []
+    return menuList.filter(item => {
+        if (typeof item.show === 'function') {
+            return item.show(row) !== false
+        }
+        return item.show !== false
+    })
+}
+const toggleAction = (rowIndex, prop) => {
+    const key = `${rowIndex}-${prop}`
+    actionExpanded.value[key] = !actionExpanded.value[key]
+}
+
 // ========== 计算属性 ==========
 // 显示的列(根据设备类型)
 const displayColumns = computed(() => {
@@ -351,7 +384,7 @@ const getCellStyle = (column, row) => {
         style.minWidth = w
         style.maxWidth = w
         style.wordBreak = 'break-all'
-        
+
         // 如果是自定义插槽,允许内容换行或由内部元素自己控制溢出,不强制隐藏
         if (column.slot) {
             style.whiteSpace = 'normal'
@@ -362,6 +395,11 @@ const getCellStyle = (column, row) => {
             style.overflow = 'hidden'
             style.textOverflow = 'ellipsis'
         }
+    } else {
+        // 如果没有定宽,保证默认情况下单元格内容不会被直接 hidden 切掉下拉弹窗
+        if (column.slot) {
+            style.overflow = 'visible'
+        }
     }
     if (column.cellStyle) {
         if (typeof column.cellStyle === 'function') {
@@ -481,9 +519,9 @@ const openRowDetail = (row) => {
     if (props.isPages) {
         emit('go-pages', row)
     } else {
-        // 保存当前行和需要显示的列(有 prop 且有 label)
+        // 保存当前行和需要显示的列(有 prop 且有 label) pc 详情不展示操作按钮
         detailRow.value = { ...row, note: getNoteText(row, locale.value, userStore) }
-        detailColumns.value = props.columns.filter(col => col && col.prop && col.label)
+        detailColumns.value = !isMobile.value ? props.columns.filter(col => col && col.prop && col.label &&  col.type !== 'action') : props.columns.filter(col => col && col.prop && col.label)
         detailVisible.value = true
     }
 }
@@ -684,6 +722,7 @@ defineExpose({
     width: 100%;
     // overflow-x: auto;
     // -webkit-overflow-scrolling: touch;
+    margin-top: px2rpx(20);
     max-height: calc(100vh - 209px);
     color: var(--color-slate-800);
 
@@ -699,19 +738,43 @@ defineExpose({
     :deep(.uni-table-scroll) {
         width: 100%;
         max-height: calc(100vh - 375px);
-        /* 当只有一条数据时,下拉菜单或弹窗会溢出,因此需设为可见 */
-        overflow: visible !important;
+        //min-height: 300px;
+        overflow-y: auto;
+        overflow-x: auto;
+
+        /* 强制显示滚动条并美化 */
+        &::-webkit-scrollbar {
+            width: 8px;
+            height: 8px;
+            display: block; /* 强制在某些webkit浏览器中显示 */
+            background-color: transparent;
+        }
+        &::-webkit-scrollbar-track {
+            background-color: #f5f5f5;
+            border-radius: 4px;
+        }
+        &::-webkit-scrollbar-thumb {
+            background-color: #c0c4cc;
+            border-radius: 4px;
+
+            &:hover {
+                background-color: #909399;
+            }
+        }
     }
 
     :deep(.uni-table) {
-        min-height: px2rpx(200) !important;
-        overflow: visible !important;
+        border-radius: 8px;
+        box-shadow: 0 1px 4px rgba(0,0,0,0.02);
 
         .uni-table-th {
             position: sticky;
             top: 0;
             z-index: 100;
             transition: all 0.3s;
+            background-color: #fafafa !important;
+            border-bottom: 1px solid #ebeef5 !important;
+            color: #606266;
 
             .header-content {
                 display: flex;
@@ -739,12 +802,15 @@ defineExpose({
         }
 
         .uni-table-tr {
-            &:last-child {
-                border-bottom: none !important;
+            transition: background-color 0.2s ease;
+            border-bottom: 1px solid #ebeef5 !important;
+
+            &:hover {
+                background-color: #f5f7fa !important;
             }
 
-            .uni-table-th {
-                border-bottom: 1px solid #141d22 !important;
+            &:last-child {
+                border-bottom: none !important;
             }
         }
 
@@ -761,13 +827,50 @@ defineExpose({
             }
         }
 
-        .uni-table-th,
         .uni-table-td {
             padding: px2rpx(16) px2rpx(5);
-            color: var(--color-slate-800);
+            color: #303133;
+            box-sizing: border-box;
+            vertical-align: middle;
+            font-size: 14px;
+            white-space: nowrap;
+        }
+
+        .uni-table-th {
+            padding: px2rpx(14) px2rpx(5);
             box-sizing: border-box;
-            /* 保证只有一条数据时,插槽弹窗不会被父元素裁剪 */
-            overflow: visible !important;
+            vertical-align: middle;
+            font-size: 14px;
+            white-space: nowrap;
+            word-break: keep-all;
+        }
+
+
+        .action-wrapper {
+            max-width: 180px;
+            white-space: normal;
+        }
+
+        .action-list {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 6px 5px;
+            align-items: center;
+        }
+
+        .action-btn {
+            color: var(--color-primary);
+            text-decoration: underline;
+            cursor: pointer;
+            font-size: px2rpx(12);
+            white-space: nowrap;
+        }
+
+        .action-toggle-btn {
+            color: #909399;
+            cursor: pointer;
+            font-size: px2rpx(12);
+            white-space: nowrap;
         }
 
         .expand-cell {
@@ -794,16 +897,19 @@ defineExpose({
 
 /* 分页样式 */
 .pagination-container {
-    margin: px2rpx(20) px2rpx(20);
+    margin: px2rpx(20) 0;
     display: flex;
     align-items: center;
     justify-content: flex-end;
     gap: px2rpx(20);
+    position: relative;
+    z-index: 10;
+    background-color: transparent;
 
     .pagination {
         display: flex;
         align-items: center;
-        padding: px2rpx(10);
+        //padding: px2rpx(10);
     }
 
     .page-item {

+ 9 - 19
pages/ib/agentList.vue

@@ -20,13 +20,6 @@
         :show-operation="true"
         :showPagination="true"
       >
-        <template #action="{ row }">
-          <cwg-dropdown :menu-list="menuList(row)" @menuClick="handleMenuClick">
-            <view class="pc-header-btn">
-              <cwg-icon name="crm-ellipsis" :size="24" />
-            </view>
-          </cwg-dropdown>
-        </template>
       </cwg-tabel>
     </view>
 
@@ -162,8 +155,16 @@
     {
       prop: 'action',
       label: t('Label.Action'),
+      type: 'action',
       align: 'center',
-      slot: 'action',
+      menuList: [
+        {
+          label: t('Ib.Custom.Btn'),
+          type: 'DisplaySettings',
+          btnClick: (row) => handleMenuClick({ type: 'DisplaySettings', row }),
+          show: (row) => row.agentUpdatePurview == '1',
+        },
+      ]
     },
   ])
 
@@ -198,17 +199,6 @@
     search.value.endDate = val[1]
   }
 
-  // 下拉菜单配置
-  const menuList = (row) => {
-    return [
-      {
-        label: t('Ib.Custom.Btn'),
-        type: 'DisplaySettings',
-        row,
-        show: row.agentUpdatePurview == '1',
-      },
-    ].filter((item) => item.show)
-  }
   const handleMenuClick = (item) => {
     if (item.type == 'DisplaySettings') {
       const { dealLogin, id,permissionDisplay,pIbNo,agentDistributionRatio} = item.row

+ 2 - 2
pages/ib/components/pointDialog.vue

@@ -8,7 +8,7 @@
       <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" color="#000"></cwg-icon>
+            <cwg-icon name="crm-option" :size="22" color="#000"></cwg-icon>
             {{ t('Ib.Index.Spread5') }}
           </view>
           <view class="account-type-grid">
@@ -303,7 +303,7 @@
     align-items: center;
     margin-bottom: px2rpx(15);
     font-weight: bold;
-    font-size: px2rpx(14);
+    font-size: px2rpx(18);
   }
 
   .section-title i {

+ 44 - 16
pages/ib/customer.vue

@@ -69,20 +69,29 @@
         :show-operation="true"
         :showPagination="true"
       >
-        <template #action="{ row }">
-          <view class="action-btn">
-            <cwg-dropdown :menu-list="menuList(row)" @menuClick="handleMenuClick">
-              <view class="pc-header-btn">
-                <cwg-icon name="crm-ellipsis" :size="24" color="#000"/>
-              </view>
-            </cwg-dropdown>
-          </view>
+        <template #documentary="{ row }">
+          <button class="action-btn" @click.stop="handleMenuClick({type: 'documentary', row})">
+            {{ t('Documentary.AgentBackground.item1') }}
+          </button>
+        </template>
+        <template #applyIb="{ row }">
+          <button v-if="row.ibStatus == 1 && row.belongsType != 1" class="action-btn"
+                  @click.stop="handleMenuClick({type: 'applyIb', row})">{{ t('Home.msg.ibTitle') }}
+          </button>
+          <view v-else>--</view>
+        </template>
+        <template #Point="{ row }">
+          <button v-if="row.belongsType != 1" class="action-btn" @click.stop="handleMenuClick({type: 'Point', row})">
+            {{ t('Home.msg.ibTitle') }}
+          </button>
+          <view v-else>--</view>
         </template>
       </cwg-tabel>
       <!-- 跟单全局设置     -->
       <DocumentaryDialog :visible="docVisible" :detail="formInfoRow" @close="closeDoc" @confirm="confirmDoc" />
       <!-- 开户调整     -->
       <PointDialog :visible="pointVisible" :detail="pointForm" @close="closePoint" @confirm="confirmPoint" />
+      <!-- 申请成为代理     -->
       <ApplyIbDialog :visible="applyVisible" :detail="applyForm" @close="closeApply" @confirm="confirmApply" />
     </view>
   </cwg-page-wrapper>
@@ -183,8 +192,28 @@
     {
       prop: 'action',
       label: t('Label.Action'),
+      type: 'action',
       align: 'center',
-      slot: 'action',
+      menuList: [
+        {
+          label: t('Documentary.AgentBackground.item1'),
+          type: 'documentary',
+          btnClick:(row)=>handleMenuClick({type: 'documentary', row}),
+          show: true,
+        },
+        {
+          label: t('Home.msg.ibTitle'),
+          type: 'applyIb',
+          btnClick:(row)=>handleMenuClick({type: 'applyIb', row}),
+          show: (row)=>row.ibStatus == 1 && row.belongsType != 1,
+        },
+        {
+          label: t('Ib.Custom.AccountAdjust'),
+          type: 'Point',
+          btnClick:(row)=>handleMenuClick({type: 'Point', row}),
+          show: (row)=>row.belongsType != 1,
+        },
+      ]
     },
   ])
 
@@ -276,18 +305,17 @@
     ].filter((item) => item.show)
   }
   const handleMenuClick = (item) => {
-    const { value } = item
-    if (value.type == 'documentary') {
-      const { cId, id, permissionDisplay } = value.row
+    if (item.type == 'documentary') {
+      const { cId, id, permissionDisplay } = item.row
       formInfoRow.value = {
         cId, id, permissionDisplay,
       }
       docVisible.value = true
-    } else if (value.type == 'applyIb') {
-      applyForm.value = value.row
+    } else if (item.type == 'applyIb') {
+      applyForm.value = item.row
       applyVisible.value = true
-    } else if (value.type == 'Point') {
-      const { cId, id, comPoint1, hide1 } = value.row
+    } else if (item.type == 'Point') {
+      const { cId, id, comPoint1, hide1 } = item.row
       pointForm.value = {
         cId, id, comPoint1, hide1,
       }

+ 3 - 2
pages/ib/index.vue

@@ -1,7 +1,8 @@
 <template>
   <cwg-page-wrapper class="create-page" :isHeaderFixed="true" :bgColor="'#f8f9f9'">
     <cwg-header :title="t('Home.page_ib.item1')" :showBack="false" />
-    <uni-row class="demo-uni-row uni-row1">
+    <uni-loading v-if="loading" />
+    <uni-row v-else class="demo-uni-row uni-row1">
       <uni-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
         <view class="dashboard-container">
           <!-- 余额卡片 -->
@@ -390,7 +391,7 @@
         </uni-forms>
       </view>
     </cwg-popup>
-    <uni-loading v-if="loading" />
+
   </cwg-page-wrapper>
 </template>
 

+ 38 - 31
pages/ib/recording.vue

@@ -22,14 +22,6 @@
         :show-operation="true"
         :showPagination="true"
       >
-        <template #approveDesc="{row}">
-          <text v-if="reasons[row.approveDesc]">
-            {{
-              isZh ? reasons[row.approveDesc].content : reasons[row.approveDesc].enContent
-            }}
-          </text>
-          <text v-else>{{ row.approveDesc }}</text>
-        </template>
         <template #remitChannelName="{row}">
           <text>
             {{
@@ -79,7 +71,6 @@
   const { numberFormat, numberDecimal } = useFilters()
   const { t, locale } = useI18n()
   const { columnList, mobileList, apiList } = useRecordingConst()
-  const reasons = ref({})
   let { Code } = Config
   const typeList = computed(() => [
     { text: t('Ib.Recording.NewAccount'), value: 1 },
@@ -97,11 +88,33 @@
     { text: t('Ib.Transfer.IbAccountTransfer'), value: 13 },
   ])
 
+  const getCurrentMonthRange = () => {
+    const now = new Date()
+    const year = now.getFullYear()
+    const month = now.getMonth()
+    
+    // 第一天
+    const firstDay = new Date(year, month, 1)
+    // 最后一天
+    const lastDay = new Date(year, month + 1, 0)
+    
+    const format = (date) => {
+      const y = date.getFullYear()
+      const m = String(date.getMonth() + 1).padStart(2, '0')
+      const d = String(date.getDate()).padStart(2, '0')
+      return `${y}-${m}-${d}`
+    }
+    
+    return [format(firstDay), format(lastDay)]
+  }
+
+  const defaultDateRange = getCurrentMonthRange()
+
   const search = ref({
     types: 1,
-    date: '',
-    startDate: '',
-    endDate: '',
+    date: defaultDateRange,
+    startDate: defaultDateRange[0],
+    endDate: defaultDateRange[1],
   })
   const isZh = computed(() => {
     return ['cn', 'zhHant'].indexOf(locale.value) != -1
@@ -127,26 +140,16 @@
   const listApi = computed(() => {
     return search.value.types == 4? (params)=> ibApi[apiList.value[search.value.types]]({ ...params ,type: 4}): (params)=> ibApi[apiList.value[search.value.types]]({ ...params })
   })
-  //获取原因列表
-  const searchReasons = async () => {
-    let res = await customApi.reasonsRefusalList({ type: null })
-    if (res.code == Code.StatusOK) {
-      if (res.data == null) {
-        reasons.value = {}
-      } else {
-        reasons.value = res.data
-      }
-    } else {
-      uni.showToast({
-        title: res.msg,
-        icon: 'none',
-      })
-    }
-  }
+
 
   const handleDateChange = (val) => {
-    search.value.startDate = val[0]
-    search.value.endDate = val[1]
+    if (val && val.length === 2) {
+      search.value.startDate = val[0]
+      search.value.endDate = val[1]
+    } else {
+      search.value.startDate = ''
+      search.value.endDate = ''
+    }
   }
   const cancel = async (id) => {
     try {
@@ -174,7 +177,7 @@
   }
 
   onMounted(() => {
-    searchReasons()
+
   })
 </script>
 <style lang="scss" scoped>
@@ -183,5 +186,9 @@
   .search-content {
     display: flex;
     justify-content: space-between;
+    .uni-date {
+      width: px2rpx(250) !important;
+      flex: none;
+    }
   }
 </style>

+ 21 - 34
pages/ib/subsList.vue

@@ -44,15 +44,6 @@
         :show-operation="true"
         :showPagination="true"
       >
-        <template #action="{ row }">
-          <view style="display: flex; justify-content: center;">
-            <cwg-dropdown :menu-list="menuList(row)" @menuClick="handleMenuClick">
-              <view class="pc-header-btn">
-                <cwg-icon name="crm-ellipsis" :size="24" color="#000"/>
-              </view>
-            </cwg-dropdown>
-          </view>
-        </template>
       </cwg-tabel>
     </view>
     <ApplyIbDialog ref="applyIbDialogRef" :visible="applyVisible" @close="closeApplyIb" @confirm="confirmApply"
@@ -134,7 +125,7 @@
   })
   const exclusiveRow = ref<any>(null)
   // 表格列配置
-  const columns = ref([
+  const columns = computed(() => [
     {
       prop: 'cId',
       label: t('Label.CidAccount'),
@@ -173,12 +164,26 @@
     {
       prop: 'action',
       label: t('Label.Action'),
+      type: 'action',
       align: 'center',
-      slot: 'action',
+      menuList: [
+        {
+          label: t('Ib.Custom.Commit3'),
+          type: 'vietnamDistribution',
+          btnClick: (row) => handleMenuClick({ type: 'vietnamDistribution', row }),
+          show: true,
+        },
+        {
+          label: t('Ib.Custom.Commit5'),
+          type: 'exclusiveCommission',
+          btnClick: (row) => handleMenuClick({ type: 'exclusiveCommission', row }),
+          show: (row) => row.exclusiveCommissionOptions?.length > 0,
+        },
+      ]
     },
   ])
 
-  const mobilePrimaryFields = ref([
+  const mobilePrimaryFields = computed(() => [
     {
       prop: 'cId',
       label: t('Label.CidAccount'),
@@ -239,35 +244,17 @@
   onMounted(() => {
     // applyVisible.value = true
   })
-  // 下拉菜单配置
-  const menuList = (row) => {
-    return [
-      {
-        label: t('Ib.Custom.Commit3'),
-        type: 'vietnamDistribution',
-        row,
-        show: true,
-      },
-      {
-        label: t('Ib.Custom.Commit5'),
-        type: 'exclusiveCommission',
-        row,
-        show: row.exclusiveCommissionOptions?.length > 0,
-      },
-    ].filter((item) => item.show)
-  }
   const handleMenuClick = (item) => {
-    const { value } = item
-    if (value.type == 'vietnamDistribution') {
-      const { agentId, id } = value.row
+    if (item.type == 'vietnamDistribution') {
+      const { agentId, id } = item.row
       applyDetail.value = {
         id: id || agentId,
       }
       formDia.value = false
       applyType.value = 'vietnam'
       applyVisible.value = true
-    } else if (value.type == 'exclusiveCommission') {
-      openExclusiveCommission(value.row)
+    } else if (item.type == 'exclusiveCommission') {
+      openExclusiveCommission(item.row)
     }
   }
   const addSub = () => {

+ 8 - 3
pages/mine/components/PersonalInfoTab.vue

@@ -1,6 +1,7 @@
 <template>
   <view class="personal-info-tab">
-    <view class="user-form">
+    <uni-loading v-if="loading" />
+    <view v-else class="user-form">
       <uni-row class="demo-uni-row">
         <!--                <uni-col :xs="24" :sm="24" :md="24" :lg="6" :xl="6">-->
         <!--                    <view class="avatar-section">-->
@@ -243,6 +244,8 @@
     'next': [];
   }>()
 
+  const loading = ref(false)
+
   const formData = computed({
     get: () => props.modelValue,
     set: (val) => emit('update:modelValue', val),
@@ -453,8 +456,10 @@
     emit('next')
   }
 
-  onMounted(() => {
-    getCountry()
+  onMounted(async () => {
+    loading.value = true
+    await getCountry()
+    loading.value = false
   })
 </script>