Compare commits
32 Commits
c7af2194cc
...
jiagou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55c0b1fd22 | ||
|
|
cec340da43 | ||
|
|
183d43b664 | ||
|
|
3e408d5740 | ||
|
|
855deb4643 | ||
|
|
5a9d111d4c | ||
|
|
9ec42f18f3 | ||
|
|
321e686d68 | ||
|
|
3d8e13c665 | ||
|
|
3fe4dbe47f | ||
|
|
c742a65aa0 | ||
|
|
7c409e8528 | ||
|
|
4d8403609f | ||
|
|
769bc23edb | ||
| 1f8b24c0bf | |||
|
|
8bfc1dc683 | ||
|
|
9b2cdecc16 | ||
|
|
b1942e90e0 | ||
|
|
15668dc769 | ||
|
|
db9707e866 | ||
|
|
eb324ceada | ||
| aca5727878 | |||
| 12a3668b7f | |||
| 96e7b9b1e2 | |||
|
|
5046e7467f | ||
|
|
23a286cb64 | ||
|
|
c43c0592c6 | ||
| cb83a3269e | |||
| f2f802b73a | |||
|
|
4078f2e543 | ||
|
|
94439fddaa | ||
|
|
06a92f2e97 |
@@ -83,3 +83,15 @@ export function getInfo() {
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重新发送验证码
|
||||||
|
export function sendSmsAgain(data) {
|
||||||
|
return request({
|
||||||
|
method: 'post',
|
||||||
|
url: '/app/sendSmsAgain',
|
||||||
|
data,
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -417,6 +417,136 @@ html {
|
|||||||
background-color: #ffffff !important;
|
background-color: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* #ifdef H5 */
|
||||||
|
/* H5端字体和边距调整 - 放大1.5倍 */
|
||||||
|
html, body {
|
||||||
|
font-size: 150% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整页面基础字体大小 */
|
||||||
|
page {
|
||||||
|
font-size: 42rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整特定类的字体大小 */
|
||||||
|
.fs_10 {
|
||||||
|
font-size: 30rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_12 {
|
||||||
|
font-size: 36rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_14 {
|
||||||
|
font-size: 42rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_16 {
|
||||||
|
font-size: 48rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_18 {
|
||||||
|
font-size: 54rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_20 {
|
||||||
|
font-size: 60rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_22 {
|
||||||
|
font-size: 66rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_24 {
|
||||||
|
font-size: 72rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_26 {
|
||||||
|
font-size: 78rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_28 {
|
||||||
|
font-size: 84rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_30 {
|
||||||
|
font-size: 90rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs_32 {
|
||||||
|
font-size: 96rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整边距类 */
|
||||||
|
.mar_le30 {
|
||||||
|
margin-left: 90rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_le25 {
|
||||||
|
margin-left: 75rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_le20 {
|
||||||
|
margin-left: 60rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_le15 {
|
||||||
|
margin-left: 45rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_le10 {
|
||||||
|
margin-left: 30rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_le5 {
|
||||||
|
margin-left: 15rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_ri5 {
|
||||||
|
margin-right: 15rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_ri10 {
|
||||||
|
margin-right: 30rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_ri15 {
|
||||||
|
margin-right: 45rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_ri20 {
|
||||||
|
margin-right: 60rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_ri25 {
|
||||||
|
margin-right: 75rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_top0 {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_top5 {
|
||||||
|
margin-top: 15rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_top10 {
|
||||||
|
margin-top: 30rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_top15 {
|
||||||
|
margin-top: 45rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_top20 {
|
||||||
|
margin-top: 60rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mar_top25 {
|
||||||
|
margin-top: 75rpx !important;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 弹性布局 */
|
/* 弹性布局 */
|
||||||
|
|||||||
@@ -584,6 +584,86 @@ function isInWechatMiniProgramWebview() {
|
|||||||
function isEmptyObject(obj) {
|
function isEmptyObject(obj) {
|
||||||
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
|
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 农历日期工具
|
||||||
|
* 提供公历转农历日期的中文表示
|
||||||
|
*/
|
||||||
|
export const LunarUtil = {
|
||||||
|
/**
|
||||||
|
* 获取农历日期的中文表示
|
||||||
|
* @param {number} year - 公历年
|
||||||
|
* @param {number} month - 公历月 (1-12)
|
||||||
|
* @param {number} day - 公历日
|
||||||
|
* @returns {string} 农历日期的中文表示(初一、初二...三十)
|
||||||
|
*/
|
||||||
|
getLunarDayInChinese(year, month, day) {
|
||||||
|
// 这里使用简化的农历转换算法
|
||||||
|
// 实际项目中可以根据需要扩展更完整的农历功能
|
||||||
|
const lunarDays = this.solarToLunar(year, month, day);
|
||||||
|
return this.getDayInChinese(lunarDays.day);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简化的公历转农历日期算法
|
||||||
|
* 注意:这是一个简化版,实际农历计算更复杂
|
||||||
|
* 仅用于生成初一到三十的日期表示
|
||||||
|
*/
|
||||||
|
solarToLunar(year, month, day) {
|
||||||
|
// 这里使用简化算法,实际项目中可以使用更精确的算法
|
||||||
|
// 对于本项目,我们只需要生成初一到三十的序列
|
||||||
|
// 实际的农历计算需要考虑节气、闰月等因素
|
||||||
|
const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||||
|
|
||||||
|
// 处理闰年
|
||||||
|
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
|
||||||
|
daysInMonth[1] = 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算当年已过天数
|
||||||
|
let dayOfYear = 0;
|
||||||
|
for (let i = 0; i < month - 1; i++) {
|
||||||
|
dayOfYear += daysInMonth[i];
|
||||||
|
}
|
||||||
|
dayOfYear += day;
|
||||||
|
|
||||||
|
// 简化的农历月份计算(实际农历月份计算更复杂)
|
||||||
|
const lunarMonth = Math.ceil(dayOfYear / 29.5);
|
||||||
|
const lunarDay = (dayOfYear % 29) || 29;
|
||||||
|
|
||||||
|
return {
|
||||||
|
month: lunarMonth,
|
||||||
|
day: lunarDay
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将农历日期转换为中文表示
|
||||||
|
* @param {number} day - 农历日
|
||||||
|
* @returns {string} 中文表示(初一、初二...三十)
|
||||||
|
*/
|
||||||
|
getDayInChinese(day) {
|
||||||
|
if (day === 1) {
|
||||||
|
return '初一';
|
||||||
|
} else if (day === 15) {
|
||||||
|
return '十五';
|
||||||
|
} else if (day === 30) {
|
||||||
|
return '三十';
|
||||||
|
} else {
|
||||||
|
const digits = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
|
||||||
|
if (day <= 10) {
|
||||||
|
return '初' + digits[day];
|
||||||
|
} else if (day <= 19) {
|
||||||
|
return '十' + (day === 10 ? '' : digits[day - 10]);
|
||||||
|
} else if (day <= 29) {
|
||||||
|
return '廿' + (day === 20 ? '' : digits[day - 20]);
|
||||||
|
} else {
|
||||||
|
return '三十';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 身份证号码校验工具
|
* 身份证号码校验工具
|
||||||
* 支持15位和18位身份证号码校验
|
* 支持15位和18位身份证号码校验
|
||||||
@@ -941,6 +1021,7 @@ export default {
|
|||||||
cloneDeep,
|
cloneDeep,
|
||||||
formatDate,
|
formatDate,
|
||||||
IdCardValidator,
|
IdCardValidator,
|
||||||
|
LunarUtil,
|
||||||
getdeviceInfo,
|
getdeviceInfo,
|
||||||
checkingPhoneRegExp,
|
checkingPhoneRegExp,
|
||||||
checkingEmailRegExp,
|
checkingEmailRegExp,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, nextTick } from 'vue';
|
import { ref, watch, nextTick, getCurrentInstance } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
@@ -26,11 +26,18 @@ const wrapStyle = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const contentRef = ref(null);
|
const contentRef = ref(null);
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
|
||||||
// 获取高度(兼容 H5 + 小程序)
|
// 获取高度(兼容 H5 + 小程序)
|
||||||
function getContentHeight() {
|
function getContentHeight() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const query = uni.createSelectorQuery().in(this ? this : undefined);
|
let query;
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
query = uni.createSelectorQuery().in(instance);
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
query = uni.createSelectorQuery();
|
||||||
|
// #endif
|
||||||
query
|
query
|
||||||
.select('.content-inner')
|
.select('.content-inner')
|
||||||
.boundingClientRect((data) => {
|
.boundingClientRect((data) => {
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view v-if="show" class="filter-container">
|
<view v-if="show" class="filter-container">
|
||||||
<!-- 头部 -->
|
<!-- 左侧标签页 -->
|
||||||
<!-- <view class="filter-header">
|
|
||||||
<text class="back-btn" @click="handleClose">
|
|
||||||
<uni-icons type="left" size="24"></uni-icons>
|
|
||||||
</text>
|
|
||||||
<text class="filter-title">喀什智慧就业平台</text>
|
|
||||||
<view class="back-btn"></view>
|
|
||||||
</view> -->
|
|
||||||
|
|
||||||
<!-- 标签页 -->
|
|
||||||
<view class="filter-tabs">
|
<view class="filter-tabs">
|
||||||
<view
|
<view
|
||||||
v-for="(tab, index) in tabs"
|
v-for="(tab, index) in tabs"
|
||||||
@@ -22,6 +13,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 右侧内容区域 -->
|
||||||
|
<view class="filter-right">
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<view class="filter-content">
|
<view class="filter-content">
|
||||||
<!-- 学历要求 -->
|
<!-- 学历要求 -->
|
||||||
@@ -78,6 +71,24 @@
|
|||||||
</radio-group>
|
</radio-group>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 地区 -->
|
||||||
|
<view v-if="activeTab === 'area'" class="content-section">
|
||||||
|
<radio-group @change="(e) => handleSelect('area', e)">
|
||||||
|
<label
|
||||||
|
v-for="option in areaOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="radio-item"
|
||||||
|
:class="{ checked: selectedValues['area'] === String(option.value) }"
|
||||||
|
>
|
||||||
|
<radio
|
||||||
|
:value="String(option.value)"
|
||||||
|
:checked="selectedValues['area'] === String(option.value)"
|
||||||
|
/>
|
||||||
|
<text class="option-label">{{ option.label }}</text>
|
||||||
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 岗位类型 -->
|
<!-- 岗位类型 -->
|
||||||
<view v-if="activeTab === 'jobType'" class="content-section">
|
<view v-if="activeTab === 'jobType'" class="content-section">
|
||||||
<radio-group @change="(e) => handleSelect('jobType', e)">
|
<radio-group @change="(e) => handleSelect('jobType', e)">
|
||||||
@@ -103,12 +114,14 @@
|
|||||||
<button class="footer-btn confirm-btn" @click="handleConfirm">确认</button>
|
<button class="footer-btn confirm-btn" @click="handleConfirm">确认</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onBeforeMount } from 'vue';
|
import { ref, reactive, onBeforeMount } from 'vue';
|
||||||
import useDictStore from '@/stores/useDictStore';
|
import useDictStore from '@/stores/useDictStore';
|
||||||
const { getTransformChildren } = useDictStore();
|
const dictStore = useDictStore();
|
||||||
|
const { getTransformChildren } = dictStore;
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
@@ -131,7 +144,8 @@ const tabs = [
|
|||||||
{ key: 'education', label: '学历要求' },
|
{ key: 'education', label: '学历要求' },
|
||||||
{ key: 'experience', label: '工作经验' },
|
{ key: 'experience', label: '工作经验' },
|
||||||
{ key: 'scale', label: '公司规模' },
|
{ key: 'scale', label: '公司规模' },
|
||||||
{ key: 'jobType', label: '岗位类型' }
|
{ key: 'jobType', label: '岗位类型' },
|
||||||
|
{ key: 'area', label: '地区' }
|
||||||
];
|
];
|
||||||
|
|
||||||
// 当前激活的标签
|
// 当前激活的标签
|
||||||
@@ -142,6 +156,7 @@ const selectedValues = reactive({
|
|||||||
education: '',
|
education: '',
|
||||||
experience: '',
|
experience: '',
|
||||||
scale: '',
|
scale: '',
|
||||||
|
area: '',
|
||||||
jobType: ''
|
jobType: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,14 +164,28 @@ const selectedValues = reactive({
|
|||||||
const educationOptions = ref([]);
|
const educationOptions = ref([]);
|
||||||
const experienceOptions = ref([]);
|
const experienceOptions = ref([]);
|
||||||
const scaleOptions = ref([]);
|
const scaleOptions = ref([]);
|
||||||
|
const areaOptions = ref([]);
|
||||||
const jobTypeOptions = ref([]);
|
const jobTypeOptions = ref([]);
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(true);
|
||||||
|
|
||||||
// 初始化获取数据
|
// 初始化获取数据
|
||||||
onBeforeMount(() => {
|
onBeforeMount(async () => {
|
||||||
|
try {
|
||||||
|
// 先获取字典数据
|
||||||
|
await dictStore.getDictData();
|
||||||
|
// 再初始化选项数据
|
||||||
educationOptions.value = getTransformChildren('education', '学历要求').options || [];
|
educationOptions.value = getTransformChildren('education', '学历要求').options || [];
|
||||||
experienceOptions.value = getTransformChildren('experience', '工作经验').options || [];
|
experienceOptions.value = getTransformChildren('experience', '工作经验').options || [];
|
||||||
scaleOptions.value = getTransformChildren('scale', '公司规模').options || [];
|
scaleOptions.value = getTransformChildren('scale', '公司规模').options || [];
|
||||||
|
areaOptions.value = getTransformChildren('area', '地区').options || [];
|
||||||
jobTypeOptions.value = getJobTypeData();
|
jobTypeOptions.value = getJobTypeData();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取字典数据失败:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理选项选择
|
// 处理选项选择
|
||||||
@@ -195,7 +224,7 @@ const handleClose = () => {
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-header {
|
.filter-header {
|
||||||
@@ -231,17 +260,17 @@ const handleClose = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-tabs {
|
.filter-tabs {
|
||||||
|
width: 200rpx;
|
||||||
|
border-right: 1rpx solid #eee;
|
||||||
|
background-color: #f8f8f8;
|
||||||
display: flex;
|
display: flex;
|
||||||
border-bottom: 1rpx solid #eee;
|
flex-direction: column;
|
||||||
background-color: #fff;
|
|
||||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
height: 100rpx;
|
||||||
height: 90rpx;
|
line-height: 100rpx;
|
||||||
line-height: 90rpx;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 30rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #666;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
@@ -249,14 +278,15 @@ const handleClose = () => {
|
|||||||
&.active {
|
&.active {
|
||||||
color: #256BFA;
|
color: #256BFA;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
left: 0;
|
||||||
left: 25%;
|
top: 25%;
|
||||||
width: 50%;
|
width: 4rpx;
|
||||||
height: 4rpx;
|
height: 50%;
|
||||||
background-color: #256BFA;
|
background-color: #256BFA;
|
||||||
border-radius: 2rpx;
|
border-radius: 2rpx;
|
||||||
}
|
}
|
||||||
@@ -268,6 +298,13 @@ const handleClose = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-right {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.filter-content {
|
.filter-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 40rpx 32rpx;
|
padding: 40rpx 32rpx;
|
||||||
|
|||||||
@@ -277,7 +277,8 @@ const getPhoneNumber = (e) => {
|
|||||||
$api.msg('获取用户信息失败');
|
$api.msg('获取用户信息失败');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$api.msg('登录失败,请重试');
|
// $api.msg('登录失败,请重试');
|
||||||
|
$api.msg(resData.msg || '登录失败,请重试');
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
|||||||
@@ -37,15 +37,8 @@ export function useColumnCount(onChange = () => {}) {
|
|||||||
count = 2
|
count = 2
|
||||||
// #endif
|
// #endif
|
||||||
// #ifndef H5
|
// #ifndef H5
|
||||||
if (width >= 1000) {
|
// 小程序端固定显示1列
|
||||||
count = 5
|
count = 1
|
||||||
} else if (width >= 750) {
|
|
||||||
count = 4
|
|
||||||
} else if (width >= 500) {
|
|
||||||
count = 3
|
|
||||||
} else {
|
|
||||||
count = 2
|
|
||||||
}
|
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
if (count !== columnCount.value) {
|
if (count !== columnCount.value) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,8 +3,7 @@
|
|||||||
<!-- 自定义tabbar -->
|
<!-- 自定义tabbar -->
|
||||||
<CustomTabBar :currentPage="2" />
|
<CustomTabBar :currentPage="2" />
|
||||||
|
|
||||||
<!-- 微信授权登录弹窗 -->
|
|
||||||
<WxAuthLogin ref="wxAuthLoginRef" @success="handleLoginSuccess"></WxAuthLogin>
|
|
||||||
<!-- 抽屉遮罩层 -->
|
<!-- 抽屉遮罩层 -->
|
||||||
<view v-if="isDrawerOpen" class="overlay" @click="toggleDrawer"></view>
|
<view v-if="isDrawerOpen" class="overlay" @click="toggleDrawer"></view>
|
||||||
|
|
||||||
@@ -25,17 +24,21 @@
|
|||||||
<scroll-view scroll-y :show-scrollbar="false" class="chat-scroll">
|
<scroll-view scroll-y :show-scrollbar="false" class="chat-scroll">
|
||||||
<view
|
<view
|
||||||
class="drawer-rows"
|
class="drawer-rows"
|
||||||
@click="changeDialogue(item)"
|
|
||||||
v-for="(item, index) in filteredList"
|
v-for="(item, index) in filteredList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
>
|
>
|
||||||
|
<view v-if="!item.isTitle" class="drawer-row-container">
|
||||||
<view
|
<view
|
||||||
v-if="!item.isTitle"
|
|
||||||
class="drawer-row-list"
|
class="drawer-row-list"
|
||||||
:class="{ 'drawer-row-active': item.sessionId === chatSessionID }"
|
:class="{ 'drawer-row-active': item.sessionId === chatSessionID }"
|
||||||
|
@click="changeDialogue(item)"
|
||||||
>
|
>
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</view>
|
</view>
|
||||||
|
<view class="drawer-row-delete" @click.stop="deleteDialogue(item)">
|
||||||
|
<uni-icons type="trash" size="24" color="#FF4D4F"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="drawer-row-title" v-else>
|
<view class="drawer-row-title" v-else>
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</view>
|
</view>
|
||||||
@@ -85,7 +88,7 @@ import useUserStore from '@/stores/useUserStore';
|
|||||||
import { tabbarManager } from '@/utils/tabbarManager';
|
import { tabbarManager } from '@/utils/tabbarManager';
|
||||||
import aiPaging from './components/ai-paging.vue';
|
import aiPaging from './components/ai-paging.vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import WxAuthLogin from '@/components/WxAuthLogin/WxAuthLogin.vue';
|
|
||||||
const { isTyping, tabeList, chatSessionID } = storeToRefs(useChatGroupDBStore());
|
const { isTyping, tabeList, chatSessionID } = storeToRefs(useChatGroupDBStore());
|
||||||
const { userInfo } = storeToRefs(useUserStore());
|
const { userInfo } = storeToRefs(useUserStore());
|
||||||
const isDrawerOpen = ref(false);
|
const isDrawerOpen = ref(false);
|
||||||
@@ -93,7 +96,7 @@ const scrollIntoView = ref(false);
|
|||||||
|
|
||||||
const searchText = ref('');
|
const searchText = ref('');
|
||||||
const paging = ref(null);
|
const paging = ref(null);
|
||||||
const wxAuthLoginRef = ref(null);
|
|
||||||
|
|
||||||
// 实时过滤
|
// 实时过滤
|
||||||
const filteredList = computed(() => {
|
const filteredList = computed(() => {
|
||||||
@@ -119,7 +122,7 @@ onShow(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 监听退出登录事件,显示微信登录弹窗
|
// 监听退出登录事件,显示微信登录弹窗
|
||||||
uni.$on('showLoginModal', () => {
|
uni.$on('showLoginModal', () => {
|
||||||
wxAuthLoginRef.value?.open();
|
uni.navigateTo({ url: '/pages/login/wx-login' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -166,6 +169,21 @@ const changeDialogue = (item) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteDialogue = (item) => {
|
||||||
|
if (item.sessionId) {
|
||||||
|
uni.showModal({
|
||||||
|
content: '确定删除该会话吗?',
|
||||||
|
success(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
useChatGroupDBStore().deleteDialogue(item.sessionId);
|
||||||
|
$api.msg('会话删除成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function updateSetting() {
|
function updateSetting() {
|
||||||
$api.msg('该功能正在开发中,敬请期待后续更新!');
|
$api.msg('该功能正在开发中,敬请期待后续更新!');
|
||||||
}
|
}
|
||||||
@@ -284,16 +302,39 @@ footer-height = 98rpx
|
|||||||
padding: 0 24rpx
|
padding: 0 24rpx
|
||||||
margin-top: 50rpx
|
margin-top: 50rpx
|
||||||
margin-bottom: 16rpx
|
margin-bottom: 16rpx
|
||||||
|
.drawer-row-container
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: space-between
|
||||||
|
padding: 0 24rpx
|
||||||
|
height: 66rpx
|
||||||
|
|
||||||
.drawer-row-list
|
.drawer-row-list
|
||||||
height: 66rpx;
|
flex: 1
|
||||||
|
height: 66rpx
|
||||||
line-height: 66rpx
|
line-height: 66rpx
|
||||||
font-size: 28rpx
|
font-size: 28rpx
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
text-overflow: ellipsis
|
text-overflow: ellipsis
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #595959;
|
color: #595959;
|
||||||
padding: 0 24rpx
|
|
||||||
|
.drawer-row-delete
|
||||||
|
margin-left: 20rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
padding: 10rpx
|
||||||
|
opacity: 0.6
|
||||||
|
&:hover
|
||||||
|
&:active
|
||||||
|
opacity: 1
|
||||||
|
|
||||||
.drawer-row-active
|
.drawer-row-active
|
||||||
|
color: #333333;
|
||||||
|
background: #F6F6F6;
|
||||||
|
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||||
|
|
||||||
.drawer-row-list:active
|
.drawer-row-list:active
|
||||||
color: #333333;
|
color: #333333;
|
||||||
background: #F6F6F6;
|
background: #F6F6F6;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -120,7 +120,7 @@ const rangeOptions = ref([
|
|||||||
{ value: 0, text: '推荐' },
|
{ value: 0, text: '推荐' },
|
||||||
{ value: 1, text: '最热' },
|
{ value: 1, text: '最热' },
|
||||||
{ value: 2, text: '最新发布' },
|
{ value: 2, text: '最新发布' },
|
||||||
{ value: 3, text: '疆外' },
|
// { value: 3, text: '疆外' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function choosePosition(index) {
|
function choosePosition(index) {
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ const rangeOptions = ref([
|
|||||||
{ value: 0, text: '推荐' },
|
{ value: 0, text: '推荐' },
|
||||||
{ value: 1, text: '最热' },
|
{ value: 1, text: '最热' },
|
||||||
{ value: 2, text: '最新发布' },
|
{ value: 2, text: '最新发布' },
|
||||||
{ value: 3, text: '疆外' },
|
// { value: 3, text: '疆外' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function changeRangeShow() {
|
function changeRangeShow() {
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ const rangeOptions = ref([
|
|||||||
{ value: 0, text: '推荐' },
|
{ value: 0, text: '推荐' },
|
||||||
{ value: 1, text: '最热' },
|
{ value: 1, text: '最热' },
|
||||||
{ value: 2, text: '最新发布' },
|
{ value: 2, text: '最新发布' },
|
||||||
{ value: 3, text: '疆外' },
|
// { value: 3, text: '疆外' },
|
||||||
]);
|
]);
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getSubway();
|
getSubway();
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ const rangeOptions = ref([
|
|||||||
{ value: 0, text: '推荐' },
|
{ value: 0, text: '推荐' },
|
||||||
{ value: 1, text: '最热' },
|
{ value: 1, text: '最热' },
|
||||||
{ value: 2, text: '最新发布' },
|
{ value: 2, text: '最新发布' },
|
||||||
{ value: 3, text: '疆外' },
|
// { value: 3, text: '疆外' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function choosePosition(index) {
|
function choosePosition(index) {
|
||||||
|
|||||||
@@ -46,12 +46,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||||
const { $api, navTo, navBack } = inject('globalFunction');
|
const { $api, navTo, navBack, LunarUtil } = inject('globalFunction');
|
||||||
const weekMap = ['日', '一', '二', '三', '四', '五', '六'];
|
const weekMap = ['日', '一', '二', '三', '四', '五', '六'];
|
||||||
const calendarData = ref([]);
|
const calendarData = ref([]);
|
||||||
const current = ref({});
|
const current = ref({});
|
||||||
import lunarModule from '@/packageA/lib/lunar-javascript@1.7.2.js';
|
|
||||||
const { Solar, Lunar } = lunarModule;
|
|
||||||
|
|
||||||
const isRecord = ref(false);
|
const isRecord = ref(false);
|
||||||
const recordNum = ref(4);
|
const recordNum = ref(4);
|
||||||
@@ -162,12 +160,11 @@ function getMonthCalendarData({ year, month, selectableDates = [] }) {
|
|||||||
const d = prevLastDate - i;
|
const d = prevLastDate - i;
|
||||||
const prevMonth = month - 1 <= 0 ? 12 : month - 1;
|
const prevMonth = month - 1 <= 0 ? 12 : month - 1;
|
||||||
const prevYear = month - 1 <= 0 ? year - 1 : year;
|
const prevYear = month - 1 <= 0 ? year - 1 : year;
|
||||||
const solar = Solar.fromYmd(prevYear, prevMonth, d);
|
const nl = LunarUtil.getLunarDayInChinese(prevYear, prevMonth, d);
|
||||||
const lunar = Lunar.fromSolar(solar);
|
|
||||||
const dateStr = `${prevYear}-${String(prevMonth).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
const dateStr = `${prevYear}-${String(prevMonth).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
||||||
list.push({
|
list.push({
|
||||||
day: d,
|
day: d,
|
||||||
nl: lunar.getDayInChinese(),
|
nl: nl,
|
||||||
isThisMonth: false,
|
isThisMonth: false,
|
||||||
isToday: dateStr === todayStr,
|
isToday: dateStr === todayStr,
|
||||||
isSelectable: isSelected(prevYear, prevMonth, d),
|
isSelectable: isSelected(prevYear, prevMonth, d),
|
||||||
@@ -179,12 +176,11 @@ function getMonthCalendarData({ year, month, selectableDates = [] }) {
|
|||||||
|
|
||||||
// 当前月天数
|
// 当前月天数
|
||||||
for (let d = 1; d <= lastDate; d++) {
|
for (let d = 1; d <= lastDate; d++) {
|
||||||
const solar = Solar.fromYmd(year, month, d);
|
const nl = LunarUtil.getLunarDayInChinese(year, month, d);
|
||||||
const lunar = Lunar.fromSolar(solar);
|
|
||||||
const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
||||||
list.push({
|
list.push({
|
||||||
day: d,
|
day: d,
|
||||||
nl: lunar.getDayInChinese(),
|
nl: nl,
|
||||||
isThisMonth: true,
|
isThisMonth: true,
|
||||||
isToday: dateStr === todayStr,
|
isToday: dateStr === todayStr,
|
||||||
isSelectable: isSelected(year, month, d),
|
isSelectable: isSelected(year, month, d),
|
||||||
@@ -199,12 +195,11 @@ function getMonthCalendarData({ year, month, selectableDates = [] }) {
|
|||||||
for (let d = 1; d <= remaining; d++) {
|
for (let d = 1; d <= remaining; d++) {
|
||||||
const nextMonth = month + 1 > 12 ? 1 : month + 1;
|
const nextMonth = month + 1 > 12 ? 1 : month + 1;
|
||||||
const nextYear = month + 1 > 12 ? year + 1 : year;
|
const nextYear = month + 1 > 12 ? year + 1 : year;
|
||||||
const solar = Solar.fromYmd(nextYear, nextMonth, d);
|
const nl = LunarUtil.getLunarDayInChinese(nextYear, nextMonth, d);
|
||||||
const lunar = Lunar.fromSolar(solar);
|
|
||||||
const dateStr = `${nextYear}-${String(nextMonth).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
const dateStr = `${nextYear}-${String(nextMonth).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
||||||
list.push({
|
list.push({
|
||||||
day: d,
|
day: d,
|
||||||
nl: lunar.getDayInChinese(),
|
nl: nl,
|
||||||
isThisMonth: false,
|
isThisMonth: false,
|
||||||
isToday: dateStr === todayStr,
|
isToday: dateStr === todayStr,
|
||||||
isSelectable: isSelected(nextYear, nextMonth, d),
|
isSelectable: isSelected(nextYear, nextMonth, d),
|
||||||
|
|||||||
@@ -47,7 +47,6 @@
|
|||||||
return {
|
return {
|
||||||
kw: "", //搜索关键
|
kw: "", //搜索关键
|
||||||
user: uni.getStorageSync("CAuserInfo").user,
|
user: uni.getStorageSync("CAuserInfo").user,
|
||||||
winHeight: wx.getWindowInfo().windowHeight,
|
|
||||||
jobDataList: [],
|
jobDataList: [],
|
||||||
jobList,
|
jobList,
|
||||||
scrollTop: 0, //tab标题的滚动条位置
|
scrollTop: 0, //tab标题的滚动条位置
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
<text class="icon icon-101"></text>
|
<text class="icon icon-101"></text>
|
||||||
<text class="title">职业测评</text>
|
<text class="title">职业测评</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="item" @click="navDetail(2)">
|
<!-- <view class="item" @click="navDetail(2)">
|
||||||
<text class="icon icon-102"></text>
|
<text class="icon icon-102"></text>
|
||||||
<text class="title">测评报告</text>
|
<text class="title">测评报告</text>
|
||||||
</view>
|
</view> -->
|
||||||
</view>
|
</view>
|
||||||
<view class="head-title">探索中心</view>
|
<view class="head-title">探索中心</view>
|
||||||
<view class="nav-block">
|
<view class="nav-block">
|
||||||
@@ -68,8 +68,7 @@
|
|||||||
// 演示入
|
// 演示入
|
||||||
navDetail(index){
|
navDetail(index){
|
||||||
switch (index){
|
switch (index){
|
||||||
case 1:
|
case 1: {
|
||||||
case 2: {
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: "/packageCa/pagesTest/testList"
|
url: "/packageCa/pagesTest/testList"
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -566,15 +566,42 @@ export default {
|
|||||||
this.serviceForm.practicalSolutionTime = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
this.serviceForm.practicalSolutionTime = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 使用密码学安全随机源生成标识符
|
||||||
|
generateSecureId(length = 16) {
|
||||||
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
const charsLength = chars.length;
|
||||||
|
const randomBytes = new Uint8Array(length);
|
||||||
|
|
||||||
|
// H5/现代浏览器
|
||||||
|
if (typeof globalThis !== 'undefined' && globalThis.crypto && typeof globalThis.crypto.getRandomValues === 'function') {
|
||||||
|
globalThis.crypto.getRandomValues(randomBytes);
|
||||||
|
}
|
||||||
|
// 微信小程序环境
|
||||||
|
else if (typeof wx !== 'undefined' && typeof wx.getRandomValues === 'function') {
|
||||||
|
wx.getRandomValues(randomBytes);
|
||||||
|
}
|
||||||
|
// 兜底:若运行环境不支持 CSPRNG,显式报错,避免继续使用可预测随机数
|
||||||
|
else {
|
||||||
|
throw new Error('当前环境不支持密码学安全随机数,请在服务端生成标识符');
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = '';
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
id += chars[randomBytes[i] % charsLength];
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
|
||||||
// 触发文件上传
|
// 触发文件上传
|
||||||
triggerFileUpload() {
|
triggerFileUpload() {
|
||||||
if (this.serviceForm.fileUrl.length < 6) {
|
if (this.serviceForm.fileUrl.length < 6) {
|
||||||
// 模拟添加文件
|
// 模拟添加文件
|
||||||
const mockFiles = ['文档.pdf', '图片.jpg', '表格.xlsx', '报告.docx'];
|
const mockFiles = ['文档.pdf', '图片.jpg', '表格.xlsx', '报告.docx'];
|
||||||
const randomFile = mockFiles[Math.floor(Math.random() * mockFiles.length)];
|
const secureId = this.generateSecureId(20);
|
||||||
|
const randomFile = mockFiles[Date.now() % mockFiles.length];
|
||||||
this.serviceForm.fileUrl.push({
|
this.serviceForm.fileUrl.push({
|
||||||
name: randomFile,
|
name: randomFile,
|
||||||
url: `mock-url/${Date.now()}/${randomFile}`
|
url: `mock-url/${secureId}/${randomFile}`
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({ title: '最多只能上传6个文件', icon: 'none' });
|
uni.showToast({ title: '最多只能上传6个文件', icon: 'none' });
|
||||||
|
|||||||
@@ -400,11 +400,7 @@
|
|||||||
<!-- 筛选 -->
|
<!-- 筛选 -->
|
||||||
<select-filter ref="selectFilterModel"></select-filter>
|
<select-filter ref="selectFilterModel"></select-filter>
|
||||||
|
|
||||||
<!-- 微信授权登录弹窗 -->
|
|
||||||
<WxAuthLogin
|
|
||||||
ref="wxAuthLoginRef"
|
|
||||||
@success="handleLoginSuccess"
|
|
||||||
></WxAuthLogin>
|
|
||||||
|
|
||||||
<!-- <view class="maskFristEntry" v-if="maskFristEntry">
|
<!-- <view class="maskFristEntry" v-if="maskFristEntry">
|
||||||
<view class="entry-content">
|
<view class="entry-content">
|
||||||
@@ -531,7 +527,7 @@ import {
|
|||||||
} from "@/stores/useRecommedIndexedDBStore.js";
|
} from "@/stores/useRecommedIndexedDBStore.js";
|
||||||
import { useScrollDirection } from "@/hook/useScrollDirection";
|
import { useScrollDirection } from "@/hook/useScrollDirection";
|
||||||
import { useColumnCount } from "@/hook/useColumnCount";
|
import { useColumnCount } from "@/hook/useColumnCount";
|
||||||
import WxAuthLogin from "@/components/WxAuthLogin/WxAuthLogin.vue";
|
|
||||||
import IconfontIcon from "@/components/IconfontIcon/IconfontIcon.vue";
|
import IconfontIcon from "@/components/IconfontIcon/IconfontIcon.vue";
|
||||||
// 企业卡片组件已内联到模板中
|
// 企业卡片组件已内联到模板中
|
||||||
// 滚动状态管理
|
// 滚动状态管理
|
||||||
@@ -584,7 +580,7 @@ const loadmoreRef = ref(null);
|
|||||||
const conditionSearch = ref({});
|
const conditionSearch = ref({});
|
||||||
const waterfallcolumn = ref(2);
|
const waterfallcolumn = ref(2);
|
||||||
const maskFristEntry = ref(false);
|
const maskFristEntry = ref(false);
|
||||||
const wxAuthLoginRef = ref(null);
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tabIndex: "all",
|
tabIndex: "all",
|
||||||
});
|
});
|
||||||
@@ -684,7 +680,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 监听退出登录事件,显示微信登录弹窗
|
// 监听退出登录事件,显示微信登录弹窗
|
||||||
uni.$on("showLoginModal", () => {
|
uni.$on("showLoginModal", () => {
|
||||||
wxAuthLoginRef.value?.open();
|
uni.navigateTo({ url: '/pages/login/wx-login' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -712,8 +708,8 @@ watch(
|
|||||||
const checkLogin = () => {
|
const checkLogin = () => {
|
||||||
const tokenValue = uni.getStorageSync("token") || "";
|
const tokenValue = uni.getStorageSync("token") || "";
|
||||||
if (!tokenValue || !hasLogin.value) {
|
if (!tokenValue || !hasLogin.value) {
|
||||||
// 未登录,打开授权弹窗
|
// 未登录,跳转到登录页面
|
||||||
wxAuthLoginRef.value?.open();
|
uni.navigateTo({ url: '/pages/login/wx-login' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
17
pages.json
17
pages.json
@@ -3,7 +3,10 @@
|
|||||||
{
|
{
|
||||||
"path": "pages/index/index",
|
"path": "pages/index/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "喀什智慧就业平台"
|
"navigationBarTitleText": "喀什智慧就业平台",
|
||||||
|
// #ifdef H5
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
// #endif
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -76,6 +79,18 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/login/wx-login",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "登录"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/login/sms-verify",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "短信验证"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/resume-guide/resume-guide",
|
"path": "pages/resume-guide/resume-guide",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@@ -87,12 +87,13 @@
|
|||||||
<view class="cards" v-if="fairList.length">
|
<view class="cards" v-if="fairList.length">
|
||||||
<view class="card press-button" v-for="(item, index) in fairList" :key="index"
|
<view class="card press-button" v-for="(item, index) in fairList" :key="index"
|
||||||
@click="goDetail(item.jobFairId)">
|
@click="goDetail(item.jobFairId)">
|
||||||
<view class="card-title">
|
|
||||||
{{ item.jobFairTitle }}
|
|
||||||
<view class="center-date"
|
<view class="center-date"
|
||||||
:style="{ color: getTimeStatus(item.jobFairStartTime, item.jobFairEndTime).color,borderColor: getTimeStatus(item.jobFairStartTime, item.jobFairEndTime).color }">
|
:style="{ color: getTimeStatus(item.jobFairStartTime, item.jobFairEndTime).color,borderColor: getTimeStatus(item.jobFairStartTime, item.jobFairEndTime).color }">
|
||||||
{{ getTimeStatus(item.jobFairStartTime, item.jobFairEndTime).statusText }}
|
{{ getTimeStatus(item.jobFairStartTime, item.jobFairEndTime).statusText }}
|
||||||
</view>
|
</view>
|
||||||
|
<view class="card-title">
|
||||||
|
{{ item.jobFairTitle }}
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<view class="card-row">
|
<view class="card-row">
|
||||||
<text class="">{{ item.jobFairAddress }}</text>
|
<text class="">{{ item.jobFairAddress }}</text>
|
||||||
@@ -160,7 +161,7 @@
|
|||||||
import {
|
import {
|
||||||
tabbarManager
|
tabbarManager
|
||||||
} from "@/utils/tabbarManager";
|
} from "@/utils/tabbarManager";
|
||||||
import WxAuthLogin from "@/components/WxAuthLogin/WxAuthLogin.vue";
|
|
||||||
import config from "@/config.js";
|
import config from "@/config.js";
|
||||||
import CryptoJS from 'crypto-js'
|
import CryptoJS from 'crypto-js'
|
||||||
const {
|
const {
|
||||||
@@ -514,7 +515,6 @@
|
|||||||
} else {
|
} else {
|
||||||
$api.msg('请先登录');
|
$api.msg('请先登录');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFair(type = "add") {
|
function getFair(type = "add") {
|
||||||
@@ -1012,10 +1012,21 @@
|
|||||||
|
|
||||||
.cards .card {
|
.cards .card {
|
||||||
margin-top: 28rpx;
|
margin-top: 28rpx;
|
||||||
padding: 32rpx;
|
padding: 45rpx 32rpx 32rpx 32rpx;
|
||||||
background: linear-gradient(to bottom, #e3efff 0%, #fbfdff 100%);
|
background: linear-gradient(to bottom, #e3efff 0%, #fbfdff 100%);
|
||||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
|
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
|
position: relative;
|
||||||
|
.center-date {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 24rpx;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
border: 1rpx solid;
|
||||||
|
padding: 5rpx 10rpx;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cards .card-title {
|
.cards .card-title {
|
||||||
@@ -1041,16 +1052,7 @@
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.center-date {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 24rpx;
|
|
||||||
// position: absolute;
|
|
||||||
// right: 0;
|
|
||||||
// top: 0;
|
|
||||||
border: 1rpx solid;
|
|
||||||
padding: 5rpx 10rpx;
|
|
||||||
margin-left: 10rpx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cards .card-row {
|
.cards .card-row {
|
||||||
|
|||||||
@@ -307,7 +307,8 @@
|
|||||||
<view class="item btn-feel" v-if="!job.recommend">
|
<view class="item btn-feel" v-if="!job.recommend">
|
||||||
<view class="falls-card" :class="{ 'disabled-card': Number(job.jobStatus) === 1 }" @click="nextDetail(job)">
|
<view class="falls-card" :class="{ 'disabled-card': Number(job.jobStatus) === 1 }" @click="nextDetail(job)">
|
||||||
<view class="falls-card-pay">
|
<view class="falls-card-pay">
|
||||||
<view class="pay-text">
|
<view class="fl_1 falls-card-title">{{ job.jobTitle }}</view>
|
||||||
|
<view class="fr_1 pay-text">
|
||||||
<Salary-Expectation
|
<Salary-Expectation
|
||||||
:max-salary="job.maxSalary"
|
:max-salary="job.maxSalary"
|
||||||
:min-salary="job.minSalary"
|
:min-salary="job.minSalary"
|
||||||
@@ -316,8 +317,10 @@
|
|||||||
</view>
|
</view>
|
||||||
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
<view>
|
||||||
<view class="fl_box fl_warp">
|
<!-- <view class="fl_1 falls-card-title">{{ job.jobTitle }}</view> -->
|
||||||
|
|
||||||
|
<view class="fr_1 fl_box fl_warp">
|
||||||
<view class="falls-card-education mar_ri10" v-if="job.education">
|
<view class="falls-card-education mar_ri10" v-if="job.education">
|
||||||
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
||||||
</view>
|
</view>
|
||||||
@@ -325,22 +328,24 @@
|
|||||||
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="falls-card-company" v-show="isShowJw !== 3">
|
|
||||||
{{ config.appInfo.areaName }}
|
|
||||||
<!-- {{ job.jobLocation }} -->
|
|
||||||
<dict-Label dictType="jobLocationAreaCode" :value="job.jobLocationAreaCode"></dict-Label>
|
|
||||||
</view>
|
</view>
|
||||||
|
<!-- <view class="falls-card-company" v-show="isShowJw !== 3">
|
||||||
|
{{ config.appInfo.areaName }}
|
||||||
|
{{ job.jobLocation }}
|
||||||
|
<dict-Label dictType="jobLocationAreaCode" :value="job.jobLocationAreaCode"></dict-Label>
|
||||||
|
</view> -->
|
||||||
<view class="falls-card-pepleNumber">
|
<view class="falls-card-pepleNumber">
|
||||||
<view>
|
<view>
|
||||||
<image class="point2" src="/static/icon/pintDate.png"></image>
|
<image class="point2" src="/static/icon/pintDate.png"></image>
|
||||||
<view class="fl_1">
|
<view class="fl_1">
|
||||||
{{ job.postingDate || '发布日期' }}
|
发布日期:{{ job.postingDate || '暂无数据' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view>
|
<view>
|
||||||
|
|
||||||
<image class="point3" src="/static/icon/pointpeople.png"></image>
|
<image class="point3" src="/static/icon/pointpeople.png"></image>
|
||||||
<view class="fl_1">
|
<view class="fl_1">
|
||||||
{{ vacanciesTo(job.vacancies) }}
|
招聘人数:{{ vacanciesTo(job.vacancies) }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -349,6 +354,10 @@
|
|||||||
<view class="fl_1">
|
<view class="fl_1">
|
||||||
{{ job.companyName }}
|
{{ job.companyName }}
|
||||||
</view>
|
</view>
|
||||||
|
<view class="fr-1">
|
||||||
|
地区:{{ config.appInfo.areaName }}
|
||||||
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<!-- 招聘者显示上下架开关 -->
|
<!-- 招聘者显示上下架开关 -->
|
||||||
<view class="falls-card-actions" v-if="isRecruiter">
|
<view class="falls-card-actions" v-if="isRecruiter">
|
||||||
@@ -395,7 +404,8 @@
|
|||||||
<view class="item btn-feel" v-if="!job.recommend">
|
<view class="item btn-feel" v-if="!job.recommend">
|
||||||
<view class="falls-card" :class="{ 'disabled-card': Number(job.jobStatus) === 1 }" @click="nextDetail(job)">
|
<view class="falls-card" :class="{ 'disabled-card': Number(job.jobStatus) === 1 }" @click="nextDetail(job)">
|
||||||
<view class="falls-card-pay">
|
<view class="falls-card-pay">
|
||||||
<view class="pay-text">
|
<view class="fl_1 falls-card-title">{{ job.jobTitle }}</view>
|
||||||
|
<view class="fr_1 pay-text">
|
||||||
<Salary-Expectation
|
<Salary-Expectation
|
||||||
:max-salary="job.maxSalary"
|
:max-salary="job.maxSalary"
|
||||||
:min-salary="job.minSalary"
|
:min-salary="job.minSalary"
|
||||||
@@ -404,7 +414,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
|
||||||
<view class="fl_box fl_warp">
|
<view class="fl_box fl_warp">
|
||||||
<view class="falls-card-education mar_ri10" v-if="job.education">
|
<view class="falls-card-education mar_ri10" v-if="job.education">
|
||||||
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
||||||
@@ -413,16 +423,16 @@
|
|||||||
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="falls-card-company" v-show="isShowJw !== 3">
|
<!-- <view class="falls-card-company" v-show="isShowJw !== 3">
|
||||||
{{ config.appInfo.areaName }}
|
地区:{{ config.appInfo.areaName }}
|
||||||
<!-- {{ job.jobLocation }} -->
|
地址:{{ job.jobLocation }}
|
||||||
<dict-Label dictType="jobLocationAreaCode" :value="job.jobLocationAreaCode"></dict-Label>
|
<dict-Label dictType="jobLocationAreaCode" :value="job.jobLocationAreaCode"></dict-Label>
|
||||||
</view>
|
</view> -->
|
||||||
<view class="falls-card-pepleNumber">
|
<view class="falls-card-pepleNumber">
|
||||||
<view>
|
<view>
|
||||||
<image class="point2" src="/static/icon/pintDate.png"></image>
|
<image class="point2" src="/static/icon/pintDate.png"></image>
|
||||||
<view class="fl_1">
|
<view class="fl_1">
|
||||||
{{ job.postingDate || '发布日期' }}
|
发布日期:{{ job.postingDate || '暂无数据' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view>
|
<view>
|
||||||
@@ -437,6 +447,10 @@
|
|||||||
<view class="fl_1">
|
<view class="fl_1">
|
||||||
{{ job.companyName }}
|
{{ job.companyName }}
|
||||||
</view>
|
</view>
|
||||||
|
<view class="fr-1">
|
||||||
|
地区:{{ config.appInfo.areaName }}
|
||||||
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<!-- 招聘者显示上下架开关 -->
|
<!-- 招聘者显示上下架开关 -->
|
||||||
<view class="falls-card-actions" v-if="isRecruiter">
|
<view class="falls-card-actions" v-if="isRecruiter">
|
||||||
@@ -486,8 +500,7 @@
|
|||||||
@update:show="(value) => showNewFilter = value"
|
@update:show="(value) => showNewFilter = value"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 微信授权登录弹窗 -->
|
|
||||||
<WxAuthLogin ref="wxAuthLoginRef" @success="handleLoginSuccess" />
|
|
||||||
|
|
||||||
<!-- <view class="maskFristEntry" v-if="maskFristEntry">
|
<!-- <view class="maskFristEntry" v-if="maskFristEntry">
|
||||||
<view class="entry-content">
|
<view class="entry-content">
|
||||||
@@ -612,7 +625,7 @@ import newFilterPage from '@/components/new-filter-page/new-filter-page.vue';
|
|||||||
import { useRecommedIndexedDBStore, jobRecommender } from '@/stores/useRecommedIndexedDBStore.js';
|
import { useRecommedIndexedDBStore, jobRecommender } from '@/stores/useRecommedIndexedDBStore.js';
|
||||||
import { useScrollDirection } from '@/hook/useScrollDirection';
|
import { useScrollDirection } from '@/hook/useScrollDirection';
|
||||||
import { useColumnCount } from '@/hook/useColumnCount';
|
import { useColumnCount } from '@/hook/useColumnCount';
|
||||||
import WxAuthLogin from '@/components/WxAuthLogin/WxAuthLogin.vue';
|
|
||||||
import IconfontIcon from '@/components/IconfontIcon/IconfontIcon.vue'
|
import IconfontIcon from '@/components/IconfontIcon/IconfontIcon.vue'
|
||||||
// 企业卡片组件已内联到模板中
|
// 企业卡片组件已内联到模板中
|
||||||
// 滚动状态管理
|
// 滚动状态管理
|
||||||
@@ -703,7 +716,7 @@ const loadmoreRef = ref(null);
|
|||||||
const conditionSearch = ref({});
|
const conditionSearch = ref({});
|
||||||
const waterfallcolumn = ref(2);
|
const waterfallcolumn = ref(2);
|
||||||
const maskFristEntry = ref(false);
|
const maskFristEntry = ref(false);
|
||||||
const wxAuthLoginRef = ref(null);
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tabIndex: 'all',
|
tabIndex: 'all',
|
||||||
});
|
});
|
||||||
@@ -818,7 +831,7 @@ onMounted(() => {
|
|||||||
getCompanyInfo();
|
getCompanyInfo();
|
||||||
// pageNull.value = 0;
|
// pageNull.value = 0;
|
||||||
uni.$on('showLoginModal', () => {
|
uni.$on('showLoginModal', () => {
|
||||||
wxAuthLoginRef.value?.open();
|
uni.navigateTo({ url: '/pages/login/wx-login' });
|
||||||
pageNull.value = 0;
|
pageNull.value = 0;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -832,7 +845,7 @@ onMounted(() => {
|
|||||||
// 绑定新的监听
|
// 绑定新的监听
|
||||||
uni.$on('showLoginModal', () => {
|
uni.$on('showLoginModal', () => {
|
||||||
console.log('收到showLoginModal事件,打开登录弹窗');
|
console.log('收到showLoginModal事件,打开登录弹窗');
|
||||||
wxAuthLoginRef.value?.open();
|
uni.navigateTo({ url: '/pages/login/wx-login' });
|
||||||
pageNull.value = 0;
|
pageNull.value = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="app-custom-root">
|
<view class="app-custom-root">
|
||||||
<view class="app-container">
|
<view class="app-container">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<!-- 自定义导航栏 -->
|
||||||
|
<view class="custom-nav" :style="{paddingTop: statusBarHeight + 'px'}">
|
||||||
|
<view class="nav-content">
|
||||||
|
<view class="nav-back" @click="back"><text class="nav-back-text">‹</text></view>
|
||||||
|
<view class="nav-title">喀什智慧就业平台</view>
|
||||||
|
<view class="nav-placeholder"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
<!-- 主体内容区域 -->
|
<!-- 主体内容区域 -->
|
||||||
<view class="container-main">
|
<view class="container-main">
|
||||||
<IndexOne @onShowTabbar="changeShowTabbar" />
|
<IndexOne @onShowTabbar="changeShowTabbar" />
|
||||||
@@ -26,7 +36,13 @@ const userStore = useUserStore();
|
|||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
// useReadMsg().fetchMessages();
|
// useReadMsg().fetchMessages();
|
||||||
});
|
});
|
||||||
|
// 返回按钮功能
|
||||||
|
function back() {
|
||||||
|
// uni.navigateBack({
|
||||||
|
// delta: 1
|
||||||
|
// });
|
||||||
|
window.location.href = 'https://www.xjksly.cn/mechine-single-vue/';
|
||||||
|
}
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 更新自定义tabbar选中状态
|
// 更新自定义tabbar选中状态
|
||||||
tabbarManager.updateSelected(0);
|
tabbarManager.updateSelected(0);
|
||||||
@@ -191,4 +207,39 @@ onShow(() => {
|
|||||||
background: #FFFFFF
|
background: #FFFFFF
|
||||||
width: 4rpx
|
width: 4rpx
|
||||||
height: 20rpx
|
height: 20rpx
|
||||||
|
/* 自定义导航栏样式 */
|
||||||
|
.custom-nav
|
||||||
|
background: linear-gradient(135deg, #8a9bf0, #c3cafa, #e7ebfe)
|
||||||
|
width: 100%
|
||||||
|
box-shadow: 0 2rpx 10rpx rgba(138, 155, 240, 0.2)
|
||||||
|
border-radius: 0
|
||||||
|
.nav-content
|
||||||
|
height: 80rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: space-between
|
||||||
|
padding: 0 40rpx
|
||||||
|
.nav-back
|
||||||
|
width: 120rpx
|
||||||
|
height: 80rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: flex-start
|
||||||
|
color: #2f56e8
|
||||||
|
font-weight: 400
|
||||||
|
transition: all 0.3s ease
|
||||||
|
&:hover
|
||||||
|
transform: translateX(-5rpx)
|
||||||
|
.nav-back-text
|
||||||
|
font-size: 56rpx
|
||||||
|
line-height: 1
|
||||||
|
text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.1)
|
||||||
|
.nav-title
|
||||||
|
color: #4a55b0
|
||||||
|
font-size: 36rpx
|
||||||
|
font-weight: 600
|
||||||
|
text-shadow: 1rpx 1rpx 2rpx rgba(255, 255, 255, 0.8)
|
||||||
|
letter-spacing: 2rpx
|
||||||
|
.nav-placeholder
|
||||||
|
width: 120rpx
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
634
pages/login/sms-verify.vue
Normal file
634
pages/login/sms-verify.vue
Normal file
@@ -0,0 +1,634 @@
|
|||||||
|
<template>
|
||||||
|
<view class="sms-verify-page">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<!-- <view class="nav-bar">
|
||||||
|
<view class="nav-back" @click="goBack">
|
||||||
|
<uni-icons type="arrowleft" size="24" color="#333"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="nav-title">短信验证</view>
|
||||||
|
<view class="nav-placeholder"></view>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
|
<!-- 页面内容 -->
|
||||||
|
<view class="page-content">
|
||||||
|
<!-- 安全提示 -->
|
||||||
|
<view class="security-tip">
|
||||||
|
<view class="tip-icon">
|
||||||
|
<uni-icons type="auth-filled" size="36" color="#256BFA"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="tip-text">为了您的账户安全需要您进行验证</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 手机号显示 -->
|
||||||
|
<view class="phone-display">
|
||||||
|
<view class="phone-label">验证码将发送至</view>
|
||||||
|
<view class="phone-number">{{ formattedPhone }}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 验证码输入区域 -->
|
||||||
|
<view class="sms-input-area">
|
||||||
|
<view class="input-label">请输入6位数字验证码</view>
|
||||||
|
<view class="single-input-container">
|
||||||
|
<input
|
||||||
|
ref="smsInput"
|
||||||
|
class="single-input"
|
||||||
|
type="tel"
|
||||||
|
inputmode="numeric"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
maxlength="6"
|
||||||
|
:value="smsCode"
|
||||||
|
@input="onCodeInput"
|
||||||
|
@paste="onPaste"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
:focus="autoFocus"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 倒计时和重发 -->
|
||||||
|
<view class="countdown-section">
|
||||||
|
<view v-if="countdown > 0" class="countdown-text">
|
||||||
|
{{ countdown }}秒后重新获取
|
||||||
|
</view>
|
||||||
|
<view v-else class="resend-text" @click="resendSms">
|
||||||
|
重新获取验证码
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<button class="submit-btn" :disabled="!canSubmit" @click="submitVerification">
|
||||||
|
<text v-if="!loading">确认</text>
|
||||||
|
<view v-else class="loading-spinner"></view>
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, inject, computed, onMounted, onUnmounted } from 'vue';
|
||||||
|
import { onLoad } from '@dcloudio/uni-app';
|
||||||
|
import useUserStore from '@/stores/useUserStore';
|
||||||
|
import { tabbarManager } from '@/utils/tabbarManager';
|
||||||
|
|
||||||
|
const { $api } = inject('globalFunction');
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
// 从页面参数获取数据
|
||||||
|
const phone = ref('');
|
||||||
|
const openid = ref('');
|
||||||
|
const unionid = ref('');
|
||||||
|
const userType = ref('');
|
||||||
|
const orgType = ref('');
|
||||||
|
|
||||||
|
// 验证码相关
|
||||||
|
const smsCode = ref(''); // 单个字符串验证码
|
||||||
|
const smsInput = ref(null); // 输入框引用
|
||||||
|
const countdown = ref(60); // 倒计时
|
||||||
|
const timer = ref(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
const autoFocus = ref(true); // 自动聚焦
|
||||||
|
|
||||||
|
// 格式化手机号:只显示前三位和后四位,中间用星号代替
|
||||||
|
const formattedPhone = computed(() => {
|
||||||
|
if (!phone.value || phone.value.trim() === '') {
|
||||||
|
return '未知号码';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理手机号,移除空格和特殊字符
|
||||||
|
const cleanPhone = phone.value.replace(/\D/g, '');
|
||||||
|
|
||||||
|
if (cleanPhone.length < 11) {
|
||||||
|
return phone.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = cleanPhone.substring(0, 3);
|
||||||
|
const suffix = cleanPhone.substring(cleanPhone.length - 4);
|
||||||
|
return `${prefix}****${suffix}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 是否可以提交
|
||||||
|
const canSubmit = computed(() => {
|
||||||
|
return smsCode.value.length === 6 && !loading.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面加载时获取参数
|
||||||
|
onLoad(async (options) => {
|
||||||
|
// 尝试多种可能的手机号字段名(按优先级)
|
||||||
|
const possiblePhoneFields = [
|
||||||
|
'phone', 'mobile', 'phoneNumber', 'tel',
|
||||||
|
'phoneNum', 'userPhone', 'telephone', 'mobilePhone', 'cellphone',
|
||||||
|
'userTel', 'userMobile', 'contactPhone'
|
||||||
|
];
|
||||||
|
|
||||||
|
let foundPhone = '';
|
||||||
|
for (const field of possiblePhoneFields) {
|
||||||
|
if (options[field]) {
|
||||||
|
foundPhone = options[field];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没找到,尝试从URL参数中解析
|
||||||
|
if (!foundPhone) {
|
||||||
|
const currentPages = getCurrentPages();
|
||||||
|
if (currentPages.length > 0) {
|
||||||
|
const currentPage = currentPages[currentPages.length - 1];
|
||||||
|
|
||||||
|
// 尝试从页面路由参数中获取
|
||||||
|
if (currentPage.$page && currentPage.$page.fullPath) {
|
||||||
|
const urlParams = new URLSearchParams(currentPage.$page.fullPath.split('?')[1] || '');
|
||||||
|
for (const field of possiblePhoneFields) {
|
||||||
|
const value = urlParams.get(field);
|
||||||
|
if (value) {
|
||||||
|
foundPhone = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
phone.value = foundPhone || '';
|
||||||
|
openid.value = options.openid || '';
|
||||||
|
unionid.value = options.unionid || '';
|
||||||
|
userType.value = options.userType || '';
|
||||||
|
orgType.value = options.orgType || '';
|
||||||
|
|
||||||
|
// 如果手机号仍然为空,显示错误信息
|
||||||
|
if (!phone.value) {
|
||||||
|
uni.showToast({ title: '无法获取手机号,请返回重试', icon: 'none' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
startCountdown();
|
||||||
|
|
||||||
|
// 自动聚焦到输入框
|
||||||
|
setTimeout(() => {
|
||||||
|
if (smsInput.value && typeof smsInput.value.focus === 'function') {
|
||||||
|
smsInput.value.focus();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
const startCountdown = () => {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
countdown.value = 60;
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
if (countdown.value > 0) {
|
||||||
|
countdown.value--;
|
||||||
|
} else {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重发验证码
|
||||||
|
const resendSms = async () => {
|
||||||
|
if (countdown.value > 0) return;
|
||||||
|
|
||||||
|
// 检查手机号是否为空
|
||||||
|
if (!phone.value) {
|
||||||
|
uni.showToast({ title: '手机号获取失败,请返回重试', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({ title: '发送中...' });
|
||||||
|
try {
|
||||||
|
// 调用重新发送验证码接口
|
||||||
|
const requestParams = { phone: phone.value };
|
||||||
|
// 只有单位用户才传递机构类型
|
||||||
|
if (userType.value === '0') {
|
||||||
|
requestParams.orgType = orgType.value;
|
||||||
|
requestParams.userType = userType.value;
|
||||||
|
}
|
||||||
|
const res = await $api.createRequest('/app/sendSmsAgain', requestParams, 'post');
|
||||||
|
|
||||||
|
// 检查状态码
|
||||||
|
if (res.code === 200 ) {
|
||||||
|
uni.hideLoading();
|
||||||
|
|
||||||
|
uni.showToast({ title: '验证码已发送', icon: 'success' });
|
||||||
|
startCountdown();
|
||||||
|
} else {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: res.msg || '发送失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: error.msg || '发送失败,请重试', icon: 'none' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 验证码输入处理
|
||||||
|
const onCodeInput = (e) => {
|
||||||
|
let value = e.detail.value.replace(/\D/g, ''); // 只保留数字
|
||||||
|
|
||||||
|
// 限制为6位数字
|
||||||
|
if (value.length > 6) {
|
||||||
|
value = value.substring(0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
smsCode.value = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 粘贴事件处理
|
||||||
|
const onPaste = (e) => {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
// 微信小程序中,使用异步方式获取剪贴板
|
||||||
|
setTimeout(() => {
|
||||||
|
pasteFromClipboard();
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
// 尝试阻止默认行为
|
||||||
|
if (e && e.preventDefault) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
if (e && e.stopPropagation) {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
// 其他平台(H5/App)使用标准粘贴处理
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
let pasteText = '';
|
||||||
|
if (e.clipboardData && e.clipboardData.getData) {
|
||||||
|
pasteText = e.clipboardData.getData('text');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pasteText) {
|
||||||
|
// 处理粘贴的文本
|
||||||
|
handlePaste(pasteText);
|
||||||
|
} else {
|
||||||
|
// 使用异步方式获取剪贴板
|
||||||
|
setTimeout(() => {
|
||||||
|
pasteFromClipboard();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理粘贴的文本
|
||||||
|
const handlePaste = (text) => {
|
||||||
|
// 提取数字
|
||||||
|
const digits = text.replace(/\D/g, '');
|
||||||
|
|
||||||
|
if (digits.length === 0) {
|
||||||
|
uni.showToast({ title: '剪贴板中没有找到验证码', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限制为6位数字
|
||||||
|
const code = digits.substring(0, 6);
|
||||||
|
smsCode.value = code;
|
||||||
|
|
||||||
|
uni.showToast({ title: '已粘贴验证码', icon: 'success' });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 从剪贴板粘贴验证码
|
||||||
|
const pasteFromClipboard = () => {
|
||||||
|
uni.getClipboardData({
|
||||||
|
success: (res) => {
|
||||||
|
const text = res.data || '';
|
||||||
|
handlePaste(text);
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
uni.showToast({ title: '读取剪贴板失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交验证
|
||||||
|
const submitVerification = async () => {
|
||||||
|
if (!canSubmit.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
const code = smsCode.value;
|
||||||
|
|
||||||
|
// 检查手机号是否为空
|
||||||
|
if (!phone.value) {
|
||||||
|
uni.showToast({ title: '手机号获取失败,请返回重试', icon: 'none' });
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 调用接口 /app/appLoginPhone
|
||||||
|
const requestParams = {
|
||||||
|
smsCode: code,
|
||||||
|
phone: phone.value,
|
||||||
|
openid: openid.value,
|
||||||
|
unionid: unionid.value,
|
||||||
|
userType: userType.value
|
||||||
|
};
|
||||||
|
// 只有单位用户才传递机构类型
|
||||||
|
if (userType.value === '0') {
|
||||||
|
requestParams.orgType = orgType.value;
|
||||||
|
}
|
||||||
|
const res = await $api.createRequest('/app/appLoginPhone', requestParams, 'post');
|
||||||
|
|
||||||
|
if (res.token && res.code === 200) {
|
||||||
|
// 登录成功,存储token
|
||||||
|
await userStore.loginSetToken(res.token).then((resume) => {
|
||||||
|
// 更新用户类型到缓存
|
||||||
|
if (res.isCompanyUser !== undefined) {
|
||||||
|
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||||
|
userInfo.isCompanyUser = Number(res.isCompanyUser); // 0-企业用户,1-求职者
|
||||||
|
uni.setStorageSync('userInfo', userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showToast({ title: '登录成功', icon: 'success' });
|
||||||
|
|
||||||
|
// 刷新tabbar以显示正确的用户类型
|
||||||
|
tabbarManager.refreshTabBar();
|
||||||
|
console.log(userType.value , res.isCompanyUser);
|
||||||
|
console.log('用户登录成功,简历信息-resume:', resume);
|
||||||
|
console.log('用户登录成功,简历信息-res:', res);
|
||||||
|
if (!resume?.data?.jobTitleId) {
|
||||||
|
if (!res.idCard) {
|
||||||
|
console.log('用户登录成功,没有身份证号');
|
||||||
|
if (userType.value == '1') {
|
||||||
|
// 求职者跳转到个人信息补全页面
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/packageA/pages/complete-info/complete-info?step=1'
|
||||||
|
});
|
||||||
|
} else if (userType.value == '0') {
|
||||||
|
// 招聘者跳转到企业信息补全页面
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/packageA/pages/complete-info/company-info'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 跳转到首页
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('用户登录成功,有简历信息--');
|
||||||
|
// 跳转到首页
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
// 只有在非企业用户且确实需要简历信息时才显示错误
|
||||||
|
// 企业用户可能没有简历信息,这是正常的
|
||||||
|
if (userType.value !== '0') {
|
||||||
|
uni.showToast({ title: '获取用户信息失败', icon: 'none' });
|
||||||
|
} else {
|
||||||
|
console.log('企业用户登录成功,简历信息可能为空');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: res.msg || '验证失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
uni.showToast({ title: error || '验证失败,请重试', icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 返回上一页
|
||||||
|
const goBack = () => {
|
||||||
|
uni.navigateBack();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件销毁时清除定时器
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.sms-verify-page
|
||||||
|
min-height: 100vh
|
||||||
|
background: linear-gradient(135deg, #F7F9FF 0%, #FFFFFF 100%)
|
||||||
|
|
||||||
|
.nav-bar
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: space-between
|
||||||
|
height: 88rpx
|
||||||
|
padding: 0 32rpx
|
||||||
|
background: #FFFFFF
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04)
|
||||||
|
|
||||||
|
.nav-back
|
||||||
|
width: 60rpx
|
||||||
|
height: 60rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
border-radius: 50%
|
||||||
|
transition: background-color 0.2s ease
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background-color: #F5F5F5
|
||||||
|
|
||||||
|
.nav-title
|
||||||
|
font-size: 32rpx
|
||||||
|
font-weight: 600
|
||||||
|
color: #333333
|
||||||
|
|
||||||
|
.nav-placeholder
|
||||||
|
width: 60rpx
|
||||||
|
|
||||||
|
.page-content
|
||||||
|
padding: 80rpx 48rpx 48rpx
|
||||||
|
|
||||||
|
.security-tip
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
margin-bottom: 60rpx
|
||||||
|
padding: 32rpx
|
||||||
|
background: linear-gradient(135deg, rgba(37, 107, 250, 0.08) 0%, rgba(30, 91, 255, 0.04) 100%)
|
||||||
|
border-radius: 24rpx
|
||||||
|
border: 1rpx solid rgba(37, 107, 250, 0.1)
|
||||||
|
|
||||||
|
.tip-icon
|
||||||
|
margin-bottom: 20rpx
|
||||||
|
width: 64rpx
|
||||||
|
height: 64rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
background: #FFFFFF
|
||||||
|
border-radius: 50%
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(37, 107, 250, 0.15)
|
||||||
|
|
||||||
|
.tip-text
|
||||||
|
font-size: 28rpx
|
||||||
|
font-weight: 500
|
||||||
|
color: #256BFA
|
||||||
|
text-align: center
|
||||||
|
line-height: 1.4
|
||||||
|
|
||||||
|
.phone-display
|
||||||
|
text-align: center
|
||||||
|
margin-bottom: 80rpx
|
||||||
|
|
||||||
|
.phone-label
|
||||||
|
font-size: 28rpx
|
||||||
|
color: #666666
|
||||||
|
margin-bottom: 16rpx
|
||||||
|
opacity: 0.8
|
||||||
|
|
||||||
|
.phone-number
|
||||||
|
font-size: 44rpx
|
||||||
|
font-weight: 700
|
||||||
|
color: #333333
|
||||||
|
letter-spacing: 2rpx
|
||||||
|
background: linear-gradient(135deg, #256BFA 0%, #1E5BFF 100%)
|
||||||
|
-webkit-background-clip: text
|
||||||
|
-webkit-text-fill-color: transparent
|
||||||
|
background-clip: text
|
||||||
|
|
||||||
|
.sms-input-area
|
||||||
|
margin-bottom: 60rpx
|
||||||
|
|
||||||
|
.input-label
|
||||||
|
font-size: 28rpx
|
||||||
|
color: #666666
|
||||||
|
text-align: center
|
||||||
|
margin-bottom: 24rpx
|
||||||
|
font-weight: 500
|
||||||
|
|
||||||
|
.single-input-container
|
||||||
|
margin-bottom: 16rpx
|
||||||
|
|
||||||
|
.single-input
|
||||||
|
width: 100%
|
||||||
|
height: 120rpx
|
||||||
|
border: 3rpx solid #E8ECF4
|
||||||
|
border-radius: 20rpx
|
||||||
|
font-size: 48rpx
|
||||||
|
font-weight: 700
|
||||||
|
color: #333333
|
||||||
|
background: #FFFFFF
|
||||||
|
text-align: center
|
||||||
|
padding: 0 32rpx
|
||||||
|
box-sizing: border-box
|
||||||
|
outline: none
|
||||||
|
caret-color: #256BFA
|
||||||
|
transition: all 0.3s ease
|
||||||
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05)
|
||||||
|
|
||||||
|
&:focus
|
||||||
|
border-color: #256BFA
|
||||||
|
background: #FFFFFF
|
||||||
|
box-shadow: 0 8rpx 32rpx rgba(37, 107, 250, 0.2)
|
||||||
|
transform: translateY(-2rpx)
|
||||||
|
|
||||||
|
&::placeholder
|
||||||
|
color: #CCCCCC
|
||||||
|
font-size: 32rpx
|
||||||
|
font-weight: normal
|
||||||
|
|
||||||
|
.countdown-section
|
||||||
|
text-align: center
|
||||||
|
margin-bottom: 80rpx
|
||||||
|
|
||||||
|
.countdown-text
|
||||||
|
font-size: 28rpx
|
||||||
|
color: #999999
|
||||||
|
font-weight: 500
|
||||||
|
|
||||||
|
.resend-text
|
||||||
|
font-size: 28rpx
|
||||||
|
color: #256BFA
|
||||||
|
font-weight: 600
|
||||||
|
cursor: pointer
|
||||||
|
padding: 12rpx 24rpx
|
||||||
|
border-radius: 24rpx
|
||||||
|
background: rgba(37, 107, 250, 0.1)
|
||||||
|
display: inline-block
|
||||||
|
transition: all 0.2s ease
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background: rgba(37, 107, 250, 0.2)
|
||||||
|
transform: scale(0.98)
|
||||||
|
|
||||||
|
.submit-btn
|
||||||
|
width: 100%
|
||||||
|
height: 96rpx
|
||||||
|
background: linear-gradient(135deg, #256BFA 0%, #1E5BFF 100%)
|
||||||
|
border-radius: 48rpx
|
||||||
|
color: #FFFFFF
|
||||||
|
font-size: 34rpx
|
||||||
|
font-weight: 600
|
||||||
|
border: none
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
box-shadow: 0 8rpx 32rpx rgba(37, 107, 250, 0.3)
|
||||||
|
transition: all 0.3s ease
|
||||||
|
position: relative
|
||||||
|
overflow: hidden
|
||||||
|
|
||||||
|
&::before
|
||||||
|
content: ''
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: -100%
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent)
|
||||||
|
transition: left 0.5s ease
|
||||||
|
|
||||||
|
&:not(:disabled):hover::before
|
||||||
|
left: 100%
|
||||||
|
|
||||||
|
&:not(:disabled):active
|
||||||
|
transform: translateY(2rpx)
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(37, 107, 250, 0.3)
|
||||||
|
|
||||||
|
&:disabled
|
||||||
|
opacity: 0.5
|
||||||
|
cursor: not-allowed
|
||||||
|
box-shadow: none
|
||||||
|
|
||||||
|
.loading-spinner
|
||||||
|
width: 48rpx
|
||||||
|
height: 48rpx
|
||||||
|
border: 4rpx solid rgba(255, 255, 255, 0.3)
|
||||||
|
border-radius: 50%
|
||||||
|
border-top: 4rpx solid #FFFFFF
|
||||||
|
animation: spin 1s linear infinite
|
||||||
|
|
||||||
|
// 按钮重置样式
|
||||||
|
button::after
|
||||||
|
border: none
|
||||||
|
|
||||||
|
// 动画定义
|
||||||
|
@keyframes spin
|
||||||
|
0%
|
||||||
|
transform: rotate(0deg)
|
||||||
|
100%
|
||||||
|
transform: rotate(360deg)
|
||||||
|
|
||||||
|
// 页面进入动画
|
||||||
|
.sms-verify-page
|
||||||
|
animation: fadeIn 0.4s ease-out
|
||||||
|
|
||||||
|
@keyframes fadeIn
|
||||||
|
from
|
||||||
|
opacity: 0
|
||||||
|
transform: translateY(20rpx)
|
||||||
|
to
|
||||||
|
opacity: 1
|
||||||
|
transform: translateY(0)
|
||||||
|
</style>
|
||||||
697
pages/login/wx-login.vue
Normal file
697
pages/login/wx-login.vue
Normal file
@@ -0,0 +1,697 @@
|
|||||||
|
<template>
|
||||||
|
<view class="wx-login-page">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<!-- <view class="nav-bar">
|
||||||
|
<view class="nav-back" @click="goBack">
|
||||||
|
<uni-icons type="arrowleft" size="24" color="#333"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="nav-title">登录</view>
|
||||||
|
<view class="nav-placeholder"></view>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
|
<!-- 页面内容 -->
|
||||||
|
<view class="page-content">
|
||||||
|
<!-- Logo和标题 -->
|
||||||
|
<view class="auth-header">
|
||||||
|
<image class="auth-logo" src="@/static/logo2-S.png" mode="aspectFit"></image>
|
||||||
|
<view class="auth-title">欢迎使用就业服务</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 角色选择 -->
|
||||||
|
<view class="role-select">
|
||||||
|
<view class="role-title">请选择您的角色</view>
|
||||||
|
<view class="role-options">
|
||||||
|
<view
|
||||||
|
class="role-item"
|
||||||
|
:class="{ active: userType === 1 }"
|
||||||
|
@click="selectRole(1)"
|
||||||
|
>
|
||||||
|
<view class="role-icon">
|
||||||
|
<uni-icons type="person" size="32" :color="userType === 1 ? '#256BFA' : '#999'"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="role-text">个人</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="role-item"
|
||||||
|
:class="{ active: userType === 0 }"
|
||||||
|
@click="selectRole(0)"
|
||||||
|
>
|
||||||
|
<view class="role-icon">
|
||||||
|
<uni-icons type="shop" size="32" :color="userType === 0 ? '#256BFA' : '#999'"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="role-text">单位</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 机构类型选择(仅单位角色显示) -->
|
||||||
|
<view v-if="userType === 0" class="org-type-select">
|
||||||
|
<view class="org-type-title">请选择机构类型</view>
|
||||||
|
<view class="org-type-options">
|
||||||
|
<view
|
||||||
|
v-for="option in orgTypeOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="org-type-item"
|
||||||
|
:class="{ active: orgType === option.value }"
|
||||||
|
@click="selectOrgType(option.value)"
|
||||||
|
>
|
||||||
|
<view class="org-type-text">{{ option.label }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 授权说明 -->
|
||||||
|
<view class="auth-tips">
|
||||||
|
<view class="tip-item">
|
||||||
|
<uni-icons type="checkmarkempty" size="16" color="#256BFA"></uni-icons>
|
||||||
|
<text>保护您的个人信息安全</text>
|
||||||
|
</view>
|
||||||
|
<view class="tip-item">
|
||||||
|
<uni-icons type="checkmarkempty" size="16" color="#256BFA"></uni-icons>
|
||||||
|
<text>为您推荐更合适的岗位</text>
|
||||||
|
</view>
|
||||||
|
<view class="tip-item">
|
||||||
|
<uni-icons type="checkmarkempty" size="16" color="#256BFA"></uni-icons>
|
||||||
|
<text>享受完整的就业服务</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 授权按钮 -->
|
||||||
|
<view class="auth-actions">
|
||||||
|
<!-- 微信小程序使用 open-type="getPhoneNumber" -->
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<button
|
||||||
|
class="auth-btn primary"
|
||||||
|
open-type="getPhoneNumber"
|
||||||
|
@getphonenumber="onWxGetPhoneNumber"
|
||||||
|
>
|
||||||
|
<uni-icons type="phone" size="20" color="#FFFFFF"></uni-icons>
|
||||||
|
<text>手机号快捷登录</text>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<!-- H5和App使用普通按钮 -->
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
|
<button class="auth-btn primary" @click="wxLogin">
|
||||||
|
<uni-icons type="phone" size="20" color="#FFFFFF"></uni-icons>
|
||||||
|
<text>手机号快捷登录</text>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<!-- 测试登录按钮(仅开发环境) -->
|
||||||
|
<!-- #ifdef APP-PLUS || H5 -->
|
||||||
|
<button class="auth-btn secondary" @click="testLogin">
|
||||||
|
<text>测试账号登录</text>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 用户协议 -->
|
||||||
|
<view class="auth-agreement">
|
||||||
|
<view class="agreement-checkbox" @click="toggleAgreement">
|
||||||
|
<uni-icons
|
||||||
|
:type="agreedToAgreement ? 'checkbox-filled' : 'circle'"
|
||||||
|
size="20"
|
||||||
|
:color="agreedToAgreement ? '#256BFA' : '#999'"
|
||||||
|
></uni-icons>
|
||||||
|
<text class="agreement-text">我已阅读并同意</text>
|
||||||
|
</view>
|
||||||
|
<text class="link" @click="openAgreement('user')">《隐私协议》</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, inject, onMounted, computed } from 'vue';
|
||||||
|
import { onLoad } from '@dcloudio/uni-app';
|
||||||
|
import useUserStore from '@/stores/useUserStore';
|
||||||
|
import useDictStore from '@/stores/useDictStore';
|
||||||
|
|
||||||
|
const { $api } = inject('globalFunction');
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const dictStore = useDictStore();
|
||||||
|
|
||||||
|
const userType = ref(null); // 用户角色:1-求职者,0-企业
|
||||||
|
const orgType = ref(null); // 机构类型
|
||||||
|
const orgTypeOptions = ref([]); // 机构类型选项
|
||||||
|
const agreedToAgreement = ref(false); // 是否同意用户协议
|
||||||
|
|
||||||
|
// 计算是否可提交
|
||||||
|
const canSubmit = computed(() => {
|
||||||
|
if (userType.value === null) return false;
|
||||||
|
if (userType.value === 0 && orgType.value === null) return false;
|
||||||
|
if (!agreedToAgreement.value) return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取机构类型字典
|
||||||
|
const getOrgTypeDict = async () => {
|
||||||
|
try {
|
||||||
|
const options = await dictStore.getDictSelectOption('org_type');
|
||||||
|
orgTypeOptions.value = options;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取机构类型字典失败:', error);
|
||||||
|
// 使用备用数据
|
||||||
|
orgTypeOptions.value = [
|
||||||
|
{ label: '有限责任公司', value: '1' },
|
||||||
|
{ label: '股份有限公司', value: '2' },
|
||||||
|
{ label: '个人独资企业', value: '3' },
|
||||||
|
{ label: '合伙企业', value: '4' },
|
||||||
|
{ label: '外商投资企业', value: '5' },
|
||||||
|
{ label: '其他', value: '6' }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择角色
|
||||||
|
const selectRole = (type) => {
|
||||||
|
userType.value = type;
|
||||||
|
orgType.value = null; // 切换角色时重置机构类型选择
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择机构类型
|
||||||
|
const selectOrgType = (type) => {
|
||||||
|
orgType.value = type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换协议同意状态
|
||||||
|
const toggleAgreement = () => {
|
||||||
|
agreedToAgreement.value = !agreedToAgreement.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开用户协议
|
||||||
|
const openAgreement = (type) => {
|
||||||
|
const urls = {
|
||||||
|
user: '/packageA/pages/agreement/user',
|
||||||
|
privacy: '/packageA/pages/agreement/privacy'
|
||||||
|
};
|
||||||
|
|
||||||
|
uni.navigateTo({
|
||||||
|
url: urls[type]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 返回上一页
|
||||||
|
const goBack = () => {
|
||||||
|
uni.navigateBack();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 通用的验证函数
|
||||||
|
const validateForm = () => {
|
||||||
|
if (userType.value === null) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先选择您的角色(个人或单位)',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userType.value === 0 && orgType.value === null) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请选择机构类型',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!agreedToAgreement.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先阅读并同意隐私协议',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 微信小程序授权前的检查
|
||||||
|
const checkBeforeWxAuth = (e) => {
|
||||||
|
// 验证表单
|
||||||
|
if (!validateForm()) {
|
||||||
|
// 阻止微信授权流程
|
||||||
|
if (e && e.preventDefault) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
console.log('Validation passed, allowing wx auth');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 微信获取手机号
|
||||||
|
const onWxGetPhoneNumber = async (e) => {
|
||||||
|
const { encryptedData, iv } = e.detail;
|
||||||
|
// 使用通用验证函数
|
||||||
|
if (!validateForm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
||||||
|
uni.login({
|
||||||
|
provider: 'weixin',
|
||||||
|
success: (loginRes) => {
|
||||||
|
const code = loginRes.code;
|
||||||
|
|
||||||
|
// 调用接口 /app/appWxphoneSmsCode
|
||||||
|
uni.showLoading({ title: '获取验证码中...' });
|
||||||
|
|
||||||
|
// 根据用户类型构建参数
|
||||||
|
const requestParams = {
|
||||||
|
code,
|
||||||
|
encryptedData,
|
||||||
|
iv,
|
||||||
|
userType: userType.value
|
||||||
|
};
|
||||||
|
// 只有单位用户才传递机构类型
|
||||||
|
if (userType.value === 0) {
|
||||||
|
requestParams.orgType = orgType.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api.createRequest('/app/appWxphoneSmsCode', requestParams, 'post').then((resData) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
// 检查可能的手机号字段
|
||||||
|
const possiblePhoneFields = ['phone', 'mobile', 'phoneNumber', 'tel', 'mobilePhone'];
|
||||||
|
let phoneValue = '';
|
||||||
|
for (const field of possiblePhoneFields) {
|
||||||
|
if (resData[field]) {
|
||||||
|
phoneValue = resData[field];
|
||||||
|
console.log(`从接口返回中找到手机号字段 "${field}": ${phoneValue}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resData.code === 200 || resData.success) {
|
||||||
|
// 跳转到短信验证页面,传递参数
|
||||||
|
const params = {
|
||||||
|
phone: phoneValue || '', // 接口返回的手机号
|
||||||
|
openid: resData.openid || '',
|
||||||
|
unionid: resData.unionid || '',
|
||||||
|
userType: userType.value
|
||||||
|
};
|
||||||
|
// 只有单位用户才传递机构类型
|
||||||
|
if (userType.value === 0) {
|
||||||
|
params.orgType = orgType.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/login/sms-verify?' + Object.keys(params)
|
||||||
|
.map(key => `${key}=${encodeURIComponent(params[key])}`)
|
||||||
|
.join('&')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$api.msg(resData.msg || '获取验证码失败');
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
$api.msg(err.msg || '获取验证码失败,请重试');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '获取登录信息失败,请重试',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (e.detail.errMsg === 'getPhoneNumber:fail user deny') {
|
||||||
|
uni.showToast({
|
||||||
|
title: '您取消了授权',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '获取手机号失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// H5/App 微信登录(暂保持原有逻辑,后续可调整)
|
||||||
|
const wxLogin = () => {
|
||||||
|
// 使用通用验证函数
|
||||||
|
if (!validateForm()) {
|
||||||
|
console.log('Validation failed in wxLogin');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// #ifdef H5
|
||||||
|
// H5端跳转到H5登录页面
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/login/h5-login'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
// App微信登录逻辑(暂保持原有逻辑)
|
||||||
|
uni.getProvider({
|
||||||
|
service: 'oauth',
|
||||||
|
success: (res) => {
|
||||||
|
if (~res.provider.indexOf('weixin')) {
|
||||||
|
uni.login({
|
||||||
|
provider: 'weixin',
|
||||||
|
success: (loginRes) => {
|
||||||
|
console.log('微信登录成功:', loginRes);
|
||||||
|
|
||||||
|
// 根据用户类型构建参数
|
||||||
|
const loginParams = {
|
||||||
|
code: loginRes.code,
|
||||||
|
userType: userType.value
|
||||||
|
};
|
||||||
|
// 只有单位用户才传递机构类型
|
||||||
|
if (userType.value === 0) {
|
||||||
|
loginParams.orgType = orgType.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用后端接口进行登录
|
||||||
|
$api.createRequest('/app/appLogin', loginParams, 'post').then((resData) => {
|
||||||
|
if (resData.token) {
|
||||||
|
userStore.loginSetToken(resData.token).then((resume) => {
|
||||||
|
// 更新用户类型到缓存
|
||||||
|
if (resData.isCompanyUser !== undefined) {
|
||||||
|
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||||
|
userInfo.isCompanyUser = resData.isCompanyUser ? 0 : 1;
|
||||||
|
uni.setStorageSync('userInfo', userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
// 登录成功后返回上一页
|
||||||
|
uni.navigateBack();
|
||||||
|
}).catch((error) => {
|
||||||
|
// 只有在非企业用户且确实需要简历信息时才显示错误
|
||||||
|
// 企业用户可能没有简历信息,这是正常的
|
||||||
|
if (userType.value !== 0) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '获取用户信息失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('企业用户登录成功,简历信息可能为空');
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
uni.navigateBack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('微信登录失败:', err);
|
||||||
|
uni.showToast({
|
||||||
|
title: '微信登录失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// 测试账号登录(仅开发环境)
|
||||||
|
const testLogin = () => {
|
||||||
|
// 使用通用验证函数
|
||||||
|
if (!validateForm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({ title: '登录中...' });
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
username: 'test',
|
||||||
|
password: 'test',
|
||||||
|
};
|
||||||
|
|
||||||
|
$api.createRequest('/app/login', params, 'post').then((resData) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
|
||||||
|
userStore.loginSetToken(resData.token).then((resume) => {
|
||||||
|
// 更新用户类型到缓存
|
||||||
|
if (resData.isCompanyUser !== undefined) {
|
||||||
|
const userInfo = uni.getStorageSync('userInfo') || {};
|
||||||
|
userInfo.isCompanyUser = resData.isCompanyUser ? 0 : 1;
|
||||||
|
uni.setStorageSync('userInfo', userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '测试登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
// 登录成功后返回上一页
|
||||||
|
uni.navigateBack();
|
||||||
|
}).catch((error) => {
|
||||||
|
// 只有在非企业用户且确实需要简历信息时才显示错误
|
||||||
|
// 企业用户可能没有简历信息,这是正常的
|
||||||
|
if (userType.value !== 0) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '获取用户信息失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('企业用户测试登录成功,简历信息可能为空');
|
||||||
|
uni.showToast({
|
||||||
|
title: '测试登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
uni.navigateBack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: err.msg || '登录失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面加载时获取字典数据
|
||||||
|
onLoad(() => {
|
||||||
|
getOrgTypeDict();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.wx-login-page
|
||||||
|
min-height: 100vh
|
||||||
|
background: #FFFFFF
|
||||||
|
|
||||||
|
.nav-bar
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: space-between
|
||||||
|
height: 88rpx
|
||||||
|
padding: 0 32rpx
|
||||||
|
border-bottom: 1rpx solid #f5f5f5
|
||||||
|
|
||||||
|
.nav-back
|
||||||
|
width: 60rpx
|
||||||
|
height: 60rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
|
||||||
|
.nav-title
|
||||||
|
font-size: 32rpx
|
||||||
|
font-weight: 600
|
||||||
|
color: #333333
|
||||||
|
|
||||||
|
.nav-placeholder
|
||||||
|
width: 60rpx
|
||||||
|
|
||||||
|
.page-content
|
||||||
|
padding: 40rpx 40rpx 60rpx
|
||||||
|
|
||||||
|
.auth-header
|
||||||
|
text-align: center
|
||||||
|
margin-bottom: 40rpx
|
||||||
|
|
||||||
|
.auth-logo
|
||||||
|
width: 120rpx
|
||||||
|
height: 120rpx
|
||||||
|
margin: 0 auto 24rpx
|
||||||
|
|
||||||
|
.auth-title
|
||||||
|
font-size: 36rpx
|
||||||
|
font-weight: 600
|
||||||
|
color: #333333
|
||||||
|
margin-bottom: 12rpx
|
||||||
|
|
||||||
|
.role-select
|
||||||
|
margin-bottom: 32rpx
|
||||||
|
.role-title
|
||||||
|
font-size: 28rpx
|
||||||
|
font-weight: 500
|
||||||
|
color: #333333
|
||||||
|
margin-bottom: 20rpx
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.role-options
|
||||||
|
display: flex
|
||||||
|
justify-content: space-between
|
||||||
|
gap: 20rpx
|
||||||
|
|
||||||
|
.role-item
|
||||||
|
flex: 1
|
||||||
|
background: #F7F8FA
|
||||||
|
border: 2rpx solid #E5E5E5
|
||||||
|
border-radius: 16rpx
|
||||||
|
padding: 32rpx 20rpx
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
align-items: center
|
||||||
|
position: relative
|
||||||
|
transition: all 0.3s ease
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
&.active
|
||||||
|
background: #F0F5FF
|
||||||
|
border-color: #256BFA
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(37, 107, 250, 0.15)
|
||||||
|
|
||||||
|
.role-icon
|
||||||
|
margin-bottom: 16rpx
|
||||||
|
|
||||||
|
.role-text
|
||||||
|
font-size: 28rpx
|
||||||
|
color: #333333
|
||||||
|
font-weight: 500
|
||||||
|
|
||||||
|
.org-type-select
|
||||||
|
margin-bottom: 22rpx
|
||||||
|
|
||||||
|
.org-type-title
|
||||||
|
font-size: 28rpx
|
||||||
|
font-weight: 500
|
||||||
|
color: #333333
|
||||||
|
margin-bottom: 20rpx
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.org-type-options
|
||||||
|
display: flex
|
||||||
|
flex-wrap: wrap
|
||||||
|
gap: 16rpx
|
||||||
|
|
||||||
|
.org-type-item
|
||||||
|
display:inline-block
|
||||||
|
background: #F7F8FA
|
||||||
|
border: 2rpx solid #E5E5E5
|
||||||
|
border-radius: 10rpx
|
||||||
|
padding: 10rpx 10rpx
|
||||||
|
transition: all 0.3s ease
|
||||||
|
cursor: pointer
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
&.active
|
||||||
|
background: #F0F5FF
|
||||||
|
border-color: #256BFA
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(37, 107, 250, 0.15)
|
||||||
|
|
||||||
|
.org-type-text
|
||||||
|
font-size: 22rpx
|
||||||
|
color: #333333
|
||||||
|
font-weight: 500
|
||||||
|
|
||||||
|
.auth-tips
|
||||||
|
background: #F7F8FA
|
||||||
|
border-radius: 16rpx
|
||||||
|
padding: 24rpx
|
||||||
|
margin-bottom: 40rpx
|
||||||
|
|
||||||
|
.tip-item
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
margin-bottom: 16rpx
|
||||||
|
font-size: 26rpx
|
||||||
|
color: #666666
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
margin-bottom: 0
|
||||||
|
|
||||||
|
text
|
||||||
|
margin-left: 12rpx
|
||||||
|
|
||||||
|
.auth-actions
|
||||||
|
margin-bottom: 32rpx
|
||||||
|
|
||||||
|
.auth-btn
|
||||||
|
width: 100%
|
||||||
|
height: 88rpx
|
||||||
|
border-radius: 44rpx
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
font-size: 32rpx
|
||||||
|
font-weight: 500
|
||||||
|
border: none
|
||||||
|
margin-bottom: 20rpx
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
margin-bottom: 0
|
||||||
|
|
||||||
|
&.primary
|
||||||
|
background: linear-gradient(135deg, #256BFA 0%, #1E5BFF 100%)
|
||||||
|
color: #FFFFFF
|
||||||
|
box-shadow: 0 8rpx 20rpx rgba(37, 107, 250, 0.3)
|
||||||
|
|
||||||
|
&.secondary
|
||||||
|
background: #F7F8FA
|
||||||
|
color: #666666
|
||||||
|
|
||||||
|
&:disabled
|
||||||
|
opacity: 0.5
|
||||||
|
cursor: not-allowed
|
||||||
|
background: #CCCCCC !important
|
||||||
|
box-shadow: none !important
|
||||||
|
|
||||||
|
text
|
||||||
|
margin-left: 12rpx
|
||||||
|
|
||||||
|
.auth-agreement
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
font-size: 24rpx
|
||||||
|
color: #999999
|
||||||
|
line-height: 1.6
|
||||||
|
flex-wrap: wrap
|
||||||
|
gap: 8rpx
|
||||||
|
|
||||||
|
.agreement-checkbox
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
.agreement-text
|
||||||
|
margin-left: 8rpx
|
||||||
|
color: #666666
|
||||||
|
|
||||||
|
.link
|
||||||
|
color: #256BFA
|
||||||
|
text-decoration: underline
|
||||||
|
|
||||||
|
// 按钮重置样式
|
||||||
|
button::after
|
||||||
|
border: none
|
||||||
|
</style>
|
||||||
@@ -144,10 +144,7 @@ function close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function confirm() {
|
function confirm() {
|
||||||
// 调用退出登录
|
useUserStore().logOut(false); // 不显示登录弹窗
|
||||||
useUserStore().logOut();
|
|
||||||
// 关闭弹窗
|
|
||||||
popup.value.close();
|
|
||||||
// 跳转到首页
|
// 跳转到首页
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: '/pages/index/index'
|
url: '/pages/index/index'
|
||||||
@@ -163,9 +160,9 @@ onShow(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.$on('showLoginModal', () => {
|
uni.$on('showLoginModal', () => {
|
||||||
// 这里可以显示微信登录弹窗
|
// 这里可以显示微信登录弹窗
|
||||||
// 由于这个页面没有 WxAuthLogin 组件,我们跳转到首页让首页处理
|
// 跳转到微信登录页面
|
||||||
uni.reLaunch({
|
uni.navigateTo({
|
||||||
url: '/pages/index/index'
|
url: '/pages/login/wx-login'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -175,9 +175,9 @@ onShow(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
uni.$on('showLoginModal', () => {
|
uni.$on('showLoginModal', () => {
|
||||||
// 这里可以显示微信登录弹窗
|
// 这里可以显示微信登录弹窗
|
||||||
// 由于这个页面没有 WxAuthLogin 组件,我们跳转到首页让首页处理
|
// 跳转到微信登录页面
|
||||||
uni.reLaunch({
|
uni.navigateTo({
|
||||||
url: '/pages/index/index'
|
url: '/pages/login/wx-login'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -191,7 +191,11 @@ function close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function confirm() {
|
function confirm() {
|
||||||
useUserStore().logOut();
|
useUserStore().logOut(false); // 不显示登录弹窗
|
||||||
|
// 跳转到首页
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAbove90 = (percent) => parseFloat(percent) < 90;
|
const isAbove90 = (percent) => parseFloat(percent) < 90;
|
||||||
|
|||||||
@@ -31,8 +31,7 @@
|
|||||||
<!-- 自定义tabbar -->
|
<!-- 自定义tabbar -->
|
||||||
<CustomTabBar :currentPage="3" />
|
<CustomTabBar :currentPage="3" />
|
||||||
|
|
||||||
<!-- 微信授权登录弹窗 -->
|
|
||||||
<WxAuthLogin ref="wxAuthLoginRef" @success="handleLoginSuccess"></WxAuthLogin>
|
|
||||||
|
|
||||||
<!-- 统一使用系统tabBar -->
|
<!-- 统一使用系统tabBar -->
|
||||||
</view>
|
</view>
|
||||||
@@ -46,14 +45,14 @@ import Tabbar from '@/components/tabbar/midell-box.vue';
|
|||||||
import ReadComponent from './read.vue';
|
import ReadComponent from './read.vue';
|
||||||
import UnreadComponent from './unread.vue';
|
import UnreadComponent from './unread.vue';
|
||||||
import { tabbarManager } from '@/utils/tabbarManager';
|
import { tabbarManager } from '@/utils/tabbarManager';
|
||||||
import WxAuthLogin from '@/components/WxAuthLogin/WxAuthLogin.vue';
|
|
||||||
const loadedMap = reactive([false, false]);
|
const loadedMap = reactive([false, false]);
|
||||||
const swiperRefs = [ref(null), ref(null)];
|
const swiperRefs = [ref(null), ref(null)];
|
||||||
const components = [ReadComponent, UnreadComponent];
|
const components = [ReadComponent, UnreadComponent];
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useReadMsg } from '@/stores/useReadMsg';
|
import { useReadMsg } from '@/stores/useReadMsg';
|
||||||
const { unreadCount } = storeToRefs(useReadMsg());
|
const { unreadCount } = storeToRefs(useReadMsg());
|
||||||
const wxAuthLoginRef = ref(null);
|
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 获取消息列表
|
// 获取消息列表
|
||||||
@@ -71,7 +70,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 监听退出登录事件,显示微信登录弹窗
|
// 监听退出登录事件,显示微信登录弹窗
|
||||||
uni.$on('showLoginModal', () => {
|
uni.$on('showLoginModal', () => {
|
||||||
wxAuthLoginRef.value?.open();
|
uni.navigateTo({ url: '/pages/login/wx-login' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,17 @@ const useDictStore = defineStore("dict", () => {
|
|||||||
getIndustryDict() // 获取行业
|
getIndustryDict() // 获取行业
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching dictionary data:', error);
|
console.error('Error fetching dictionary data:', error);
|
||||||
|
// 确保即使出错也能返回空数组
|
||||||
|
if (!dictType && !dictName) {
|
||||||
|
state.education = [];
|
||||||
|
state.experience = [];
|
||||||
|
state.area = [];
|
||||||
|
state.scale = [];
|
||||||
|
state.sex = [];
|
||||||
|
state.affiliation = [];
|
||||||
|
state.nature = [];
|
||||||
|
state.noticeType = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,7 +140,7 @@ const useDictStore = defineStore("dict", () => {
|
|||||||
return {
|
return {
|
||||||
label: title,
|
label: title,
|
||||||
key: key || dictType,
|
key: key || dictType,
|
||||||
options: state[dictType],
|
options: state[dictType] || [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -74,10 +74,17 @@ const useUserStore = defineStore("user", () => {
|
|||||||
uni.removeStorageSync('token')
|
uni.removeStorageSync('token')
|
||||||
uni.removeStorageSync('Padmin-Token')
|
uni.removeStorageSync('Padmin-Token')
|
||||||
// 如果需要显示登录弹窗,则通过事件通知页面显示微信登录弹窗
|
// 如果需要显示登录弹窗,则通过事件通知页面显示微信登录弹窗
|
||||||
if (showLoginModal) {
|
// if (showLoginModal) {
|
||||||
// 通过 uni.$emit 发送全局事件,通知页面显示登录弹窗
|
// // 通过 uni.$emit 发送全局事件,通知页面显示登录弹窗
|
||||||
uni.$emit('showLoginModal');
|
// uni.$emit('showLoginModal');
|
||||||
}
|
// }
|
||||||
|
//#ifdef H5
|
||||||
|
// 跳转到首页
|
||||||
|
window.location.href = 'https://www.xjksly.cn/mechine-single-vue/';
|
||||||
|
//#endif
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUserInfo = () => {
|
const getUserInfo = () => {
|
||||||
@@ -96,7 +103,13 @@ const useUserStore = defineStore("user", () => {
|
|||||||
similarityJobs.setUserInfo(resume.data)
|
similarityJobs.setUserInfo(resume.data)
|
||||||
setUserInfo(resume);
|
setUserInfo(resume);
|
||||||
reslove(resume)
|
reslove(resume)
|
||||||
}).catch(() => reject());
|
}).catch((error) => {
|
||||||
|
// 对于企业用户,简历接口可能失败,但这不应该阻止登录流程
|
||||||
|
// 记录错误但不reject,让登录流程继续
|
||||||
|
console.warn('获取简历信息失败,可能是企业用户或无简历信息:', error);
|
||||||
|
// 返回一个空的简历对象,让登录流程继续
|
||||||
|
reslove({ data: {} });
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
|
|||||||
dataId: customDataID
|
dataId: customDataID
|
||||||
};
|
};
|
||||||
if (fileUrls && fileUrls.length) {
|
if (fileUrls && fileUrls.length) {
|
||||||
params['fileUrl'] = fileUrls.map((item) => item.url);
|
params['fileUrl'] = fileUrls.map((item) => item.serverPath || item.url);
|
||||||
}
|
}
|
||||||
// ------>
|
// ------>
|
||||||
const MsgData = {
|
const MsgData = {
|
||||||
@@ -335,6 +335,72 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除消息
|
||||||
|
async function deleteMessages(indices) {
|
||||||
|
// 按索引从大到小排序,避免删除时索引变化
|
||||||
|
const sortedIndices = [...indices].sort((a, b) => b - a);
|
||||||
|
|
||||||
|
// 从内存中删除消息
|
||||||
|
for (const index of sortedIndices) {
|
||||||
|
const message = messages.value[index];
|
||||||
|
if (message && message.id) {
|
||||||
|
// 从本地数据库中删除
|
||||||
|
await baseDB.db.delete(massageName.value, message.id);
|
||||||
|
}
|
||||||
|
messages.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除会话
|
||||||
|
async function deleteDialogue(sessionId) {
|
||||||
|
if (!baseDB.isDBReady) await baseDB.initDB();
|
||||||
|
|
||||||
|
// 删除会话下的所有消息
|
||||||
|
const messageList = await baseDB.db.queryByField(massageName.value, 'parentGroupId', sessionId);
|
||||||
|
for (const message of messageList) {
|
||||||
|
if (message.id) {
|
||||||
|
await baseDB.db.delete(massageName.value, message.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除会话本身
|
||||||
|
const sessionList = await baseDB.db.queryByField(tableName.value, 'sessionId', sessionId);
|
||||||
|
for (const session of sessionList) {
|
||||||
|
if (session.id) {
|
||||||
|
await baseDB.db.delete(tableName.value, session.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新获取所有会话并重新分组
|
||||||
|
const allSessions = await baseDB.db.getAll(tableName.value);
|
||||||
|
if (allSessions.length) {
|
||||||
|
const [result, lastData] = insertSortData(allSessions);
|
||||||
|
tabeList.value = result;
|
||||||
|
} else {
|
||||||
|
tabeList.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果删除的是当前会话,切换到第一个会话或清空
|
||||||
|
if (chatSessionID.value === sessionId) {
|
||||||
|
if (tabeList.value.length > 0) {
|
||||||
|
// 找到第一个非标题的会话
|
||||||
|
const firstSession = tabeList.value.find(item => !item.isTitle);
|
||||||
|
if (firstSession) {
|
||||||
|
chatSessionID.value = firstSession.sessionId;
|
||||||
|
await initMessage(firstSession.sessionId);
|
||||||
|
} else {
|
||||||
|
// 没有会话了
|
||||||
|
chatSessionID.value = '';
|
||||||
|
messages.value = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 没有会话了
|
||||||
|
chatSessionID.value = '';
|
||||||
|
messages.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
messages,
|
messages,
|
||||||
isTyping,
|
isTyping,
|
||||||
@@ -348,7 +414,9 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
|
|||||||
changeDialogue,
|
changeDialogue,
|
||||||
getStearm,
|
getStearm,
|
||||||
getHistory,
|
getHistory,
|
||||||
badFeedback
|
badFeedback,
|
||||||
|
deleteMessages,
|
||||||
|
deleteDialogue
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
list: this.value ? this.value : [],
|
list: this.value ? this.value : [],
|
||||||
column: this.column < 2 ? 2 : this.column,
|
column: this.column < 1 ? 1 : this.column,
|
||||||
columnSpace: this.columnSpace <= 5 ? this.columnSpace : 5,
|
columnSpace: this.columnSpace <= 5 ? this.columnSpace : 5,
|
||||||
imageKey: this.imageKey,
|
imageKey: this.imageKey,
|
||||||
seat: this.seat,
|
seat: this.seat,
|
||||||
@@ -179,7 +179,7 @@ export default {
|
|||||||
this.isRefresh = true;
|
this.isRefresh = true;
|
||||||
this.adds = [];
|
this.adds = [];
|
||||||
this.data.list = this.value ? this.value : [];
|
this.data.list = this.value ? this.value : [];
|
||||||
this.data.column = this.column < 2 ? 2 : this.column >= this.maxColumn ? this.maxColumn : this.column;
|
this.data.column = this.column < 1 ? 1 : this.column >= this.maxColumn ? this.maxColumn : this.column;
|
||||||
this.data.columnSpace = this.columnSpace <= 5 ? this.columnSpace : 5;
|
this.data.columnSpace = this.columnSpace <= 5 ? this.columnSpace : 5;
|
||||||
this.data.imageKey = this.imageKey;
|
this.data.imageKey = this.imageKey;
|
||||||
this.data.seat = this.seat;
|
this.data.seat = this.seat;
|
||||||
|
|||||||
@@ -44,22 +44,11 @@ export function navigateToLoginPage(options = {}) {
|
|||||||
|
|
||||||
switch (platform) {
|
switch (platform) {
|
||||||
case 'mp-weixin':
|
case 'mp-weixin':
|
||||||
// 小程序端使用微信授权登录,直接显示微信授权弹窗
|
|
||||||
uni.$emit('showLoginModal', { loginType: 'wechat' });
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 'h5':
|
|
||||||
uni.showToast({
|
|
||||||
title: '请先登录',
|
|
||||||
icon: 'none',
|
|
||||||
duration: 2000
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 'app':
|
case 'app':
|
||||||
// App端使用微信授权登录
|
case 'h5':
|
||||||
uni.$emit('showLoginModal', { loginType: 'wechat' });
|
// 跳转到微信登录页面
|
||||||
return;
|
loginPage = '/pages/login/wx-login';
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
loginPage = '/pages/login/h5-login';
|
loginPage = '/pages/login/h5-login';
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ export function uploadFile(tempFilePaths, loading = false) {
|
|||||||
header["Authorization"] = encodeURIComponent(Authorization);
|
header["Authorization"] = encodeURIComponent(Authorization);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
uni.uploadFile({
|
uni.uploadFile({
|
||||||
url: config.baseUrl + '/app/file/upload',
|
url: config.baseUrl + '/app/file/uploadFile',
|
||||||
filePath: tempFilePaths,
|
filePath: tempFilePaths,
|
||||||
name: 'file',
|
name: 'file',
|
||||||
header,
|
header,
|
||||||
|
|||||||
Reference in New Issue
Block a user