AccountList.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <template>
  2. <view class="container">
  3. <view class="row">
  4. <view class="col-12">
  5. <view class="border-0 card-header">
  6. <view class="d-flex flex-wrap gap-3 align-items-center justify-content-between mb-3">
  7. <h3 class="mb-0" style="align-self: flex-start" v-t="'Custom.Index.AccountList'"></h3>
  8. <view type="button" class="btn btn-danger btn-shadow waves-effect cursor-pointer" @click="createAccount">
  9. <view class="d-flex align-items-center">
  10. <cwg-icon name="crm-plus" :size="14" color="#fff" />
  11. <text v-t="'Custom.Index.AddAccount'" />
  12. </view>
  13. </view>
  14. </view>
  15. </view>
  16. </view>
  17. <view class="col-lg-12">
  18. <view class="clearfix">
  19. <view class="card">
  20. <view class="card-header">
  21. <view class="nav nav-underline card-header-tabs">
  22. <view class="nav-item cwg-cursor cursor-pointer" v-for="(tab, index) in tabs" :key="index"
  23. @click="handleTabClick(tab.value)">
  24. <view class="nav-link" :class="{ 'active': tab.value === cativeIndex }">{{ tab.text
  25. }}
  26. </view>
  27. </view>
  28. </view>
  29. </view>
  30. <view class="card-body">
  31. <view class="tab-content">
  32. <view class="row mb-4">
  33. <view class="col-lg-4 col-md-6"><cwg-combox v-model:value="platformActive"
  34. :clearable="false" :options="platformOptions" /></view>
  35. </view>
  36. <view class="row">
  37. <AccountCard v-for="acc in accounts" :zhtype="cativeIndex" :key="acc.accountNumber"
  38. :account="acc" :is-grid-layout="isGridLayout" @action="handleAction"
  39. @copy="handleCopy" @change-password="handleChangePassword" />
  40. <view class="table-loading-mask">
  41. <uni-loading v-if="loading" />
  42. </view>
  43. <view v-if="!loading && accounts.length == 0" class="list-empty-state col-12">
  44. <cwg-empty-state />
  45. </view>
  46. <DeleteAccountDialogs ref="deleteAccountDialogRef"
  47. v-model:visible="deleteAccountDialogVisible" />
  48. <cwg-improve-popup v-model:visible="dialogCheck" @confirm="confirm" />
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. </template>
  58. <script setup lang="ts">
  59. import { computed, ref, onMounted, watch, onUnmounted } from 'vue';
  60. import { useI18n } from 'vue-i18n';
  61. const { t, locale } = useI18n();
  62. import useRouter from "@/hooks/useRouter";
  63. const router = useRouter();
  64. import { customApi } from '@/service/custom';
  65. import { userApi } from '@/api/user';
  66. import useUserStore from "@/stores/use-user-store";
  67. const userStore = useUserStore();
  68. import AccountCard from './AccountCard.vue'
  69. import DeleteAccountDialogs from './DeleteAccountDialogs.vue'
  70. import { useFilters } from '@/composables/useFilters'
  71. const { numberFormat, numberDecimal } = useFilters()
  72. const search = ref({ platform: 'MT4' })
  73. import useGlobalStore from '@/stores/use-global-store'
  74. const globalStore = useGlobalStore()
  75. const isDark = computed(() => globalStore.theme === 'dark')
  76. const isAfterJuly28 = () => {
  77. const now = new Date();
  78. const july28 = new Date(2025, 6, 28, 0, 0, 0); // 月份从0开始,所以7月是6
  79. return now >= july28;
  80. }
  81. const platformActive = ref('All')
  82. const platformOptions = computed(() => ([
  83. { value: 'All', text: t('State.All') },
  84. { value: 'MT4', text: 'MT4' },
  85. { value: 'MT5', text: 'MT5' },
  86. ]))
  87. const handleAction = (type) => { /* 处理交易/入金等 */ };
  88. const handleCopy = (text: string) => {
  89. uni.setClipboardData({
  90. data: text,
  91. success: function () {
  92. uni.showToast({
  93. title: t('Btn.item8'),
  94. icon: 'none',
  95. duration: 2000
  96. });
  97. }
  98. });
  99. }
  100. const handleChangePassword = () => { /* 跳转修改密码 */ };
  101. const typeMap = computed(() => ({
  102. 1: t('AccountType.ClassicAccount'),
  103. 2: t('AccountType.SeniorAccount'),
  104. 3: !isAfterJuly28() ? t('AccountType.AgencyAccount') : '',
  105. 5: t('AccountType.SpeedAccount'),
  106. 6: t('AccountType.SpeedAccount'),
  107. 7: t('AccountType.StandardAccount'),
  108. 8: t('AccountType.CentAccount')
  109. }));
  110. const cativeIndex = ref('real')
  111. const isGridLayout = ref(true)
  112. const tabs = computed(() => ([
  113. { value: 'real', text: t('vu.item1') },
  114. { value: 'demo', text: t('vu.item2') },
  115. { value: 'del', text: t('vu.account.item1') },
  116. ]))
  117. const toggleLayout = () => {
  118. isGridLayout.value = !isGridLayout.value
  119. }
  120. const tableRef = ref(null)
  121. const expanded = ref(null)
  122. const toggleRowExpand = (row) => {
  123. expanded.value = row.expanded ? row.rowIndex : null
  124. }
  125. const toggleExpand = (index) => {
  126. tableRef?.value.toggleRowExpand(index)
  127. }
  128. const createActionButtons = (row) => {
  129. console.log(row, 'row');
  130. return computed(() => [
  131. {
  132. icon: 'crm-circle-dollar-to-slot',
  133. text: t('Custom.Index.Deposit'),
  134. action: 'deposit',
  135. disabled: row.closeFunctions?.indexOf('1') !== -1,
  136. show: true,
  137. class: 'deposit-btn'
  138. },
  139. {
  140. icon: 'crm-credit-card',
  141. text: t('Custom.Index.Withdrawals'),
  142. action: 'withdraw',
  143. disabled: row.closeFunctions?.indexOf('2') !== -1,
  144. show: true,
  145. class: 'withdraw-btn'
  146. },
  147. {
  148. icon: 'crm-money-bill-transfer',
  149. text: t('Custom.Index.Transfer'),
  150. action: 'transfer',
  151. disabled: (
  152. row.closeFunctions?.indexOf('5') !== -1 ||
  153. row.closeFunctions?.indexOf('6') !== -1 ||
  154. row.closeFunctions?.indexOf('3') !== -1
  155. ),
  156. show: true,
  157. class: 'transfer-btn'
  158. },
  159. {
  160. icon: 'crm-gear',
  161. text: t('Custom.Index.Settings'),
  162. action: 'settings',
  163. disabled: row.closeFunctions?.indexOf('4') !== -1,
  164. show: true,
  165. class: 'settings-btn'
  166. },
  167. {
  168. icon: 'crm-award',
  169. text: t('standardRebate.item1'),
  170. action: 'standardRebate',
  171. disabled: false,
  172. show: row.type === 7,
  173. class: 'rebate-btn'
  174. }
  175. ])
  176. }
  177. // 处理按钮点击
  178. const handleActionBtn = (action, row) => {
  179. switch (action) {
  180. case 'deposit':
  181. toDeposit(row)
  182. break
  183. case 'withdraw':
  184. toWithdraw(row)
  185. break
  186. case 'transfer':
  187. toTransfer(row)
  188. break
  189. case 'settings':
  190. toSettings(row)
  191. break
  192. case 'standardRebate':
  193. toStandardRebate(row)
  194. break
  195. }
  196. }
  197. const deleteAccountDialogVisible = ref(false)
  198. const openDeleteAccountDialogs = () => {
  199. deleteAccountDialogVisible.value = true
  200. }
  201. const createAccount = () => {
  202. getCustomLoginInfo()
  203. }
  204. const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
  205. const loading = ref(false)
  206. let debounceTimer: ReturnType<typeof setTimeout> | null = null
  207. const handleTabClick = (value: string) => {
  208. if (loading.value) return
  209. if (debounceTimer) {
  210. clearTimeout(debounceTimer)
  211. }
  212. debounceTimer = setTimeout(() => {
  213. cativeIndex.value = value
  214. debounceTimer = null
  215. }, 200)
  216. }
  217. // 获取客户登录信息
  218. const dialogCheck = ref(false)
  219. async function getCustomLoginInfo() {
  220. try {
  221. const res = await userApi.getUserInfo();
  222. userStore.saveUserInfo(res.data);
  223. if (res.code === 200) {
  224. if (
  225. res.data.customInfo.status == 2 &&
  226. res.data.customInfo.applyRealStatus == 2
  227. ) {
  228. router.push(`/pages/customer/account-select?server=${cativeIndex.value}`)
  229. } else {
  230. dialogCheck.value = true;
  231. }
  232. }
  233. } catch (error) {
  234. // console.log(error, 111);
  235. }
  236. }
  237. const confirm = () => {
  238. dialogCheck.value = false;
  239. router.push(`/pages/mine/improveImmediately`)
  240. }
  241. const AccountList = ref([])
  242. const getAccountList = async () => {
  243. AccountList.value = []
  244. loading.value = true
  245. var api
  246. switch (cativeIndex.value) {
  247. case 'real':
  248. api = customApi.AccountAllList
  249. break;
  250. case 'demo':
  251. api = customApi.demoList
  252. break;
  253. case 'del':
  254. api = customApi.deleteAccountList
  255. break;
  256. }
  257. const res = await api({
  258. page: {
  259. current: 1,
  260. size: 100
  261. }
  262. })
  263. if (res.code === 200) {
  264. AccountList.value = res.data
  265. }
  266. loading.value = false
  267. }
  268. const groupCurrency1 = (type) => {
  269. if (type == "GBP") {
  270. return "£";
  271. } else if (type == "USD") {
  272. return "$";
  273. } else if (type == "EUR") {
  274. return "€";
  275. } else if (type == "USC") {
  276. return "¢";
  277. } else {
  278. return "$";
  279. }
  280. }
  281. // 格式化数值函数
  282. function formatMoney(value,currency) {
  283. if (value === null || value === undefined) value = 0;
  284. const sign = value >= 0 ? '' : '-';
  285. const absoluteValue = Math.abs(value);
  286. return groupCurrency1(currency) + sign + numberDecimal(absoluteValue);
  287. }
  288. // 转换数组
  289. const accounts = computed(() => {
  290. if (!AccountList.value || AccountList.value.length == 0) return []
  291. let filteredAccounts = AccountList.value
  292. if (platformActive.value !== 'All') {
  293. filteredAccounts = filteredAccounts.filter(acc =>
  294. (acc.platform || 'MT4') === platformActive.value
  295. )
  296. }
  297. return filteredAccounts.map((acc, index) => {
  298. const currency = acc.currency || 'USD';
  299. const floating = acc.floating ?? 0;
  300. let labels = [t('vu.item1'), 'MT4', 'Standard'];
  301. labels[0] = cativeIndex.value == 'demo' ? t('vu.item2') : t('vu.item1');
  302. labels[1] = acc.platform || 'MT4';
  303. labels[2] = typeMap.value[acc.type];
  304. let nickname = typeMap.value[acc.type];
  305. let fwq
  306. if (cativeIndex.value != 'demo') {
  307. fwq = acc.platform == 'MT4' ? 'CWGMarketsLtd-Live' : 'CWGMarketsSVG-Live';
  308. } else {
  309. fwq = acc.platform == 'MT4' ? 'CWGMarketsLtd-Demo' : 'CWGMarketsSVG-Demo';
  310. }
  311. const balance = acc.balance
  312. return {
  313. ...acc,
  314. labels,
  315. isExpanded: index == 0,
  316. balance,
  317. accountNumber: acc.login.toString(),
  318. nickname,
  319. fwq,
  320. balanceWithSymbol: acc.balanceWithSymbol ?? '$0.00',
  321. creditWithSymbol: acc.creditWithSymbol ?? '$0.00',
  322. equityWithSymbol: acc.equityWithSymbol ?? '$0.00',
  323. currency,
  324. actualLeverage: '1:' + (acc.leverage ?? 0),
  325. floatingPL: acc.floatingWithSymbol ?? '$0.00',
  326. platform: acc.platform || 'MT4',
  327. server: acc.groupCode || '',
  328. login: acc.login.toString(),
  329. listType: cativeIndex.value
  330. };
  331. })
  332. })
  333. onMounted(async () => {
  334. await getAccountList()
  335. })
  336. onUnmounted(() => {
  337. if (debounceTimer) {
  338. clearTimeout(debounceTimer)
  339. }
  340. })
  341. watch(cativeIndex, (newVal) => {
  342. // search.value.platform = tabs.value[newVal].id
  343. getAccountList()
  344. platformActive.value = 'All'
  345. })
  346. // watch(platformActive, (newVal) => {
  347. // setAccountList()
  348. // })
  349. </script>
  350. <style scoped lang="scss">
  351. @import "@/uni.scss";
  352. .btn {
  353. margin: 0;
  354. }
  355. </style>