index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <template>
  2. <div
  3. id="review_Email"
  4. v-loading="pictLoading"
  5. class="view"
  6. element-loading-background="rgba(43, 48, 67, 0.65)"
  7. element-loading-spinner="el-icon-loading"
  8. >
  9. <div class="crm_search">
  10. <el-form ref="formRef" :model="search" label-width="">
  11. <el-row>
  12. <el-col :span="24" :md="24" :lg="24">
  13. <el-form-item>
  14. <el-select
  15. v-model="search.tag"
  16. class="crm_search_down crm-border-radius-no"
  17. :placeholder="$t('Placeholder.Choose')"
  18. >
  19. <el-option
  20. v-for="option in searchTagOptions"
  21. :key="option.value"
  22. :label="$t(option.label)"
  23. :value="option.value"
  24. ></el-option>
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item style="margin-right: 10px">
  28. <el-input
  29. v-if="search.tag == 1"
  30. v-model.trim="search.cId"
  31. class="crm-border-left-no crm-border-radius-no"
  32. clearable
  33. :placeholder="$t('Placeholder.Input')"
  34. @keyup.enter="toSearch"
  35. ></el-input>
  36. <el-input
  37. v-if="search.tag == 2"
  38. v-model.trim="search.mobile"
  39. class="crm-border-left-no crm-border-radius-no"
  40. clearable
  41. :placeholder="$t('Placeholder.Input')"
  42. @keyup.enter="toSearch"
  43. ></el-input>
  44. <el-input
  45. v-if="search.tag == 3"
  46. v-model.trim="search.email"
  47. class="crm-border-left-no crm-border-radius-no"
  48. clearable
  49. :placeholder="$t('Placeholder.Input')"
  50. @keyup.enter="toSearch"
  51. ></el-input>
  52. <el-input
  53. v-if="search.tag == 5"
  54. v-model.trim="search.currency"
  55. class="crm-border-left-no crm-border-radius-no"
  56. clearable
  57. :placeholder="$t('Placeholder.Input')"
  58. @keyup.enter="toSearch"
  59. ></el-input>
  60. </el-form-item>
  61. <el-form-item style="margin-right: 10px">
  62. <el-input
  63. v-model.trim="search.cardNumber"
  64. class="crm-border-radius-no"
  65. clearable
  66. :placeholder="$t('Placeholder.Input') + $t('Ucard.Transactions.s1')"
  67. @keyup.enter="toSearch"
  68. ></el-input>
  69. </el-form-item>
  70. <el-form-item style="margin-right: 10px">
  71. <el-select
  72. v-model="search.type"
  73. class="crm-border-radius-no"
  74. clearable
  75. :placeholder="$t('Ucard.Transactions.s3')"
  76. @change="toSearch"
  77. >
  78. <el-option
  79. v-for="option in transactionTypeOptions"
  80. :key="option.value"
  81. :label="$t(option.label)"
  82. :value="option.value"
  83. ></el-option>
  84. </el-select>
  85. </el-form-item>
  86. <el-form-item>
  87. <el-select
  88. v-model="search.status"
  89. class="crm-border-radius-no"
  90. clearable
  91. :placeholder="$t('Ucard.Transactions.s5')"
  92. @change="toSearch"
  93. >
  94. <el-option
  95. v-for="option in statusOptions"
  96. :key="option.value"
  97. :label="$t(option.label)"
  98. :value="option.value"
  99. ></el-option>
  100. </el-select>
  101. </el-form-item>
  102. <el-form-item>
  103. <el-button class="crm-border-radius-no crm-border-left-no" @click="toSearch">
  104. <el-icon><Search /></el-icon>
  105. </el-button>
  106. </el-form-item>
  107. </el-col>
  108. </el-row>
  109. <el-form-item>
  110. <el-button
  111. v-if="display['R-Transactions-Export'] && display['R-Transactions-Export'].show"
  112. type="primary"
  113. style="margin-left: 8px"
  114. @click="exportAgents"
  115. >{{ $t('Btn.Export') }}</el-button
  116. >
  117. </el-form-item>
  118. </el-form>
  119. <div class="card-mock-demo" style="margin: 30px 0">
  120. <el-table :data="mock_tableData" stripe style="margin-top: 20px; width: 100%">
  121. <el-table-column prop="" align="left" :label="$t('Label.CidAccount')">
  122. <template #default="scope">
  123. <span>{{ scope.row.cId || '--' }}</span>
  124. </template>
  125. </el-table-column>
  126. <el-table-column prop="" align="left" :label="$t('Label.Name')">
  127. <template #default="scope">
  128. <span v-if="scope.row.firstName">{{ scope.row.firstName + ' ' }}</span>
  129. <span v-if="scope.row.middle">{{ scope.row.middle + ' ' }}</span>
  130. <span v-if="scope.row.lastName">{{ scope.row.lastName }}</span>
  131. <span v-if="!scope.row.firstName && !scope.row.lastName && !scope.row.middle">{{
  132. '--'
  133. }}</span>
  134. </template>
  135. </el-table-column>
  136. <el-table-column prop="" align="left" :label="$t('Label.Email')">
  137. <template #default="scope">
  138. {{ scope.row.email || '--' }}
  139. </template>
  140. </el-table-column>
  141. <el-table-column prop="mobile" align="left" :label="$t('Ucard.KycAuth.item2')">
  142. <template #default="scope"> {{ scope.row.areaCode }} {{ scope.row.mobile }} </template>
  143. </el-table-column>
  144. <el-table-column prop="cardNumber" align="left" :label="$t('Ucard.Transactions.item2')">
  145. <template #default="scope">
  146. <span
  147. v-if="scope.row.cardNumber"
  148. class="crm-text-underline"
  149. @click="cardOpen(scope.row.cardNumber)"
  150. >{{ scope.row.cardNumber || '--' }}</span
  151. >
  152. <span v-else>{{ scope.row.cardNumber || '--' }}</span>
  153. </template>
  154. </el-table-column>
  155. <!-- <el-table-column prop="cardTypeId" align="left" :label="$t('Ucard.Transactions.item1')" /> -->
  156. <el-table-column prop="currency" align="left" :label="$t('Ucard.Transactions.item3')" />
  157. <el-table-column prop="amount" align="left" :label="$t('Ucard.Transactions.item4')" />
  158. <el-table-column prop="fee" align="left" :label="$t('Ucard.Transactions.item5')" />
  159. <el-table-column prop="tradeNo" align="left" :label="$t('Ucard.Transactions.item8')" />
  160. <el-table-column prop="type" align="left" :label="$t('Ucard.Transactions.item9')">
  161. <template #default="scope">
  162. <span>
  163. {{ $t(transactionTypeMap[scope.row.type]) }}
  164. </span>
  165. </template>
  166. </el-table-column>
  167. <el-table-column prop="status" align="left" :label="$t('Ucard.Transactions.item11')">
  168. <template #default="scope">
  169. <span
  170. v-if="scope.row.status === 'succeed' || scope.row.status === 'success'"
  171. class="state crm_state_blue"
  172. >{{ $t('Ucard.Transactions.t18') }}</span
  173. >
  174. <span
  175. v-else-if="scope.row.status === 'failed' || scope.row.status === 'fail'"
  176. class="state crm_state_gray"
  177. >{{ $t('Ucard.Transactions.t25') }}</span
  178. >
  179. <span v-else-if="scope.row.status === 'processing'" class="state crm_state_orange">{{
  180. $t('card.Status.t3')
  181. }}</span>
  182. <span
  183. v-else-if="scope.row.status === 'wait_process'"
  184. class="state crm_state_yellow"
  185. >{{ $t('card.Status.t5') }}</span
  186. >
  187. <span v-else class="state crm_state_green">{{ $t('Ucard.Transactions.t24') }}</span>
  188. </template>
  189. </el-table-column>
  190. <el-table-column prop="" align="center" :label="$t('Label.Action')">
  191. <template #default="scope">
  192. <el-dropdown trigger="click" @command="handleCommand">
  193. <span class="el-dropdown-link crm-cursor">
  194. <i style="font-weight: bold; font-size: 20px" class="iconfont iconcaidan"></i>
  195. </span>
  196. <template #dropdown>
  197. <el-dropdown-menu>
  198. <el-dropdown-item
  199. v-if="display['R-Transactions-Btn1'].show"
  200. :command="{ type: 1, row: scope.row }"
  201. >
  202. <el-icon><Operation /></el-icon>
  203. {{ $t('R-Hire-Check') }}
  204. </el-dropdown-item>
  205. </el-dropdown-menu>
  206. </template>
  207. </el-dropdown>
  208. </template>
  209. </el-table-column>
  210. </el-table>
  211. </div>
  212. </div>
  213. <PagePagination
  214. :pager-info="pagerInfo"
  215. @current-change="handleCurrentChange"
  216. @size-change="handleSizeChange"
  217. />
  218. <detailed-info-cid
  219. :dialog-info-cid="dialogInfoCid"
  220. :form-info="formInfo"
  221. :is-trading="true"
  222. @close="close"
  223. >
  224. </detailed-info-cid>
  225. <div v-if="dialogInfoCid" class="crm_verified_info_mask" @click="closeDia"></div>
  226. <ViewCardSingle
  227. :dialog-info-trading-single="dialogInfoTradingSingle"
  228. :form-list="formSingle"
  229. :editor-type="editorType"
  230. @close-single="closeSingle"
  231. >
  232. </ViewCardSingle>
  233. <div v-if="dialogInfoTradingSingle" class="crm_verified_info_mask" @click="closeSingle"></div>
  234. </div>
  235. </template>
  236. <script setup>
  237. import { ref, reactive, computed, watch, onMounted, inject } from 'vue'
  238. import { useRouter } from 'vue-router'
  239. import Service from '@/service/ucard'
  240. import Config from '@/config'
  241. import Service1 from '@/service/customer'
  242. import PagePagination from '@/components/pagePagination/index.vue'
  243. import DetailedInfoCid from '@/views/components/DetailedInfoCid/index.vue'
  244. import ViewCardSingle from '@/views/components/ViewCardSingle/index.vue'
  245. import { exportExcel } from '@/utils/export'
  246. import {
  247. searchTagOptions,
  248. statusOptions,
  249. transactionTypeMap,
  250. transactionTypeOptions,
  251. } from '@/views/card/CardTransactions/const'
  252. import { Operation } from '@element-plus/icons-vue'
  253. import { useI18n } from 'vue-i18n'
  254. const { Code } = Config
  255. const { t } = useI18n()
  256. const Session = inject('session')
  257. const pigeon = inject('pigeon')
  258. const router = useRouter()
  259. // 响应式数据
  260. const pictLoading = ref(false)
  261. const dialogInfoTradingSingle = ref(false)
  262. const formSingle = ref({})
  263. const editorType = ref(4)
  264. const search = reactive({
  265. tag: 1,
  266. mobile: '',
  267. cId: '',
  268. email: '',
  269. cardNumber: '',
  270. currency: '',
  271. type: '',
  272. dataType: '',
  273. status: '',
  274. })
  275. const mock_tableData = ref([])
  276. const pagerInfo = reactive({ row: 10, current: 1, pageTotal: 0, rowTotal: 0 })
  277. const dialogInfoCid = ref(false)
  278. const formInfo = ref({})
  279. const formRef = ref()
  280. // 计算属性
  281. const display = computed(() => {
  282. return JSON.parse(Session.Get('display', true))
  283. })
  284. // 方法
  285. // 导出
  286. const exportAgents = async () => {
  287. exportExcel('/wasabi/card/transac/record/export', { ...search }, 'Bank_Card_Transactions')
  288. }
  289. // 银行卡详情
  290. const cardOpen = (cardNumber) => {
  291. router.push({ name: 'R-CardDetail', params: { cardNumber: cardNumber } })
  292. }
  293. const searchSingleCid = async (cId) => {
  294. const res = await Service1.cidRealSingle({
  295. id: cId,
  296. })
  297. if (res.code == Code.StatusOK) {
  298. // 注意:这里原代码有 editor 变量,但组件中未定义,保持原逻辑
  299. // if (this.editor) {
  300. // this.formList = res.data;
  301. // this.dialogInfoAdd = true;
  302. // } else {
  303. formInfo.value = res.data
  304. searchRealAll(cId)
  305. // }
  306. } else {
  307. pigeon.error(res.msg)
  308. }
  309. }
  310. // 获取cid下的真实账户信息
  311. const searchRealAll = async (cId) => {
  312. const res = await Service1.realCustomerListAll({
  313. cId: cId,
  314. page: {
  315. current: 1,
  316. row: 1,
  317. },
  318. })
  319. if (res.code == Code.StatusOK) {
  320. formInfo.value.realList = res.data
  321. dialogInfoCid.value = true
  322. } else {
  323. pigeon.error(res.msg)
  324. }
  325. }
  326. // 详细信息关闭cid/pibno
  327. const closeDia = () => {
  328. dialogInfoCid.value = false
  329. }
  330. const close = (val) => {
  331. dialogInfoCid.value = val
  332. }
  333. const toSearch = () => {
  334. pagerInfo.current = 1
  335. searchFunc()
  336. }
  337. // 更新
  338. const updateCardTypes = async () => {
  339. const res = await Service.updateCardTypes({})
  340. if (res.code == Code.StatusOK) {
  341. pigeon.success(t('Msg.SearchSuccess'))
  342. searchFunc()
  343. } else {
  344. pigeon.error(res.msg)
  345. }
  346. }
  347. // 查看
  348. const closeSingle = () => {
  349. dialogInfoTradingSingle.value = false
  350. }
  351. const handleCommand = (command) => {
  352. switch (command.type) {
  353. case 1:
  354. dialogInfoTradingSingle.value = true
  355. formSingle.value = command.row
  356. break
  357. }
  358. }
  359. // 列表
  360. const searchFunc = async () => {
  361. pictLoading.value = true
  362. if (!display.value['R-Transactions-Search']?.show) {
  363. pigeon.warning(t('Msg.NotDisplay'))
  364. pictLoading.value = false
  365. return
  366. }
  367. try {
  368. const res = await Service.transactionsList({
  369. ...search,
  370. page: {
  371. current: pagerInfo.current,
  372. row: pagerInfo.row,
  373. },
  374. })
  375. if (res.code == Code.StatusOK) {
  376. mock_tableData.value = res.data
  377. if (res.page != null) {
  378. pagerInfo.rowTotal = res.page.rowTotal
  379. pagerInfo.pageTotal = res.page.pageTotal
  380. } else {
  381. pagerInfo.rowTotal = 0
  382. }
  383. pigeon.success(t('Msg.SearchSuccess'))
  384. } else {
  385. pigeon.error(res.msg)
  386. }
  387. } catch (error) {
  388. pigeon.error(res.msg)
  389. }
  390. pictLoading.value = false
  391. }
  392. const handleSizeChange = (val) => {
  393. pagerInfo.row = val
  394. searchFunc()
  395. }
  396. const handleCurrentChange = (val) => {
  397. pagerInfo.current = val
  398. searchFunc()
  399. }
  400. // 生命周期
  401. onMounted(() => {
  402. searchFunc()
  403. })
  404. // 监听器
  405. watch(
  406. () => search.tag,
  407. () => {
  408. search.mobile = ''
  409. search.email = ''
  410. search.cId = ''
  411. search.cardNumber = ''
  412. search.currency = ''
  413. search.type = ''
  414. search.dataType = ''
  415. search.status = ''
  416. }
  417. )
  418. </script>
  419. <style scoped lang="scss">
  420. #review_Email {
  421. .crm_search {
  422. .search_action_btn {
  423. .delete {
  424. background-color: #a1a1a1;
  425. }
  426. .delete.active {
  427. background-color: #368fec;
  428. }
  429. }
  430. }
  431. .el-table .state {
  432. display: inline-block;
  433. min-width: 80px;
  434. max-width: 150px;
  435. box-sizing: border-box;
  436. line-height: 1.5;
  437. border-radius: 2px;
  438. padding: 2px 10px;
  439. color: #ffffff;
  440. }
  441. }
  442. </style>
  443. <style lang="scss">
  444. #review_Email {
  445. .dialog_header_w {
  446. .crm_search_down {
  447. width: 400px;
  448. }
  449. }
  450. }
  451. </style>