app-手机验证码登录

This commit is contained in:
lSun 2025-08-28 17:00:20 +08:00
parent 3fa5f7177f
commit c8cee60f31
9 changed files with 66 additions and 21 deletions

5
components.d.ts vendored
View File

@ -3,9 +3,11 @@
// @ts-nocheck // @ts-nocheck
// Generated by unplugin-vue-components // Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {} export {}
declare module 'vue' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
@ -15,7 +17,6 @@ declare module 'vue' {
VanDatePicker: typeof import('vant/es')['DatePicker'] VanDatePicker: typeof import('vant/es')['DatePicker']
VanField: typeof import('vant/es')['Field'] VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form'] VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanNavBar: typeof import('vant/es')['NavBar'] VanNavBar: typeof import('vant/es')['NavBar']
VanOverlay: typeof import('vant/es')['Overlay'] VanOverlay: typeof import('vant/es')['Overlay']
VanPicker: typeof import('vant/es')['Picker'] VanPicker: typeof import('vant/es')['Picker']

View File

@ -116,6 +116,38 @@ export default class Crypoto implements CrypotoType {
return ciphertext return ciphertext
} }
decrypt: any; // decrypt: any;
decrypt(cipherText: string) {
if (!cipherText) {
console.error("密文为空或未定义");
return "";
}
const key = this.key;
const iv = this.iv;
// 如果后端传来的密文是 Base64URL 格式,需要先转成 Base64 标准格式
const base64Str = cipherText.replace(/-/g, '+').replace(/_/g, '/');
// 创建包含 ciphertext 的 CipherParams 对象
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Base64.parse(base64Str)
});
const decryptResult = CryptoJS.AES.decrypt(cipherParams, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
const decryptedStr = decryptResult.toString(CryptoJS.enc.Utf8);
if (!decryptedStr) {
console.error("解密结果为空,请检查密钥/IV是否匹配 或 密文是否正确");
}
return decryptedStr;
}
} }

View File

@ -158,7 +158,7 @@
console.log(res.status) console.log(res.status)
showSuccessToast('登录成功!') showSuccessToast('登录成功!')
localStorage.setItem('token', res.data.token) localStorage.setItem('token', res.data.token)
localStorage.setItem('phoneNumber', username.value) localStorage.setItem('phoneNumber', cry.encrypt(username.value))
localStorage.setItem('avatarUrl', 'https://img.zcool.cn/community/0104c958b69c23a801219c77ba5da2.png?x-oss-process=image/auto-orient,1/resize,m_lfit,w_1280,limit_1/sharpen,100') localStorage.setItem('avatarUrl', 'https://img.zcool.cn/community/0104c958b69c23a801219c77ba5da2.png?x-oss-process=image/auto-orient,1/resize,m_lfit,w_1280,limit_1/sharpen,100')
// 3h // 3h
const overDate = new Date().getTime() - 8 * 60 * 60 * 1000 + 3 * 60 * 60 * 1000 const overDate = new Date().getTime() - 8 * 60 * 60 * 1000 + 3 * 60 * 60 * 1000

View File

