record.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <template>
  2. <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
  3. <cwg-header :title="t('Documentary.TundManagement.item10')" />
  4. <view class="info-card">
  5. <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch"
  6. @reset="handleReset" />
  7. <cwg-tabel ref="tableRef" :columns="currentColumns" :immediate="false" :queryParams="search" :api="listApi"
  8. :show-operation="false">
  9. <template #status="{ row }">
  10. <view v-if="getStatusText(row)" class="status-tag" :class="getStatusClass(row.status)">
  11. {{ getStatusText(row) }}
  12. </view>
  13. <view v-else></view>
  14. </template>
  15. <template #accountType="{ row }">
  16. {{ getAccountTypeText(row.dealLoginType || row.followAccountType) }}
  17. </template>
  18. </cwg-tabel>
  19. </view>
  20. </cwg-page-wrapper>
  21. </template>
  22. <script setup lang="ts">
  23. import { computed, ref, nextTick, watch } from 'vue';
  24. import { useI18n } from 'vue-i18n';
  25. const { t, locale } = useI18n();
  26. import { documentaryApi } from '@/service/documentary';
  27. import useUserStore from "@/stores/use-user-store";
  28. const userStore = useUserStore();
  29. const userInfo = computed(() => userStore.userInfo);
  30. import { useAccountOptions } from '@/composables/useAccountOptions'
  31. const { loginOptions, isLoaded, isSuccess } = useAccountOptions()
  32. import { useFilters } from '@/composables/useFilters'
  33. const { numberFormat, numberDesensitization, numberDecimal } = useFilters()
  34. const search = ref({
  35. type: 1, followLogin: null,
  36. })
  37. const typeMap = computed(() => ([
  38. { value: 1, text: t('Documentary.TundManagement.item58') },
  39. { value: 2, text: t('Documentary.TundManagement.item47') },
  40. ]));
  41. const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
  42. // 账户类型映射
  43. const accountTypeMap = {
  44. 1: 'AccountType.ClassicAccount',
  45. 2: 'AccountType.SeniorAccount',
  46. 5: 'AccountType.SpeedAccount',
  47. 6: 'AccountType.SpeedAccount',
  48. 7: 'AccountType.StandardAccount',
  49. 8: 'AccountType.CentAccount'
  50. }
  51. // 拒绝原因映射(示例)
  52. const reasons = ref({})
  53. // 根据类型获取列配置
  54. const getColumnsByType = (type: number) => {
  55. switch (type) {
  56. case 1: //信号源申请
  57. return [
  58. {
  59. prop: 'dealLogin',
  60. label: t('Documentary.TundManagement.item25'),
  61. align: 'center',
  62. headerAlign: 'center',
  63. formatter: ({ row }) => numberDesensitization(row.dealLogin) || '--'
  64. },
  65. {
  66. prop: 'dealPlatform',
  67. label: t('Label.Platform'),
  68. align: 'center',
  69. headerAlign: 'center',
  70. formatter: ({ row }) => row.dealPlatform || '--'
  71. },
  72. {
  73. prop: 'dealLoginType',
  74. label: t('Label.AccountType'),
  75. align: 'center',
  76. slot: 'accountType' // 多语言枚举
  77. },
  78. {
  79. prop: 'dealLeverage',
  80. label: t('Label.Leverage'),
  81. align: 'center',
  82. formatter: ({ row }) => row.dealLeverage ? `1:${row.dealLeverage}` : '--'
  83. },
  84. {
  85. prop: 'distributionType',
  86. label: t('Documentary.TundManagement.item38'),
  87. align: 'center',
  88. headerAlign: 'center',
  89. formatter: ({ row }) => row.distributionType === 1 ? t('Documentary.TundManagement.item59') : '--'
  90. },
  91. {
  92. prop: 'distributionRatio',
  93. label: t('Documentary.TundManagement.item39'),
  94. align: 'center',
  95. headerAlign: 'center',
  96. formatter: ({ row }) => (row.distributionRatio || '0') + '%'
  97. },
  98. {
  99. prop: 'settlementCycle',
  100. label: t('Documentary.TundManagement.item55'),
  101. align: 'center',
  102. headerAlign: 'center',
  103. formatter: ({ row }) => row.settlementCycle || '--'
  104. },
  105. {
  106. prop: 'approveTime',
  107. label: t('Documentary.TundManagement.item56'),
  108. align: 'center',
  109. formatter: ({ row }) => row.approveTime || '--'
  110. },
  111. {
  112. prop: 'status',
  113. label: t('Documentary.TundManagement.item57'),
  114. align: 'center',
  115. slot: 'status' // 状态
  116. },
  117. {
  118. prop: 'approveDesc',
  119. label: t('Label.Note'),
  120. align: 'center',
  121. type: 'note' // 备注多语言
  122. }
  123. ]
  124. case 2: // 取消记录
  125. return [
  126. {
  127. prop: 'dealNickname',
  128. label: t('Documentary.tradingCenter.item1'),
  129. align: 'center',
  130. headerAlign: 'center',
  131. formatter: ({ row }) => row.dealNickname || '--'
  132. },
  133. {
  134. prop: 'dealLogin',
  135. label: t('Documentary.tradingCenter.item18'),
  136. align: 'center',
  137. headerAlign: 'center',
  138. formatter: ({ row }) => numberDesensitization(row.dealLogin) || '--'
  139. },
  140. {
  141. prop: 'followLogin',
  142. label: t('Documentary.console.item28'),
  143. align: 'center',
  144. headerAlign: 'center',
  145. formatter: ({ row }) => row.followLogin || '--'
  146. },
  147. {
  148. prop: 'followPlatform',
  149. label: t('Label.Platform'),
  150. align: 'center',
  151. formatter: ({ row }) => row.followPlatform || '--'
  152. },
  153. {
  154. prop: 'followLoginType',
  155. label: t('Label.AccountType'),
  156. align: 'center',
  157. slot: 'followAccountType'
  158. },
  159. {
  160. prop: 'followLeverage',
  161. label: t('Label.Leverage'),
  162. align: 'center',
  163. formatter: ({ row }) => row.followLeverage ? `1:${row.followLeverage}` : '--'
  164. },
  165. {
  166. prop: 'distributionType',
  167. label: t('Documentary.TundManagement.item38'),
  168. align: 'center',
  169. headerAlign: 'center',
  170. formatter: () => t('Documentary.TundManagement.item59')
  171. },
  172. {
  173. prop: 'distributionRatio',
  174. label: t('Documentary.TundManagement.item39'),
  175. align: 'center',
  176. headerAlign: 'center',
  177. formatter: ({ row }) => (row.distributionRatio || '0') + '%'
  178. },
  179. {
  180. prop: 'settlementCycle',
  181. label: t('Documentary.TundManagement.item55'),
  182. align: 'center',
  183. headerAlign: 'center',
  184. formatter: ({ row }) => row.settlementCycle || '--'
  185. },
  186. {
  187. prop: 'timeRange',
  188. label: t('Documentary.TundManagement.item51') + ' / ' + t('Documentary.TundManagement.item52'),
  189. align: 'center',
  190. slot: 'timeRange' // 开始-结束时间
  191. },
  192. {
  193. prop: 'endTime',
  194. label: t('Documentary.TundManagement.item56'),
  195. align: 'center',
  196. formatter: ({ row }) => row.endTime || '--'
  197. }
  198. ]
  199. }
  200. }
  201. // 动态传入筛选字段配置
  202. const filterFields = computed(() => [
  203. { key: 'type', type: 'select', label: t('Custom.PaymentHistory.payType'), placeholder: t('placeholder.choose'), options: typeMap.value, defaultValue: 1 },
  204. isLoaded.value && isSuccess.value && { key: 'followLogin', type: 'select', label: t('Custom.PaymentHistory.TradingAccount'), placeholder: t('placeholder.login'), options: loginOptions || [], defaultValue: search?.login || undefined, clearable: true },
  205. { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
  206. ])
  207. const searchParams = ref({})
  208. const tableRef = ref(null)
  209. const handleSearch = (params) => {
  210. search.value = params
  211. nextTick(() => {
  212. tableRef.value.refreshTable()
  213. })
  214. }
  215. const handleReset = (params) => {
  216. search.value = params
  217. nextTick(() => {
  218. tableRef.value.refreshTable()
  219. })
  220. }
  221. // 当前列配置
  222. const currentColumns = computed(() => getColumnsByType(search.value.type))
  223. // 获取状态文本
  224. const getStatusText = (row: any) => {
  225. const status = row.status
  226. // 根据不同记录类型处理状态
  227. if (search.value.type === 1) {
  228. if (status === 0) return t('State.ToBeProcessed')
  229. if (status === 2) return t('State.Completed')
  230. if (status === 1) return t('State.InTheProcessing')
  231. if (status === 3) return t('State.Refused')
  232. } else if (search.value.type === 2) {
  233. if (status === 1) return t('State.ToBeProcessed')
  234. if (status === 2 && row.leverageStatus === 2) return t('State.Completed')
  235. if (status === 2 && row.leverageStatus === 1) return t('State.InTheProcessing')
  236. if (status === 3) return t('State.Refused')
  237. } else if (search.value.type === 3 || search.value.type === 5) {
  238. if (status === 1) return t('State.ToBeProcessed')
  239. if (status === 2 && row.withdrawStatus === 2 && row.depositStatus === 2) return t('State.Completed')
  240. if (status === 2 && (row.withdrawStatus === 1 || row.depositStatus === 1)) return t('State.InTheProcessing')
  241. if (status === 3 || row.withdrawStatus === 3 || row.depositStatus === 3) return t('State.Refused')
  242. } else {
  243. // 活动申请等
  244. if (status === 1) return t('State.ToBeProcessed')
  245. if (status === 2) return t('State.Completed')
  246. if (status === 3) return t('State.Refused')
  247. }
  248. return ''
  249. }
  250. // 获取状态样式类
  251. const getStatusClass = (status: number) => {
  252. const classMap: Record<number, string> = {
  253. 1: 'status-pending',
  254. 2: 'status-success',
  255. 3: 'status-processing',
  256. 4: 'status-danger'
  257. }
  258. return classMap[status] || ''
  259. }
  260. // 获取账户类型文本
  261. const getAccountTypeText = (type: number) => {
  262. const key = accountTypeMap[type as keyof typeof accountTypeMap]
  263. return key ? t(key) : '--'
  264. }
  265. // 格式化数字
  266. const formatNumber = (value: string | number) => {
  267. if (!value) return '--'
  268. const num = Number(value)
  269. return isNaN(num) ? '--' : num.toFixed(2)
  270. }
  271. // 格式化备注
  272. const formatNote = (approveDesc: string) => {
  273. if (!approveDesc) return '--'
  274. const reason = reasons.value[approveDesc as keyof typeof reasons.value]
  275. if (reason) {
  276. return isZh.value ? reason.content : reason.enContent
  277. }
  278. return approveDesc
  279. }
  280. const listApi = ref(null)
  281. watch(() => search.value.type, (newVal) => {
  282. switch (newVal) {
  283. case 1:
  284. search.value.status = null
  285. search.value.followLogin = null
  286. listApi.value = documentaryApi.followDealList
  287. break
  288. case 2:
  289. search.value.status = null
  290. search.value.followLogin = null
  291. listApi.value = documentaryApi.followDealSubscribeList
  292. search.value.status = 2
  293. break
  294. }
  295. }, { immediate: true })
  296. </script>
  297. <style scoped lang="scss">
  298. @import "@/uni.scss";
  299. .avatar {
  300. width: px2rpx(60);
  301. height: px2rpx(60);
  302. border-radius: 4px;
  303. }
  304. .content-title {
  305. display: flex;
  306. justify-content: space-between;
  307. align-items: center;
  308. font-size: px2rpx(20);
  309. font-weight: 500;
  310. .content-title-btns {
  311. margin: px2rpx(8) 0;
  312. display: flex;
  313. align-items: center;
  314. justify-content: center;
  315. gap: px2rpx(12);
  316. .btn-primary {
  317. min-width: px2rpx(120);
  318. background-color: var(--color-error);
  319. color: white;
  320. padding: 0 px2rpx(12);
  321. border: none;
  322. font-size: px2rpx(14);
  323. text-align: center;
  324. cursor: pointer;
  325. display: flex;
  326. align-items: center;
  327. justify-content: center;
  328. gap: px2rpx(8);
  329. }
  330. .btn-primary:active {
  331. background-color: #cf1322;
  332. ;
  333. }
  334. }
  335. }
  336. .operation-btn {
  337. :deep(span) {
  338. display: flex;
  339. align-items: center;
  340. justify-content: center;
  341. gap: px2rpx(4);
  342. cursor: pointer;
  343. background-color: var(--color-slate-150);
  344. padding: px2rpx(8) 0;
  345. }
  346. }
  347. .operation-btn.disabled {
  348. cursor: not-allowed;
  349. opacity: 0.5;
  350. }
  351. .search-bar {
  352. display: flex;
  353. align-items: center;
  354. justify-content: flex-start;
  355. flex-wrap: wrap;
  356. gap: px2rpx(16);
  357. margin: px2rpx(16) 0;
  358. .cwg-combox,
  359. .uni-easyinput,
  360. .uni-date {
  361. width: px2rpx(240) !important;
  362. flex: none;
  363. }
  364. }
  365. </style>