flat: bug修复
This commit is contained in:
@@ -64,7 +64,7 @@
|
|||||||
<view v-if="hasLogin" :class="{ 'match-move-top': isMachineEnv }" class="match-card-out">
|
<view v-if="hasLogin" :class="{ 'match-move-top': isMachineEnv }" class="match-card-out">
|
||||||
<view class="match-card">
|
<view class="match-card">
|
||||||
<image class="match-card-bg" src="@/static/icon/match-card-bg.png" />
|
<image class="match-card-bg" src="@/static/icon/match-card-bg.png" />
|
||||||
<view class="title">简历匹配职位</view>
|
<view class="title">为您匹配的职位</view>
|
||||||
<view class="match-item-container">
|
<view class="match-item-container">
|
||||||
<AIMatch :tags="matchTags" :loading="matchLoading" @tag-click="handleTagClick"></AIMatch>
|
<AIMatch :tags="matchTags" :loading="matchLoading" @tag-click="handleTagClick"></AIMatch>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppLayout title="就业服务程序">
|
<AppLayout :title="pageTitle">
|
||||||
<view v-if="isMachineEnv && !hasLogin" class="alipay-login-container">
|
<view v-if="isMachineEnv && !hasLogin" class="alipay-login-container">
|
||||||
<!-- 切换 -->
|
<!-- 切换 -->
|
||||||
<view class="login-method-switch">
|
<view class="login-method-switch">
|
||||||
<view
|
|
||||||
class="method-item"
|
|
||||||
:class="{ active: loginMethod === 'face' }"
|
|
||||||
@click="switchLoginMethod('face')"
|
|
||||||
>
|
|
||||||
扫脸登录
|
|
||||||
</view>
|
|
||||||
<view
|
<view
|
||||||
class="method-item"
|
class="method-item"
|
||||||
:class="{ active: loginMethod === 'qrcode' }"
|
:class="{ active: loginMethod === 'qrcode' }"
|
||||||
@@ -17,6 +10,13 @@
|
|||||||
>
|
>
|
||||||
扫码登录
|
扫码登录
|
||||||
</view>
|
</view>
|
||||||
|
<view
|
||||||
|
class="method-item"
|
||||||
|
:class="{ active: loginMethod === 'face' }"
|
||||||
|
@click="switchLoginMethod('face')"
|
||||||
|
>
|
||||||
|
扫脸登录
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="login-scan-area">
|
<view class="login-scan-area">
|
||||||
@@ -64,7 +64,8 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="countdown-container">
|
<view class="countdown-container">
|
||||||
<view class="countdown-wrapper">
|
<!-- 刷脸不限时间 -->
|
||||||
|
<view class="countdown-wrapper" v-if="loginMethod === 'qrcode'">
|
||||||
<text class="countdown-number">{{ countdown }}</text>
|
<text class="countdown-number">{{ countdown }}</text>
|
||||||
<text class="countdown-text">秒后自动返回</text>
|
<text class="countdown-text">秒后自动返回</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -236,7 +237,7 @@ let scanInterval = null;
|
|||||||
const countdown = ref(60);
|
const countdown = ref(60);
|
||||||
let countdownTimer = null;
|
let countdownTimer = null;
|
||||||
const loginMethod = ref('qrcode'); // 'qrcode' / 'face'
|
const loginMethod = ref('qrcode'); // 'qrcode' / 'face'
|
||||||
|
const pageTitle = ref('就享家服务程序');
|
||||||
onLoad((parmas) => {
|
onLoad((parmas) => {
|
||||||
getTreeselect();
|
getTreeselect();
|
||||||
if (!isMachineEnv.value) {
|
if (!isMachineEnv.value) {
|
||||||
@@ -264,6 +265,7 @@ onMounted(() => {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
stopScanAnimation();
|
stopScanAnimation();
|
||||||
stopCountdown();
|
stopCountdown();
|
||||||
@@ -274,7 +276,7 @@ const startCountdown = () => {
|
|||||||
countdown.value = 60;
|
countdown.value = 60;
|
||||||
countdownTimer = setInterval(() => {
|
countdownTimer = setInterval(() => {
|
||||||
countdown.value--;
|
countdown.value--;
|
||||||
if (countdown.value <= 0) {
|
if (countdown.value <= 0 && loginMethod.value === 'qrcode') {
|
||||||
returnToHome();
|
returnToHome();
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -316,6 +318,7 @@ const switchLoginMethod = (method) => {
|
|||||||
faceService.close();
|
faceService.close();
|
||||||
qrHandler.start();
|
qrHandler.start();
|
||||||
playTextDirectly('扫码登录');
|
playTextDirectly('扫码登录');
|
||||||
|
resetCountdown();
|
||||||
break;
|
break;
|
||||||
case 'face':
|
case 'face':
|
||||||
qrHandler.close();
|
qrHandler.close();
|
||||||
@@ -323,14 +326,16 @@ const switchLoginMethod = (method) => {
|
|||||||
playTextDirectly('扫脸登录');
|
playTextDirectly('扫脸登录');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resetCountdown();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleFaceLogin() {
|
async function handleFaceLogin() {
|
||||||
try {
|
try {
|
||||||
const authCode = await faceService.startFaceLogin();
|
const authCode = await faceService.startFaceLogin();
|
||||||
console.log('拿到 AuthCode:', authCode);
|
console.log('authCode获取:', authCode);
|
||||||
|
if (authCode.name) {
|
||||||
|
pageTitle.value = `就享家服务程序(${authCode.name})`;
|
||||||
|
}
|
||||||
$api.createRequest('/app/alipay/scanLogin', authCode, 'POST').then((resData) => {
|
$api.createRequest('/app/alipay/scanLogin', authCode, 'POST').then((resData) => {
|
||||||
loginSetToken(resData.token).then((resume) => {
|
loginSetToken(resData.token).then((resume) => {
|
||||||
if (resume.data.jobTitleId) {
|
if (resume.data.jobTitleId) {
|
||||||
@@ -338,6 +343,11 @@ async function handleFaceLogin() {
|
|||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: '/pages/index/index',
|
url: '/pages/index/index',
|
||||||
});
|
});
|
||||||
|
// 登录成功、数据回填
|
||||||
|
if (resume.data.sex) {
|
||||||
|
pageTitle.value = `就享家服务程序(${name})`;
|
||||||
|
fromValue.sex = resume.data.sex === '男' ? 0 : 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<view v-show="searchFocus" class="search-mask" ></view>
|
<view v-show="searchFocus" class="search-mask"></view>
|
||||||
<view>
|
<view>
|
||||||
<view class="top">
|
<view class="top">
|
||||||
<image
|
<image
|
||||||
@@ -40,8 +40,12 @@
|
|||||||
@confirm="searchBtn"
|
@confirm="searchBtn"
|
||||||
/>
|
/>
|
||||||
<!-- 联想搜索下拉列表 -->
|
<!-- 联想搜索下拉列表 -->
|
||||||
<scroll-view scroll-y class="search-suggestions" v-show="showSuggestions && filteredSuggestions.length">
|
<scroll-view
|
||||||
<view
|
scroll-y
|
||||||
|
class="search-suggestions"
|
||||||
|
v-show="showSuggestions && filteredSuggestions.length"
|
||||||
|
>
|
||||||
|
<view
|
||||||
class="suggestion-item"
|
class="suggestion-item"
|
||||||
v-for="(item, index) in filteredSuggestions"
|
v-for="(item, index) in filteredSuggestions"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -144,13 +148,10 @@ const filteredSuggestions = computed(() => {
|
|||||||
|
|
||||||
const searchText = searchValue.value.toLowerCase();
|
const searchText = searchValue.value.toLowerCase();
|
||||||
try {
|
try {
|
||||||
return majorDataSource.value.filter(item =>
|
return majorDataSource.value.filter((item) => item.toLowerCase().includes(searchText));
|
||||||
item.toLowerCase().includes(searchText)
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const pageState = reactive({
|
const pageState = reactive({
|
||||||
@@ -207,26 +208,28 @@ const { columnCount, columnSpace } = useColumnCount(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
if(options.keyWord){
|
if (options.keyWord) {
|
||||||
searchValue.value = decodeURIComponent(options.keyWord)
|
searchValue.value = decodeURIComponent(options.keyWord);
|
||||||
searchBtn()
|
searchBtn();
|
||||||
}
|
}
|
||||||
let arr = uni.getStorageSync('searchList');
|
let arr = uni.getStorageSync('searchList');
|
||||||
if (arr) {
|
if (arr) {
|
||||||
historyList.value = uni.getStorageSync('searchList');
|
historyList.value = uni.getStorageSync('searchList');
|
||||||
}
|
}
|
||||||
|
|
||||||
getMajorDataSource()
|
getMajorDataSource();
|
||||||
});
|
});
|
||||||
|
|
||||||
function getMajorDataSource() {
|
function getMajorDataSource() {
|
||||||
const LoadCache = (resData) => {
|
const LoadCache = (resData) => {
|
||||||
if (resData.code === 200) {
|
if (resData.code === 200) {
|
||||||
majorDataSource.value = resData.data;
|
majorDataSource.value = resData.data;
|
||||||
console.log(majorDataSource.value)
|
console.log(majorDataSource.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$api.createRequestWithCache('/app/common/majorManagement/getMajorList', {}, 'GET', false, LoadCache).then(LoadCache);
|
$api.createRequestWithCache('/app/common/majorManagement/getMajorList', {}, 'GET', false, LoadCache).then(
|
||||||
|
LoadCache
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置搜索类型并触发搜索
|
// 设置搜索类型并触发搜索
|
||||||
@@ -247,7 +250,7 @@ function setSearchType(type) {
|
|||||||
pageState.page = 0;
|
pageState.page = 0;
|
||||||
|
|
||||||
// 触发搜索
|
// 触发搜索
|
||||||
playTextDirectly('正在为您查找岗位')
|
playTextDirectly('正在为您查找岗位');
|
||||||
|
|
||||||
// 根据搜索类型设置不同的参数
|
// 根据搜索类型设置不同的参数
|
||||||
if (searchType.value === 'job') {
|
if (searchType.value === 'job') {
|
||||||
@@ -332,7 +335,7 @@ function searchBtn() {
|
|||||||
if (!searchValue.value) {
|
if (!searchValue.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
playTextDirectly('正在为您查找岗位')
|
playTextDirectly('正在为您查找岗位');
|
||||||
|
|
||||||
// 保存到历史记录(仅当搜索成功时保存)
|
// 保存到历史记录(仅当搜索成功时保存)
|
||||||
historyList.value.unshift(searchValue.value);
|
historyList.value.unshift(searchValue.value);
|
||||||
@@ -443,6 +446,16 @@ function getJobList(type = 'add') {
|
|||||||
listCom.value = [...listCom.value, ...reslist];
|
listCom.value = [...listCom.value, ...reslist];
|
||||||
} else {
|
} else {
|
||||||
listCom.value = [...rows];
|
listCom.value = [...rows];
|
||||||
|
// 一体机语音提示
|
||||||
|
if (searchType.value === 'major') {
|
||||||
|
if (rows.length) {
|
||||||
|
$api.msg('为您找到相关专业的职位');
|
||||||
|
playTextDirectly(`为您找到相关专业的职位`);
|
||||||
|
} else {
|
||||||
|
$api.msg('未找到相关专业的职位,请尝试其他关键词');
|
||||||
|
playTextDirectly(`未找到相关专业的职位,请尝试其他关键词`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pageState.total = resData.total;
|
pageState.total = resData.total;
|
||||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||||
|
|||||||
227
utils/IDCardParser.js
Normal file
227
utils/IDCardParser.js
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
// 使用示例:
|
||||||
|
// import IDCardParser from '@/utils/IDCardParser';
|
||||||
|
|
||||||
|
// const handleCheck = (idStr) => {
|
||||||
|
// const parser = new IDCardParser(idStr);
|
||||||
|
// const result = parser.getInfo();
|
||||||
|
// if(result.valid) {
|
||||||
|
// // 填充表单
|
||||||
|
// console.log(result.age, result.gender);
|
||||||
|
// } else {
|
||||||
|
// alert(result.message);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class IDCardParser {
|
||||||
|
constructor(idNumber) {
|
||||||
|
this.idNumber = idNumber ? idNumber.trim().toUpperCase() : "";
|
||||||
|
this.provinceMap = {
|
||||||
|
11: "北京市",
|
||||||
|
12: "天津市",
|
||||||
|
13: "河北省",
|
||||||
|
14: "山西省",
|
||||||
|
15: "内蒙古自治区",
|
||||||
|
21: "辽宁省",
|
||||||
|
22: "吉林省",
|
||||||
|
23: "黑龙江省",
|
||||||
|
31: "上海市",
|
||||||
|
32: "江苏省",
|
||||||
|
33: "浙江省",
|
||||||
|
34: "安徽省",
|
||||||
|
35: "福建省",
|
||||||
|
36: "江西省",
|
||||||
|
37: "山东省",
|
||||||
|
41: "河南省",
|
||||||
|
42: "湖北省",
|
||||||
|
43: "湖南省",
|
||||||
|
44: "广东省",
|
||||||
|
45: "广西壮族自治区",
|
||||||
|
46: "海南省",
|
||||||
|
50: "重庆市",
|
||||||
|
51: "四川省",
|
||||||
|
52: "贵州省",
|
||||||
|
53: "云南省",
|
||||||
|
54: "西藏自治区",
|
||||||
|
61: "陕西省",
|
||||||
|
62: "甘肃省",
|
||||||
|
63: "青海省",
|
||||||
|
64: "宁夏回族自治区",
|
||||||
|
65: "新疆维吾尔自治区",
|
||||||
|
71: "台湾省",
|
||||||
|
81: "香港特别行政区",
|
||||||
|
82: "澳门特别行政区"
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化验证结果
|
||||||
|
const validation = this._validate();
|
||||||
|
this.isValid = validation.isValid;
|
||||||
|
this.errorMsg = validation.msg;
|
||||||
|
|
||||||
|
// 如果合法,预先解析数据
|
||||||
|
if (this.isValid) {
|
||||||
|
this._parseData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心校验逻辑
|
||||||
|
*/
|
||||||
|
_validate() {
|
||||||
|
// 1. 基础正则 (18位,末位数字或X)
|
||||||
|
if (!/^\d{17}[\d|X]$/.test(this.idNumber)) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
msg: "格式错误:必须是18位,末位为数字或X"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 省份校验
|
||||||
|
const provinceCode = parseInt(this.idNumber.substring(0, 2));
|
||||||
|
if (!this.provinceMap[provinceCode]) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
msg: "省份代码错误"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 日期合法性严格校验
|
||||||
|
const year = parseInt(this.idNumber.substring(6, 10));
|
||||||
|
const month = parseInt(this.idNumber.substring(10, 12));
|
||||||
|
const day = parseInt(this.idNumber.substring(12, 14));
|
||||||
|
|
||||||
|
const date = new Date(year, month - 1, day);
|
||||||
|
// JS Date会自动纠错(例如2月30会变成3月),所以必须反向比对
|
||||||
|
if (
|
||||||
|
date.getFullYear() !== year ||
|
||||||
|
date.getMonth() + 1 !== month ||
|
||||||
|
date.getDate() !== day
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
msg: "出生日期无效"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查年份范围(可选,例如限制在1900年以后)
|
||||||
|
if (year < 1900 || date > new Date()) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
msg: "出生日期不在合理范围内"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 校验码计算 (ISO 7064:1983.MOD 11-2)
|
||||||
|
if (!this._checkSum()) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
msg: "校验码错误(身份证可能无效)"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid: true,
|
||||||
|
msg: "验证通过"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验码算法
|
||||||
|
*/
|
||||||
|
_checkSum() {
|
||||||
|
const factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
||||||
|
const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
||||||
|
|
||||||
|
let sum = 0;
|
||||||
|
for (let i = 0; i < 17; i++) {
|
||||||
|
sum += parseInt(this.idNumber[i]) * factors[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = sum % 11;
|
||||||
|
return checkCodes[mod] === this.idNumber[17];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析内部数据
|
||||||
|
*/
|
||||||
|
_parseData() {
|
||||||
|
const year = parseInt(this.idNumber.substring(6, 10));
|
||||||
|
const month = parseInt(this.idNumber.substring(10, 12));
|
||||||
|
const day = parseInt(this.idNumber.substring(12, 14));
|
||||||
|
|
||||||
|
this.birthDate = new Date(year, month - 1, day);
|
||||||
|
this.province = this.provinceMap[parseInt(this.idNumber.substring(0, 2))];
|
||||||
|
|
||||||
|
// 性别:第17位,奇数男,偶数女
|
||||||
|
const genderCode = parseInt(this.idNumber.substring(16, 17));
|
||||||
|
this.gender = genderCode % 2 !== 0 ? "男" : "女";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有信息
|
||||||
|
*/
|
||||||
|
getInfo() {
|
||||||
|
if (!this.isValid) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: this.errorMsg
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
idNumber: this.idNumber,
|
||||||
|
province: this.province,
|
||||||
|
birthday: this._formatDate(this.birthDate),
|
||||||
|
gender: this.gender,
|
||||||
|
age: this._calculateAge(),
|
||||||
|
zodiac: this._getZodiac(), // 生肖
|
||||||
|
constellation: this._getConstellation() // 星座
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_formatDate(date) {
|
||||||
|
const y = date.getFullYear();
|
||||||
|
const m = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const d = String(date.getDate()).padStart(2, '0');
|
||||||
|
return `${y}-${m}-${d}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_calculateAge() {
|
||||||
|
const today = new Date();
|
||||||
|
let age = today.getFullYear() - this.birthDate.getFullYear();
|
||||||
|
const m = today.getMonth() - this.birthDate.getMonth();
|
||||||
|
|
||||||
|
// 如果没过生日,年龄减1
|
||||||
|
if (m < 0 || (m === 0 && today.getDate() < this.birthDate.getDate())) {
|
||||||
|
age--;
|
||||||
|
}
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getZodiac() {
|
||||||
|
// 猴鸡狗猪鼠牛虎兔龙蛇马羊 (对应余数 0-11)
|
||||||
|
const zodiacs = "猴鸡狗猪鼠牛虎兔龙蛇马羊";
|
||||||
|
return zodiacs.charAt(this.birthDate.getFullYear() % 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getConstellation() {
|
||||||
|
const month = this.birthDate.getMonth() + 1;
|
||||||
|
const day = this.birthDate.getDate();
|
||||||
|
|
||||||
|
// 星座分割日
|
||||||
|
const dates = [20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22];
|
||||||
|
const constellations = [
|
||||||
|
"摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座",
|
||||||
|
"巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"
|
||||||
|
];
|
||||||
|
|
||||||
|
if (day < dates[month - 1]) {
|
||||||
|
return constellations[month - 1];
|
||||||
|
} else {
|
||||||
|
return constellations[month];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default IDCardParser;
|
||||||
@@ -119,8 +119,8 @@ export function createRequest(url, data = {}, method = 'GET', loading = false, h
|
|||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
uni.request({
|
uni.request({
|
||||||
// url: config.baseUrl + '/app/proxy',
|
url: config.baseUrl + '/app/proxy',
|
||||||
url: config.baseUrl + url,
|
// url: config.baseUrl + url,
|
||||||
method: method,
|
method: method,
|
||||||
data: requestData,
|
data: requestData,
|
||||||
header,
|
header,
|
||||||
|
|||||||
Reference in New Issue
Block a user