This commit is contained in:
6977
package-lock.json
generated
6977
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@
|
|||||||
"vue": "^3.4.0",
|
"vue": "^3.4.0",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
|
"html5-qrcode": "^2.3.8",
|
||||||
"uview-plus": "^3.6.29"
|
"uview-plus": "^3.6.29"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,22 @@
|
|||||||
<text>扫一扫登录</text>
|
<text>扫一扫登录</text>
|
||||||
</button>
|
</button>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showScanner" class="scanner-overlay">
|
||||||
|
<view class="scanner-container">
|
||||||
|
<view class="scanner-header">
|
||||||
|
<text>扫一扫</text>
|
||||||
|
<text class="close-btn" @tap="closeScanner">×</text>
|
||||||
|
</view>
|
||||||
|
<view id="scanner-region" class="scanner-region"></view>
|
||||||
|
<view class="scanner-tip">将二维码放入框内即可自动扫描</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="agreement">
|
<view class="agreement">
|
||||||
<view class="agreement-text">
|
<view class="agreement-text">
|
||||||
@@ -65,10 +81,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import { authApi } from '@/api/index.js';
|
import { authApi } from '@/api/index.js';
|
||||||
import { useUserStore } from '@/store/index.js';
|
import { useUserStore } from '@/store/index.js';
|
||||||
import { APP_ID, USE_WECHAT_AUTH } from '@/utils/env.js';
|
import { APP_ID, USE_WECHAT_AUTH } from '@/utils/env.js';
|
||||||
|
import { Html5Qrcode } from 'html5-qrcode';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
@@ -81,11 +98,19 @@
|
|||||||
getPathDeviceId();
|
getPathDeviceId();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (html5QrCode) {
|
||||||
|
html5QrCode.stop().catch(() => {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const identifier = ref('');
|
const identifier = ref('');
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const agreed = ref(true);
|
const agreed = ref(true);
|
||||||
const inputFocus = ref(false);
|
const inputFocus = ref(false);
|
||||||
const showError = ref(false);
|
const showError = ref(false);
|
||||||
|
const showScanner = ref(false);
|
||||||
|
let html5QrCode = null;
|
||||||
|
|
||||||
const getCode = () => {
|
const getCode = () => {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
@@ -125,35 +150,44 @@
|
|||||||
doLogin();
|
doLogin();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleScanLogin = () => {
|
const handleScanLogin = async () => {
|
||||||
// #ifdef H5
|
showScanner.value = true;
|
||||||
if (typeof wx !== 'undefined' && wx.scanQRCode) {
|
|
||||||
wx.scanQRCode({
|
try {
|
||||||
needResult: 1,
|
html5QrCode = new Html5Qrcode('scanner-region');
|
||||||
scanType: ['qrCode', 'barCode'],
|
await html5QrCode.start(
|
||||||
success: (res) => {
|
{ facingMode: 'environment' },
|
||||||
const result = res.resultStr;
|
{
|
||||||
if (result && result.includes('device_id')) {
|
fps: 10,
|
||||||
const match = result.match(/device_id[=]([^&]*)/);
|
qrbox: { width: 250, height: 250 }
|
||||||
if (match && match[1]) {
|
},
|
||||||
identifier.value = match[1];
|
(decodedText) => {
|
||||||
handleLogin();
|
const match = decodedText.match(/=([^=]+)$/);
|
||||||
}
|
if (match && match[1]) {
|
||||||
|
identifier.value = match[1];
|
||||||
|
closeScanner();
|
||||||
|
handleLogin();
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({ title: '无效的二维码', icon: 'none' });
|
uni.showToast({ title: '无效的二维码', icon: 'none' });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: () => {
|
() => {}
|
||||||
uni.showToast({ title: '扫码失败,请重试', icon: 'none' });
|
);
|
||||||
}
|
} catch (err) {
|
||||||
});
|
console.error('扫码失败', err);
|
||||||
} else {
|
uni.showToast({ title: '无法访问摄像头', icon: 'none' });
|
||||||
uni.showToast({ title: '扫一扫功能暂不可用', icon: 'none' });
|
closeScanner();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeScanner = async () => {
|
||||||
|
showScanner.value = false;
|
||||||
|
if (html5QrCode) {
|
||||||
|
try {
|
||||||
|
await html5QrCode.stop();
|
||||||
|
} catch (e) {}
|
||||||
|
html5QrCode = null;
|
||||||
}
|
}
|
||||||
// #endif
|
|
||||||
// #ifndef H5
|
|
||||||
uni.showToast({ title: '请在微信中打开', icon: 'none' });
|
|
||||||
// #endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPathDeviceId = () => {
|
const getPathDeviceId = () => {
|
||||||
@@ -469,4 +503,52 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scanner-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
z-index: 999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanner-container {
|
||||||
|
width: 600rpx;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanner-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 32rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom: 1rpx solid var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
font-size: 48rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanner-region {
|
||||||
|
width: 100%;
|
||||||
|
height: 600rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanner-tip {
|
||||||
|
padding: 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
29
utils/wxsdk.js
Normal file
29
utils/wxsdk.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { BASE_URL, APP_ID } from './env.js';
|
||||||
|
|
||||||
|
export const initWxSdk = async () => {
|
||||||
|
if (typeof wx === 'undefined') return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${BASE_URL}/api/c/v1/wx/signature?url=${encodeURIComponent(window.location.href)}`);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.code === 200 || data.code === 0) {
|
||||||
|
wx.config({
|
||||||
|
debug: false,
|
||||||
|
appId: APP_ID,
|
||||||
|
timestamp: data.data.timestamp,
|
||||||
|
nonceStr: data.data.nonceStr,
|
||||||
|
signature: data.data.signature,
|
||||||
|
jsApiList: ['scanQRCode']
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
wx.ready(() => resolve(true));
|
||||||
|
wx.error(() => resolve(false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('WX SDK init failed', e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user