AccountList.vue 11 KB

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