subscribe-list.vue 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. <template>
  2. <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
  3. <cwg-header :title="t('Documentary.TundManagement.item45')" />
  4. <view class="content-container">
  5. <view class="info-card">
  6. <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch"
  7. @reset="handleReset" />
  8. <cwg-tabel ref="tableRef" :columns="currentColumns" :immediate="false" :queryParams="search"
  9. :api="listApi" :show-operation="true" :showPagination="true">
  10. <!-- 账户类型列自定义渲染 -->
  11. <template #followType="{ row }">
  12. <text v-t="followTypeMap[row.followType || row.loginType]" />
  13. </template>
  14. <template #timeRange="{ row }">
  15. <view class="sp-view-tab">
  16. {{ row.startTime || '--' }}
  17. </view>
  18. <view class="sp-view-tab-b">
  19. {{ row.endTime || '--' }}
  20. </view>
  21. </template>
  22. <!-- 金额列格式化 -->
  23. <template #balanceEquity="{ row }">
  24. <view class="sp-view-tab">
  25. {{ numberDecimal(row.followBalance || 0) }}
  26. </view>
  27. <view class="sp-view-tab-b">
  28. {{ numberDecimal(row.followEquity || 0) }}
  29. </view>
  30. </template>
  31. </cwg-tabel>
  32. </view>
  33. </view>
  34. <!--取消订阅提示-->
  35. <cwg-popup v-model:visible="dialogSubscribeCancelTip" type="center" :mask-click="false" :show-footers="true"
  36. :title="t('Documentary.TundManagement.item47')">
  37. <view class="dia-content">
  38. <view class="des1" style="font-size: 16px; line-height: 1.6; margin: 30px 0 50px">
  39. {{ t('Documentary.TundManagement.item60') }}
  40. </view>
  41. </view>
  42. <template #footer>
  43. <button @click="ToUnSubscribeCancelTip">{{ t('Btn.Cancel') }}</button>
  44. <button type="primary" @click="ToUnSubscribe">{{ t('Documentary.TundManagement.item47') }}</button>
  45. </template>
  46. </cwg-popup>
  47. <!-- 取消订阅设置 -->
  48. <cwg-popup v-model:visible="dialogSubscribeCancel" type="center" :mask-click="false" :show-footers="true"
  49. :title="t('Documentary.TundManagement.item47')">
  50. <view class="dia-content">
  51. <uni-forms ref="dialogSubscribeDataCancelRef" :model="dialogSubscribeDataCancel" label-position="top">
  52. <!-- 信号源账户信息 -->
  53. <view class="fllow-title">
  54. <text class="title">{{ t('Documentary.tradingCenter.item28') }}</text>
  55. </view>
  56. <view class="delete-grid">
  57. <view class="delete-row">
  58. <view class="delete-item">
  59. <text class="delete-label">{{ t('Documentary.tradingCenter.item29') }}</text>
  60. <text class="delete-value">{{ numberDesensitization(dialogSubscribeDataCancel.dealLogin)
  61. }}</text>
  62. </view>
  63. <view class="delete-item">
  64. <text class="delete-label">{{ t('Documentary.console.item3') }}</text>
  65. <text class="delete-value">{{ dialogSubscribeDataCancel.dealPlatform || '--' }}</text>
  66. </view>
  67. </view>
  68. <view class="delete-row">
  69. <view class="delete-item">
  70. <text class="delete-label">{{ t('Documentary.console.item7') }}</text>
  71. <text class="delete-value">{{ numberFormat(dialogSubscribeDataCancel.dealBalance || 0)
  72. }}</text>
  73. </view>
  74. <view class="delete-item">
  75. <text class="delete-label">{{ t('Label.AccountType') }}</text>
  76. <text class="delete-value"
  77. v-t="followTypeMap[dialogSubscribeDataCancel.followType || dialogSubscribeDataCancel.loginType]" />
  78. </view>
  79. </view>
  80. <view class="delete-row">
  81. <view class="delete-item">
  82. <text class="delete-label">{{ t('Documentary.console.item6') }}</text>
  83. <text class="delete-value">{{ numberFormat(dialogSubscribeDataCancel.dealEquity || 0)
  84. }}</text>
  85. </view>
  86. <view class="delete-item">
  87. <text class="delete-label">{{ t('Documentary.tradingCenter.item30') }}</text>
  88. <text class="delete-value">
  89. <text v-if="dialogSubscribeDataCancel.distributionType == 1"
  90. v-t="'Documentary.TundManagement.item59'"></text>
  91. <text v-else>--</text>
  92. </text>
  93. </view>
  94. </view>
  95. <view class="delete-row">
  96. <view class="delete-item">
  97. <text class="delete-label">{{ t('Label.Credit') }}</text>
  98. <text class="delete-value">{{ numberFormat(dialogSubscribeDataCancel.dealCredit || 0)
  99. }}</text>
  100. </view>
  101. <view class="delete-item">
  102. <text class="delete-label">{{ t('Documentary.tradingCenter.item31') }}</text>
  103. <text class="delete-value">{{ dialogSubscribeDataCancel.distributionRatio || '0'
  104. }}%</text>
  105. </view>
  106. </view>
  107. <view class="delete-row">
  108. <view class="delete-item">
  109. <text class="delete-label">{{ t('Label.Leverage') }}</text>
  110. <text class="delete-value">1:{{ dialogSubscribeDataCancel.dealLeverage || '0' }}</text>
  111. </view>
  112. <view class="delete-item">
  113. <text class="delete-label">{{ t('Documentary.tradingCenter.item32') }}</text>
  114. <text class="delete-value">{{ dialogSubscribeDataCancel.settlementCycle || '--'
  115. }}</text>
  116. </view>
  117. </view>
  118. </view>
  119. <!-- 跟随账户设置 -->
  120. <view class="fllow-title">
  121. <text class="title">{{ t('Documentary.tradingCenter.item33') }}</text>
  122. </view>
  123. <view class="delete-grid">
  124. <view class="delete-row">
  125. <view class="delete-item">
  126. <text class="delete-label">{{ t('Documentary.tradingCenter.item29') }}</text>
  127. <text class="delete-value">{{ dialogSubscribeDataCancel.followLogin || '--' }}</text>
  128. </view>
  129. <view class="delete-item">
  130. <text class="delete-label">{{ t('Label.Leverage') }}</text>
  131. <text class="delete-value">1:{{ dialogSubscribeDataCancel.followLeverage || '--'
  132. }}</text>
  133. </view>
  134. </view>
  135. <view class="delete-row">
  136. <view class="delete-item">
  137. <text class="delete-label">{{ t('Documentary.tradingCenter.item35') }}</text>
  138. <text class="delete-value"
  139. v-t="followTypeMap[dialogSubscribeDataCancel.followType || dialogSubscribeDataCancel.loginType]" />
  140. </view>
  141. <view class="delete-item" v-if="dialogSubscribeDataCancel.followType == 1">
  142. <text class="delete-label">{{ t('Documentary.tradingCenter.item119') }}</text>
  143. <text class="delete-value">{{ (dialogSubscribeDataCancel.volume / 100) || '--' }}</text>
  144. </view>
  145. <view class="delete-item" v-if="dialogSubscribeDataCancel.followType == 2">
  146. <text class="delete-label">{{ t('Documentary.tradingCenter.item36') }}</text>
  147. <text class="delete-value">{{ dialogSubscribeDataCancel.ratio || '--' }}%</text>
  148. </view>
  149. </view>
  150. </view>
  151. <!-- 保护设置 -->
  152. <view class="fllow-title">
  153. <text class="title">{{ t('Documentary.tradingCenter.item37') }}</text>
  154. </view>
  155. <view class="delete-grid">
  156. <view class="delete-row">
  157. <view class="delete-item">
  158. <text class="delete-label">{{ t('Documentary.tradingCenter.item38') }}</text>
  159. <text class="delete-value">
  160. <text v-if="dialogSubscribeDataCancel.protectType == 1"
  161. v-t="'Documentary.tradingCenter.item120'"></text>
  162. <text v-if="dialogSubscribeDataCancel.protectType == 2"
  163. v-t="'Documentary.tradingCenter.item121'"></text>
  164. <text v-if="!dialogSubscribeDataCancel.protectType">--</text>
  165. </text>
  166. </view>
  167. <view class="delete-item" v-if="dialogSubscribeDataCancel.protectType == 1">
  168. <text class="delete-label">{{ t('Documentary.tradingCenter.item39') }}</text>
  169. <text class="delete-value">{{ dialogSubscribeDataCancel.protectAmount || '--'
  170. }}($)</text>
  171. </view>
  172. <view class="delete-item" v-if="dialogSubscribeDataCancel.protectType == 2">
  173. <text class="delete-label">{{ t('Documentary.tradingCenter.item122') }}</text>
  174. <text class="delete-value">{{ dialogSubscribeDataCancel.protectRatio || '--'
  175. }}(%)</text>
  176. </view>
  177. </view>
  178. </view>
  179. <!-- 订阅时间 -->
  180. <view class="fllow-title">
  181. <text class="title">{{ t('Documentary.TundManagement.item50') }}</text>
  182. </view>
  183. <view class="delete-grid">
  184. <view class="delete-row">
  185. <view class="delete-item">
  186. <text class="delete-label">{{ t('Documentary.TundManagement.item51') }}</text>
  187. <text class="delete-value">{{ dialogSubscribeDataCancel.startTime || '--' }}</text>
  188. </view>
  189. <view class="delete-item">
  190. <text class="delete-label">{{ t('Documentary.TundManagement.item52') }}</text>
  191. <text class="delete-value">{{ dialogSubscribeDataCancel.endTime || '--' }}</text>
  192. </view>
  193. </view>
  194. </view>
  195. <view class="delete-tip">
  196. <text v-t="'Documentary.TundManagement.item53'"></text>
  197. </view>
  198. </uni-forms>
  199. </view>
  200. <template #footer>
  201. <button @click="ToUnSubscribeCancel">{{ t('Btn.Cancel') }}</button>
  202. <button type="primary" @click="dialogSubscribeCancelTipOpen" :disabled="flag">{{ t('Btn.Confirm')
  203. }}</button>
  204. </template>
  205. </cwg-popup>
  206. <!-- 跟单设置 -->
  207. <cwg-popup v-model:visible="dialogSubscribeFllow" type="center" :mask-click="false" :show-footers="true"
  208. :title="t('Documentary.TundManagement.item48')">
  209. <view class="dia-content">
  210. <uni-forms ref="dialogSubscribeFllowRef" :model="dialogSubscribeFllowDataSelect" :rules="rules"
  211. label-position="top" :label-width="120">
  212. <!-- 信号源账户信息 -->
  213. <view class="fllow-title">
  214. <text class="title">{{ t('Documentary.tradingCenter.item28') }}</text>
  215. </view>
  216. <view class="delete-grid">
  217. <view class="delete-row">
  218. <view class="delete-item">
  219. <text class="delete-label">{{ t('Documentary.tradingCenter.item29') }}</text>
  220. <text class="delete-value">{{ numberDesensitization(dialogSubscribeFllowData.dealLogin)
  221. }}</text>
  222. </view>
  223. <view class="delete-item">
  224. <text class="delete-label">{{ t('Documentary.console.item3') }}</text>
  225. <text class="delete-value">{{ dialogSubscribeFllowData.dealPlatform || '--' }}</text>
  226. </view>
  227. </view>
  228. <view class="delete-row">
  229. <view class="delete-item">
  230. <text class="delete-label">{{ t('Documentary.console.item7') }}</text>
  231. <text class="delete-value">{{ numberFormat(dialogSubscribeFllowData.dealBalance)
  232. }}</text>
  233. </view>
  234. <view class="delete-item">
  235. <text class="delete-label">{{ t('Label.AccountType') }}</text>
  236. <text class="delete-value">{{ accountTypeName(dialogSubscribeFllowData.dealLoginType)
  237. }}</text>
  238. </view>
  239. </view>
  240. <view class="delete-row">
  241. <view class="delete-item">
  242. <text class="delete-label">{{ t('Documentary.console.item6') }}</text>
  243. <text class="delete-value">{{ numberFormat(dialogSubscribeFllowData.dealEquity)
  244. }}</text>
  245. </view>
  246. <view class="delete-item">
  247. <text class="delete-label">{{ t('Documentary.tradingCenter.item30') }}</text>
  248. <text class="delete-value">
  249. <text v-if="dialogSubscribeFllowData.distributionType == 1"
  250. v-t="'Documentary.TundManagement.item59'"></text>
  251. <text v-else>--</text>
  252. </text>
  253. </view>
  254. </view>
  255. <view class="delete-row">
  256. <view class="delete-item">
  257. <text class="delete-label">{{ t('Label.Credit') }}</text>
  258. <text class="delete-value">{{ numberFormat(dialogSubscribeFllowData.dealCredit)
  259. }}</text>
  260. </view>
  261. <view class="delete-item">
  262. <text class="delete-label">{{ t('Documentary.tradingCenter.item31') }}</text>
  263. <text class="delete-value">{{ dialogSubscribeFllowData.distributionRatio || '0'
  264. }}%</text>
  265. </view>
  266. </view>
  267. <view class="delete-row">
  268. <view class="delete-item">
  269. <text class="delete-label">{{ t('Label.Leverage') }}</text>
  270. <text class="delete-value">1:{{ dialogSubscribeFllowData.dealLeverage || '0' }}</text>
  271. </view>
  272. <view class="delete-item">
  273. <text class="delete-label">{{ t('Documentary.tradingCenter.item32') }}</text>
  274. <text class="delete-value">{{ dialogSubscribeFllowData.settlementCycle || '--' }}</text>
  275. </view>
  276. </view>
  277. </view>
  278. <!-- 跟随账户设置 -->
  279. <view class="fllow-title">
  280. <text class="title">{{ t('Documentary.tradingCenter.item33') }}</text>
  281. </view>
  282. <view class="delete-grid">
  283. <view class="delete-row">
  284. <view class="delete-item">
  285. <text class="delete-label">{{ t('Documentary.tradingCenter.item29') }}</text>
  286. <text class="delete-value">{{ dialogSubscribeFllowData.followLogin || '--' }}</text>
  287. </view>
  288. <view class="delete-item">
  289. <text class="delete-label">{{ t('Label.Leverage') }}</text>
  290. <text class="delete-value">1:{{ dialogSubscribeFllowData.followLeverage || '--'
  291. }}</text>
  292. </view>
  293. </view>
  294. </view>
  295. <!-- 可编辑的跟单设置 -->
  296. <view class="form-row" style="margin-top: 20px;">
  297. <view class="form-col">
  298. <uni-forms-item name="followType" :label="t('Documentary.tradingCenter.item35') + ':'">
  299. <cwg-combox v-model:value="dialogSubscribeFllowDataSelect.followType" :clearable="false"
  300. :options="[
  301. { text: t('Documentary.tradingCenter.item118'), value: 3 },
  302. { text: t('Documentary.tradingCenter.item117'), value: 2 },
  303. { text: t('Documentary.tradingCenter.item116'), value: 1 }
  304. ]" :placeholder="t('placeholder.choose')" />
  305. </uni-forms-item>
  306. </view>
  307. <view class="form-col" v-if="dialogSubscribeFllowDataSelect.followType == 1">
  308. <uni-forms-item name="volume" :label="t('Documentary.tradingCenter.item120') + ':'">
  309. <uni-easyinput v-model="dialogSubscribeFllowDataSelect.volume"
  310. :placeholder="t('placeholder.input')" />
  311. </uni-forms-item>
  312. </view>
  313. <view class="form-col" v-if="dialogSubscribeFllowDataSelect.followType == 2">
  314. <uni-forms-item name="ratio" :label="t('Documentary.tradingCenter.item123') + '(%)'">
  315. <uni-easyinput v-model="dialogSubscribeFllowDataSelect.ratio"
  316. :placeholder="t('placeholder.input')" />
  317. </uni-forms-item>
  318. </view>
  319. </view>
  320. <!-- 保护设置 -->
  321. <view class="fllow-title">
  322. <text class="title">{{ t('Documentary.tradingCenter.item37') }}</text>
  323. <switch :checked="dialogSubscribeFllowDataSelect.protect === 1"
  324. @change="e => dialogSubscribeFllowDataSelect.protect = e.detail.value ? 1 : 0"
  325. color="#cf1322" />
  326. </view>
  327. <view class="form-item">
  328. </view>
  329. <view class="form-row" v-if="dialogSubscribeFllowDataSelect.protect">
  330. <view class="form-col">
  331. <uni-forms-item name="protectType" :label="t('Documentary.tradingCenter.item38') + ':'">
  332. <cwg-combox v-model:value="dialogSubscribeFllowDataSelect.protectType"
  333. :clearable="false"
  334. :options="[{ text: t('Documentary.tradingCenter.item120'), value: 1 }]"
  335. :placeholder="t('placeholder.choose')" />
  336. </uni-forms-item>
  337. </view>
  338. <view class="form-col" v-if="dialogSubscribeFllowDataSelect.protectType == 1">
  339. <uni-forms-item name="protectAmount" :label="t('Documentary.tradingCenter.item39') + ':'">
  340. <uni-easyinput v-model="dialogSubscribeFllowDataSelect.protectAmount"
  341. :placeholder="t('placeholder.input')">
  342. <template #suffix>($)</template>
  343. </uni-easyinput>
  344. </uni-forms-item>
  345. </view>
  346. <view class="form-col" v-if="dialogSubscribeFllowDataSelect.protectType == 2">
  347. <uni-forms-item name="protectRatio" :label="t('Documentary.tradingCenter.item122') + ':'">
  348. <uni-easyinput v-model="dialogSubscribeFllowDataSelect.protectRatio"
  349. :placeholder="t('placeholder.input')">
  350. <template #suffix>(%)</template>
  351. </uni-easyinput>
  352. </uni-forms-item>
  353. </view>
  354. </view>
  355. <!-- 订阅时间 -->
  356. <view class="fllow-title">
  357. <text class="title">{{ t('Documentary.TundManagement.item50') }}</text>
  358. </view>
  359. <view class="delete-grid">
  360. <view class="delete-row">
  361. <view class="delete-item">
  362. <text class="delete-label">{{ t('Documentary.TundManagement.item51') }}</text>
  363. <text class="delete-value">{{ dialogSubscribeFllowData.startTime || '--' }}</text>
  364. </view>
  365. <view class="delete-item">
  366. <text class="delete-label">{{ t('Documentary.TundManagement.item52') }}</text>
  367. <text class="delete-value">{{ dialogSubscribeFllowData.endTime || '--' }}</text>
  368. </view>
  369. </view>
  370. </view>
  371. <view class="delete-tip">
  372. <text v-t="'Documentary.TundManagement.item54'"></text>
  373. </view>
  374. </uni-forms>
  375. </view>
  376. <template #footer>
  377. <button @click="FllowSettingCancel">{{ t('Btn.Cancel') }}</button>
  378. <button type="primary" @click="FllowSetting">{{ t('Btn.Confirm') }}</button>
  379. </template>
  380. </cwg-popup>
  381. </cwg-page-wrapper>
  382. </template>
  383. <script setup lang="ts">
  384. import { computed, ref, nextTick, onMounted, reactive, watch } from 'vue';
  385. import { useI18n } from 'vue-i18n';
  386. const { t, locale } = useI18n();
  387. import { documentaryApi } from '@/service/documentary';
  388. import { useFilters } from '@/composables/useFilters'
  389. const { numberFormat, numberDesensitization, numberDecimal } = useFilters()
  390. const search = ref({
  391. status: 1,
  392. followLogin: '',
  393. endTime: '',
  394. startTime: ''
  395. })
  396. const typeMap = [
  397. { value: 'MT4', text: 'MT4' },
  398. { value: 'MT5', text: 'MT5' }]
  399. // 动态传入筛选字段配置
  400. const filterFields = computed(() => [
  401. { key: 'followPlatform', type: 'select', label: t('Label.Platform'), placeholder: t('placeholder.choose'), options: typeMap },
  402. !isSubscribeLoading.value && { key: 'followLogin', type: 'select', label: t('Documentary.console.item28'), placeholder: t('placeholder.choose'), options: SubscribeDownData.value },
  403. { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
  404. ])
  405. const followTypeMap = {
  406. 1: 'Documentary.tradingCenter.item116',
  407. 2: 'Documentary.tradingCenter.item117',
  408. 3: 'Documentary.tradingCenter.item118'
  409. }
  410. const rules = {
  411. password: {
  412. rules: [
  413. {
  414. required: true,
  415. validateFunction: (rule, value, data, callback) => {
  416. if (Config.Pattern.Password.test(value)) {
  417. callback()
  418. } else {
  419. callback(t('vaildate.password.format'))
  420. }
  421. return true
  422. }
  423. }
  424. ]
  425. },
  426. agree: {
  427. rules: [
  428. {
  429. validateFunction: (rule, value, data, callback) => {
  430. if (value) {
  431. callback()
  432. } else {
  433. callback(t('vaildate.agree.empty'))
  434. }
  435. return true
  436. }
  437. }
  438. ]
  439. },
  440. platform: {
  441. rules: [
  442. {
  443. required: true,
  444. errorMessage: t('vaildate.select.empty')
  445. }
  446. ]
  447. },
  448. currency: {
  449. rules: [
  450. {
  451. required: true,
  452. errorMessage: t('vaildate.select.empty')
  453. }
  454. ]
  455. },
  456. leverage: {
  457. rules: [
  458. {
  459. required: true,
  460. errorMessage: t('vaildate.select.empty')
  461. }
  462. ]
  463. },
  464. loginType: {
  465. rules: [
  466. {
  467. required: true,
  468. errorMessage: t('vaildate.select.empty')
  469. }
  470. ]
  471. },
  472. dealLogin: {
  473. rules: [
  474. {
  475. required: true,
  476. errorMessage: t('vaildate.select.empty')
  477. }
  478. ]
  479. },
  480. distributionType: {
  481. rules: [
  482. {
  483. required: true,
  484. errorMessage: t('vaildate.select.empty')
  485. }
  486. ]
  487. },
  488. distributionRatio: {
  489. rules: [
  490. {
  491. required: true,
  492. errorMessage: t('vaildate.input.empty')
  493. },
  494. {
  495. validateFunction: (rule, value, data, callback) => {
  496. if (value >= 0 && value <= 50) {
  497. callback()
  498. } else {
  499. callback('0-50')
  500. }
  501. return true
  502. }
  503. }
  504. ]
  505. },
  506. settlementCycle: {
  507. rules: [
  508. {
  509. required: true,
  510. errorMessage: t('vaildate.input.empty')
  511. }
  512. ]
  513. },
  514. historyShow: {
  515. rules: [
  516. {
  517. required: true,
  518. errorMessage: t('vaildate.select.empty')
  519. }
  520. ]
  521. },
  522. historyTime: {
  523. rules: [
  524. {
  525. required: true,
  526. errorMessage: t('vaildate.select.empty')
  527. }
  528. ]
  529. },
  530. introduceShow: {
  531. rules: [
  532. {
  533. required: true,
  534. errorMessage: t('vaildate.select.empty')
  535. }
  536. ]
  537. },
  538. protectAmount: {
  539. rules: [
  540. {
  541. required: true,
  542. errorMessage: t('vaildate.input.empty')
  543. }
  544. ]
  545. },
  546. protectRatio: {
  547. rules: [
  548. {
  549. required: true,
  550. errorMessage: t('vaildate.input.empty')
  551. }
  552. ]
  553. },
  554. nickname: {
  555. rules: [
  556. {
  557. required: true,
  558. errorMessage: t('vaildate.input.empty')
  559. },
  560. {
  561. validateFunction: (rule, value, data, callback) => {
  562. if (value && /^[0-9a-zA-Z]{1,24}$/.test(value)) {
  563. callback()
  564. } else {
  565. callback(t('Msg.nickname'))
  566. }
  567. return true
  568. }
  569. }
  570. ]
  571. },
  572. personalSignature: {
  573. rules: [
  574. {
  575. required: true,
  576. errorMessage: t('vaildate.input.empty')
  577. },
  578. {
  579. validateFunction: (rule, value, data, callback) => {
  580. if (!value || /^[\u4e00-\u9fa5a-zA-Z\s]*$/.test(value)) {
  581. callback()
  582. } else {
  583. callback(t('Documentary.console.item38'))
  584. }
  585. return true
  586. }
  587. }
  588. ]
  589. },
  590. traderStrategy: {
  591. rules: [
  592. {
  593. required: true,
  594. errorMessage: t('vaildate.input.empty')
  595. },
  596. {
  597. validateFunction: (rule, value, data, callback) => {
  598. if (!value || /^[\u4e00-\u9fa5a-zA-Z\s]*$/.test(value)) {
  599. callback()
  600. } else {
  601. callback(t('Documentary.console.item38'))
  602. }
  603. return true
  604. }
  605. }
  606. ]
  607. },
  608. followType: {
  609. rules: [
  610. {
  611. required: true,
  612. errorMessage: t('vaildate.select.empty')
  613. }
  614. ]
  615. },
  616. volume: {
  617. rules: [
  618. {
  619. required: true,
  620. errorMessage: t('vaildate.input.empty')
  621. }
  622. ]
  623. },
  624. ratio: {
  625. rules: [
  626. {
  627. required: true,
  628. errorMessage: t('vaildate.input.empty')
  629. }
  630. ]
  631. }
  632. }
  633. const SubscribeDownData = ref([])
  634. //获取客户跟单账户的下拉列表
  635. const isSubscribeLoading = ref(false)
  636. const getSubscribeLoginDown = async () => {
  637. isSubscribeLoading.value = true
  638. let res = await documentaryApi.followDealSubscribeLoginList({
  639. platform: "",
  640. page: null,
  641. });
  642. if (res.code == 200) {
  643. SubscribeDownData.value = res.data?.map(item => ({
  644. text: t('Documentary.console.item28') + '-' + item.followLogin || '--',
  645. value: item.followLogin
  646. })) || []
  647. } else {
  648. uni.showToast({
  649. title: res.msg,
  650. icon: 'none'
  651. })
  652. }
  653. isSubscribeLoading.value = false
  654. }
  655. const searchParams = ref({})
  656. const tableRef = ref(null)
  657. const handleSearch = (params) => {
  658. search.value = { ...search.value, ...params }
  659. nextTick(() => {
  660. tableRef.value.refreshTable()
  661. })
  662. }
  663. const handleReset = (params) => {
  664. search.value = { ...search.value, ...params }
  665. nextTick(() => {
  666. tableRef.value.refreshTable()
  667. })
  668. }
  669. const currentColumns = computed(() => [
  670. {
  671. prop: 'dealNickname',
  672. label: t('Documentary.tradingCenter.item1'),
  673. align: 'center',
  674. formatter: ({ row }) => row.dealNickname || '--'
  675. },
  676. {
  677. prop: 'dealLogin',
  678. label: t('Documentary.tradingCenter.item18'),
  679. align: 'center',
  680. formatter: ({ row }) => numberDesensitization(row.dealLogin) || '--'
  681. },
  682. {
  683. prop: 'followLogin',
  684. label: t('Documentary.console.item28'),
  685. align: 'center',
  686. formatter: ({ row }) => row.followLogin || '--'
  687. },
  688. {
  689. prop: 'followPlatform',
  690. label: t('Label.Platform'),
  691. align: 'center',
  692. formatter: ({ row }) => row.followPlatform || '--'
  693. },
  694. {
  695. prop: 'followLeverage',
  696. label: t('Label.Leverage'),
  697. align: 'center',
  698. formatter: ({ row }) => row.followLeverage ? `1:${row.followLeverage}` : '--'
  699. },
  700. {
  701. prop: 'followType',
  702. label: t('Documentary.TundManagement.item19'),
  703. align: 'center',
  704. slot: 'followType'
  705. },
  706. {
  707. prop: 'followValue',
  708. label: t('Documentary.TundManagement.item20'),
  709. align: 'center',
  710. },
  711. {
  712. prop: 'balanceEquity',
  713. label: t('Label.Balance') + '/' + t('Label.Equity'),
  714. align: 'center',
  715. slot: 'balanceEquity',
  716. },
  717. {
  718. prop: 'timeRange',
  719. label: t('Documentary.TundManagement.item26') + ' / ' + t('Documentary.TundManagement.item27'),
  720. align: 'center',
  721. slot: 'timeRange',
  722. },
  723. {
  724. prop: 'followProfit',
  725. label: t('Documentary.TundManagement.item21'),
  726. align: 'center',
  727. formatter: ({ row }) => numberDecimal(row.followProfit || 0)
  728. },
  729. {
  730. prop: 'action',
  731. label: t('Label.Action'),
  732. type: 'action',
  733. align: 'center',
  734. menuList: [
  735. {
  736. label: t('Documentary.TundManagement.item47'),
  737. type: 'Unsubscribe',
  738. btnClick: (row) => handleMenuClick({ type: 'Unsubscribe', row }),
  739. show: true,
  740. },
  741. {
  742. label: t('Documentary.TundManagement.item48'),
  743. type: 'settings',
  744. btnClick: (row) => handleMenuClick({ type: 'settings', row }),
  745. show: true,
  746. }
  747. ],
  748. },
  749. ])
  750. const dialogSubscribeFllow = ref(false)
  751. const dialogSubscribeDataCancel = ref({})
  752. const dialogSubscribeCancel = ref(false)
  753. const dialogSubscribeFllowData = ref({})
  754. const dialogSubscribeFllowDataSelect = ref({})
  755. const dialogSubscribeFllowRef = ref(null)
  756. const handleMenuClick = (item) => {
  757. if (item.type == "Unsubscribe") {
  758. dialogSubscribeDataCancel.value = item.row;
  759. dialogSubscribeCancel.value = true;
  760. } else if (item.type == "settings") {
  761. dialogSubscribeFllowData.value = item.row;
  762. dialogSubscribeFllowDataSelect.value = {
  763. protect: item.row.protect,
  764. protectType: item.row.protectType,
  765. protectAmount: item.row.protectAmount,
  766. protectRatio: item.row.protectRatio,
  767. followType: item.row.followType,
  768. volume: item.row.volume / 100,
  769. ratio: item.row.ratio,
  770. };
  771. dialogSubscribeFllow.value = true;
  772. }
  773. }
  774. const dialogSubscribeCancelTip = ref(false)
  775. const dialogSubscribeDataCancelRef = ref(null)
  776. //取消订阅
  777. const ToUnSubscribe = async () => {
  778. try {
  779. if (flag.value) {
  780. return;
  781. } else {
  782. flag.value = true;
  783. }
  784. let res = await documentaryApi.followDealSubscribeUnsubscribe({
  785. id: dialogSubscribeDataCancel.value.id,
  786. });
  787. if (res.code == 200) {
  788. uni.showToast({
  789. title: t('Msg.Success'),
  790. icon: 'none'
  791. })
  792. ToUnSubscribeCancel();
  793. ToUnSubscribeCancelTip();
  794. tableRef.value.refreshTable()
  795. getSubscribeLoginDown();
  796. flag.value = false;
  797. } else {
  798. uni.showToast({
  799. title: res.msg,
  800. icon: 'none'
  801. })
  802. flag.value = false;
  803. }
  804. } catch (error) {
  805. return false;
  806. }
  807. }
  808. const ToUnSubscribeCancel = () => {
  809. dialogSubscribeDataCancelRef?.value?.clearValidate()
  810. dialogSubscribeCancel.value = false;
  811. }
  812. const dialogSubscribeCancelTipOpen = () => {
  813. ToUnSubscribeCancel();
  814. dialogSubscribeCancelTip.value = true;
  815. }
  816. const ToUnSubscribeCancelTip = () => {
  817. ToUnSubscribeCancel();
  818. dialogSubscribeCancelTip.value = false;
  819. }
  820. //跟单设置
  821. const FllowSetting = async () => {
  822. try {
  823. await dialogSubscribeFllowRef.value.validate()
  824. if (flag.value) {
  825. return;
  826. } else {
  827. flag.value = true;
  828. }
  829. let primary = {
  830. id: dialogSubscribeFllowData.value.id,
  831. protect: dialogSubscribeFllowDataSelect.value.protect,
  832. protectType: dialogSubscribeFllowDataSelect.value.protect
  833. ? dialogSubscribeFllowDataSelect.value.protectType
  834. : null,
  835. protectAmount:
  836. dialogSubscribeFllowDataSelect.value.protect &&
  837. dialogSubscribeFllowDataSelect.value.protectType == 1
  838. ? dialogSubscribeFllowDataSelect.value.protectAmount
  839. : null,
  840. protectRatio:
  841. dialogSubscribeFllowDataSelect.value.protect &&
  842. dialogSubscribeFllowDataSelect.value.protectType == 2
  843. ? dialogSubscribeFllowDataSelect.value.protectRatio
  844. : null,
  845. followType: dialogSubscribeFllowDataSelect.value.followType,
  846. volume:
  847. dialogSubscribeFllowDataSelect.value.followType == 1
  848. ? dialogSubscribeFllowDataSelect.value.volume * 100
  849. : null,
  850. ratio:
  851. dialogSubscribeFllowDataSelect.value.followType == 2
  852. ? dialogSubscribeFllowDataSelect.value.ratio
  853. : null,
  854. };
  855. let res = await documentaryApi.followDealSubscribeUpdate(primary);
  856. if (res.code == 200) {
  857. uni.showToast({
  858. title: t('Msg.Success'),
  859. icon: 'none'
  860. })
  861. FllowSettingCancel();
  862. tableRef.value.refreshTable()
  863. getSubscribeLoginDown();
  864. flag.value = false;
  865. } else {
  866. uni.showToast({
  867. title: res.msg,
  868. icon: 'none'
  869. })
  870. flag.value = false;
  871. }
  872. } catch (error) {
  873. flag.value = false;
  874. }
  875. }
  876. const FllowSettingCancel = function () {
  877. dialogSubscribeFllowRef?.value?.clearValidate()
  878. dialogSubscribeFllow.value = false;
  879. }
  880. const flag = ref(false)
  881. const listApi = ref(null)
  882. onMounted(() => {
  883. getSubscribeLoginDown()
  884. listApi.value = documentaryApi.followDealSubscribeList
  885. })
  886. </script>
  887. <style scoped lang="scss">
  888. @import "@/uni.scss";
  889. .sp-view-tab {
  890. border-bottom: 1px dashed #98989880;
  891. line-height: 2;
  892. }
  893. .sp-view-tab-b {
  894. line-height: 2;
  895. }
  896. .avatar {
  897. width: px2rpx(60);
  898. height: px2rpx(60);
  899. border-radius: 4px;
  900. }
  901. .content-title {
  902. display: flex;
  903. justify-content: space-between;
  904. align-items: center;
  905. font-size: px2rpx(22);
  906. font-weight: 500;
  907. color: var(--bs-emphasis-color);
  908. background-color: rgba(255, 255, 255, 0);
  909. .content-title-btns {
  910. display: flex;
  911. align-items: center;
  912. justify-content: center;
  913. gap: px2rpx(12);
  914. .btn-primary {
  915. min-width: px2rpx(120);
  916. background-color: var(--color-error);
  917. color: #fff;
  918. padding: 0 px2rpx(12);
  919. border: none;
  920. font-size: px2rpx(14);
  921. text-align: center;
  922. cursor: pointer;
  923. display: flex;
  924. align-items: center;
  925. justify-content: center;
  926. gap: px2rpx(8);
  927. }
  928. .btn-primary1 {
  929. background-color: #cf1322;
  930. ;
  931. }
  932. .btn-primary2 {
  933. background-color: var(--color-secondary-focus);
  934. }
  935. }
  936. }
  937. .operation-btn {
  938. :deep(text) {
  939. display: flex;
  940. align-items: center;
  941. justify-content: center;
  942. gap: px2rpx(4);
  943. cursor: pointer;
  944. background-color: var(--color-slate-150);
  945. padding: px2rpx(8) 0;
  946. }
  947. }
  948. .operation-btn.disabled {
  949. cursor: not-allowed;
  950. opacity: 0.5;
  951. }
  952. .search-bar {
  953. display: flex;
  954. align-items: center;
  955. justify-content: flex-start;
  956. flex-wrap: wrap;
  957. gap: px2rpx(16);
  958. margin: px2rpx(26) 0;
  959. .cwg-combox,
  960. .uni-easyinput,
  961. .uni-date {
  962. width: px2rpx(240) !important;
  963. flex: none;
  964. }
  965. }
  966. .dia-content {
  967. padding: px2rpx(20);
  968. .uni-forms-item {
  969. width: 100%;
  970. }
  971. .grid-layout {
  972. display: grid;
  973. grid-template-columns: 1fr 1fr;
  974. gap: px2rpx(20);
  975. margin: px2rpx(24) 0;
  976. padding: px2rpx(20);
  977. background-color: transparent;
  978. border-radius: px2rpx(8);
  979. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  980. }
  981. .fllow-title {
  982. display: flex;
  983. align-items: center;
  984. justify-content: space-between;
  985. border-bottom: 1px solid #eee;
  986. padding-bottom: 10px;
  987. margin: px2rpx(10) 0 px2rpx(16);
  988. .title {
  989. font-weight: bold;
  990. color: var(--bs-heading-color);
  991. padding-left: 8px;
  992. border-left: 4px solid #eb3f57;
  993. font-size: 16px;
  994. }
  995. }
  996. .delete-grid {
  997. margin: px2rpx(16) 0;
  998. }
  999. .delete-row {
  1000. display: grid;
  1001. grid-template-columns: 1fr 1fr;
  1002. gap: px2rpx(12);
  1003. @media screen and (max-width: 768px) {
  1004. grid-template-columns: 1fr;
  1005. }
  1006. }
  1007. .delete-item {
  1008. flex: 1;
  1009. display: flex;
  1010. justify-content: space-between;
  1011. align-items: center;
  1012. padding: px2rpx(12) 0;
  1013. border-bottom: 1px dashed #e9ecef;
  1014. }
  1015. .delete-label {
  1016. font-size: px2rpx(14);
  1017. color: var(--bs-body-color);
  1018. }
  1019. .delete-value {
  1020. font-size: px2rpx(14);
  1021. color: var(--bs-emphasis-color);
  1022. font-weight: 400;
  1023. }
  1024. .delete-tip {
  1025. margin-top: px2rpx(26);
  1026. font-size: px2rpx(14);
  1027. color: var(--bs-body-color);
  1028. line-height: 1.5;
  1029. padding-top: px2rpx(16);
  1030. }
  1031. .tip-star {
  1032. color: #dc3545;
  1033. margin-right: px2rpx(4);
  1034. }
  1035. .agree {
  1036. margin-top: px2rpx(20);
  1037. }
  1038. .checkbox-agree {
  1039. display: flex;
  1040. align-items: flex-start;
  1041. gap: px2rpx(8);
  1042. .agree-text {
  1043. font-size: px2rpx(14);
  1044. color: var(--bs-body-color);
  1045. line-height: 1.5;
  1046. width: 100%;
  1047. white-space: wrap;
  1048. .a {
  1049. color: #007bff;
  1050. text-decoration: underline;
  1051. margin: 0 px2rpx(4);
  1052. &:hover {
  1053. color: #0056b3;
  1054. }
  1055. }
  1056. }
  1057. }
  1058. .fllow-content {
  1059. margin-bottom: px2rpx(16);
  1060. .tit {
  1061. font-size: px2rpx(14);
  1062. font-weight: 500;
  1063. color: var(--bs-body-color);
  1064. margin-bottom: px2rpx(6);
  1065. text-transform: uppercase;
  1066. letter-spacing: px2rpx(0.5);
  1067. }
  1068. .con {
  1069. font-size: px2rpx(16);
  1070. font-weight: 400;
  1071. color: var(--bs-emphasis-color);
  1072. line-height: 1.4;
  1073. }
  1074. }
  1075. .form-row {
  1076. display: grid;
  1077. grid-template-columns: 1fr 1fr;
  1078. gap: px2rpx(20);
  1079. margin-top: px2rpx(16);
  1080. }
  1081. .form-item {
  1082. display: flex;
  1083. flex-direction: column;
  1084. align-items: flex-start;
  1085. text {
  1086. font-size: px2rpx(14);
  1087. font-weight: 500;
  1088. color: var(--bs-body-color);
  1089. margin-bottom: px2rpx(8);
  1090. white-space: nowrap;
  1091. }
  1092. input,
  1093. select,
  1094. textarea {
  1095. width: 100%;
  1096. padding: px2rpx(10);
  1097. border: 1px solid #ced4da;
  1098. border-radius: px2rpx(4);
  1099. font-size: px2rpx(14);
  1100. transition: all 0.2s ease;
  1101. &:focus {
  1102. outline: none;
  1103. border-color: #4dabf7;
  1104. box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.2);
  1105. }
  1106. }
  1107. textarea {
  1108. resize: vertical;
  1109. min-height: px2rpx(100);
  1110. }
  1111. }
  1112. .tip-red {
  1113. color: #dc3545;
  1114. font-size: px2rpx(14);
  1115. margin: px2rpx(12) 0 px2rpx(24) 0;
  1116. }
  1117. .tip-text {
  1118. margin-top: px2rpx(24);
  1119. font-size: px2rpx(14);
  1120. color: var(--bs-body-color);
  1121. line-height: 1.5;
  1122. padding: px2rpx(16);
  1123. background-color: #e7f3ff;
  1124. border-radius: px2rpx(4);
  1125. border-left: 4px solid #4dabf7;
  1126. }
  1127. }
  1128. /* 弹窗按钮样式 */
  1129. :deep(.cwg-popup__footer) {
  1130. display: flex;
  1131. gap: px2rpx(20);
  1132. padding: px2rpx(20);
  1133. border-top: 1px solid #e9ecef;
  1134. button {
  1135. flex: 1;
  1136. padding: px2rpx(12) 0;
  1137. border-radius: px2rpx(4);
  1138. font-size: px2rpx(14);
  1139. font-weight: 500;
  1140. transition: all 0.2s ease;
  1141. &:first-child {
  1142. background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  1143. color: #495057;
  1144. border: 1px solid #ced4da;
  1145. &:hover {
  1146. background-color: transparent;
  1147. border-color: #adb5bd;
  1148. }
  1149. &:active {
  1150. transform: scale(0.98);
  1151. }
  1152. }
  1153. &:last-child {
  1154. background-color: #dc3545;
  1155. color: white;
  1156. border: 1px solid #dc3545;
  1157. &:hover {
  1158. background-color: #c82333;
  1159. border-color: #bd2130;
  1160. }
  1161. &:active {
  1162. transform: scale(0.98);
  1163. }
  1164. }
  1165. }
  1166. }
  1167. </style>