record.vue 13 KB

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