trade-position.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <template>
  2. <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
  3. <cwg-header :title="t('Ib.Report.Tit4')" />
  4. <view class="info-card">
  5. <view class="search-bar">
  6. <cwg-combox v-model:value="search.type" :options="typeMap" :placeholder="t('placeholder.choose')" />
  7. <cwg-combox v-model:value="search.orderStatus" :options="orderStatusMap"
  8. :placeholder="t('Custom.PaymentHistory.StatusPlaceholder')" />
  9. <uni-easyinput v-model="search.login" :placeholder="t('placeholder.login')" />
  10. <uni-datetime-picker type="daterange" v-model="search.date"
  11. :placeholder="t('placeholder.Start') + ' - ' + t('placeholder.End')" />
  12. </view>
  13. <cwg-tabel ref="tableRef" :columns="columns" :mobilePrimaryFields="mobilePrimaryFields"
  14. :queryParams="search" :api="listApi" :show-operation="false" :showPagination="false">
  15. <template #symbol="{ row }">
  16. <view class="symbol-cell">
  17. <view class="pair">{{ getSymbolParts(row.symbol)[0] }}/{{ getSymbolParts(row.symbol)[1]
  18. }}</view>
  19. <view class="desc">{{ row.openPrice }}
  20. <text :class="getCmdColorClass(row.cmdName)">{{ formatCmdName(row.cmdName) }}{{ row.volume
  21. }}{{ t('Label.Lot') }}</text>
  22. </view>
  23. </view>
  24. </template>
  25. <template #profit="{ row }">
  26. <view class="symbol-cell">
  27. <text :class="getProfitColorClass(row.profit)">{{ row.profit || 0 }}</text>
  28. </view>
  29. </template>
  30. </cwg-tabel>
  31. </view>
  32. </cwg-page-wrapper>
  33. </template>
  34. <script setup lang="ts">
  35. import { computed, ref } from 'vue';
  36. import { useI18n } from 'vue-i18n';
  37. const { t, locale } = useI18n();
  38. import { customApi } from '@/service/custom';
  39. const search = ref(
  40. {
  41. "reportType": 3,
  42. "agentId": null,
  43. "groupType": null,
  44. "login": "",
  45. "cId": "",
  46. "customName": "",
  47. "ibNo": "",
  48. "symbol": "",
  49. "cmdName": "",
  50. "platform": "MT4",
  51. "salesNo": "",
  52. "salesName": "",
  53. "dwType": null,
  54. "customType": 0,
  55. "rankingType": 1,
  56. "loginTypes": [],
  57. "isShort": 0,
  58. "detail_type": 4,
  59. "date": [
  60. "1970-01-01",
  61. "2026-03-27"
  62. ],
  63. "startDate": "1970-01-01",
  64. "endDate": "2026-03-27",
  65. "orderColumn": null,
  66. "orderType": null,
  67. "page": {
  68. "current": 1,
  69. "row": 10
  70. }
  71. }
  72. )
  73. const typeMap = computed(() => ([
  74. { value: null, text: t('Custom.PaymentHistory.All') },
  75. { value: 1, text: t('Custom.PaymentHistory.Deposit') },
  76. { value: 2, text: t('Custom.PaymentHistory.Withdrawals') }
  77. ]));
  78. const orderStatusMap = computed(() => ([
  79. { value: null, text: t('Custom.PaymentHistory.All') },
  80. { value: 1, text: t('State.ToBeProcessed') },
  81. { value: 2, text: t('State.Completed') },
  82. { value: 3, text: t('State.InTheProcessing') },
  83. { value: 4, text: t('State.Refused') },
  84. { value: 5, text: t('State.expireTime') },
  85. { value: 6, text: t('State.Cancelled') },
  86. ]));
  87. // 表格列配置
  88. const columns = ref([
  89. {
  90. prop: 'symbol',
  91. label: t('Label.Varieties'), // 交易品种
  92. align: 'left'
  93. },
  94. {
  95. prop: 'cmdName',
  96. label: t('Label.Type'), // 类型
  97. align: 'left'
  98. },
  99. {
  100. prop: 'openTime',
  101. label: t('Label.OpenTime'), // 开仓时间(协调世界时)
  102. align: 'left'
  103. },
  104. {
  105. prop: 'volume',
  106. label: t('Label.Volume'), // 手
  107. formatter: ({ row }) => `${row.volume || 0} ${t('Label.Lot')}`,
  108. align: 'right'
  109. },
  110. {
  111. prop: 'openPrice',
  112. label: t('Label.OpenPrice'), // 开仓价
  113. align: 'right'
  114. },
  115. {
  116. prop: 'tp',
  117. label: t('Label.EP'), // 止盈
  118. align: 'right'
  119. },
  120. {
  121. prop: 'sl',
  122. label: t('Label.EL'), // 止损
  123. align: 'right'
  124. },
  125. {
  126. prop: 'profit',
  127. label: t('Label.ProfitLoss') + '(USD)', // 利润, USD
  128. slot: 'profit',
  129. align: 'right'
  130. },
  131. {
  132. prop: 'comment',
  133. label: t('Label.Note'),
  134. align: 'right',
  135. isTabel: false
  136. },
  137. {
  138. prop: 'more',
  139. type: 'more',
  140. width: 20,
  141. align: 'right'
  142. },
  143. ])
  144. const mobilePrimaryFields = ref([
  145. {
  146. prop: 'symbol',
  147. label: t('Label.Varieties'), // 交易品种
  148. align: 'left',
  149. slot: 'symbol'
  150. },
  151. {
  152. prop: 'profit',
  153. label: t('Label.ProfitLoss') + '(USD)', // 利润, USD
  154. slot: 'profit',
  155. align: 'right'
  156. },
  157. {
  158. prop: 'more',
  159. type: 'more',
  160. width: 20,
  161. align: 'right'
  162. },
  163. ])
  164. const listApi = ref(null)
  165. listApi.value = customApi.tradePosition
  166. const getSymbolParts = (sym: string) => {
  167. if (!sym) return ['', '']
  168. const s = String(sym).toUpperCase()
  169. if (s.includes('/')) {
  170. const [base, quote] = s.split('/')
  171. return [base, quote]
  172. }
  173. const base = s.slice(0, 3)
  174. const quote = s.slice(3)
  175. return [base, quote]
  176. }
  177. const formatCmdName = (cmd: string) => {
  178. const v = String(cmd || '').toLowerCase()
  179. if (v.includes('sell')) return '卖出'
  180. if (v.includes('buy')) return '买入'
  181. return cmd || ''
  182. }
  183. const getCmdColorClass = (cmd: string) => {
  184. const v = String(cmd || '').toLowerCase()
  185. if (v.includes('sell')) return 'is-sell'
  186. if (v.includes('buy')) return 'is-buy'
  187. return ''
  188. }
  189. const getProfitColorClass = (profit: any) => {
  190. const n = Number(profit)
  191. if (!Number.isFinite(n) || n === 0) return ''
  192. return n > 0 ? 'is-profit' : 'is-loss'
  193. }
  194. </script>
  195. <style scoped lang="scss">
  196. @import "@/uni.scss";
  197. .avatar {
  198. width: px2rpx(60);
  199. height: px2rpx(60);
  200. border-radius: 4px;
  201. }
  202. .content-title {
  203. display: flex;
  204. justify-content: space-between;
  205. align-items: center;
  206. font-size: px2rpx(20);
  207. font-weight: 500;
  208. .content-title-btns {
  209. margin: px2rpx(8) 0;
  210. display: flex;
  211. align-items: center;
  212. justify-content: center;
  213. gap: px2rpx(12);
  214. .btn-primary {
  215. min-width: px2rpx(120);
  216. background-color: var(--color-error);
  217. color: white;
  218. padding: 0 px2rpx(12);
  219. border: none;
  220. font-size: px2rpx(14);
  221. text-align: center;
  222. cursor: pointer;
  223. display: flex;
  224. align-items: center;
  225. justify-content: center;
  226. gap: px2rpx(8);
  227. }
  228. .btn-primary:active {
  229. background-color: var(--color-navy-700);
  230. }
  231. }
  232. }
  233. .operation-btn {
  234. :deep(span) {
  235. display: flex;
  236. align-items: center;
  237. justify-content: center;
  238. gap: px2rpx(4);
  239. cursor: pointer;
  240. background-color: var(--color-slate-150);
  241. padding: px2rpx(8) 0;
  242. }
  243. }
  244. .operation-btn.disabled {
  245. cursor: not-allowed;
  246. opacity: 0.5;
  247. }
  248. .symbol-cell {
  249. display: inline-flex;
  250. align-items: flex-start;
  251. gap: 0.25rem;
  252. flex-direction: column;
  253. .pair {
  254. font-weight: 600;
  255. color: var(--color-slate-900);
  256. }
  257. .desc {
  258. color: var(--color-slate-600);
  259. }
  260. }
  261. .is-sell,
  262. .is-loss {
  263. color: #eb483f;
  264. }
  265. .is-buy,
  266. .is-profit {
  267. color: #46cd7c;
  268. }
  269. .search-bar {
  270. display: flex;
  271. align-items: center;
  272. justify-content: flex-start;
  273. flex-wrap: wrap;
  274. gap: px2rpx(16);
  275. margin: px2rpx(16) 0;
  276. .cwg-combox,
  277. .uni-easyinput,
  278. .uni-date {
  279. width: px2rpx(240) !important;
  280. flex: none;
  281. }
  282. }
  283. </style>