subscribe-list.vue 46 KB

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