| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- <template>
- <uni-popup ref="cardRef" type="center" background-color="#fff">
- <view class="dialog-container">
- <view class="dialog-header">
- <text class="dialog-title" v-t="'PersonalManagement.CardVerify.Title'" />
- <view class="dialog-close" @click="close">
- <text>×</text>
- </view>
- </view>
- <view class="qrcode-page">
- <view class="container">
- <view class="title" v-t="'PersonalManagement.CardVerify.UploadTitle'"></view>
- <!-- 说明 -->
- <uni-file-picker limit="9" :title="t('PersonalManagement.CardVerify.UploadTip')"
- @select="fileSelect" @delete="fileDelete"></uni-file-picker>
- <!-- 邮箱验证码部分 -->
- <view>
- <view class="code-input-wrapper">
- <view class="code-input">
- <cwg-input v-model:value="cardEmailCode" :label="t('newSignup.item9')"
- fkey="cardEmailCode" type="text" :required="true" rulesKey="cardEmailCode"
- :placeholder="t('newSignup.item10')" @change="handleChange" />
- </view>
- <view class="get-code-btn1">
- <view class="ok-button">
- <u-button type="primary" block>{{ getCodeString }}</u-button>
- </view>
- </view>
- <view class="get-code-btn">
- <view class="cwg-button">
- <u-button type="primary" block @click="handleGetCode">{{ getCodeString }}</u-button>
- </view>
- </view>
- </view>
- </view>
- <view class="notice">
- <view class="notice-title">
- <text class="icon">ⓘ</text>
- <text>{{ t('PersonalManagement.CardVerify.NoticeTitle') }}</text>
- </view>
- <view class="notice-list">
- <text v-for="(item, index) in noticeItems" :key="index" class="notice-item">
- {{ index + 1 }}. {{ item }}
- </text>
- </view>
- </view>
- <!-- 演示视频 -->
- <cwg-video-player :video-url="videoUrl"></cwg-video-player>
- </view>
- </view>
- <view class="dialog-footer">
- <view class="btn btn-cancel" @click="close">{{ t('Btn.Cancel') }}</view>
- <view class="btn btn-confirm" @click="submit">{{ t('Btn.Confirm') }}</view>
- </view>
- </view>
- </uni-popup>
- </template>
- <script setup lang="ts">
- import { ref, computed, nextTick } from 'vue'
- import { useI18n } from 'vue-i18n'
- import { customApi } from '@/service/custom';
- import { showToast } from "@/utils/toast";
- import config from '@/config';
- import { userToken } from '@/composables/config'
- import { useEmailCountdown } from '@/hooks/useEmailCountdown';
- const {
- time,
- text: getCodeString,
- canSend,
- start,
- restore
- } = useEmailCountdown()
- const { t, locale } = useI18n()
- const cardEmailCode = ref('')
- const form = ref({
- bankId: null,
- email: ''
- })
- const emit = defineEmits(["success"]);
- // 发送邮箱验证码
- async function sendEmailCode() {
- try {
- if (!form.value.bankId) {
- showToast(t("PersonalManagement.CardVerify.MissingBankId"));
- return false;
- }
- const res = await customApi.customBankCardSendCode({
- bankId: form.value.bankId
- });
- if (res.code === 200) {
- if (res.data && (res.data.emailCode || res.data.code)) {
- cardEmailCode.value = res.data.emailCode || res.data.code;
- }
- start()
- return true;
- } else {
- showToast(t("Msg.CodeFail"));
- return false;
- }
- } catch (error: any) {
- console.log(error, 12);
- showToast(t("Msg.CodeFail"));
- return false;
- }
- }
- async function handleGetCode() {
- if (!canSend.value) return
- await sendEmailCode();
- }
- // 视频URL
- const videoUrl = computed(() => {
- const lang = locale.value || 'en'
- const videos = {
- cn: "https://player.vimeo.com/video/1152417528?badge=0&autopause=0&player_id=0&app_id=58479",
- zhHant: "https://player.vimeo.com/video/1152417614?badge=0&autopause=0&player_id=0&app_id=58479",
- en: "https://player.vimeo.com/video/1152417671?badge=0&autopause=0&player_id=0&app_id=58479",
- }
- return videos[lang] || videos.en
- })
- // uni-file-picker 相关
- const selectedFiles = ref([]) // 选择的文件列表
- const uploadedFiles = ref([]) // 上传成功的文件列表
- // 选择文件
- const fileSelect = async (e) => {
- selectedFiles.value = e.tempFiles
- for (const file of e.tempFiles) {
- await uploadFile(file)
- }
- }
- // 上传文件
- const uploadFile = (file) => {
- return new Promise((resolve, reject) => {
- const tempFile = file.path || file.url
- uni.uploadFile({
- url: config.Host80 + '/custom/bank/upload',
- filePath: tempFile,
- name: 'file',
- header: {
- 'Access-Token': userToken.value
- },
- success: (uploadRes) => {
- const data = JSON.parse(uploadRes.data)
- console.log(data, 1111);
- if (data.code === 200) {
- // 保存上传成功后的文件信息
- uploadedFiles.value.push(data.data)
- resolve(data)
- } else {
- uni.showToast({
- title: data.msg || '上传失败',
- icon: 'none'
- })
- reject(new Error(data.msg))
- }
- },
- fail: (err) => {
- uni.showToast({
- title: '上传失败',
- icon: 'none'
- })
- reject(err)
- }
- })
- })
- }
- // 删除文件
- const fileDelete = (e) => {
- const index = uploadedFiles.value.findIndex(f => f.uuid === e.tempFile.uuid)
- if (index !== -1) {
- uploadedFiles.value.splice(index, 1)
- }
- }
- // 说明项
- const noticeItems = computed(() => [
- t('PersonalManagement.CardVerify.NoticeItem1'),
- t('PersonalManagement.CardVerify.NoticeItem2'),
- t('PersonalManagement.CardVerify.NoticeItem3'),
- t('PersonalManagement.CardVerify.NoticeItem4'),
- t('PersonalManagement.CardVerify.NoticeItem5'),
- t('PersonalManagement.CardVerify.NoticeItem6'),
- t('PersonalManagement.CardVerify.NoticeItem7')
- ])
- const cardRef = ref(null)
- // 打开弹窗
- const open = async (e, item) => {
- form.value = { ...item, bankId: item.id }
- console.log(item, 2222);
- await nextTick();
- restore()
- cardRef.value?.open();
- };
- // 关闭弹窗
- const close = () => {
- cardRef.value?.close();
- };
- const submit = async () => {
- if (!cardEmailCode.value) {
- showToast(t("vaildate.emailCode.empty"));
- return;
- }
- try {
- const res = await customApi.customBankCardVerify({
- bankId: form.value.bankId,
- emailCode: cardEmailCode.value,
- fileList: uploadedFiles.value
- });
- if (res.code === 200) {
- showToast(res.msg);
- close();
- emit("success");
- } else {
- showToast(res.msg || t("common.error"));
- }
- } catch (error) {
- showToast(t("common.error"));
- }
- };
- // 暴露方法
- defineExpose({
- open,
- close
- });
- </script>
- <style lang="scss" scoped>
- .dialog-container {
- width: 90vw;
- max-width: px2rpx(800);
- max-height: 85vh;
- background: #fff;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- .dialog-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: px2rpx(20) px2rpx(24);
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- flex-shrink: 0;
- .dialog-title {
- font-size: px2rpx(20);
- font-weight: 700;
- color: #fff;
- letter-spacing: 0.5px;
- }
- .dialog-close {
- width: px2rpx(36);
- height: px2rpx(36);
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: px2rpx(32);
- color: rgba(255, 255, 255, 0.9);
- cursor: pointer;
- transition: all 0.3s;
- border-radius: 50%;
- background: rgba(255, 255, 255, 0.1);
- &:hover {
- background: rgba(255, 255, 255, 0.2);
- transform: rotate(90deg);
- }
- &:active {
- transform: rotate(90deg) scale(0.9);
- }
- }
- }
- .dialog-footer {
- display: flex;
- gap: px2rpx(12);
- justify-content: flex-end;
- padding: px2rpx(16);
- border-top: 1px solid #f3f4f6;
- .btn {
- min-width: px2rpx(120);
- padding: px2rpx(12) px2rpx(24);
- border-radius: px2rpx(6);
- font-size: px2rpx(14);
- font-weight: 600;
- border: none;
- cursor: pointer;
- text-align: center;
- transition: all 0.3s;
- display: flex;
- align-items: center;
- justify-content: center;
- &.btn-cancel {
- background: #f3f4f6;
- color: #6b7280;
- &:hover {
- background: #e5e7eb;
- }
- &:active {
- background: #d1d5db;
- }
- }
- &.btn-confirm {
- background: #ea2027;
- color: #fff;
- &:hover {
- background: #d11920;
- }
- &:active {
- background: #c01819;
- }
- }
- }
- }
- }
- .qrcode-page {
- flex: 1;
- overflow-y: auto;
- background: #f8f9fa;
- .container {
- padding: px2rpx(32);
- .title {
- font-size: px2rpx(18);
- font-weight: 600;
- color: #2c3e50;
- text-align: center;
- margin-bottom: px2rpx(24);
- padding-bottom: px2rpx(16);
- border-bottom: 2px solid #e9ecef;
- }
- .qrcode-wrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- margin-bottom: px2rpx(32);
- padding: px2rpx(24);
- background: #fff;
- border-radius: px2rpx(12);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
- .qrcode {
- width: px2rpx(240);
- height: px2rpx(240);
- }
- }
- .notice {
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
- border-radius: px2rpx(12);
- padding: px2rpx(24);
- margin-bottom: px2rpx(32);
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
- border-left: 4px solid #667eea;
- .notice-title {
- display: flex;
- align-items: center;
- gap: px2rpx(8);
- font-size: px2rpx(16);
- font-weight: 700;
- color: #2c3e50;
- margin-bottom: px2rpx(16);
- .icon {
- width: px2rpx(24);
- height: px2rpx(24);
- display: flex;
- align-items: center;
- justify-content: center;
- background: #667eea;
- color: #fff;
- border-radius: 50%;
- font-size: px2rpx(16);
- font-weight: bold;
- }
- }
- .notice-list {
- .notice-item {
- display: block;
- font-size: px2rpx(14);
- color: #495057;
- line-height: 1.8;
- margin-bottom: px2rpx(10);
- padding-left: px2rpx(8);
- position: relative;
- &:last-child {
- margin-bottom: 0;
- }
- &::before {
- content: '';
- position: absolute;
- left: 0;
- top: px2rpx(10);
- width: px2rpx(4);
- height: px2rpx(4);
- background: #667eea;
- border-radius: 50%;
- }
- }
- }
- }
- .video-section {
- background: #fff;
- border-radius: px2rpx(12);
- padding: px2rpx(24);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
- .video-title {
- font-size: px2rpx(16);
- font-weight: 600;
- color: #2c3e50;
- margin-bottom: px2rpx(16);
- display: flex;
- align-items: center;
- gap: px2rpx(8);
- &::before {
- content: '';
- width: px2rpx(4);
- height: px2rpx(18);
- background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
- border-radius: px2rpx(2);
- }
- }
- .video-wrapper {
- width: 100%;
- border-radius: px2rpx(8);
- overflow: hidden;
- background: #000;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- video {
- width: 100%;
- height: px2rpx(300);
- display: block;
- }
- }
- }
- }
- }
- // 验证码区域
- .code-input-label {
- font-size: var(--font-size-16);
- line-height: px2rpx(44);
- letter-spacing: px2rpx(1);
- color: #474747;
- }
- .code-input-wrapper {
- position: relative;
- display: flex;
- align-items: center;
- }
- .code-input {
- flex: 1;
- }
- .get-code-btn1 {
- min-width: px2rpx(100);
- margin-left: px2rpx(8);
- .ok-button {
- .u-button {
- background-color: var(--color-white);
- opacity: 0;
- }
- }
- }
- .get-code-btn {
- position: absolute;
- right: 0;
- bottom: px2rpx(12);
- min-width: px2rpx(100);
- background-color: var(--color-error);
- z-index: 1;
- margin-left: px2rpx(8);
- .cwg-button {
- margin: 0;
- }
- .cwg-button .u-button {
- border-radius: px2rpx(8);
- height: px2rpx(46) !important;
- }
- }
- /* 移动端优化 */
- @media screen and (max-width: 768px) {
- .dialog-container {
- width: 95vw;
- max-height: 90vh;
- }
- .qrcode-page .container {
- padding: px2rpx(20);
- .qrcode-wrapper .qrcode {
- width: px2rpx(200);
- height: px2rpx(200);
- }
- .video-section .video-wrapper video {
- height: px2rpx(240);
- }
- }
- }
- /* 滚动条美化 */
- .qrcode-page::-webkit-scrollbar {
- width: px2rpx(6);
- }
- .qrcode-page::-webkit-scrollbar-track {
- background: #f1f1f1;
- }
- .qrcode-page::-webkit-scrollbar-thumb {
- background: #c1c1c1;
- border-radius: px2rpx(3);
- &:hover {
- background: #a8a8a8;
- }
- }
- </style>
|