@ -33,20 +33,20 @@
@cancel="showHospitalPicker = false" @cancel="showHospitalPicker = false"
/> />
</van-popup> </van-popup>
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">检查类型</h2> <h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">选择套餐</h2>
<van-field <van-field
v-model="result2" v-model="result2"
is-link is-link
readonly readonly
name="checkId" name="checkId"
placeholder="点击选择检查类型" placeholder="点击选择套餐"
@click="showTypePicker = true" @click="showTypePicker = true"
style="margin-bottom: 0.3rem" style="margin-bottom: 0.3rem"
autocomplete="off" autocomplete="off"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '请选择一个检查类型' message: '请选择一个套餐'
} }
]" ]"
/> />
@ -61,7 +61,7 @@
@close="cascaderClose" @close="cascaderClose"
@change="onChange" @change="onChange"
/> />
<div class="inner-package" v-if="showTotalTc"> <!-- <div class="inner-package" v-if="showTotalTc">
<h2 class="inner-tit"> <h2 class="inner-tit">
{{ personalPackageName }} {{ personalPackageName }}
<span style="display: flex; align-items: center;" v-if="pushBtn" @click="flodTc"> 展开 <van-icon name="arrow-down" size="26"/></span> <span style="display: flex; align-items: center;" v-if="pushBtn" @click="flodTc"> 展开 <van-icon name="arrow-down" size="26"/></span>
@ -81,7 +81,7 @@
<div class="cfm-btn"> <div class="cfm-btn">
<van-button class="confirm-package" type="primary" @click="closePopup">确认套餐</van-button> <van-button class="confirm-package" type="primary" @click="closePopup">确认套餐</van-button>
</div> </div>
</div> </div> -->
</van-popup> </van-popup>
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">体检时间</h2> <h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">体检时间</h2>
@ -425,10 +425,14 @@
// //
const onChange = (res: any) => { const onChange = (res: any) => {
console.log(res) console.log("孙亮",res)
result2.value = res.selectedOptions[0]?.text; result2.value = res.selectedOptions[0]?.text;
examType.value = res.selectedOptions[0]?.value examType.value = res.selectedOptions[0]?.value;
getPackageDetail({
personalPackageName.value =res.selectedOptions[0]?.text;
packageId.value = res.selectedOptions[0]?.value;
/* getPackageDetail({
checkId: JSON.stringify(res.selectedOptions[0].value), checkId: JSON.stringify(res.selectedOptions[0].value),
token: localStorage.getItem('token'), token: localStorage.getItem('token'),
combType: 2 combType: 2
@ -459,7 +463,7 @@
} }
}).catch((err: any) => { }).catch((err: any) => {
console.log(err) console.log(err)
}) }) */
} }
// //

View File

@ -112,6 +112,9 @@
import { editNewPwd, sendVeriCode } from '../../api/ForgetPassword' import { editNewPwd, sendVeriCode } from '../../api/ForgetPassword'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import './scss/index.scss' import './scss/index.scss'
import Crypoto from '../../api/AesCbc'
const cry: any = new Crypoto()
const phoneNumPlaceHolder = ref<string>('请输入手机号') const phoneNumPlaceHolder = ref<string>('请输入手机号')
const pwdPlaceHolder = ref<string>('请输入新密码') const pwdPlaceHolder = ref<string>('请输入新密码')
@ -316,7 +319,7 @@
onMounted(() => { onMounted(() => {
console.log(route.query.phoneNum) console.log(route.query.phoneNum)
if (route.query) { if (route.query) {
phoneNumber.value = route.query.phoneNum phoneNumber.value = cry.decrypt(route.query.phoneNum)
} else { } else {
phoneNumber.value = '' phoneNumber.value = ''
} }

View File

@ -15,7 +15,7 @@
</div> </div>
<h2 class="tit">体检服务</h2> <h2 class="tit">体检服务</h2>
<div class="services"> <div class="services">
<div v-if="personnelType !== '0'" class="services-item" @click="judgePreOrdered()"> <div class="services-item" @click="judgePreOrdered()">
<img :src="preOrderImg" alt=""/> <img :src="preOrderImg" alt=""/>
<span>体检预约</span> <span>体检预约</span>
</div> </div>

View File

@ -205,6 +205,8 @@
}) })
} }
}) })
}else{
showFailToast('登录失败!没有找到这个号码')
} }
}).catch(() => { }).catch(() => {
showFailToast('登录失败!') showFailToast('登录失败!')

View File

@ -9,7 +9,7 @@
<h1>体检单据</h1> <h1>体检单据</h1>
<h2>套餐名称</h2> <h2>套餐名称</h2>
<span>{{ packageName }}</span> <span>{{ packageName }}</span>
<h2>体检项目</h2> <!-- <h2>体检项目</h2>
<span v-for="(item, index) in receiptInfo" :key="index"> <span v-for="(item, index) in receiptInfo" :key="index">
{{ item.mealName + ' ' }} {{ item.mealName + ' ' }}
</span> </span>
@ -18,7 +18,7 @@
<div class="content">{{ item.mealName }}{{ item.mealContent }}</div> <div class="content">{{ item.mealName }}{{ item.mealContent }}</div>
<div class="meal-price">{{ item.mealPrice }}</div> <div class="meal-price">{{ item.mealPrice }}</div>
</div> </div>
<h2 style="color: red;">体检总价{{ totalPrice }}</h2> <h2 style="color: red;">体检总价{{ totalPrice }}</h2> -->
</div> </div>
</template> </template>

View File

@ -47,7 +47,9 @@
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { showConfirmDialog } from 'vant'; import { showConfirmDialog } from 'vant';
import Crypoto from '../../api/AesCbc'
const cry: any = new Crypoto()
const router = useRouter() const router = useRouter()
const userInfo = ref<any>({}) const userInfo = ref<any>({})
// //
@ -94,11 +96,12 @@
token: localStorage.getItem('token') token: localStorage.getItem('token')
}).then((res: any) => { }).then((res: any) => {
userInfo.value = res.data.obj[0] userInfo.value = res.data.obj[0]
userInfo.value.phyName= cry.decrypt(userInfo.value.phyName)
const data = res.data.obj[0] const data = res.data.obj[0]
localStorage.setItem('phyName', data.phyName) localStorage.setItem('phyName', data.phyName)
localStorage.setItem('idcard', data.idcard) localStorage.setItem('idcard', cry.decrypt(data.idcard))
localStorage.setItem('age', data.age) localStorage.setItem('age', data.age)
localStorage.setItem('telepNumber', data.telepNumber) localStorage.setItem('telepNumber', cry.decrypt(data.telepNumber))
localStorage.setItem('departName', data.departName) localStorage.setItem('departName', data.departName)
localStorage.setItem('id', data.id) localStorage.setItem('id', data.id)
if (Number(data.sex) === 1) { if (Number(data.sex) === 1) {