trading-management.vue 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. <template>
  2. <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
  3. <view class="container">
  4. <view class="row">
  5. <view class="col-12">
  6. <view class="border-0 card-header">
  7. <view class="d-flex flex-wrap gap-3 align-items-center justify-content-between mb-3">
  8. <h3 class="mb-0" style="align-self: flex-start" v-t="'Documentary.TundManagement.item11'">
  9. </h3>
  10. <button class="btn btn-secondary btn-shadow waves-effect" @click="getCustomLoginDownLogin">
  11. <view class="d-flex align-items-center">
  12. <cwg-icon icon="crm-plus" :size="16" color="#fff" />
  13. <text v-t="'Documentary.TundManagement.item12'" />
  14. </view>
  15. </button>
  16. </view>
  17. </view>
  18. </view>
  19. </view>
  20. </view>
  21. <view class="content-container list-content-empty" v-if="accountDataLoading || accountData.length > 0">
  22. <uni-loading v-if="accountDataLoading" />
  23. <view class="field-container" v-else>
  24. <view class="account-l-con" v-for="(item, index) in accountData" :key="index">
  25. <view class="tit">
  26. <view>
  27. <i class="el-icon-success green-icon"></i><text class="tit-tit"
  28. v-t="'Documentary.TundManagement.item13'"></text>
  29. - {{ item.dealLogin || "--" }}
  30. </view>
  31. <view class="caozuo">
  32. <cwg-icon class="cwg-cursor cursor-pointer"
  33. :data-tooltip="t('Documentary.TundManagement.item28')" name="crm-trash-can"
  34. @click="dialogFllowDele(item)" />
  35. <cwg-icon class="cwg-cursor cursor-pointer"
  36. :data-tooltip="t('Documentary.TundManagement.item31')" name="cog-outline"
  37. @click="dialogFllowUpdate(item)" />
  38. </view>
  39. </view>
  40. <view class="account-grid">
  41. <view class="account-grid-item">
  42. <view class="sub" v-t="'Label.TradingAccount'"></view>
  43. <view class="num">{{ item.dealLogin || "--" }}</view>
  44. </view>
  45. <view class="account-grid-item">
  46. <view class="sub" v-t="'Label.PlatformType'"></view>
  47. <view class="num">{{ item.dealPlatform || "--" }}</view>
  48. </view>
  49. <view class="account-grid-item">
  50. <view class="sub" v-t="'Label.AccountType'"></view>
  51. <view class="num">
  52. <text>{{ groupTypeName(item.dealLoginType) }}</text>
  53. </view>
  54. </view>
  55. <view class="account-grid-item">
  56. <view class="sub" v-t="'Label.Leverage'"></view>
  57. <view class="num">
  58. <text v-if="item.dealLeverage">1:{{ item.dealLeverage }}</text>
  59. <text v-else>{{ "--" }}</text>
  60. </view>
  61. </view>
  62. <view class="account-grid-item">
  63. <view class="sub" v-t="'Label.Balance'"></view>
  64. <view class="num">
  65. {{ numberFormat(item.dealBalance || 0) }}
  66. </view>
  67. </view>
  68. <view class="account-grid-item">
  69. <view class="sub" v-t="'Label.Equity'"></view>
  70. <view class="num">{{ numberFormat(item.dealEquity || 0) }}</view>
  71. </view>
  72. <view class="account-grid-item">
  73. <view class="sub" v-t="'Documentary.TundManagement.item14'"></view>
  74. <view class="num">{{ optObj[item.settlementCycle] || "--" }}</view>
  75. </view>
  76. <view class="account-grid-item">
  77. <view class="sub" v-t="'Documentary.TundManagement.item15'"></view>
  78. <view class="num">
  79. <text v-if="item.distributionType == 1"
  80. v-t="'Documentary.TundManagement.item59'"></text>
  81. </view>
  82. </view>
  83. <view class="account-grid-item">
  84. <view class="sub" v-t="'Documentary.TundManagement.item16'"></view>
  85. <view class="num">{{ item.distributionRatio || "0" }}%</view>
  86. </view>
  87. </view>
  88. </view>
  89. </view>
  90. </view>
  91. <view v-else class="content-container list-content-empty">
  92. <view class="list-empty-state">
  93. <cwg-empty-state />
  94. </view>
  95. </view>
  96. <!-- 删除信号源 -->
  97. <cwg-popup v-model:visible="dialogFllowDelete" type="center" :mask-click="false" :show-footers="true"
  98. :title="t('Documentary.TundManagement.item28')">
  99. <view class="dia-content">
  100. <view class="fllow-title delete-title">
  101. <text class="title">{{ t('Documentary.TundManagement.item29') }}</text>
  102. </view>
  103. <view class="delete-grid">
  104. <view class="delete-row">
  105. <view class="delete-item">
  106. <text class="delete-label">{{ t('Documentary.tradingCenter.item29') }}</text>
  107. <text class="delete-value">{{ dialogFllowDataDelete.dealLogin || '--' }}</text>
  108. </view>
  109. <view class="delete-item">
  110. <text class="delete-label">{{ t('Documentary.console.item3') }}</text>
  111. <text class="delete-value">{{ dialogFllowDataDelete.dealPlatform || '--' }}</text>
  112. </view>
  113. </view>
  114. <view class="delete-row">
  115. <view class="delete-item">
  116. <text class="delete-label">{{ t('Documentary.console.item7') }}</text>
  117. <text class="delete-value">{{ numberFormat(dialogFllowDataDelete.dealBalance || 0) }}</text>
  118. </view>
  119. <view class="delete-item">
  120. <text class="delete-label">{{ t('Label.AccountType') }}</text>
  121. <text class="delete-value">
  122. <text> {{ groupTypeName(dialogFllowDataDelete.dealLoginType) }}</text>
  123. </text>
  124. </view>
  125. </view>
  126. <view class="delete-row">
  127. <view class="delete-item">
  128. <text class="delete-label">{{ t('Documentary.console.item6') }}</text>
  129. <text class="delete-value">{{ numberFormat(dialogFllowDataDelete.dealEquity) }}</text>
  130. </view>
  131. <view class="delete-item">
  132. <text class="delete-label">{{ t('Documentary.tradingCenter.item30') }}</text>
  133. <text class="delete-value">
  134. <text v-if="dialogFllowDataDelete.distributionType == 1"
  135. v-t="'Documentary.TundManagement.item59'"></text>
  136. </text>
  137. </view>
  138. </view>
  139. <view class="delete-row">
  140. <view class="delete-item">
  141. <text class="delete-label">{{ t('Label.Credit') }}</text>
  142. <text class="delete-value">{{ numberFormat(dialogFllowDataDelete.dealCredit || 0) }}</text>
  143. </view>
  144. <view class="delete-item">
  145. <text class="delete-label">{{ t('Documentary.tradingCenter.item31') }}</text>
  146. <text class="delete-value">{{ dialogFllowDataDelete.distributionRatio || '0' }}%</text>
  147. </view>
  148. </view>
  149. <view class="delete-row">
  150. <view class="delete-item">
  151. <text class="delete-label">{{ t('Label.Leverage') }}</text>
  152. <text class="delete-value">1:{{ dialogFllowDataDelete.dealLeverage || '0' }}</text>
  153. </view>
  154. <view class="delete-item">
  155. <text class="delete-label">{{ t('Documentary.tradingCenter.item32') }}</text>
  156. <text class="delete-value">{{ optObj[dialogFllowDataDelete.settlementCycle] || '--'
  157. }}</text>
  158. </view>
  159. </view>
  160. </view>
  161. <view class="delete-tip">
  162. <text v-t="'Documentary.TundManagement.item30'"></text>
  163. </view>
  164. </view>
  165. <template #footer>
  166. <button @click="FllowDeleCancel">{{ t('Btn.Cancel') }}</button>
  167. <button type="primary" @click="FllowDele">{{ t('Btn.Confirm') }}</button>
  168. </template>
  169. </cwg-popup>
  170. <!-- 信号源设置 -->
  171. <cwg-popup v-model:visible="dialogFllow" type="center" :mask-click="false" :show-footers="true"
  172. :title="t('Documentary.TundManagement.item31')" width="650px">
  173. <uni-forms ref="formRef" :model="dialogFllowData" :rules="rules" label-position="top">
  174. <!-- 名片信息 -->
  175. <view class="dia-content">
  176. <!-- 名片信息 -->
  177. <view class="fllow-title">
  178. <text class="title">{{ t('Documentary.tradingCenter.item126') }}</text>
  179. </view>
  180. <view class="form-item">
  181. <uni-forms-item name="nickname" :label="t('Documentary.console.item20')">
  182. <uni-easyinput v-model="dialogFllowData.nickname" :placeholder="t('placeholder.input')"
  183. @blur="validateAmount" />
  184. </uni-forms-item>
  185. </view>
  186. <view class="form-row">
  187. <view class="form-col">
  188. <view class="form-item">
  189. <uni-forms-item name="personalSignature" :label="t('Documentary.console.item21')">
  190. <uni-easyinput v-model="dialogFllowData.personalSignature"
  191. :placeholder="t('placeholder.input')" type="textarea"
  192. @input="filterChineseEnglishOnlyForApply('personalSignature', $event, 1)" />
  193. </uni-forms-item>
  194. </view>
  195. </view>
  196. <view class="form-col">
  197. <view class="form-item">
  198. <uni-forms-item name="traderStrategy" :label="t('Documentary.console.item22')">
  199. <uni-easyinput v-model="dialogFllowData.traderStrategy"
  200. :placeholder="t('placeholder.input')" type="textarea"
  201. @input="filterChineseEnglishOnlyForApply('traderStrategy', $event, 1)" />
  202. </uni-forms-item>
  203. </view>
  204. </view>
  205. </view>
  206. <view class="tip-red">
  207. <text v-t="'Documentary.console.item37'"></text>
  208. </view>
  209. <!-- 账户信息 -->
  210. <view class="fllow-title">
  211. <text class="title">{{ t('Documentary.TundManagement.item29') }}</text>
  212. </view>
  213. <view class="delete-grid">
  214. <view class="delete-row">
  215. <view class="delete-item">
  216. <text class="delete-label">{{ t('Documentary.console.item3') }}</text>
  217. <text class="delete-value">{{ dialogFllowData.dealPlatform || '--' }}</text>
  218. </view>
  219. <view class="delete-item">
  220. <text class="delete-label">{{ t('Documentary.tradingCenter.item29') }}</text>
  221. <text class="delete-value">{{ dialogFllowData.dealLogin || '--' }}</text>
  222. </view>
  223. </view>
  224. <view class="delete-row">
  225. <view class="delete-item">
  226. <text class="delete-label">{{ t('Label.AccountType') }}</text>
  227. <text class="delete-value">
  228. <text> {{ groupTypeName(dialogFllowData.dealLoginType) }}</text>
  229. </text>
  230. </view>
  231. <view class="delete-item">
  232. <text class="delete-label">{{ t('Label.Leverage') }}</text>
  233. <text class="delete-value">1:{{ dialogFllowData.dealLeverage || '0' }}</text>
  234. </view>
  235. </view>
  236. </view>
  237. <!-- 展示设置 -->
  238. <view class="fllow-title">
  239. <text class="title">{{ t('Documentary.TundManagement.item32') }}</text>
  240. </view>
  241. <view class="form-row">
  242. <view class="form-col">
  243. <view class="form-item">
  244. <uni-forms-item name="historyShow" :label="t('Documentary.TundManagement.item34')">
  245. <cwg-combox v-model:value="dialogFllowData.historyShow" :clearable="false"
  246. :options="[{ text: t('Btn.item6'), value: 1 }, { text: t('Btn.item7'), value: 0 }]"
  247. :placeholder="t('placeholder.choose')" />
  248. </uni-forms-item>
  249. </view>
  250. </view>
  251. <view class="form-col">
  252. <view class="form-item">
  253. <uni-forms-item name="historyTime" :label="t('Documentary.TundManagement.item35')">
  254. <uni-datetime-picker v-model="dialogFllowData.historyTime" type="date"
  255. :placeholder="t('placeholder.input')" @change="handleDateChange" />
  256. <!-- <uni-date-picker type="date" v-model="dialogFllowData.historyTime" /> -->
  257. </uni-forms-item>
  258. </view>
  259. </view>
  260. </view>
  261. <view class="form-item">
  262. <uni-forms-item name="introduceShow" :label="t('Documentary.TundManagement.item36')">
  263. <cwg-combox v-model:value="dialogFllowData.historyShow" :clearable="false"
  264. :options="[{ text: t('Btn.item6'), value: 1 }, { text: t('Btn.item7'), value: 0 }]"
  265. :placeholder="t('placeholder.choose')" />
  266. </uni-forms-item>
  267. </view>
  268. <!-- 分润设置 -->
  269. <view class="fllow-title">
  270. <text class="title">{{ t('Documentary.TundManagement.item33') }}</text>
  271. </view>
  272. <!-- 已有订阅 → 只读 -->
  273. <view v-if="dialogFllowData.followCount" class="delete-grid">
  274. <view class="delete-row">
  275. <view class="delete-item">
  276. <text class="delete-label">{{ t('Documentary.TundManagement.item38') }}</text>
  277. <text class="delete-value">{{ dialogFllowData.distributionType || '--' }}</text>
  278. </view>
  279. <view class="delete-item">
  280. <text class="delete-label">{{ t('Documentary.tradingCenter.item32') }}</text>
  281. <text class="delete-value">{{ dialogFllowData.settlementCycle || '--' }}</text>
  282. </view>
  283. </view>
  284. <view class="delete-row">
  285. <view class="delete-item">
  286. <text class="delete-label">{{ t('Documentary.TundManagement.item39') }}</text>
  287. <text class="delete-value">{{ dialogFllowData.distributionRatio || '--' }}</text>
  288. </view>
  289. <view class="delete-item">
  290. <text class="delete-label">{{ t('Documentary.tradingCenter.item32') }}</text>
  291. <text class="delete-value">{{ dialogFllowData.settlementCycle || '--' }}</text>
  292. </view>
  293. </view>
  294. </view>
  295. <!-- 无订阅 → 可编辑 -->
  296. <view v-else class="form-row">
  297. <view class="form-col">
  298. <view class="form-item">
  299. <uni-forms-item name="distributionType" :label="t('Documentary.TundManagement.item38')">
  300. <cwg-combox v-model:value="dialogFllowData.distributionType" :clearable="false"
  301. :options="[{ text: t('Documentary.TundManagement.item59'), value: 1 }]"
  302. :placeholder="t('placeholder.choose')" />
  303. </uni-forms-item>
  304. </view>
  305. </view>
  306. <view class="form-col">
  307. <view class="form-item">
  308. <uni-forms-item name="distributionRatio"
  309. :label="t('Documentary.TundManagement.item39') + '(%)'">
  310. <uni-easyinput v-model="dialogFllowData.distributionRatio"
  311. :placeholder="t('placeholder.input')" />
  312. </uni-forms-item>
  313. </view>
  314. </view>
  315. <view class="form-col">
  316. <view class="form-item">
  317. <uni-forms-item name="settlementCycle" :label="t('Documentary.tradingCenter.item32')">
  318. <cwg-combox v-model:value="dialogFllowData.settlementCycle" :clearable="false"
  319. :options="optList1" :placeholder="t('placeholder.choose')" />
  320. </uni-forms-item>
  321. </view>
  322. </view>
  323. </view>
  324. </view>
  325. </uni-forms>
  326. <template #footer>
  327. <button @click="FllowUpdateCancel">{{ t('Btn.Cancel') }}</button>
  328. <button type="primary" @click="FllowUpdate">{{ t('Btn.Confirm') }}</button>
  329. </template>
  330. </cwg-popup>
  331. <!--申请成为信号源-->
  332. <cwg-popup v-model:visible="dialogFllowApply" type="center" :mask-click="false" :show-footers="true"
  333. :title="t('Documentary.TundManagement.item41')" width="650px">
  334. <uni-forms ref="applyRef" :model="dialogFllowDataApply" :rules="rules" label-position="top"
  335. label-width="200px">
  336. <!-- 名片信息 -->
  337. <view class="dia-content">
  338. <!-- 名片信息 -->
  339. <view class="fllow-title">
  340. <text class="title">{{ t('Documentary.tradingCenter.item126') }}</text>
  341. </view>
  342. <view class="form-item">
  343. <uni-forms-item name="nickname" :label="t('Documentary.console.item20')">
  344. <uni-easyinput v-model="dialogFllowDataApply.nickname" :placeholder="t('placeholder.input')"
  345. @blur="validateAmount" />
  346. </uni-forms-item>
  347. </view>
  348. <view class="form-row">
  349. <view class="form-col">
  350. <view class="form-item">
  351. <uni-forms-item name="personalSignature" :label="t('Documentary.console.item21')">
  352. <uni-easyinput v-model="dialogFllowDataApply.personalSignature"
  353. :placeholder="t('placeholder.input')" type="textarea"
  354. @input="filterChineseEnglishOnlyForApply('personalSignature', $event, 2)" />
  355. </uni-forms-item>
  356. </view>
  357. </view>
  358. <view class="form-col">
  359. <view class="form-item">
  360. <uni-forms-item name="traderStrategy" :label="t('Documentary.console.item22')">
  361. <uni-easyinput v-model="dialogFllowDataApply.traderStrategy"
  362. :placeholder="t('placeholder.input')" type="textarea"
  363. @input="filterChineseEnglishOnlyForApply('traderStrategy', $event, 2)" />
  364. </uni-forms-item>
  365. </view>
  366. </view>
  367. </view>
  368. <view class="tip-red">
  369. <text v-t="'Documentary.console.item37'"></text>
  370. </view>
  371. <!-- 账户信息 -->
  372. <view class="fllow-title">
  373. <text class="title">{{ t('Documentary.TundManagement.item29') }}{{ fundRequirementText }}</text>
  374. </view>
  375. <view class="form-row">
  376. <view class="form-col">
  377. <view class="form-item">
  378. <uni-forms-item name="dealLogin" :label="t('Label.TradingAccount')">
  379. <cwg-combox v-model:value="dialogFllowDataApply.dealLogin" :clearable="false"
  380. :options="loginOptions" :placeholder="t('placeholder.choose')"
  381. @change="selectLoginDeal" />
  382. </uni-forms-item>
  383. </view>
  384. </view>
  385. <view class="form-col">
  386. <view class="form-item">
  387. <uni-forms-item name="platform" :label="t('Label.PlatformType')">
  388. <cwg-combox v-model:value="dialogFllowDataApply.platform" :clearable="false"
  389. :options="[{ text: 'MT4', value: 'MT4' }, { text: 'MT5', value: 'MT5' }]"
  390. :placeholder="t('placeholder.choose')" :disabled="true" />
  391. </uni-forms-item>
  392. </view>
  393. </view>
  394. </view>
  395. <view class="form-row">
  396. <view class="form-col">
  397. <view class="form-item">
  398. <uni-forms-item name="loginType" :label="t('Label.AccountType')">
  399. <cwg-combox v-model:value="dialogFllowDataApply.loginType" :clearable="false"
  400. :options="[
  401. { text: t('AccountType.ClassicAccount'), value: 1 },
  402. { text: t('AccountType.SeniorAccount'), value: 2 },
  403. { text: t('AccountType.SpeedAccount'), value: 5 },
  404. { text: t('AccountType.SpeedAccount'), value: 6 },
  405. { text: t('AccountType.StandardAccount'), value: 7 },
  406. { text: t('AccountType.CentAccount'), value: 8 }
  407. ]" :placeholder="t('placeholder.choose')" :disabled="true" />
  408. </uni-forms-item>
  409. </view>
  410. </view>
  411. <view class="form-col">
  412. <view class="form-item">
  413. <uni-forms-item name="leverage" :label="t('Label.Leverage')">
  414. <uni-easyinput v-model="dialogFllowDataApply.leverage"
  415. :placeholder="t('placeholder.input')" :disabled="true" />
  416. </uni-forms-item>
  417. </view>
  418. </view>
  419. </view>
  420. <!-- 展示设置 -->
  421. <view class="fllow-title">
  422. <text class="title">{{ t('Documentary.TundManagement.item32') }}</text>
  423. </view>
  424. <view class="form-row">
  425. <view class="form-col">
  426. <view class="form-item">
  427. <uni-forms-item name="historyShow" :label="t('Documentary.TundManagement.item34')">
  428. <cwg-combox v-model:value="dialogFllowDataApply.historyShow" :clearable="false"
  429. :options="[{ text: t('Btn.item6'), value: 1 }, { text: t('Btn.item7'), value: 0 }]"
  430. :placeholder="t('placeholder.choose')" />
  431. </uni-forms-item>
  432. </view>
  433. </view>
  434. <view class="form-col">
  435. <view class="form-item">
  436. <uni-forms-item name="historyTime" :label="t('Documentary.TundManagement.item35')">
  437. <uni-datetime-picker v-model="dialogFllowDataApply.historyTime" type="date"
  438. :placeholder="t('Documentary.TundManagement.item37')" />
  439. </uni-forms-item>
  440. </view>
  441. </view>
  442. </view>
  443. <view class="form-item">
  444. <uni-forms-item name="introduceShow" :label="t('Documentary.TundManagement.item36')">
  445. <cwg-combox v-model:value="dialogFllowDataApply.introduceShow" :clearable="false"
  446. :options="[{ text: t('Btn.item6'), value: 1 }, { text: t('Btn.item7'), value: 0 }]"
  447. :placeholder="t('placeholder.choose')" />
  448. </uni-forms-item>
  449. </view>
  450. <!-- 分润设置 -->
  451. <view class="fllow-title">
  452. <text class="title">{{ t('Documentary.TundManagement.item33') }}</text>
  453. </view>
  454. <view class="form-row">
  455. <view class="form-col">
  456. <view class="form-item">
  457. <uni-forms-item name="distributionType" :label="t('Documentary.TundManagement.item38')">
  458. <cwg-combox v-model:value="dialogFllowDataApply.distributionType" :clearable="false"
  459. :options="[{ text: t('Documentary.TundManagement.item59'), value: 1 }]"
  460. :placeholder="t('placeholder.choose')" />
  461. </uni-forms-item>
  462. </view>
  463. </view>
  464. <view class="form-col">
  465. <view class="form-item">
  466. <uni-forms-item name="distributionRatio"
  467. :label="t('Documentary.TundManagement.item39') + '(%)'">
  468. <uni-easyinput v-model="dialogFllowDataApply.distributionRatio"
  469. :placeholder="t('placeholder.input')" />
  470. </uni-forms-item>
  471. </view>
  472. </view>
  473. <view class="form-col">
  474. <view class="form-item">
  475. <uni-forms-item name="settlementCycle" :label="t('Documentary.tradingCenter.item32')">
  476. <cwg-combox v-model:value="dialogFllowDataApply.settlementCycle" :clearable="false"
  477. :options="optList1" :placeholder="t('placeholder.choose')" />
  478. </uni-forms-item>
  479. </view>
  480. </view>
  481. </view>
  482. <uni-forms-item class="agree" name="agree">
  483. <checkbox-group :value="dialogFllowDataApply.agree ? ['1'] : []" @change="onAgreeChange">
  484. <label class="checkbox-agree">
  485. <checkbox value="1" :checked="dialogFllowDataApply.agree" />
  486. <text class="agree-text">
  487. {{ t('Documentary.TundManagement.item42') }}
  488. <cwg-link type="pdf" style="text-decoration: underline;" class="a"
  489. :url="isZh ? 'pdf/CopyTradeUserAgreementcn.pdf' : 'pdf/CopyTradeUserAgreement.pdf'"
  490. target="_blank" title="Documentary.TundManagement.item43" />
  491. {{ t('Documentary.TundManagement.item42_2') }}
  492. </text>
  493. </label>
  494. </checkbox-group>
  495. </uni-forms-item>
  496. </view>
  497. </uni-forms>
  498. <template #footer>
  499. <button @click="ApplyFllowCancel">{{ t('Btn.Cancel') }}</button>
  500. <button type="primary" @click="ApplyFllow">{{ t('Btn.Confirm') }}</button>
  501. </template>
  502. </cwg-popup>
  503. </cwg-page-wrapper>
  504. </template>
  505. <script setup lang="ts">
  506. import { computed, ref, nextTick, onMounted, reactive, watch } from 'vue';
  507. import { isAfterJuly28 } from '@/utils/dateUtils'
  508. import { useI18n } from 'vue-i18n';
  509. const { t, locale } = useI18n();
  510. import { documentaryApi } from '@/service/documentary';
  511. import useUserStore from "@/stores/use-user-store";
  512. const userStore = useUserStore();
  513. const userInfo = computed(() => userStore.userInfo);
  514. import { useFilters } from '@/composables/useFilters'
  515. const { numberFormat, numberDecimal } = useFilters()
  516. import { useFollowEnum } from '@/pages/follow/const/enum'
  517. const { optObj, optList1 } = useFollowEnum()
  518. const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
  519. const formRef = ref(null)
  520. const rules = computed(() => ({
  521. password: {
  522. rules: [
  523. {
  524. required: true,
  525. validateFunction: (rule, value, data, callback) => {
  526. if (Config.Pattern.Password.test(value)) {
  527. callback()
  528. } else {
  529. callback(t('vaildate.password.format'))
  530. }
  531. return true
  532. }
  533. }
  534. ]
  535. },
  536. agree: {
  537. rules: [
  538. {
  539. validateFunction: (rule, value, data, callback) => {
  540. if (value) {
  541. callback()
  542. } else {
  543. callback(t('vaildate.agree.empty'))
  544. }
  545. return true
  546. }
  547. }
  548. ]
  549. },
  550. platform: {
  551. rules: [
  552. {
  553. required: true,
  554. errorMessage: t('vaildate.select.empty')
  555. }
  556. ]
  557. },
  558. currency: {
  559. rules: [
  560. {
  561. required: true,
  562. errorMessage: t('vaildate.select.empty')
  563. }
  564. ]
  565. },
  566. leverage: {
  567. rules: [
  568. {
  569. required: true,
  570. errorMessage: t('vaildate.select.empty')
  571. }
  572. ]
  573. },
  574. loginType: {
  575. rules: [
  576. {
  577. required: true,
  578. errorMessage: t('vaildate.select.empty')
  579. }
  580. ]
  581. },
  582. dealLogin: {
  583. rules: [
  584. {
  585. required: true,
  586. errorMessage: t('vaildate.select.empty')
  587. }
  588. ]
  589. },
  590. distributionType: {
  591. rules: [
  592. {
  593. required: true,
  594. errorMessage: t('vaildate.select.empty')
  595. }
  596. ]
  597. },
  598. distributionRatio: {
  599. rules: [
  600. {
  601. required: true,
  602. errorMessage: t('vaildate.input.empty')
  603. },
  604. {
  605. validateFunction: (rule, value, data, callback) => {
  606. if (value >= 0 && value <= 50) {
  607. callback()
  608. } else {
  609. callback('0-50')
  610. }
  611. return true
  612. }
  613. }
  614. ]
  615. },
  616. settlementCycle: {
  617. rules: [
  618. {
  619. required: true,
  620. errorMessage: t('vaildate.input.empty')
  621. }
  622. ]
  623. },
  624. historyShow: {
  625. rules: [
  626. {
  627. required: true,
  628. errorMessage: t('vaildate.select.empty')
  629. }
  630. ]
  631. },
  632. historyTime: {
  633. rules: [
  634. {
  635. required: true,
  636. errorMessage: t('vaildate.select.empty')
  637. }
  638. ]
  639. },
  640. introduceShow: {
  641. rules: [
  642. {
  643. required: true,
  644. errorMessage: t('vaildate.select.empty')
  645. }
  646. ]
  647. },
  648. protectAmount: {
  649. rules: [
  650. {
  651. required: true,
  652. errorMessage: t('vaildate.input.empty')
  653. }
  654. ]
  655. },
  656. protectRatio: {
  657. rules: [
  658. {
  659. required: true,
  660. errorMessage: t('vaildate.input.empty')
  661. }
  662. ]
  663. },
  664. nickname: {
  665. rules: [
  666. {
  667. required: true,
  668. errorMessage: t('vaildate.input.empty')
  669. },
  670. {
  671. validateFunction: (rule, value, data, callback) => {
  672. if (value && /^[0-9a-zA-Z]{1,24}$/.test(value)) {
  673. callback()
  674. } else {
  675. callback(t('Msg.nickname'))
  676. }
  677. return true
  678. }
  679. }
  680. ]
  681. },
  682. personalSignature: {
  683. rules: [
  684. {
  685. required: true,
  686. errorMessage: t('vaildate.input.empty')
  687. },
  688. {
  689. validateFunction: (rule, value, data, callback) => {
  690. if (!value || /^[\u4e00-\u9fa5a-zA-Z\s]*$/.test(value)) {
  691. callback()
  692. } else {
  693. callback(t('Documentary.console.item38'))
  694. }
  695. return true
  696. }
  697. }
  698. ]
  699. },
  700. traderStrategy: {
  701. rules: [
  702. {
  703. required: true,
  704. errorMessage: t('vaildate.input.empty')
  705. },
  706. {
  707. validateFunction: (rule, value, data, callback) => {
  708. if (!value || /^[\u4e00-\u9fa5a-zA-Z\s]*$/.test(value)) {
  709. callback()
  710. } else {
  711. callback(t('Documentary.console.item38'))
  712. }
  713. return true
  714. }
  715. }
  716. ]
  717. },
  718. followType: {
  719. rules: [
  720. {
  721. required: true,
  722. errorMessage: t('vaildate.select.empty')
  723. }
  724. ]
  725. },
  726. volume: {
  727. rules: [
  728. {
  729. required: true,
  730. errorMessage: t('vaildate.input.empty')
  731. }
  732. ]
  733. },
  734. ratio: {
  735. rules: [
  736. {
  737. required: true,
  738. errorMessage: t('vaildate.input.empty')
  739. }
  740. ]
  741. }
  742. }));
  743. watch(locale, () => {
  744. formRef.value?.clearValidate()
  745. })
  746. const filterChineseEnglishOnlyForApply = (field, value, type) => {
  747. // 只保留中文、英文和空格
  748. const filtered = value.replace(/[^\u4e00-\u9fa5a-zA-Z\s]/g, '');
  749. // 去掉前后空格,如果没有正文内容(全是空格)就设置为空字符串
  750. const trimmed = filtered.trim();
  751. if (type == 1) {
  752. nextTick(() => {
  753. dialogFllowData.value[field] = trimmed;
  754. })
  755. } else {
  756. nextTick(() => {
  757. dialogFllowDataApply[field] = trimmed;
  758. })
  759. }
  760. }
  761. //获取客户跟单账户的下拉列表
  762. const isSubscribeLoading = ref(false)
  763. const SubscribeDownData = ref([])
  764. const getSubscribeLoginDown = async () => {
  765. isSubscribeLoading.value = true
  766. let res = await documentaryApi.followDealSubscribeLoginList({
  767. platform: "",
  768. page: null,
  769. });
  770. if (res.code == 200) {
  771. SubscribeDownData.value = res.data?.map(item => ({
  772. text: t('Documentary.console.item28') + '-' + item.dealLogin || '--',
  773. value: item.dealLogin
  774. })) || []
  775. } else {
  776. uni.showToast({
  777. title: res.msg,
  778. icon: 'none'
  779. })
  780. }
  781. isSubscribeLoading.value = false
  782. }
  783. const onAgreeChange = (e) => {
  784. dialogFllowDataApply.agree = e.detail.value.length > 0
  785. }
  786. // 单位类型
  787. function groupCurrency(type) {
  788. const map = { GBP: ': £', USD: ': $', EUR: ': €', USC: ': ¢' }
  789. return map[type] || ': $'
  790. }
  791. // 账户类型
  792. function groupTypeName(type) {
  793. const typeMap = {
  794. '1': t('AccountType.ClassicAccount'),
  795. '2': t('AccountType.SeniorAccount'),
  796. '3': isAfterJuly28() ? '--' : t('AccountType.AgencyAccount'),
  797. '5': t('AccountType.SpeedAccount'),
  798. '6': t('AccountType.SpeedAccount'),
  799. '7': t('AccountType.StandardAccount'),
  800. '8': t('AccountType.CentAccount')
  801. }
  802. return typeMap[type] || ''
  803. }
  804. const loginOptions = computed(() => loginOptionsLogin.value.map(item => ({
  805. text: `${item.login} - ${groupTypeName(item.type)} - ${t('Custom.Deposit.AvailableBalance')}${groupCurrency(item.currency)}${numberDecimal(item.balance || 0)}`,
  806. value: item.login,
  807. disable: item.balance < 1000
  808. })))
  809. const selectLoginDeal = () => {
  810. loginOptionsLogin.value.forEach((item) => {
  811. if (item.login == dialogFllowDataApply.dealLogin) {
  812. dialogFllowDataApply.leverage = "1:" + item.leverage;
  813. dialogFllowDataApply.loginType = item.type;
  814. dialogFllowDataApply.platform = item.platform;
  815. }
  816. });
  817. }
  818. const applyRef = ref(null)
  819. const dialogFllowDataApply = reactive({
  820. dealLogin: '',
  821. leverage: '',
  822. loginType: '',
  823. platform: '',
  824. currency: '',
  825. leverageStatus: '',
  826. withdrawStatus: '',
  827. depositStatus: '',
  828. accountStatus: '',
  829. status: '',
  830. note: '',
  831. followType: '',
  832. volume: '',
  833. ratio: '',
  834. traderStrategy: '',
  835. personalSignature: '',
  836. nickname: '',
  837. protectAmount: '',
  838. protectRatio: '',
  839. introduceShow: '',
  840. historyShow: '',
  841. historyTime: '',
  842. settlementCycle: '',
  843. distributionType: '',
  844. distributionRatio: '',
  845. withdrawCurrency: '',
  846. withdrawAmount: '',
  847. depositCurrency: '',
  848. depositAmount: '',
  849. withdrawLogin: '',
  850. depositLogin: '',
  851. addTime: '',
  852. title: '',
  853. })
  854. const loginOptionsLogin = ref([])
  855. const dialogFllowApply = ref(false)
  856. //获取申请信号源交易账户下拉
  857. const getCustomLoginDownLogin = async () => {
  858. if (flag.value) {
  859. return;
  860. } else {
  861. flag.value = true;
  862. }
  863. let res = await documentaryApi.CustomDropdownData({
  864. platform: "",
  865. });
  866. if (res.code == 200) {
  867. loginOptionsLogin.value = res.data;
  868. dialogFllowApply.value = true;
  869. } else {
  870. uni.showToast({
  871. title: res.msg,
  872. icon: 'none'
  873. });
  874. }
  875. flag.value = false;
  876. }
  877. watch(() => dialogFllowDataApply.dealLogin, (newVal, oldVal) => {
  878. if (newVal !== oldVal) {
  879. selectLoginDeal();
  880. }
  881. })
  882. //申请信号源
  883. const ApplyFllow = async () => {
  884. try {
  885. await applyRef.value.validate()
  886. if (flag.value) {
  887. return;
  888. } else {
  889. flag.value = true;
  890. }
  891. let res = await documentaryApi.followDealApply({
  892. ...dialogFllowDataApply,
  893. });
  894. if (res.code == 200) {
  895. uni.showToast({
  896. title: t("Msg.Success"),
  897. icon: 'none'
  898. });
  899. ApplyFllowCancel();
  900. getDealLogin();
  901. flag.value = false;
  902. } else {
  903. uni.showToast({
  904. title: res.msg,
  905. icon: 'none'
  906. });
  907. flag.value = false;
  908. }
  909. } catch (error) {
  910. uni.showToast({ title: error.msg, icon: 'none' });
  911. } finally {
  912. flag.value = false;
  913. }
  914. }
  915. const ApplyFllowCancel = () => {
  916. applyRef.value &&
  917. applyRef.value.clearValidate();
  918. dialogFllowApply.value = false;
  919. }
  920. //获取客户信号源账户
  921. const accountDataLoading = ref(false)
  922. const accountData = ref([])
  923. const accountPager = ref({
  924. current: 1,
  925. row: 10,
  926. rowTotal: 0,
  927. pageTotal: 0
  928. })
  929. const getDealLogin = async () => {
  930. accountDataLoading.value = true;
  931. let res = await documentaryApi.followDealList({
  932. platform: null,
  933. status: 2,
  934. page: {
  935. current: accountPager.value.current,
  936. row: accountPager.value.row,
  937. },
  938. });
  939. if (res.code == 200) {
  940. accountData.value = res.data || []
  941. accountPager.value.rowTotal = res.page.rowTotal;
  942. accountPager.value.pageTotal = res.page.pageTotal;
  943. } else {
  944. uni.showToast({
  945. title: res.msg,
  946. icon: 'none'
  947. });
  948. }
  949. accountDataLoading.value = false;
  950. }
  951. //修改信号源
  952. const dialogFllowData = ref({})
  953. const dialogFllow = ref(false)
  954. const dialogFllowDataDelete = ref({})
  955. const dialogFllowDelete = ref(false)
  956. const flag = ref(false)
  957. const dialogFllowUpdate = (item) => {
  958. dialogFllowData.value = item;
  959. dialogFllow.value = true;
  960. }
  961. const FllowUpdate = async () => {
  962. try {
  963. await formRef.value.validate()
  964. if (flag.value) {
  965. return;
  966. } else {
  967. flag.value = true;
  968. }
  969. let res = await documentaryApi.followDealUpdate({
  970. ...dialogFllowData.value,
  971. });
  972. if (res.code == 200) {
  973. uni.showToast({
  974. title: t("Msg.Success"),
  975. icon: 'none'
  976. });
  977. FllowUpdateCancel();
  978. tableRef.value.refreshTable()
  979. getDealLogin();
  980. getSubscribeLoginDown()
  981. flag.value = false;
  982. } else {
  983. uni.showToast({
  984. title: res.msg,
  985. icon: 'none'
  986. });
  987. flag.value = false;
  988. }
  989. } catch (error) {
  990. flag.value = false;
  991. }
  992. }
  993. const FllowUpdateCancel = () => {
  994. formRef.value && formRef.value.clearValidate();
  995. dialogFllow.value = false;
  996. }
  997. //删除信号源
  998. const dialogFllowDele = (item) => {
  999. dialogFllowDataDelete.value = item;
  1000. dialogFllowDelete.value = true;
  1001. }
  1002. const FllowDele = async () => {
  1003. if (flag.value) {
  1004. return;
  1005. } else {
  1006. flag.value = true;
  1007. }
  1008. let res = await documentaryApi.followDealDelete({
  1009. ids: [dialogFllowDataDelete.value.id],
  1010. });
  1011. if (res.code == 200) {
  1012. uni.showToast({
  1013. title: t("Msg.Success"),
  1014. icon: 'none'
  1015. });
  1016. FllowDeleCancel();
  1017. tableRef.value.refreshTable()
  1018. getDealLogin();
  1019. getSubscribeLoginDown()
  1020. flag.value = false;
  1021. } else {
  1022. uni.showToast({
  1023. title: res.msg,
  1024. icon: 'none'
  1025. });
  1026. flag.value = false;
  1027. }
  1028. }
  1029. const FllowDeleCancel = () => {
  1030. dialogFllowDelete.value = false;
  1031. }
  1032. const listApi = ref(null)
  1033. onMounted(() => {
  1034. getDealLogin()
  1035. getSubscribeLoginDown()
  1036. listApi.value = documentaryApi.followDealSubscribeDealList
  1037. })
  1038. </script>
  1039. <style scoped lang="scss">
  1040. @import "@/uni.scss";
  1041. .btn {
  1042. margin: 0;
  1043. }
  1044. .content-container {
  1045. .field-container {
  1046. display: grid;
  1047. grid-template-columns: repeat(3, 1fr);
  1048. gap: px2rpx(16);
  1049. min-width: 0;
  1050. overflow: hidden;
  1051. @media (max-width: 991px) {
  1052. grid-template-columns: 1fr;
  1053. }
  1054. .account-l-con {
  1055. background-color: transparent;
  1056. border-radius: px2rpx(8);
  1057. padding: px2rpx(20);
  1058. margin-bottom: px2rpx(16);
  1059. transition: all 0.3s ease;
  1060. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  1061. width: 100%;
  1062. border: 1px solid var(--bs-border-color);
  1063. box-sizing: border-box;
  1064. &:hover {
  1065. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  1066. transform: translateY(-2px);
  1067. }
  1068. .tit {
  1069. display: flex;
  1070. justify-content: space-between;
  1071. align-items: center;
  1072. margin-bottom: px2rpx(20);
  1073. padding-bottom: px2rpx(12);
  1074. border-bottom: 1px solid var(--bs-border-color);
  1075. view:first-child {
  1076. display: flex;
  1077. align-items: center;
  1078. gap: px2rpx(8);
  1079. .green-icon {
  1080. color: #28a745;
  1081. font-size: px2rpx(16);
  1082. }
  1083. .tit-tit {
  1084. font-size: px2rpx(16);
  1085. font-weight: 600;
  1086. color: var(--bs-emphasis-color);
  1087. }
  1088. text:last-child {
  1089. font-size: px2rpx(14);
  1090. font-weight: 500;
  1091. color: var(--bs-body-color);
  1092. }
  1093. }
  1094. .caozuo {
  1095. display: flex;
  1096. gap: px2rpx(12);
  1097. i {
  1098. font-size: px2rpx(18);
  1099. color: var(--bs-body-color);
  1100. transition: all 0.2s ease;
  1101. &:hover {
  1102. color: #eb3f57;
  1103. cursor: pointer;
  1104. }
  1105. &:active {
  1106. transform: scale(0.9);
  1107. }
  1108. }
  1109. }
  1110. }
  1111. .account-grid {
  1112. display: grid;
  1113. grid-template-columns: repeat(3, 1fr);
  1114. gap: px2rpx(16);
  1115. width: 100%;
  1116. box-sizing: border-box;
  1117. @media (max-width: 480px) {
  1118. grid-template-columns: repeat(3, 1fr);
  1119. }
  1120. .account-grid-item {
  1121. /* 🔥 核心修复 3:去掉强制最小宽度,避免超宽 */
  1122. /* min-width: px2rpx(200); */
  1123. margin-bottom: px2rpx(16);
  1124. .sub {
  1125. font-size: px2rpx(12);
  1126. font-weight: 500;
  1127. color: var(--bs-body-color);
  1128. margin-bottom: px2rpx(4);
  1129. text-transform: uppercase;
  1130. letter-spacing: px2rpx(0.5);
  1131. white-space: nowrap;
  1132. overflow: hidden;
  1133. text-overflow: ellipsis;
  1134. }
  1135. .num {
  1136. font-size: px2rpx(14);
  1137. font-weight: 400;
  1138. color: var(--bs-emphasis-color);
  1139. line-height: 1.4;
  1140. white-space: nowrap;
  1141. overflow: hidden;
  1142. text-overflow: ellipsis;
  1143. }
  1144. }
  1145. }
  1146. }
  1147. }
  1148. }
  1149. .avatar {
  1150. width: px2rpx(60);
  1151. height: px2rpx(60);
  1152. border-radius: 4px;
  1153. }
  1154. .content-title {
  1155. display: flex;
  1156. justify-content: space-between;
  1157. align-items: center;
  1158. .content-title-btns {
  1159. display: flex;
  1160. align-items: center;
  1161. justify-content: center;
  1162. gap: px2rpx(12);
  1163. margin-bottom: px2rpx(24);
  1164. .btn-primary {
  1165. min-width: px2rpx(120);
  1166. background-color: var(--color-error);
  1167. color: #fff;
  1168. padding: 0 px2rpx(12);
  1169. border: none;
  1170. font-size: px2rpx(14);
  1171. text-align: center;
  1172. cursor: pointer;
  1173. display: flex;
  1174. align-items: center;
  1175. justify-content: center;
  1176. gap: px2rpx(8);
  1177. }
  1178. .btn-primary1 {
  1179. background-color: #cf1322;
  1180. ;
  1181. }
  1182. .btn-primary2 {
  1183. background-color: var(--color-secondary-focus);
  1184. }
  1185. }
  1186. }
  1187. .operation-btn {
  1188. :deep(text) {
  1189. display: flex;
  1190. align-items: center;
  1191. justify-content: center;
  1192. gap: px2rpx(4);
  1193. cursor: pointer;
  1194. background-color: var(--color-slate-150);
  1195. padding: px2rpx(8) 0;
  1196. }
  1197. }
  1198. .operation-btn.disabled {
  1199. cursor: not-allowed;
  1200. opacity: 0.5;
  1201. }
  1202. .search-bar {
  1203. display: flex;
  1204. align-items: center;
  1205. justify-content: flex-start;
  1206. flex-wrap: wrap;
  1207. gap: px2rpx(16);
  1208. margin: px2rpx(16) 0;
  1209. .cwg-combox,
  1210. .uni-easyinput,
  1211. .uni-date {
  1212. width: px2rpx(240) !important;
  1213. flex: none;
  1214. }
  1215. }
  1216. .dia-content {
  1217. padding: px2rpx(20) px2rpx(20) px2rpx(100) px2rpx(20);
  1218. .uni-forms-item {
  1219. width: 100%;
  1220. }
  1221. .grid-layout {
  1222. display: grid;
  1223. grid-template-columns: 1fr 1fr;
  1224. gap: px2rpx(20);
  1225. margin: px2rpx(24) 0;
  1226. padding: px2rpx(20);
  1227. background-color: transparent;
  1228. border-radius: px2rpx(8);
  1229. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  1230. }
  1231. .fllow-title {
  1232. display: flex;
  1233. align-items: center;
  1234. justify-content: space-between;
  1235. border-bottom: 1px solid #eee;
  1236. padding-bottom: 10px;
  1237. margin-bottom: 10px;
  1238. .title {
  1239. font-weight: bold;
  1240. color: var(--bs-heading-color);
  1241. padding-left: 8px;
  1242. border-left: 4px solid #eb3f57;
  1243. font-size: 16px;
  1244. }
  1245. }
  1246. .delete-grid {
  1247. margin: px2rpx(16) 0;
  1248. }
  1249. .delete-row {
  1250. display: grid;
  1251. grid-template-columns: 1fr 1fr;
  1252. gap: px2rpx(12);
  1253. @media screen and (max-width: 768px) {
  1254. grid-template-columns: 1fr;
  1255. }
  1256. }
  1257. .delete-item {
  1258. flex: 1;
  1259. display: flex;
  1260. justify-content: space-between;
  1261. align-items: center;
  1262. padding: px2rpx(12) 0;
  1263. border-bottom: 1px dashed #e9ecef;
  1264. &:first-child {
  1265. padding-right: px2rpx(16);
  1266. }
  1267. &:last-child {
  1268. padding-left: px2rpx(16);
  1269. }
  1270. }
  1271. @media screen and (max-width: 768px) {
  1272. .delete-item {
  1273. &:first-child {
  1274. padding-right: px2rpx(0);
  1275. }
  1276. &:last-child {
  1277. padding-left: px2rpx(0);
  1278. }
  1279. }
  1280. }
  1281. .delete-label {
  1282. font-size: px2rpx(14);
  1283. color: var(--bs-body-color);
  1284. }
  1285. .delete-value {
  1286. font-size: px2rpx(14);
  1287. color: var(--bs-emphasis-color);
  1288. font-weight: 400;
  1289. }
  1290. .delete-tip {
  1291. margin-top: px2rpx(16);
  1292. font-size: px2rpx(14);
  1293. color: var(--bs-emphasis-color);
  1294. line-height: 1.5;
  1295. padding-top: px2rpx(16);
  1296. }
  1297. .tip-star {
  1298. color: #dc3545;
  1299. margin-right: px2rpx(4);
  1300. }
  1301. .agree {
  1302. margin-top: px2rpx(20);
  1303. }
  1304. .checkbox-agree {
  1305. display: flex;
  1306. align-items: flex-start;
  1307. gap: px2rpx(8);
  1308. :deep(.uni-checkbox-input) {
  1309. width: px2rpx(18);
  1310. height: px2rpx(18);
  1311. }
  1312. .agree-text {
  1313. font-size: px2rpx(14);
  1314. color: var(--bs-emphasis-color);
  1315. line-height: 1.3;
  1316. font-weight: normal;
  1317. width: 100%;
  1318. white-space: wrap;
  1319. .a {
  1320. color: #007bff;
  1321. text-decoration: underline;
  1322. margin: 0 px2rpx(4);
  1323. &:hover {
  1324. color: #0056b3;
  1325. }
  1326. }
  1327. }
  1328. }
  1329. .fllow-content {
  1330. margin-bottom: px2rpx(16);
  1331. .tit {
  1332. font-size: px2rpx(14);
  1333. font-weight: 500;
  1334. color: var(--bs-body-color);
  1335. margin-bottom: px2rpx(6);
  1336. text-transform: uppercase;
  1337. letter-spacing: px2rpx(0.5);
  1338. }
  1339. .con {
  1340. font-size: px2rpx(16);
  1341. font-weight: 400;
  1342. color: var(--bs-emphasis-color);
  1343. line-height: 1.4;
  1344. }
  1345. }
  1346. .form-row {
  1347. display: grid;
  1348. grid-template-columns: 1fr 1fr;
  1349. gap: px2rpx(20);
  1350. margin-top: px2rpx(16);
  1351. @media screen and (max-width: 768px) {
  1352. grid-template-columns: 1fr;
  1353. }
  1354. }
  1355. .form-item {
  1356. display: flex;
  1357. flex-direction: column;
  1358. align-items: flex-start;
  1359. text {
  1360. font-size: px2rpx(14);
  1361. font-weight: 500;
  1362. color: var(--bs-body-color);
  1363. margin-bottom: px2rpx(8);
  1364. white-space: nowrap;
  1365. }
  1366. input,
  1367. select,
  1368. textarea {
  1369. width: 100%;
  1370. padding: px2rpx(10);
  1371. border: 1px solid #ced4da;
  1372. border-radius: px2rpx(4);
  1373. font-size: px2rpx(14);
  1374. transition: all 0.2s ease;
  1375. &:focus {
  1376. outline: none;
  1377. border-color: #4dabf7;
  1378. box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.2);
  1379. }
  1380. }
  1381. textarea {
  1382. resize: vertical;
  1383. min-height: px2rpx(100);
  1384. }
  1385. }
  1386. .tip-red {
  1387. color: #dc3545;
  1388. font-size: px2rpx(14);
  1389. margin: px2rpx(12) 0 px2rpx(24) 0;
  1390. }
  1391. .tip-text {
  1392. margin-top: px2rpx(24);
  1393. font-size: px2rpx(14);
  1394. color: var(--bs-body-color);
  1395. line-height: 1.5;
  1396. padding: px2rpx(16);
  1397. background-color: #e7f3ff;
  1398. border-radius: px2rpx(4);
  1399. border-left: 4px solid #4dabf7;
  1400. }
  1401. }
  1402. /* 弹窗按钮样式 */
  1403. :deep(.cwg-popup__footer) {
  1404. display: flex;
  1405. gap: px2rpx(20);
  1406. padding: px2rpx(20);
  1407. border-top: 1px solid #e9ecef;
  1408. button {
  1409. flex: 1;
  1410. padding: px2rpx(12) 0;
  1411. border-radius: px2rpx(4);
  1412. font-size: px2rpx(14);
  1413. font-weight: 500;
  1414. transition: all 0.2s ease;
  1415. &:first-child {
  1416. background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  1417. color: #495057;
  1418. border: 1px solid #ced4da;
  1419. &:hover {
  1420. background-color: transparent;
  1421. border-color: #adb5bd;
  1422. }
  1423. &:active {
  1424. transform: scale(0.98);
  1425. }
  1426. }
  1427. &:last-child {
  1428. background-color: #dc3545;
  1429. color: white;
  1430. border: 1px solid #dc3545;
  1431. &:hover {
  1432. background-color: #c82333;
  1433. border-color: #bd2130;
  1434. }
  1435. &:active {
  1436. transform: scale(0.98);
  1437. }
  1438. }
  1439. }
  1440. }
  1441. </style>