From 9a6cd220224fd3a9a6c84b5bb37c6410a470969f Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期二, 17 三月 2026 17:53:21 +0800
Subject: [PATCH] 考点核验
---
src/views/h5/faceAuth/components/auditDialog.vue | 14
package-lock.json | 11
src/views/h5/login/bind.vue | 140 +++++++++
src/views/main/components/UploadIdCard.vue | 2
src/views/h5/login/index.vue | 21
src/utils/wxjssdk.js | 263 ----------------
src/router/index.js | 5
src/views/h5/verify/form.vue | 5
src/views/h5/login/redirect.vue | 232 +++++++++++++++
src/views/h5/verify/index.vue | 46 +-
src/views/h5/signup/index.vue | 48 ++-
src/views/h5/index.vue | 27
src/main.js | 6
src/views/h5/faceAuth/index.vue | 29 -
package.json | 1
vite.config.js | 1
src/router/h5/router.js | 20 +
src/App.vue | 21 +
src/views/h5/faceAuth/components/camera.vue | 2
19 files changed, 530 insertions(+), 364 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 106b5fd..80f3b71 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "app-web-examination-platform",
+ "name": "app-web-examination-user",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "app-web-examination-platform",
+ "name": "app-web-examination-user",
"version": "0.0.0",
"dependencies": {
"@element-plus/icons-vue": "^2.3.2",
@@ -22,6 +22,7 @@
"vconsole": "^3.15.1",
"vue": "^3.5.22",
"vue-router": "^4.6.3",
+ "weixin-js-sdk": "^1.6.5",
"xlsx": "^0.18.5",
"xlsx-js-style": "^1.2.0"
},
@@ -5712,6 +5713,12 @@
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
+ "node_modules/weixin-js-sdk": {
+ "version": "1.6.5",
+ "resolved": "https://registry.npmmirror.com/weixin-js-sdk/-/weixin-js-sdk-1.6.5.tgz",
+ "integrity": "sha512-Gph1WAWB2YN/lMOFB/ymb+hbU/wYazzJgu6PMMktCy9cSCeW5wA6Zwt0dpahJbJ+RJEwtTv2x9iIu0U4enuVSQ==",
+ "license": "MIT"
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index 757c2a8..9ef02f3 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"vconsole": "^3.15.1",
"vue": "^3.5.22",
"vue-router": "^4.6.3",
+ "weixin-js-sdk": "^1.6.5",
"xlsx": "^0.18.5",
"xlsx-js-style": "^1.2.0"
},
diff --git a/src/App.vue b/src/App.vue
index b2e0d57..a4fb8fd 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -4,10 +4,23 @@
</div>
</template>
-<script setup>
-// import { useWindowSize } from '@/utils/hook.js'
-
-// const { width, height } = useWindowSize()
+<script>
+import { isWeixin } from '@/utils/UA.js'
+import { getWxSignature } from '@/utils/wxjssdk.js'
+export default {
+ data() {
+ return {
+
+ }
+ },
+ watch: {
+ '$route.path': function(){
+ if (isWeixin) {
+ getWxSignature(this.$route)
+ }
+ },
+ }
+}
</script>
<style scoped>
diff --git a/src/main.js b/src/main.js
index 13eec40..9f4cb15 100644
--- a/src/main.js
+++ b/src/main.js
@@ -29,9 +29,9 @@
app.component(key, component)
}
-// import('vconsole').then((module) => {
-// new module.default()
-// })
+import('vconsole').then((module) => {
+ new module.default()
+})
app.config.globalProperties.$rules = ruleGenerator
app.config.globalProperties.$property = property
diff --git a/src/router/h5/router.js b/src/router/h5/router.js
index c8ebaa8..5c23388 100644
--- a/src/router/h5/router.js
+++ b/src/router/h5/router.js
@@ -20,11 +20,6 @@
component: () => import('@/views/h5/verify/noAccess.vue'),
},
{
- path: 'login',
- name: '韬唤楠岃瘉鐧诲綍',
- component: () => import('@/views/h5/login/index.vue'),
- },
- {
path: 'signup',
name: '绛惧埌',
component: () => import('@/views/h5/signup/index.vue'),
@@ -36,5 +31,20 @@
},
],
},
+ {
+ path: '/h5/login',
+ name: '韬唤楠岃瘉鐧诲綍',
+ component: () => import('@/views/h5/login/index.vue'),
+ },
+ {
+ path: '/h5/redirect',
+ name: '閲嶅畾鍚�',
+ component: () => import('@/views/h5/login/redirect.vue'),
+ },
+ {
+ path: '/h5/bind',
+ name: '缁戝畾鎵嬫満鍙�',
+ component: () => import('@/views/h5/login/bind.vue'),
+ },
]
export default router
diff --git a/src/router/index.js b/src/router/index.js
index 3b466f4..899675b 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -3,7 +3,6 @@
import errorPage from '@/router/error/index.js'
import mainPage from '@/router/main/index.js'
import h5 from '@/router/h5/router.js'
-import { useLoginStore } from '@/stores/login.js'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@@ -11,7 +10,6 @@
})
router.beforeEach((to, from, next) => {
- const { setLastRouteInfo } = useLoginStore()
if (!to.matched.length) {
if (to.path === '/') {
next({ path: '/main/home' })
@@ -19,9 +17,6 @@
next({ path: '/error/404', query: { errorUrl: to.path } })
}
} else {
- if (from.name) {
- setLastRouteInfo(from)
- }
next()
}
})
diff --git a/src/utils/wxjssdk.js b/src/utils/wxjssdk.js
index 083dcda..7312be2 100644
--- a/src/utils/wxjssdk.js
+++ b/src/utils/wxjssdk.js
@@ -1,16 +1,14 @@
import wx from 'weixin-js-sdk'
import axios from './axios'
-import store from '../store.js'
import $qxueyou from '@/config/qxueyou.js'
-import utilsUA from '@/plugins/utilsUA'
-import { getUUID, qxyResImg } from '@/plugins/utils'
+import { isWeixin, isMobile } from '@/utils/UA.js'
let newFeature = false
let oldShare = ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareQZone']
let newShare = ['updateTimelineShareData', 'updateAppMessageShareData']
-let weixinFlag = utilsUA.isWeixin
-let mobileFlag = utilsUA.isMobile
+let weixinFlag = isWeixin
+let mobileFlag = isMobile
let channel = weixinFlag && mobileFlag ? 'wx_pub' : 'wx_pub_qr'
let isWxpub = 'wx_pub'.includes(channel)
@@ -21,7 +19,7 @@
function getWxSignature(toRoute) {
if (!weixinFlag) { return false }
- axios.get('/wx/js/signature', {
+ axios.get('/system/wx/js/signature', {
params: { url: location.href }
}).then(res => {
if (!res || !res.data) {
@@ -36,193 +34,19 @@
signature: result.signature,
jsApiList: [
...(newFeature ? newShare : oldShare),
- 'chooseWXPay',
+ // 'chooseWXPay',
'chooseImage',
'getLocalImgData'
],
openTagList: ['wx-open-launch-app']
})
- wx.ready(function () {
- initShareOption(toRoute)
- })
+ // wx.ready(function () {
+ // initShareOption(toRoute)
+ // })
wx.error(function (res) {
console.log(res)
})
})
-}
-
-/**
- * 鍒濆鍖栧垎浜暟鎹�
- * @param {*} toRoute
- */
-function initShareOption(toRoute) {
- if (!weixinFlag) { return false }
-
- let uuid = getUUID()
- let shareOptions = getShareOptions(uuid,toRoute)
-
- shareOptions.success = function () {
- shareSuccess(uuid,toRoute)
- }
- shareOptions.cancel = function () {
- console.log('鍙栨秷鍒嗕韩')
- }
- shareOptions.trigger = function () {
- console.log('鐢ㄦ埛鐐瑰嚮鍙戦�佺粰鏈嬪弸')
- }
-
- // 鍚戜笅鍏煎鏃х増鍒嗕韩鎺ュ彛
- if (!newFeature) {
- wx.onMenuShareTimeline(shareOptions)
- wx.onMenuShareAppMessage(shareOptions)
- } else {
- wx.updateAppMessageShareData(shareOptions)
- wx.updateTimelineShareData(shareOptions)
- }
-}
-
-/**
- * 鑾峰彇鍒嗕韩鏁版嵁
- * @param {*} list
- */
-function getShareOptions(uuid,toRoute) {
- let result = {}
- let customShare = store.state.share.custom
- if (customShare.title) {
- result.title = customShare.title
- result.desc = customShare.desc
- } else {
- result.title = toRoute.name
- result.desc = toRoute.name
- }
- if (customShare.imgUrl) {
- if (customShare.imgUrl.includes('http')) {
- result.imgUrl = customShare.imgUrl
- } else {
- result.imgUrl = qxyResImg(customShare.imgUrl)
- }
- }
-
- if (customShare.uuidLink) {
- let pageUrl = customShare.pageUrl || toRoute.fullPath
- let encode = encodeURI(`${uuid},${$qxueyou.htmlRoot + pageUrl}`)
- result.link = customShare.uuidLink + btoa(encode)
- // result.link = customShare.uuidLink + uuid
- } else if (customShare.link) {
- result.link = customShare.link
- } else {
- result.link = location.href
- }
-
- return result
-}
-
-/**
- * 鍒嗕韩鎴愬姛鍥炶皟
- */
-function shareSuccess(uuid,toRoute) {
- let customShare = store.state.share.custom
- if (customShare.targetId) {
- let pageUrl = customShare.pageUrl || toRoute.fullPath
- axios.post('/wx/share/callback', {
- urlId: uuid,
- pageUrl: $qxueyou.htmlRoot + pageUrl,
- targetId: customShare.targetId,
- planIds: customShare.planIds
- }).then(() => {
- initShareOption(toRoute)
- })
- }
-
- // 褰撳垎浜湁鏂规Id锛岃Е鍙戞槸鍚﹀叧娉ㄥ叕浼楀彿
- if (customShare.planIds) {
- store.commit('wxh5/subscribe', '鍙婃椂鑾峰彇濂栧姳鎻愰啋')
- }
-
- let mask = store.state.share.mask
- if (mask.show) {
- let text = mask.type === 'plan' ? '鍒嗕韩鎴愬姛锛岀户缁姪鍔�' : '閭�璇锋垚鍔燂紝缁х画閭�璇�'
- let newMask = { show: true, type: mask.type, text: text, codeText: mask.codeText }
- store.commit("share/maskText", newMask)
- }
-}
-
-/**
- * 缁熶竴鏀粯鎺ュ彛澶勭悊
- * @param {*} orderId
- * @param {*} successCallback // 鏀粯鎴愬姛鍥炶皟
- * @param {*} showCodeCallback // 鏄剧ず浜岀淮鐮佸洖璋�
- */
-function unipayPay(orderId, successCallback, showCodeCallback) {
- axios.post('/wx/pay/createOrder', {
- orderId: orderId,
- channel: channel,
- redirectUrl: weixinFlag ? store.state.order.paySuccessUrl : undefined,
- }).then(res => {
- if (!res.data.data) { return false }
-
- let params = res.data.data.param
-
- if (isWxpub) { // 鍏紬鍙锋敮浠�
- chooseWXPay(params, successCallback)
- } else { // 鎵爜鏀粯
- store.commit('timer/paying', true)
- showCodeCallback && showCodeCallback(params.codeUrl)
- checkIsPay(orderId, successCallback)
- }
- })
-}
-
-function chooseWXPay(result, successCallback) {
- //璋冪敤寰俊鏀粯鎺ュ彛
- wx.chooseWXPay({
- timestamp: result.timeStamp, // 鏀粯绛惧悕鏃堕棿鎴筹紝娉ㄦ剰寰俊jssdk涓殑鎵�鏈変娇鐢╰imestamp瀛楁鍧囦负灏忓啓銆備絾鏈�鏂扮増鐨勬敮浠樺悗鍙扮敓鎴愮鍚嶄娇鐢ㄧ殑timeStamp瀛楁鍚嶉渶澶у啓鍏朵腑鐨凷瀛楃
- nonceStr: result.nonceStr, // 鏀粯绛惧悕闅忔満涓诧紝涓嶉暱浜� 32 浣�
- package: result.packageValue, // 缁熶竴鏀粯鎺ュ彛杩斿洖鐨刾repay_id鍙傛暟鍊硷紝鎻愪氦鏍煎紡濡傦細prepay_id=\*\*\*锛�
- signType: result.signType, // 绛惧悕鏂瑰紡锛岄粯璁や负'SHA1'锛屼娇鐢ㄦ柊鐗堟敮浠橀渶浼犲叆'MD5'
- paySign: result.paySign, // 鏀粯绛惧悕
- success: () => {
- successCallback && successCallback()
- },
- fail: (e) => {
- store.commit('snack/error', '璇疯仈绯绘妧鏈鏈嶈В鍐�' + e.errMsg)
- }
- })
-}
-
-/**
- * 鎵爜鏀粯鎴愬姛鐨勫洖璋�
- * @param {} orderId
- * @returns {}
- */
-function checkIsPay(orderId, successCallback) {
- if (!store.state.timer.paying) {
- return false
- }
- setTimeout(function () {
- axios.get('/transact/order/payResult', {
- params: { orderId: orderId }
- }).then(res => {
- if (res.data.success) {
- successCallback && successCallback()
- store.commit('timer/paying', false)
- } else {
- checkIsPay(orderId, successCallback)
- }
- })
- }, 2000)
-}
-
-/**
- * 鑾峰彇瀹氫綅
- * @param {*} locationCallback
- */
-function getPosition(locationCallback){
- wx.getLocation({
- success: function (res) {
- locationCallback(res)
- }
- })
}
function chooseImage(){
@@ -246,6 +70,7 @@
})
})
}
+
function getLocalImgData(localId){
return new Promise((resolve) => {
wx.getLocalImgData({
@@ -260,75 +85,7 @@
})
}
-
-/**
- * 棰勮鍥剧墖
- * @param {*} url
- * @param {*} urlList
- */
-function previewImage(current, urls){
- wx.previewImage({
- current: current, // 褰撳墠鏄剧ず鍥剧墖鐨刪ttp閾炬帴
- urls: urls ? urls : [current] // 闇�瑕侀瑙堢殑鍥剧墖http閾炬帴鍒楄〃
- })
-}
-
-/**
- * 杩斿洖灏忕▼搴忛〉闈�
- * @param {*} mpRouter // 灏忕▼搴忕殑璺敱
- * @param {*} otherCallback // 鍏朵粬鍥炶皟鎿嶄綔
- */
-function redirectToMp(mpRouter) {
- return new Promise(resolve => {
- // 闈炲井淇� 鎴� 浜虹ぞ灞�娲诲姩鍏ュ彛
- if (!weixinFlag || store.state.course.isRsjActivity) {
- resolve(true)
- return false
- }
- wx.miniProgram.getEnv(function(res) {
- if (res.miniprogram) { // 灏忕▼搴�
- wx.miniProgram.redirectTo({
- url: mpRouter,
- success: function(){
- console.log('璺宠浆鎴愬姛')
- setTimeout(() => { // 澶勭悊鍏朵粬鏈烘瀯鐨勫皬绋嬪簭璺宠浆鍦烘櫙
- resolve(true);
- }, 3000)
- },
- fail: function(){
- resolve(true)
- }
- })
- } else { // 闈炲皬绋嬪簭
- resolve(true)
- }
- })
- })
-}
-
-/**
- * 鍚戝皬绋嬪簭鍙戦�佹秷鎭�
- */
-function postMessage(data) {
- // 闈炲井淇�
- if (!weixinFlag) { return false }
-
- wx.miniProgram.getEnv(function(res) {
- if (res.miniprogram) { // 灏忕▼搴�
- wx.miniProgram.postMessage({
- data: data
- })
- }
- })
-}
-
export {
getWxSignature,
- initShareOption,
- unipayPay,
- getPosition,
- previewImage,
- chooseImage,
- redirectToMp,
- postMessage
+ chooseImage
}
diff --git a/src/views/h5/faceAuth/components/auditDialog.vue b/src/views/h5/faceAuth/components/auditDialog.vue
index 15b15e8..e7495eb 100644
--- a/src/views/h5/faceAuth/components/auditDialog.vue
+++ b/src/views/h5/faceAuth/components/auditDialog.vue
@@ -66,7 +66,8 @@
data() {
return {
dialogFlag: false,
- status: ''
+ status: '',
+ url: ''
}
},
props: {
@@ -99,16 +100,15 @@
methods: {
async submitAudit() {
this.status = 'auditing'
- const url = await uploadByBase64(this.base64 ,'浜鸿劯鐓х墖')
- if (!url) {
+ this.url = await uploadByBase64(this.base64 ,'浜鸿劯鐓х墖')
+ if (!this.url) {
this.status = 'fail'
return
}
- const params = { faceImgPath: url }
+ const params = { faceImgPath: this.url }
this.$axios.get('/system/auth/staff/checkin/face-match', { params }).then(res => {
if (res.data.code == 0) {
- // this.status = res.data.data ? 'success' : 'fail'
- this.status = 'success'
+ this.status = res.data.data ? 'success' : 'fail'
} else {
this.status = 'fail'
this.$message.error(res.data.msg || "浜鸿劯姣斿澶辫触")
@@ -119,7 +119,7 @@
},
handlerSuccess() {
this.dialogFlag = false
- this.$emit('handlerSuccess')
+ this.$emit('handlerSuccess', this.url)
}
}
}
diff --git a/src/views/h5/faceAuth/components/camera.vue b/src/views/h5/faceAuth/components/camera.vue
index 530cbe0..21bec1c 100644
--- a/src/views/h5/faceAuth/components/camera.vue
+++ b/src/views/h5/faceAuth/components/camera.vue
@@ -15,7 +15,6 @@
</template>
<script>
-import { uploadByBase64 } from '@/utils/tool.js'
export default {
data () {
return {
@@ -197,7 +196,6 @@
},
async uploadBase64(){ // 涓婁紶鍥剧墖
let base64 = this.$refs.canvasEl.toDataURL("image/png", 1);
- // const url = await uploadByBase64(base64, '鏍搁獙鐓х墖')
if (base64) {
this.$emit('handlerSuccess', base64)
this.closeCamera()
diff --git a/src/views/h5/faceAuth/index.vue b/src/views/h5/faceAuth/index.vue
index c7635b9..ef9b33a 100644
--- a/src/views/h5/faceAuth/index.vue
+++ b/src/views/h5/faceAuth/index.vue
@@ -51,6 +51,7 @@
import auditDialog from '@/views/h5/faceAuth/components/auditDialog.vue';
import { useSessionStore } from '@/stores/session.js'
import { storeToRefs } from 'pinia';
+import { chooseImage } from '@/utils/wxjssdk.js'
export default {
components: {
camera,
@@ -63,10 +64,10 @@
data() {
return {
tipItems: [
- { label: '鏍囧噯鎷嶆憚', isCheck: true },
- { label: '鏍囧噯鎷嶆憚', isCheck: true },
- { label: '鏍囧噯鎷嶆憚', isCheck: true },
- { label: '鏍囧噯鎷嶆憚', isCheck: true },
+ { label: '鏍囧噯鎷嶆憚' },
+ { label: '閬尅鑴搁儴' },
+ { label: '鎷嶆憚涓嶅叏' },
+ { label: '鍏夌嚎涓嶈冻' },
],
openCameraFlag: false,
base64: '',
@@ -86,6 +87,9 @@
'border-color': '#f8f8f8'
}
}
+ },
+ appId() {
+ return this.$route.query.appId
}
},
async mounted() {
@@ -95,9 +99,10 @@
getUserPositionStatus(evt) {
this.userPositionStatus = evt
},
- startCapture() {
+ async startCapture() {
if (isWeixin) {
- console.log('')
+ const photo = await chooseImage()
+ this.shootSuccess('data:image/jpg;base64,' + photo)
} else {
this.openCameraFlag = true
}
@@ -108,17 +113,9 @@
this.auditDialogFlag = true
}
},
- auditSuccess() {
- localStorage.setItem('isFace', true)
- if (!this.getIsSignup()) {
- this.$router.replace({ path: '/h5/signup', query: { appId: this.appId } })
- } else {
- this.$router.replace({ path: '/h5/verForm', query: { appId: this.appId }})
- }
+ auditSuccess(evt) {
+ this.$router.replace({ path: '/h5/signup', query: { appId: this.appId, url: evt } })
},
- getIsSignup() {
- return Boolean(localStorage.getItem('isSignup'))
- }
}
}
</script>
diff --git a/src/views/h5/index.vue b/src/views/h5/index.vue
index a4c46f9..fd2c39d 100644
--- a/src/views/h5/index.vue
+++ b/src/views/h5/index.vue
@@ -1,33 +1,32 @@
<template>
- <div>
+ <div v-if="userInfo.id">
<router-view></router-view>
</div>
</template>
<script>
import { useSessionStore } from '@/stores/session.js'
+import { storeToRefs } from 'pinia';
export default {
setup() {
const { setUserInfo } = useSessionStore()
- return { setUserInfo }
+ const { userInfo } = storeToRefs(useSessionStore())
+ return { setUserInfo, userInfo }
},
data() {
return {}
},
- async created() {
- await this.getUserInfo()
+ created() {
+ if (this.$route.path == '/h5/verify' && this.$route.query.appId) {
+ localStorage.setItem('verify_url', this.$route.fullPath)
+ }
+ this.getUserInfo()
},
methods: {
getUserInfo() {
- return new Promise((resolve) => {
- this.$axios.get('/system/auth/staff/profile').then(res => {
- if (res.data.code == 0) {
- this.setUserInfo(res.data.data || {})
- } else {
- this.$message.error(res.data.msg || '鑾峰彇鐢ㄦ埛淇℃伅澶辫触')
- }
- }).finally(() => {
- resolve()
- })
+ this.$axios.get('/system/auth/staff/profile').then(res => {
+ if (res.data.code == 0) {
+ this.setUserInfo(res.data.data || {})
+ }
})
},
}
diff --git a/src/views/h5/login/bind.vue b/src/views/h5/login/bind.vue
new file mode 100644
index 0000000..cf7d47a
--- /dev/null
+++ b/src/views/h5/login/bind.vue
@@ -0,0 +1,140 @@
+<template>
+ <div class="login">
+ <el-form ref="form" :model="form">
+ <el-form-item :rules="[$rules.required('璇疯緭鍏ョ粦瀹氭墜鏈哄彿') , $rules.phone()]" prop="mobile">
+ <el-input v-model="form.mobile" placeholder="璇疯緭鍏ョ粦瀹氭墜鏈哄彿" style="width: 100%" size="large" />
+ </el-form-item>
+ <el-form-item prop="code" :rules="[$rules.required('璇疯緭鍏ラ獙璇佺爜'), $rules.code()]">
+ <el-input
+ v-model="form.code"
+ placeholder="璇疯緭鍏ラ獙璇佺爜"
+ style="width: 100%" size="large"
+ >
+ <template #append>
+ <el-row style="width: 70px;justify-content: center;">
+ <el-button
+ v-if="countdown == 180"
+ style="color: var(--el-color-primary);"
+ class="cursor-p"
+ :loading="sendCodeLoading"
+ @click="sendCode()"
+ >
+ 鑾峰彇楠岃瘉鐮�
+ </el-button>
+ <el-text v-else>{{ countdown }}s</el-text>
+ </el-row>
+ </template>
+ </el-input>
+ </el-form-item>
+ </el-form>
+ <el-button @click="login()" :loading="loginLoading" type="primary" size="large" class="mt-2" style="width: 100%">缁戝畾骞剁櫥褰�</el-button>
+ </div>
+</template>
+<script>
+import { tokenUtils } from '@/utils/axios.js';
+import { useLoginStore } from '@/stores/login.js'
+import { storeToRefs } from 'pinia';
+export default {
+ setup() {
+ const { lastRouteInfo } = storeToRefs(useLoginStore())
+ return { lastRouteInfo }
+ },
+ data() {
+ return {
+ form: {
+ mobile: '',
+ code: '',
+ },
+ countdown: 180,
+ sendCodeLoading: false,
+ loginLoading: false,
+ countdownInterval: null
+ }
+ },
+ created() {
+ },
+ computed: {
+ state() {
+ return this.$route.query.state
+ },
+ openid() {
+ return this.$route.query.openid
+ },
+ wxCode() {
+ return this.$route.query.code
+ }
+ },
+ mounted() {
+ document.title = this.$route.name
+ },
+ methods: {
+ startCountdownInterval() {
+ this.clearCountdownInterval()
+ this.countdown--
+ this.countdownInterval = setInterval(() => {
+ if (this.countdown > 0) {
+ this.countdown--
+ } else {
+ this.countdown = 180
+ this.clearCountdownInterval()
+ }
+ }, 1000)
+ },
+ clearCountdownInterval() {
+ clearInterval(this.countdownInterval)
+ this.countdownInterval = null
+ },
+ async sendCode() {
+ const validate = await this.$refs.form.validateField('mobile')
+ if (validate) {
+ const data = {
+ captchaVerification: '',
+ mobile: this.form.mobile,
+ scene: 21,
+ }
+ this.sendCodeLoading = true
+ this.$axios.post('/system/auth/send-sms-code', data).then(res => {
+ if (res.data.code == 0) {
+ this.startCountdownInterval()
+ this.$message.success('宸插彂閫侀獙璇佺爜锛岃娉ㄦ剰鏌ユ敹')
+ } else {
+ this.$message.error(res.data.msg || '鑾峰彇楠岃瘉鐮佸け璐�')
+ }
+ }).finally(() => {
+ this.sendCodeLoading = false
+ })
+ }
+ },
+ login() {
+ const data = {
+ mobile: this.form.mobile,
+ code: this.form.code,
+ state: this.state,
+ openid: this.openid,
+ wxCode: this.wxCode
+ }
+ this.loginLoading = true
+ this.$axios.post('/system/auth/staff/checkin/bind', data).then(async res => {
+ if (res.data.code == 0) {
+ const resData = res.data.data
+ tokenUtils.setTokens(resData.accessToken, resData.refreshToken)
+ this.$message.success('缁戝畾鎴愬姛')
+ const path = localStorage.getItem('verify_url')
+ if (path) {
+ this.$router.replace(path)
+ }
+ } else {
+ this.$message.error(res.data.msg || '鐧诲綍澶辫触')
+ }
+ }).finally(() => {
+ this.loginLoading = false
+ })
+ },
+ }
+}
+</script>
+<style scoped>
+.login {
+ padding: 40px 20px 20px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/h5/login/index.vue b/src/views/h5/login/index.vue
index b9cd759..f434649 100644
--- a/src/views/h5/login/index.vue
+++ b/src/views/h5/login/index.vue
@@ -33,15 +33,16 @@
<script>
import { tokenUtils } from '@/utils/axios.js';
import { useLoginStore } from '@/stores/login.js'
+import { storeToRefs } from 'pinia';
import { isWeixin } from '@/utils/UA.js'
export default {
setup() {
- const { lastRouteInfo } = useLoginStore()
+ const { lastRouteInfo } = storeToRefs(useLoginStore())
return { lastRouteInfo }
},
data() {
return {
- loginType: '', //mobile銆亀eixin
+ loginType: '', //mobilePhone銆亀eixin
form: {
mobile: '',
code: '',
@@ -55,7 +56,10 @@
created() {
tokenUtils.clearTokens()
this.loginType = isWeixin ? 'weixin' : 'mobilePhone'
- this.loginType = 'mobile'
+ if (isWeixin) {
+ this.loginType = 'weixin'
+ this.$router.replace({ path: '/h5/redirect' })
+ }
},
computed: {
appId() {
@@ -114,8 +118,9 @@
const resData = res.data.data
tokenUtils.setTokens(resData.accessToken, resData.refreshToken)
this.$message.success('鐧诲綍鎴愬姛')
- if (this.lastRouteInfo.name) {
- this.$router.replace(this.lastRouteInfo)
+ const path = localStorage.getItem('verify_url')
+ if (path) {
+ this.$router.replace(path)
}
} else {
this.$message.error(res.data.msg || '鐧诲綍澶辫触')
@@ -124,12 +129,6 @@
this.loginLoading = false
})
},
- verify() {
- this.$router.push('/h5/verify')
- },
- signup() {
- this.$router.push('/h5/signup')
- }
}
}
</script>
diff --git a/src/views/h5/login/redirect.vue b/src/views/h5/login/redirect.vue
new file mode 100644
index 0000000..07fa156
--- /dev/null
+++ b/src/views/h5/login/redirect.vue
@@ -0,0 +1,232 @@
+<template>
+ <div class="wx-login-container">
+ <div class="loading-wrapper">
+ <div class="wechat-icon">
+ <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
+ <path d="M717.5 595.8c-15.7 8.3-32.6 13.9-50.4 15.7-12.6 1.3-25.3-0.4-37.6-2.9-19-3.8-36.9-10.8-53.5-20.7-3.6-2.2-7.2-4.4-10.7-6.8-19.5-13.6-36.5-29.9-50.8-49-6.5-8.6-12.1-17.9-16.9-27.5-4.8-9.7-8.3-19.8-10.6-30.3-2.2-10.1-3.2-20.3-3-30.6 0.1-5.3 0.4-10.5 1.1-15.8 1.7-12.6 5.1-24.7 10.1-36.3 6.1-14.1 14.2-27 24.4-38.5 13.9-15.6 30.4-28.1 49.3-37.2 12.9-6.3 26.5-10.6 40.6-12.8 14.1-2.2 28.4-2.2 42.6 0.1 14.2 2.3 27.8 6.7 40.7 13.1 18.9 9.2 35.4 21.7 49.3 37.3 10.2 11.5 18.3 24.5 24.4 38.5 5 11.6 8.4 23.8 10.1 36.3 0.7 5.3 1 10.5 1.1 15.8 0.2 10.3-0.8 20.5-3 30.6-2.3 10.5-5.8 20.6-10.6 30.3-4.8 9.6-10.4 18.9-16.9 27.5-14.3 19.1-31.3 35.4-50.8 49-3.5 2.4-7.1 4.6-10.7 6.8-16.6 9.9-34.5 16.9-53.5 20.7-12.3 2.5-25 4.2-37.6 2.9z" fill="#07C160"/>
+ <path d="M395.6 380.4c0 54.7 26.5 103.5 67.6 134.4-3.6 9.8-7.9 19.2-12.8 28.1-4.9 8.9-10.4 17.4-16.6 25.4-6.2 8-13.1 15.4-20.6 22.2-7.5 6.8-15.7 12.8-24.4 17.9-8.7 5.1-18 9.3-27.6 12.5-9.6 3.2-19.6 5.3-29.8 6.3-10.2 1-20.5 0.9-30.6-0.4-10.1-1.3-20-3.8-29.4-7.4-9.4-3.6-18.3-8.3-26.6-14-8.3-5.7-15.9-12.2-22.7-19.6-6.8-7.4-12.7-15.5-17.6-24.3-4.9-8.8-8.8-18.2-11.5-28-2.7-9.8-4.2-19.9-4.5-30.2-0.3-10.3 0.8-20.5 3.2-30.5 2.4-10 6.1-19.6 10.9-28.7 4.8-9.1 10.7-17.5 17.5-25.2 6.8-7.7 14.5-14.5 22.9-20.4 8.4-5.9 17.5-10.8 27.1-14.6 9.6-3.8 19.7-6.4 30-7.9 10.3-1.5 20.8-1.8 31.2-0.7 10.4 1.1 20.6 3.6 30.3 7.4 9.7 3.8 18.8 8.8 27.1 15 8.3 6.2 15.8 13.4 22.4 21.5 6.6 8.1 12.2 16.9 16.6 26.3 4.4 9.4 7.6 19.3 9.5 29.6z" fill="#07C160"/>
+ </svg>
+ </div>
+ <div class="sub-text">
+ 寰俊鎺堟潈涓�
+ <span class="dots">
+ <span class="dot"></span>
+ <span class="dot"></span>
+ <span class="dot"></span>
+ </span>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import { tokenUtils } from '@/utils/axios.js';
+import { useLoginStore } from '@/stores/login.js'
+import { storeToRefs } from 'pinia';
+export default {
+ setup() {
+ const { lastRouteInfo } = storeToRefs(useLoginStore())
+ return { lastRouteInfo }
+ },
+ data() {
+ return {
+
+ }
+ },
+ watch() {
+
+ },
+ computed: {
+ code() {
+ return this.$route.query.code
+ },
+ state() {
+ return this.$route.query.state
+ }
+ },
+ created() {
+ if (this.code && this.state) {
+ this.authSuccess()
+ } else {
+ this.redirectUrl()
+ }
+ },
+ methods: {
+ redirectUrl() {
+ const params = {
+ targetId: '',
+ redirectUrl: encodeURIComponent(window.location.href),
+ }
+ this.$axios.get('/system/auth/staff/checkin/wx-auth-redirect', { params }).then(res => {
+ if (res.data.code == 0) {
+ window.location.replace(res.data.data)
+ } else {
+ this.$message.error(res.data.msg)
+ }
+ })
+ },
+ authSuccess() {
+ const params = {
+ targetId: '',
+ code: this.code,
+ state: this.state
+ }
+ this.$axios.get('/system/auth/staff/checkin/auth-success/null', { params }).then(res => {
+ if (res.data.code == 0) {
+ const resData = res.data.data || {}
+ if (resData.userId) {
+ tokenUtils.setTokens(resData.accessToken, resData.refreshToken)
+ const path = localStorage.getItem('verify_url')
+ if (path) {
+ this.$router.replace(path)
+ }
+ } else {
+ this.$router.replace({
+ path: '/h5/bind',
+ query: {
+ state: resData.state,
+ openid: resData.openid,
+ code: resData.code
+ }
+ })
+ }
+ } else {
+ this.$message.error(res.data.msg)
+ }
+ })
+ }
+ }
+}
+</script>
+
+<style scoped>
+.wx-login-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
+}
+
+.loading-wrapper {
+ text-align: center;
+ padding: 60px 40px;
+}
+
+.wechat-icon {
+ width: 100px;
+ height: 100px;
+ margin: 0 auto 30px;
+ animation: iconPulse 2s ease-in-out infinite;
+}
+
+.wechat-icon svg {
+ width: 100%;
+ height: 100%;
+ filter: drop-shadow(0 8px 16px rgba(7, 193, 96, 0.3));
+}
+
+@keyframes iconPulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.1);
+ }
+}
+
+.loading-text {
+ font-size: 28px;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 16px;
+ display: inline-block;
+}
+
+.text-item {
+ display: inline-block;
+ opacity: 0;
+ animation: textFadeIn 0.5s ease-out forwards;
+}
+
+.text-item:nth-child(1) {
+ animation-delay: 0.2s;
+}
+
+.text-item:nth-child(2) {
+ animation-delay: 0.4s;
+}
+
+.text-item:nth-child(3) {
+ animation-delay: 0.6s;
+}
+
+.text-item:nth-child(4) {
+ animation-delay: 0.8s;
+}
+
+@keyframes textFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.dots {
+ display: inline-block;
+ margin-left: 8px;
+ vertical-align: middle;
+}
+
+.dot {
+ display: inline-block;
+ width: 6px;
+ height: 6px;
+ background: #07C160;
+ border-radius: 50%;
+ margin: 0 3px;
+ animation: dotBounce 1.4s ease-in-out infinite both;
+}
+
+.dot:nth-child(1) {
+ animation-delay: -0.32s;
+}
+
+.dot:nth-child(2) {
+ animation-delay: -0.16s;
+}
+
+.dot:nth-child(3) {
+ animation-delay: 0;
+}
+
+@keyframes dotBounce {
+ 0%, 80%, 100% {
+ transform: scale(0);
+ opacity: 0.5;
+ }
+ 40% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+.sub-text {
+ font-size: 18px;
+ color: #999;
+ animation: fadeInOut 2s ease-in-out infinite;
+}
+
+@keyframes fadeInOut {
+ 0%, 100% {
+ opacity: 0.5;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+</style>
diff --git a/src/views/h5/signup/index.vue b/src/views/h5/signup/index.vue
index 7a6f83d..99098ca 100644
--- a/src/views/h5/signup/index.vue
+++ b/src/views/h5/signup/index.vue
@@ -77,11 +77,11 @@
distance: null,
positionError: false,
positionName: '',
- positionAddress: '鍗楀北鍖烘墦鐭充簩璺崡118鍙�',
+ positionAddress: '',
currentTimeText: '',
centerPoint: {
- lat: 22.580372,
- lng: 113.946530
+ lat: 23.135618,
+ lng: 113.27077
}
}
},
@@ -104,6 +104,9 @@
},
appId() {
return this.$route.query.appId
+ },
+ url() {
+ return this.$route.query.url
}
},
created() {
@@ -118,10 +121,12 @@
this.$axios.get('/exam/verify-record/get-by-application-id', { params }).then(res => {
if (res.data.code == 0) {
const resData = res.data.data || {}
- // this.centerPoint = {
- // lat: resData.examSite?.locationLat,
- // lng: resData.examSite?.locationLng
- // }
+ if (resData.examSite?.locationLat && resData.examSite?.locationLng) {
+ this.centerPoint = {
+ lat: resData.examSite?.locationLat,
+ lng: resData.examSite?.locationLng
+ }
+ }
this.positionAddress = resData.examSite?.address
} else {
this.$message.error(res.data.msg)
@@ -140,22 +145,29 @@
}
},
signinConfirm() {
- if (!this.canSignup) {
+ if (!this.canSignup || this.confirmLoading) {
return
}
- this.$message.success('绛惧埌鎴愬姛')
- localStorage.setItem('isSignup', true)
- setTimeout(() => {
- if (this.getIsFace()) {
- this.$router.replace({ path: '/h5/face', query: { appId: this.appId }})
+ const data = {
+ targetId: this.appId,
+ targetType: 2,
+ url: this.url,
+ type: 0
+ }
+ this.confirmLoading = true
+ this.$axios.post('/exam/staff/checkin', data).then(res => {
+ if (res.data.code == 0) {
+ this.$message.success('绛惧埌鎴愬姛')
+ setTimeout(() => {
+ this.$router.replace({ path: '/h5/verForm', query: { appId: this.appId }})
+ }, 500)
} else {
- this.$router.replace({ path: '/h5/verForm', query: { appId: this.appId }})
+ this.$message.error(res.data.msg)
}
- }, 500)
+ }).finally(() => {
+ this.confirmLoading = false
+ })
},
- getIsFace() {
- return Boolean(localStorage.getItem('isFace'))
- }
}
}
</script>
diff --git a/src/views/h5/verify/form.vue b/src/views/h5/verify/form.vue
index 8409462..8fc725e 100644
--- a/src/views/h5/verify/form.vue
+++ b/src/views/h5/verify/form.vue
@@ -1,5 +1,5 @@
<template>
- <div v-if="pdfUrl">
+ <div>
<el-row class="p-3 m-0" justify="space-between" align="middle">
<el-col :span="4"></el-col>
<el-col :span="16">
@@ -28,6 +28,7 @@
<div v-if="pdfUrl" :style="{width: '100%', height: `${mainHeight - 100}px`}">
<PdfPreview v-if="pdfUrl" :url="pdfUrl"></PdfPreview>
</div>
+ <el-text class="ml-2 text-info">鑰冪偣鐢虫姤鏂囦欢鍔犺浇澶辫触...</el-text>
<div class="p-2 my-4">
<el-form ref="verifyForm" :model="form">
<el-form-item label="*浠ヤ笂鐢虫姤鍐呭鏄惁灞炲疄" prop="isVerified">
@@ -125,7 +126,7 @@
this.$axios.get('/exam/verify-record/get-by-application-id', { params }).then(res => {
if (res.data.code == 0) {
const resData = res.data.data || {}
- this.pdfUrl = this.$qxueyou.qxyRes + resData.examSiteVerifyFile
+ this.pdfUrl = resData.examSiteVerifyFile ? this.$qxueyou.qxyRes + resData.examSiteVerifyFile : ''
this.title = resData.organizationName + '-' + resData.examSite.siteName + '鑰冪偣鏍搁獙'
if (resData.id) {
this.form.isContentTrue = resData.isContentTrue
diff --git a/src/views/h5/verify/index.vue b/src/views/h5/verify/index.vue
index 02e2d30..0befee6 100644
--- a/src/views/h5/verify/index.vue
+++ b/src/views/h5/verify/index.vue
@@ -2,33 +2,27 @@
<div></div>
</template>
<script>
-import { tokenUtils } from '@/utils/axios.js';
-
export default {
components: {},
data() {
return {}
},
computed: {
- query() {
- return this.$route.query
- },
appId() {
- return this.query.appId
+ return this.$route.query.appId
}
},
async created() {
const canVerify = await this.getCanVerify()
- if (canVerify) {
- if (!this.getIsFace()) {
- this.$router.replace({ path: '/h5/face', query: { appId: this.appId }})
- } else if (!this.getIsSignup()) {
- this.$router.replace({ path: '/h5/signup', query: { appId: this.appId } })
- } else {
- this.$router.replace({ path: '/h5/verForm', query: { appId: this.appId }})
- }
- } else {
+ if (!canVerify) {
this.$router.replace('/h5/noVerAccess')
+ return
+ }
+ const checkinExist = await this.getCheckinExist()
+ if (checkinExist) {
+ this.$router.replace({ path: '/h5/verForm', query: { appId: this.appId }})
+ } else {
+ this.$router.replace({ path: '/h5/face', query: { appId: this.appId }})
}
},
mounted() {
@@ -38,7 +32,7 @@
getCanVerify() {
return new Promise((resolve) => {
const params = {
- applicationId: this.$route.query.appId
+ applicationId: this.appId
}
this.$axios.get('/exam/verify-record/can-verify', { params }).then(res => {
if (res.data.code == 0) {
@@ -51,12 +45,22 @@
})
})
},
- getIsFace() {
- return Boolean(localStorage.getItem('isFace'))
+ getCheckinExist() {
+ return new Promise((resolve) => {
+ const params = {
+ targetId: this.appId
+ }
+ this.$axios.get('/exam/staff/checkin/exist', { params }).then(res => {
+ if (res.data.code == 0) {
+ resolve(res.data.data)
+ } else {
+ resolve(false)
+ }
+ }, () => {
+ resolve(false)
+ })
+ })
},
- getIsSignup() {
- return Boolean(localStorage.getItem('isSignup'))
- }
}
}
</script>
\ No newline at end of file
diff --git a/src/views/main/components/UploadIdCard.vue b/src/views/main/components/UploadIdCard.vue
index 924684c..11d73ef 100644
--- a/src/views/main/components/UploadIdCard.vue
+++ b/src/views/main/components/UploadIdCard.vue
@@ -151,7 +151,7 @@
file: UploadRequestOptions.file,
directory: ''
}
- this.$axios.post('/infra/file/upload', data, {
+ this.$axios.post('/infra/file/exam/upload', data, {
headers: { 'Content-Type': "multipart/form-data" }
}).then(res => {
let index = this.list.findIndex(ele => ele.uid == data.file.uid)
diff --git a/vite.config.js b/vite.config.js
index 1837faf..8dad771 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -14,6 +14,7 @@
},
},
server: {
+ allowedHosts: ['dev.qxueyou.com'],
host: '0.0.0.0',
proxy: {
'/app-api': {
--
Gitblit v1.8.0