diff --git a/src/components/common/Table.vue b/src/components/common/Table.vue
index c0928ba..0f12c14 100644
--- a/src/components/common/Table.vue
+++ b/src/components/common/Table.vue
@@ -12,7 +12,12 @@
v-bind="$attrs"
@row-click="handleRowClick"
@row-contextmenu="handleRowContextmenu"
+ @selection-change="handleSelectionChange"
+ @current-change="handleCurrentChange"
>
+
+
+
+ >
+
+ {{ formatDecimalTruncate(row[column.prop]) }}
+
+
import { ref, watch } from 'vue'
import type { TableInstance } from 'element-plus'
+import { formatDecimalTruncate } from '@/utils/formatDecimal'
// 定义表格列配置接口
interface TableColumn {
@@ -60,6 +70,7 @@ interface TableColumn {
align?: 'left' | 'center' | 'right'
slotName?: string // 具名插槽名称
sortable?: boolean // 是否可排序
+ isNumber?: boolean // 是否为数字类型(自动截取小数位)
}
// 定义表格组件属性接口
@@ -73,20 +84,38 @@ interface Props {
border?: boolean // 是否显示边框
highlightCurrentRow?: boolean // 是否高亮当前行
loading?: boolean // 是否显示加载状态
+ showSelection?: boolean // 是否显示勾选列
}
const props = withDefaults(defineProps(), {
border: true,
highlightCurrentRow: true,
loading: false,
+ showSelection: false,
})
// 定义组件抛出的事件
const emit = defineEmits<{
(e: 'row-click', row: any): void // 保留原有行点击事件
(e: 'row-contextmenu', row: any, column: any, event: MouseEvent): void
+ (e: 'selection-change', rows: any[]): void // 勾选变化事件
+ (e: 'current-change', row: any): void // 当前行变化事件
}>()
+// 处理勾选变化
+const handleSelectionChange = (rows: any[]) => {
+ emit('selection-change', rows)
+}
+
+// 处理当前行变化
+const handleCurrentChange = (row: any) => {
+ // 添加空值保护,避免传递 null 导致 Vue 响应式系统报错
+ if (row === null || row === undefined) {
+ return
+ }
+ emit('current-change', row)
+}
+
const tableRef = ref()
// 维护当前选中行状态,用于二次点击取消选中
@@ -103,7 +132,7 @@ const handleRowClick = (row: any) => {
if (selectedRow.value && selectedRow.value === row) {
// 二次点击:取消选中
selectedRow.value = null
- tableRef.value?.setCurrentRow() // 不传参即清除选中 [^14^]
+ tableRef.value?.setCurrentRow(null) // 传 null 清除选中
} else {
// 首次点击或点击不同行:选中该行
selectedRow.value = row
@@ -127,16 +156,29 @@ watch(
() => {
// 数据更新时,清除选中状态
selectedRow.value = null
- tableRef.value?.setCurrentRow() // 不传参即清除选中 [^14^]
+ tableRef.value?.setCurrentRow(null)
},
{ deep: true }, // 深度监听,防止数组元素变化未触发
)
+// 监听 loading 属性变化,确保状态同步
+watch(
+ () => props.loading,
+ (newVal) => {
+ // loading 状态变化时可以执行额外的处理
+ console.log('Table loading status changed:', newVal)
+ },
+ { flush: 'sync' }, // 使用 sync 模式确保即时响应
+)
+
// 暴露清除当前选中行的方法
defineExpose({
clearCurrentRow: () => {
selectedRow.value = null
- tableRef.value?.setCurrentRow()
+ tableRef.value?.setCurrentRow(null)
+ },
+ setCurrentRow: (row: any) => {
+ tableRef.value?.setCurrentRow(row)
},
})
diff --git a/src/utils/formatDecimal.ts b/src/utils/formatDecimal.ts
new file mode 100644
index 0000000..de798cc
--- /dev/null
+++ b/src/utils/formatDecimal.ts
@@ -0,0 +1,46 @@
+/**
+ * @description: 金额格式化工具函数
+ */
+
+/**
+ * @description: 截取数字到小数点后指定位数(不四舍五入)
+ * @param value 需要格式化的值
+ * @param decimals 保留的小数位数,默认2位
+ * @returns 格式化后的字符串或数字
+ */
+export function formatDecimalTruncate(value: string | number | null | undefined, decimals: number = 2): string | number {
+ // 处理空值
+ if (value === null || value === undefined || value === '') {
+ return value ?? ''
+ }
+
+ // 转换为字符串检查原始格式
+ const originalStr = String(value)
+
+ // 转换为数字检查是否有效
+ const num = Number(value)
+
+ // 如果不是有效数字,返回原值
+ if (isNaN(num)) {
+ return value
+ }
+
+ // 分割整数和小数部分
+ const dotIndex = originalStr.indexOf('.')
+
+ // 如果没有小数点,添加小数位后返回
+ if (dotIndex === -1) {
+ return `${originalStr}.${'0'.repeat(decimals)}`
+ }
+
+ const integerPart = originalStr.substring(0, dotIndex)
+ const decimalPart = originalStr.substring(dotIndex + 1)
+
+ // 截取到指定小数位(不四舍五入)
+ const truncatedDecimal = decimalPart.substring(0, decimals)
+
+ // 补齐小数位到指定位数
+ const paddedDecimal = truncatedDecimal.padEnd(decimals, '0')
+
+ return `${integerPart}.${paddedDecimal}`
+}
\ No newline at end of file
diff --git a/src/views/capital/fundFlow/options.ts b/src/views/capital/fundFlow/options.ts
index d75fc45..2068a3e 100644
--- a/src/views/capital/fundFlow/options.ts
+++ b/src/views/capital/fundFlow/options.ts
@@ -62,9 +62,9 @@ export const tableColumns = [
//资金流向
// { prop: 'fundDirection', label: '资金流向' },
//原有金额
- { prop: 'amount', label: '变动金额' },
+ { prop: 'amount', label: '变动金额', isNumber: true },
//余额变动
- { prop: 'balance', label: '变动后余额' },
+ { prop: 'balance', label: '变动后余额' , isNumber: true},
//现有余额
// { prop: 'currentBalance', label: '现有余额' },
//状态
diff --git a/src/views/capital/rechange/options.ts b/src/views/capital/rechange/options.ts
index 2cd2b6b..adc1747 100644
--- a/src/views/capital/rechange/options.ts
+++ b/src/views/capital/rechange/options.ts
@@ -6,6 +6,6 @@ export const rechangeTableColumns = [
label: '支持货币',
align: 'center' as const
},
- { prop: 'channel_fee', label: '渠道费用', align: 'center' as const },
+ { prop: 'channel_fee', label: '渠道费用', align: 'center' as const , isNumber: true },
{ label: '操作', slotName: 'action', align: 'center' as const, width: 120 },
]
diff --git a/src/views/capital/rechangeChanl/options.ts b/src/views/capital/rechangeChanl/options.ts
index 017288a..2b7ba4e 100644
--- a/src/views/capital/rechangeChanl/options.ts
+++ b/src/views/capital/rechangeChanl/options.ts
@@ -4,7 +4,7 @@ export const tableColumns = [
//存款渠道名称
{ label: '渠道名称', prop: 'name' },
//存款渠道费用
- { label: '渠道费用', prop: 'channel_fee' },
+ { label: '渠道费用', prop: 'channel_fee', isNumber: true },
//存款渠道类型
{ label: '入金货币', prop: 'currency.symbol' },
// 接口地址
diff --git a/src/views/capital/rechangeCheck/index.vue b/src/views/capital/rechangeCheck/index.vue
index d1d3f4a..cc2f6bd 100644
--- a/src/views/capital/rechangeCheck/index.vue
+++ b/src/views/capital/rechangeCheck/index.vue
@@ -19,36 +19,16 @@
-
-
-
-
-
-
-
- {{ (currentPage - 1) * pageSize + scope.$index + 1 }}
-
-
-
-
-
-
+
+
通过
- 驳回
+ 驳回
-
-
-
-
-
-
-
-
-
- {{ (currentPage - 1) * pageSize + scope.$index + 1 }}
-
-
-
-
-
-
-
+
+
-
+
@@ -35,6 +36,10 @@ import { search, tableColumns } from './options'
import { useTransactionStore } from '@/stores/modules/transaction.ts'
import { useOrderPositionStore } from '@/stores/modules/orderPosition.ts'
+import { usePageLoading } from '@/composables/useLoading'
+
+// 按钮 loading
+const { loading, startLoading, stopLoading } = usePageLoading()
// 导出表格
import { exportToExcel } from '@/utils/exportToExcel'
@@ -57,7 +62,9 @@ const tableColumnsOptions = ref(tableColumns)
* @description: 定义搜索方法
*/
const handleSearch = async () => {
+ startLoading()
const data = await checkAccountIdIsSonForUser({ account_id: searchForm.value.account_id })
+ stopLoading()
if (!data.flag) {
return ElMessage.warning('请输入下级ID')
}
diff --git a/src/views/order/position/options.ts b/src/views/order/position/options.ts
index 51fa3db..93cd04b 100644
--- a/src/views/order/position/options.ts
+++ b/src/views/order/position/options.ts
@@ -14,9 +14,9 @@ export const tableColumns = [
// 操作类型
{ prop: 'tradeType', label: '操作类型' },
// 金额
- { prop: 'amount', label: '金额' },
+ { prop: 'amount', label: '金额', isNumber: true },
// 交易数量
- { prop: 'tradeQty', label: '交易数量' },
+ { prop: 'tradeQty', label: '交易数量'},
// 交易时间
{ prop: 'tradeTime', label: '交易时间' },
// 浮动盈亏
diff --git a/src/views/order/rechange/options.ts b/src/views/order/rechange/options.ts
index 375cd5c..aa9b710 100644
--- a/src/views/order/rechange/options.ts
+++ b/src/views/order/rechange/options.ts
@@ -51,7 +51,7 @@ export const search = [
export const tableColumns = [
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
{ prop: 'currency', label: '充值币种', align: 'center' as const },
- { prop: 'amount', label: '金额', align: 'center' as const },
+ { prop: 'amount', label: '金额', align: 'center' as const, isNumber: true },
{ prop: 'statusText', label: '状态', align: 'center' as const },
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
{ prop: 'rechangeAccount', label: '充值账号', align: 'center' as const },
diff --git a/src/views/order/withdraw/options.ts b/src/views/order/withdraw/options.ts
index 9ba1635..1245400 100644
--- a/src/views/order/withdraw/options.ts
+++ b/src/views/order/withdraw/options.ts
@@ -31,7 +31,7 @@ export const search = [
export const tableColumns = [
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
{ prop: 'currency', label: '提现币种', align: 'center' as const },
- { prop: 'amount', label: '金额', align: 'center' as const },
+ { prop: 'amount', label: '金额', align: 'center' as const, isNumber: true },
{ prop: 'statusText', label: '状态', align: 'center' as const },
{ prop: 'withdrawTime', label: '提现时间', align: 'center' as const },
{ prop: 'withdrawAccount', label: '提现账号', align: 'center' as const },
diff --git a/src/views/profile/agent/options.ts b/src/views/profile/agent/options.ts
index 3e1321b..2ac7cfb 100644
--- a/src/views/profile/agent/options.ts
+++ b/src/views/profile/agent/options.ts
@@ -38,7 +38,7 @@ export const tableColumns = [
{ prop: 'role', label: '账号角色' },
// 账号数量
{ prop: 'accountQty', label: '账号数量' },
- { prop: 'wallet_capital.amount', label: '资金', align: 'center' as const },
+ { prop: 'wallet_capital.amount', label: '资金', align: 'center' as const, isNumber: true },
// 点差分配比例
{ prop: 'marginRatio', label: '点差分配比例', slotName: 'marginRatio' },
// 手续费分成比例
diff --git a/src/views/profile/business/options.ts b/src/views/profile/business/options.ts
index e701315..f0186ae 100644
--- a/src/views/profile/business/options.ts
+++ b/src/views/profile/business/options.ts
@@ -25,34 +25,35 @@ export const marketTableColumns = [
//基本账户
{ label: '基本账户', prop: 'basicAccount', align: 'center' as const, width: '200px' },
//保证金
- { label: '保证金', prop: 'margin', align: 'center' as const, width: '200px' },
+ { label: '保证金', prop: 'margin', align: 'center' as const, width: '200px', isNumber: true },
//停止接单保证金
- { label: '停止接单保证金', prop: 'stopOrderMargin', align: 'center' as const, width: '200px' },
+ { label: '停止接单保证金', prop: 'stopOrderMargin', align: 'center' as const, width: '200px', isNumber: true },
//持仓转移保证金
{
label: '持仓转移保证金',
prop: 'positionTransferMargin',
align: 'center' as const,
width: '200px',
+ isNumber: true,
},
//头寸比率
- { label: '头寸比率', prop: 'positionRatio', align: 'center' as const, width: '150px' },
+ { label: '头寸比率', prop: 'positionRatio', align: 'center' as const, width: '150px', isNumber: true },
//点差返佣
- { label: '点差返佣', prop: 'pointSpreadCommission', align: 'center' as const, width: '200px' },
+ { label: '点差返佣', prop: 'pointSpreadCommission', align: 'center' as const, width: '200px', isNumber: true },
//点差
{ label: '点差', slotName: 'pointSpread', align: 'center' as const, width: '150px' },
//手续费比例
- { label: '手续费比例', prop: 'commissionRatio', align: 'center' as const, width: '150px' },
+ { label: '手续费比例', prop: 'commissionRatio', align: 'center' as const, width: '150px', isNumber: true },
//手续费返佣
- { label: '手续费返佣', prop: 'commissionReturn', align: 'center' as const, width: '150px' },
+ { label: '手续费返佣', prop: 'commissionReturn', align: 'center' as const, width: '150px', isNumber: true },
//浮动盈亏
- { label: '浮动盈亏', prop: 'floatProfitLoss', align: 'center' as const, width: '100px' },
+ { label: '浮动盈亏', prop: 'floatProfitLoss', align: 'center' as const, width: '100px', isNumber: true },
//平仓盈亏
- { label: '平仓盈亏', prop: 'closeProfitLoss', align: 'center' as const, width: '150px' },
+ { label: '平仓盈亏', prop: 'closeProfitLoss', align: 'center' as const, width: '150px', isNumber: true },
//风险金
- { label: '风险金', prop: 'riskMargin', align: 'center' as const, width: '150px' },
+ { label: '风险金', prop: 'riskMargin', align: 'center' as const, width: '150px', isNumber: true },
//服务费
- { label: '服务费', prop: 'serviceFee', align: 'center' as const, width: '150px' },
+ { label: '服务费', prop: 'serviceFee', align: 'center' as const, width: '150px', isNumber: true },
]
//做市商添加配置
diff --git a/src/views/profile/user/options.ts b/src/views/profile/user/options.ts
index 74f9992..da61cbb 100644
--- a/src/views/profile/user/options.ts
+++ b/src/views/profile/user/options.ts
@@ -54,7 +54,7 @@ export const clientTableColumns = [
{ prop: 'username', label: '用户名', align: 'center' as const },
{ prop: 'createdTime', label: '注册时间', align: 'center' as const },
{ prop: 'agentUsername', label: '所属代理', align: 'center' as const },
- { prop: 'wallet_capital.amount', label: '资金', align: 'center' as const },
+ { prop: 'wallet_capital.amount', label: '资金', align: 'center' as const, isNumber: true },
{ label: '状态', slotName: 'status', align: 'center' as const },
{ label: '操作', slotName: 'action', align: 'center' as const },
]
diff --git a/src/views/trade/variety/options.ts b/src/views/trade/variety/options.ts
index f09f7fa..ea05ed2 100644
--- a/src/views/trade/variety/options.ts
+++ b/src/views/trade/variety/options.ts
@@ -33,9 +33,9 @@ export const tableColumns = [
// 交易分组
{ prop: 'tradeGroup', label: '交易分组', align: 'center' as const },
// 多头库存费
- { prop: 'longStockFee', label: '多头库存费', align: 'center' as const },
+ { prop: 'longStockFee', label: '多头库存费', align: 'center' as const, isNumber: true },
// 空头库存费
- { prop: 'shortStockFee', label: '空头库存费', align: 'center' as const },
+ { prop: 'shortStockFee', label: '空头库存费', align: 'center' as const, isNumber: true },
// 类型
{ prop: 'type', label: '类型', align: 'center' as const },
// 止盈水平
diff --git a/src/views/user/Login.vue b/src/views/user/Login.vue
index 03b3334..35a15bc 100644
--- a/src/views/user/Login.vue
+++ b/src/views/user/Login.vue
@@ -52,7 +52,7 @@
- 登录
+ 登录
没有账号?去注册
@@ -74,6 +74,7 @@ import UserTabs from './components/Tabs.vue'
//公共方法/store/配置文件
import { useUserStore } from '@/stores/modules/user'
+import { useButtonLoading } from '@/composables/useLoading'
import { setStorage, getStorage } from '@/utils/storage'
import { md5Encrypt } from '@/utils/crypto'
@@ -83,6 +84,9 @@ import { passwordRules, emailRules, phoneRules, codeRules } from './config/rules
const router = useRouter()
+// 按钮 loading
+const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
+
//userText 实例
const userText = ref({
backText: '',
@@ -179,19 +183,26 @@ const handleLogin = async () => {
else if (currentTab === 'password') {
// 校验密码+验证码
await loginFormRef.value.validateField(['password', 'code'])
- // 生成device_no并保存到变量(关键修改1)
- const deviceNo = generateTimestampWithRandomNum()
- // 登录参数
- const loginParams = {
- email: loginForm.value.email,
- mobile: loginForm.value.countryCode + loginForm.value.phone,
- login_type: getStorage('loginType', 'session') === 'email' ? 1 : 2,
- code: loginForm.value.code,
- password: loginForm.value.password,
- device_no: deviceNo,
+ // 开启 loading
+ startButtonLoading()
+ try {
+ // 生成device_no并保存到变量(关键修改1)
+ const deviceNo = generateTimestampWithRandomNum()
+ // 登录参数
+ const loginParams = {
+ email: loginForm.value.email,
+ mobile: loginForm.value.countryCode + loginForm.value.phone,
+ login_type: getStorage('loginType', 'session') === 'email' ? 1 : 2,
+ code: loginForm.value.code,
+ password: loginForm.value.password,
+ device_no: deviceNo,
+ }
+ await userStore.login(loginParams)
+ setStorage('device_no', deviceNo)
+ } finally {
+ // 关闭 loading
+ stopButtonLoading()
}
- await userStore.login(loginParams)
- setStorage('device_no', deviceNo)
}
} catch (error) {
console.error('表单校验失败:', error)
diff --git a/src/views/user/Register.vue b/src/views/user/Register.vue
index 2a47f99..caf405b 100644
--- a/src/views/user/Register.vue
+++ b/src/views/user/Register.vue
@@ -94,7 +94,7 @@
>
- 注册
+ 注册
已有账号?立即登录
@@ -118,6 +118,7 @@ import UserCaptcha from './components/Captcha.vue'
import { useUserStore } from '@/stores/modules/user'
import { md5Encrypt } from '@/utils/crypto'
import { sendCaptcha, initCaptchaState, clearCaptchaTimer } from '@/utils/sendCaptcha'
+import { useButtonLoading } from '@/composables/useLoading'
//用户校验规则
import { countryOptions } from '@/views/user/config/mock'
@@ -128,6 +129,9 @@ import { useRoute } from 'vue-router'
const userStore = useUserStore()
const route = useRoute()
+// 按钮 loading
+const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
+
// UserText 实例
const userText = ref({
backText: '',
@@ -215,19 +219,25 @@ const handleRegister = async () => {
try {
// 提交时再次验证(显示错误提示)
await registerFormRef.value.validate()
+ // 开启 loading
+ startButtonLoading()
+ try {
+ // 注册参数
+ const registerParams = {
+ email: registerForm.value.email,
+ mobile: registerForm.value.countryCode + registerForm.value.phone,
+ reg_type: activeTab.value === 'email' ? 1 : 2,
+ invite_code: registerForm.value.inviteCode,
+ code: registerForm.value.code,
+ password: registerForm.value.password,
+ }
- // 注册参数
- const registerParams = {
- email: registerForm.value.email,
- mobile: registerForm.value.countryCode + registerForm.value.phone,
- reg_type: activeTab.value === 'email' ? 1 : 2,
- invite_code: registerForm.value.inviteCode,
- code: registerForm.value.code,
- password: registerForm.value.password,
+ // 注册逻辑
+ await userStore.register(registerParams)
+ } finally {
+ // 关闭 loading
+ stopButtonLoading()
}
-
- // 注册逻辑
- await userStore.register(registerParams)
} catch (error) {
console.error('表单校验失败:', error)
}
@@ -239,7 +249,7 @@ onUnmounted(() => {
})
onMounted(() => {
- registerForm.value.inviteCode = route.query.invite_code
+ registerForm.value.inviteCode = route.query.invite_code || ''
})