Merge branch 'main' into bin

This commit is contained in:
Apcallover
2025-11-27 09:08:22 +08:00
20 changed files with 754 additions and 324 deletions

View File

@@ -46,10 +46,10 @@
<view class="card-companyName">{{ job.companyName }}</view> <view class="card-companyName">{{ job.companyName }}</view>
<view class="card-tags"> <view class="card-tags">
<view class="tag"> <view class="tag">
<dict-Label dictType="education" :value="job.education"></dict-Label> {{job.education == '不限' ? '学历不限' : job.education}}
</view> </view>
<view class="tag"> <view class="tag">
<dict-Label dictType="experience" :value="job.experience"></dict-Label> {{job.experience == '不限' ? '经验不限' : job.experience}}
</view> </view>
<view class="tag"> <view class="tag">
{{ vacanciesTo(job.vacancies) }} {{ vacanciesTo(job.vacancies) }}
@@ -129,7 +129,7 @@ function parseDateTime(datetimeStr) {
} }
function nextDetail(job) { function nextDetail(job) {
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`); navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}&dataType=${job.dataType}`);
} }
</script> </script>

View File

@@ -2,10 +2,7 @@ export default {
// baseUrl: 'https://fw.rc.qingdao.gov.cn/rgpp-api/api', // 内网 // baseUrl: 'https://fw.rc.qingdao.gov.cn/rgpp-api/api', // 内网
baseUrl: 'https://qd.zhaopinzao8dian.com/api', // 测试 baseUrl: 'https://qd.zhaopinzao8dian.com/api', // 测试
// baseUrl: 'http://192.168.3.29:8081', // baseUrl: 'http://192.168.3.29:8081',
// sseAI+ // baseUrl: 'http://10.213.6.207:19010/api',
// StreamBaseURl: 'http://39.98.44.136:8000',
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
// StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai/test',
// 语音转文字 // 语音转文字
// vioceBaseURl: 'ws://39.98.44.136:8080/speech-recognition', // vioceBaseURl: 'ws://39.98.44.136:8080/speech-recognition',
vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/speech-recognition', vioceBaseURl: 'wss://qd.zhaopinzao8dian.com/api/speech-recognition',

View File

@@ -20,6 +20,7 @@ import renderCompanyCollectionRecord from '@/components/renderCompanyCollectionR
import renderJobViewRecord from '@/components/renderJobViewRecord/renderJobViewRecord.vue'; import renderJobViewRecord from '@/components/renderJobViewRecord/renderJobViewRecord.vue';
// import Tabbar from '@/components/tabbar/midell-box.vue' // import Tabbar from '@/components/tabbar/midell-box.vue'
// 自动导入 directives 目录下所有指令 // 自动导入 directives 目录下所有指令
console.log(lightAppJssdk)
const directives = import.meta.glob('./directives/*.js', { const directives = import.meta.glob('./directives/*.js', {
eager: true eager: true
}); });

View File

@@ -41,8 +41,6 @@ onReachBottom(() => {
getJobList(); getJobList();
}); });
function getJobList(type = 'add') { function getJobList(type = 'add') {
if (type === 'refresh') { if (type === 'refresh') {
pageState.page = 1; pageState.page = 1;

View File

@@ -24,7 +24,6 @@
</view> </view>
<scroll-view scroll-y class="main-scroll" @scrolltolower="getJobList('add')"> <scroll-view scroll-y class="main-scroll" @scrolltolower="getJobList('add')">
<view class="one-cards"> <view class="one-cards">
<view class="mian">
<renderJobViewRecord <renderJobViewRecord
:list="pageState.list" :list="pageState.list"
v-if="pageState.list.length" v-if="pageState.list.length"
@@ -33,7 +32,7 @@
></renderJobViewRecord> ></renderJobViewRecord>
<empty v-else pdTop="200"></empty> <empty v-else pdTop="200"></empty>
<!-- <loadmore ref="loadmoreRef"></loadmore> --> <!-- <loadmore ref="loadmoreRef"></loadmore> -->
</view>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>

View File

@@ -11,21 +11,31 @@
<view class="button-click" :class="{ active: type === 1 }" @click="changeType(1)">公司企业</view> <view class="button-click" :class="{ active: type === 1 }" @click="changeType(1)">公司企业</view>
</view> </view>
<view class="coll-main"> <view class="coll-main">
<swiper class="swiper" :current="type" @change="changeSwiperType"> <swiper class="swiper" :disable-touch="disableTouch" :current="type" @change="changeSwiperType">
<swiper-item class="list"> <swiper-item
class="list"
@touchstart.passive="handleTouchStart"
@touchmove.passive="handleTouchMove"
@touchend="disableTouch = false"
>
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower"> <scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower">
<view class="mian"> <view class="mian">
<renderJobCollectionRecord <renderJobCollectionRecord
v-if="pageState.list.length" v-if="pageState.list.length"
:list="pageState.list" :list="pageState.list"
:longitude="longitudeVal" :longitude="longitudeVal"
:latitude="latitudeVal"> :latitude="latitudeVal"
</renderJobCollectionRecord> ></renderJobCollectionRecord>
<empty v-else pdTop="200"></empty> <empty v-else pdTop="200"></empty>
</view> </view>
</scroll-view> </scroll-view>
</swiper-item> </swiper-item>
<swiper-item class="list"> <swiper-item
class="list"
@touchstart.passive="handleTouchStart"
@touchmove.passive="handleTouchMove"
@touchend="disableTouch = false"
>
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLowerCompany"> <scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLowerCompany">
<view class="mian"> <view class="mian">
<renderCompanyCollectionRecord <renderCompanyCollectionRecord
@@ -69,14 +79,79 @@ const pageCompanyState = reactive({
pageSize: 10, pageSize: 10,
}); });
const disableTouch = ref(false);
const startPointX = ref(0);
const totalPage = 2;
const THRESHOLD = 5;
onShow(() => { onShow(() => {
getJobList(); getJobList();
getCompanyList(); getCompanyList();
}); });
function handleTouchStart(e) {
// 确保有触摸点
if (e.touches.length > 0) {
startPointX.value = e.touches[0].clientX;
disableTouch.value = false;
}
}
function handleTouchMove(e) {
if (e.touches.length === 0) return;
const currentX = e.touches[0].clientX;
const diffX = currentX - startPointX.value;
if (type.value === 0) {
if (diffX > THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
if (type.value === totalPage - 1) {
if (diffX < -THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
disableTouch.value = false;
}
function changeSwiperType(e) { function changeSwiperType(e) {
const newIndex = e.detail.current;
const lastIndex = type.value;
const isSwipingRight = newIndex < lastIndex;
const isSwipingLeft = newIndex > lastIndex;
if (lastIndex === 0 && isSwipingRight) {
disableTouch.value = true;
type.value = 0;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
if (lastIndex === totalPage - 1 && isSwipingLeft) {
disableTouch.value = true;
type.value = lastIndex;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
const current = e.detail.current; const current = e.detail.current;
type.value = current; type.value = current;
disableTouch.value = false;
} }
function changeType(e) { function changeType(e) {

View File

@@ -11,9 +11,9 @@
<image src="@/static/icon/companyIcon.png" mode=""></image> <image src="@/static/icon/companyIcon.png" mode=""></image>
</view> </view>
<view class="companyinfo-right"> <view class="companyinfo-right">
<view class="row1 line_2">{{ fairInfo?.zphmc }}</view> <view class="row1 line_2" @tap="$api.copyText(fairInfo.zphmc)">{{ fairInfo?.zphmc }}</view>
<view class="row2"> <view class="row2">
<text>{{ fairInfo.jbf }}</text> <text @tap="$api.copyText(fairInfo.jbf)">{{ fairInfo.jbf }}</text>
<!-- <convert-distance <!-- <convert-distance
:alat="fairInfo.latitude" :alat="fairInfo.latitude"
:along="fairInfo.longitude" :along="fairInfo.longitude"
@@ -27,7 +27,9 @@
<image class="location-img" src="/static/icon/mapLine.png"></image> <image class="location-img" src="/static/icon/mapLine.png"></image>
<view class="location-info"> <view class="location-info">
<view class="info"> <view class="info">
<text class="info-title">{{ fairInfo.zphdz }}</text> <text class="info-title line_1" @tap="$api.copyText(fairInfo.zphdz)">
{{ fairInfo.zphdz }}
</text>
<!-- <text class="info-text">位置</text> --> <!-- <text class="info-text">位置</text> -->
</view> </view>
</view> </view>
@@ -122,11 +124,11 @@ const pageState = reactive({
const hasnext = ref(true); const hasnext = ref(true);
const zphId = ref(''); const zphId = ref('');
const pageOptions = ref({}) const pageOptions = ref({});
onLoad((options) => { onLoad((options) => {
zphId.value = options.jobFairId zphId.value = options.jobFairId;
pageOptions.value = options pageOptions.value = options;
getJobFairInfo(options.jobFairId, options.jobFairName); getJobFairInfo(options.jobFairId, options.jobFairName);
getCompanyList('refresh'); getCompanyList('refresh');
}); });
@@ -138,7 +140,7 @@ function getJobFairInfo(id,name) {
}); });
} }
function getCompanyList(type = 'add') { function getCompanyList(type = 'add') {
const { jobFairId,jobFairName} = pageOptions.value const { jobFairId, jobFairName } = pageOptions.value;
if (type === 'refresh') { if (type === 'refresh') {
pageState.current = 1; pageState.current = 1;
pageState.maxPage = 1; pageState.maxPage = 1;
@@ -150,7 +152,8 @@ function getCompanyList(type='add') {
current: pageState.current, current: pageState.current,
pageSize: pageState.pageSize, pageSize: pageState.pageSize,
}; };
$api.createRequest(`/app/internal/companyThirdPart/?zphID=${jobFairId}&zphmc=${jobFairName}`,params ).then((resData) => { $api.createRequest(`/app/internal/companyThirdPart/?zphID=${jobFairId}&zphmc=${jobFairName}`, params).then(
(resData) => {
const { rows, total } = resData; const { rows, total } = resData;
if (type === 'add') { if (type === 'add') {
const str = pageState.pageSize * (pageState.current - 1); const str = pageState.pageSize * (pageState.current - 1);
@@ -162,12 +165,13 @@ function getCompanyList(type='add') {
} }
pageState.total = resData.total; pageState.total = resData.total;
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize); pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
}); }
);
} }
const hasAppointment = () => { const hasAppointment = () => {
const isTimePassed = (timeStr) => { const isTimePassed = (timeStr) => {
if(!timeStr) return false if (!timeStr) return false;
const targetTime = new Date(timeStr.replace(/-/g, '/')).getTime(); // 兼容格式 const targetTime = new Date(timeStr.replace(/-/g, '/')).getTime(); // 兼容格式
const now = Date.now(); const now = Date.now();
return now < targetTime; return now < targetTime;

View File

@@ -5,23 +5,33 @@
<image src="@/static/icon/back-white.png" @click="navBack"></image> <image src="@/static/icon/back-white.png" @click="navBack"></image>
</view> </view>
</template> </template>
<view v-if="userInfo.resumeOcrStatus && showNotice" class="notice-line" :class="userInfo.resumeOcrStatus?.includes('成功')?'green':'blue'"> <view
<image v-if="userInfo.resumeOcrStatus?.includes('成功')" class="icon" src="@/static/icon/notice-green.png" /> v-if="userInfo.resumeOcrStatus && showNotice"
class="notice-line"
:class="userInfo.resumeOcrStatus?.includes('成功') ? 'green' : 'blue'"
>
<image
v-if="userInfo.resumeOcrStatus?.includes('成功')"
class="icon"
src="@/static/icon/notice-green.png"
/>
<image v-else class="icon" src="@/static/icon/notice-blue.png" /> <image v-else class="icon" src="@/static/icon/notice-blue.png" />
<view class="text">{{ userInfo.resumeOcrStatus }}</view> <view class="text">{{ userInfo.resumeOcrStatus }}</view>
<image @click="closeNotice" v-if="userInfo.resumeOcrStatus?.includes('成功')" class="close" src="@/static/icon/close-green.png" /> <image
@click="closeNotice"
v-if="userInfo.resumeOcrStatus?.includes('成功')"
class="close"
src="@/static/icon/close-green.png"
/>
<image @click="closeNotice" v-else class="close" src="@/static/icon/close-blue.png" /> <image @click="closeNotice" v-else class="close" src="@/static/icon/close-blue.png" />
</view> </view>
<view class="mys-container"> <view class="mys-container">
<!-- 个人信息 --> <!-- 个人信息 -->
<view <view class="card-top" style="margin-top: 12rpx; padding: 0; background: none">
class="card-top" <view class="mys-tops">
style="margin-top: 12rpx; padding: 0; background: none"
>
<view class="mys-tops btn-feel">
<view class="tops-left"> <view class="tops-left">
<view class="name"> <view class="name">
<text>{{ userInfo.name || "编辑用户名" }}</text> <text>{{ userInfo.name || '编辑用户名' }}</text>
<view class="edit-icon mar_le10"> <view class="edit-icon mar_le10">
<image <image
class="button-click" class="button-click"
@@ -31,17 +41,9 @@
</view> </view>
</view> </view>
<view class="subName"> <view class="subName">
<dict-Label <dict-Label class="mar_ri10" dictType="sex" :value="userInfo.sex"></dict-Label>
class="mar_ri10"
dictType="sex"
:value="userInfo.sex"
></dict-Label>
<text class="mar_ri10">{{ userInfo.age }}</text> <text class="mar_ri10">{{ userInfo.age }}</text>
<dict-Label <dict-Label class="mar_ri10" dictType="education" :value="userInfo.education"></dict-Label>
class="mar_ri10"
dictType="education"
:value="userInfo.education"
></dict-Label>
<dict-Label <dict-Label
class="mar_ri10" class="mar_ri10"
dictType="affiliation" dictType="affiliation"
@@ -53,17 +55,11 @@
<view class="tops-right"> <view class="tops-right">
<view class="right-imghead"> <view class="right-imghead">
<image v-if="userInfo.avatar" :src="userInfo.avatar"></image> <image v-if="userInfo.avatar" :src="userInfo.avatar"></image>
<image <image v-else-if="userInfo.sex == '0'" src="@/static/icon/boy.png"></image>
v-else-if="userInfo.sex == '0'"
src="@/static/icon/boy.png"
></image>
<image v-else src="@/static/icon/girl.png"></image> <image v-else src="@/static/icon/girl.png"></image>
</view> </view>
<view class="right-sex"> <view class="right-sex">
<image <image v-if="userInfo.sex === '0'" src="@/static/icon/boy1.png"></image>
v-if="userInfo.sex === '0'"
src="@/static/icon/boy1.png"
></image>
<image v-else src="@/static/icon/girl1.png"></image> <image v-else src="@/static/icon/girl1.png"></image>
</view> </view>
</view> </view>
@@ -72,7 +68,7 @@
<view class="mys-line"> <view class="mys-line">
<view class="line"></view> <view class="line"></view>
</view> </view>
<view class="mys-info btn-feel"> <view class="mys-info">
<view class="mys-h4"> <view class="mys-h4">
<view>求职期望</view> <view>求职期望</view>
<image <image
@@ -83,26 +79,15 @@
</view> </view>
<view class="mys-text"> <view class="mys-text">
<text>期望薪资</text> <text>期望薪资</text>
<text <text>{{ userInfo.salaryMin / 1000 }}k-{{ userInfo.salaryMax / 1000 }}k</text>
>{{ userInfo.salaryMin / 1000 }}k-{{
userInfo.salaryMax / 1000
}}k</text
>
</view> </view>
<view class="mys-text"> <view class="mys-text">
<text>期望工作地</text> <text>期望工作地</text>
<text>青岛市-</text> <text>青岛市-</text>
<dict-Label <dict-Label dictType="area" :value="Number(userInfo.area)"></dict-Label>
dictType="area"
:value="Number(userInfo.area)"
></dict-Label>
</view> </view>
<view class="mys-list"> <view class="mys-list">
<view <view class="cards button-click" v-for="(title, index) in userInfo.jobTitle" :key="index">
class="cards button-click"
v-for="(title, index) in userInfo.jobTitle"
:key="index"
>
{{ title }} {{ title }}
</view> </view>
</view> </view>
@@ -110,24 +95,14 @@
</view> </view>
<view class="card-top" style="margin-top: 24rpx"> <view class="card-top" style="margin-top: 24rpx">
<view class="mys-info" style="padding: 0"> <view class="mys-info" style="padding: 0">
<view class="mys-h4 btn-feel"> <view class="mys-h4">
<text>工作经历</text> <text>工作经历</text>
<view <view class="mys-edit-icon btn-tada" @click="navTo('/packageA/pages/workExp/workExp')">
class="mys-edit-icon btn-feel" <image class="icon button-click btn-feel" src="@/static/icon/plus.png"></image>
@click="navTo('/packageA/pages/workExp/workExp')"
>
<image
class="icon button-click btn-feel"
src="@/static/icon/plus.png"
></image>
<view class="txt">添加</view> <view class="txt">添加</view>
</view> </view>
</view> </view>
<view <view class="exp-item button-click" v-for="item in userInfo.workExp" :key="item.id">
class="exp-item btn-feel"
v-for="item in userInfo.workExp"
:key="item.id"
>
<view class="fl_box fl_justbet mar_top15"> <view class="fl_box fl_justbet mar_top15">
<view class="fs_16">{{ item.company }}</view> <view class="fs_16">{{ item.company }}</view>
<image <image
@@ -138,9 +113,7 @@
</view> </view>
<view class="mys-text fl_box fl_justbet"> <view class="mys-text fl_box fl_justbet">
<text class="color_333333 fs_14">{{ item.position }}</text> <text class="color_333333 fs_14">{{ item.position }}</text>
<text class="datetext" <text class="datetext">{{ item.startTime }}--{{ item.endTime || '至今' }}</text>
>{{ item.startTime }}--{{ item.endTime || "至今" }}</text
>
</view> </view>
<view class="mys-text"> <view class="mys-text">
<text>{{ item.duty }}</text> <text>{{ item.duty }}</text>
@@ -151,49 +124,47 @@
</view> </view>
<template #footer> <template #footer>
<view class="footer-container"> <view class="footer-container">
<view class="footer-button btn-feel" @click="chooseResume" <view class="footer-button btn-feel" @click="chooseResume">上传简历</view>
>上传简历</view
>
</view> </view>
</template> </template>
</AppLayout> </AppLayout>
</template> </template>
<script setup> <script setup>
import { reactive, inject, watch, ref, onMounted, computed } from "vue"; import { reactive, inject, watch, ref, onMounted, computed } from 'vue';
const { $api, navTo, navBack } = inject("globalFunction"); const { $api, navTo, navBack } = inject('globalFunction');
import { onLoad, onShow } from "@dcloudio/uni-app"; import { onLoad, onShow } from '@dcloudio/uni-app';
import { storeToRefs } from "pinia"; import { storeToRefs } from 'pinia';
import useUserStore from "@/stores/useUserStore"; import useUserStore from '@/stores/useUserStore';
import useDictStore from "@/stores/useDictStore"; import useDictStore from '@/stores/useDictStore';
const { userInfo } = storeToRefs(useUserStore()); const { userInfo } = storeToRefs(useUserStore());
const { getUserResume } = useUserStore(); const { getUserResume } = useUserStore();
const { getDictData, oneDictData } = useDictStore(); const { getDictData, oneDictData } = useDictStore();
import config from "@/config.js"; import config from '@/config.js';
const showNotice = ref(true) const showNotice = ref(true);
onLoad(() => { onLoad(() => {
getUserResume(); getUserResume();
}); });
function closeNotice() { function closeNotice() {
showNotice.value=false showNotice.value = false;
} }
function chooseResume() { function chooseResume() {
uni.chooseImage({ uni.chooseImage({
sizeType: ["original", "compressed"], sizeType: ['original', 'compressed'],
sourceType: ["album", "camera"], sourceType: ['album', 'camera'],
count: 1, count: 1,
success: ({ tempFilePaths, tempFiles }) => { success: ({ tempFilePaths, tempFiles }) => {
uploadResume(tempFilePaths[0], true) uploadResume(tempFilePaths[0], true)
.then((res) => { .then((res) => {
res = JSON.parse(res); res = JSON.parse(res);
getUserResume(); getUserResume();
$api.msg("上传成功"); $api.msg('上传成功');
}) })
.catch((err) => { .catch((err) => {
$api.msg("上传失败"); $api.msg('上传失败');
}); });
}, },
fail: (error) => {}, fail: (error) => {},
@@ -203,21 +174,21 @@ function chooseResume() {
function uploadResume(tempFilePath, loading) { function uploadResume(tempFilePath, loading) {
if (loading) { if (loading) {
uni.showLoading({ uni.showLoading({
title: "请稍后", title: '请稍后',
mask: true, mask: true,
}); });
} }
let Authorization = ""; let Authorization = '';
if (useUserStore().token) { if (useUserStore().token) {
Authorization = `${useUserStore().token}`; Authorization = `${useUserStore().token}`;
} }
const header = {}; const header = {};
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/oss/uploadToObs", url: config.baseUrl + '/app/oss/uploadToObs',
filePath: tempFilePath, filePath: tempFilePath,
name: "file", name: 'file',
header, header,
success: (uploadFileRes) => { success: (uploadFileRes) => {
if (uploadFileRes.statusCode === 200) { if (uploadFileRes.statusCode === 200) {

View File

@@ -9,8 +9,8 @@
width: isFullScreen ? '100%' : videoWidth + 'rpx', width: isFullScreen ? '100%' : videoWidth + 'rpx',
height: isFullScreen ? '100vh' : videoHeight + 'rpx', height: isFullScreen ? '100vh' : videoHeight + 'rpx',
}" }"
@touchstart="handleTouchStart" @touchstart.passive="handleTouchStart"
@touchmove="handleTouchMove" @touchmove.passive="handleTouchMove"
@touchend="handleTouchEnd" @touchend="handleTouchEnd"
@touchmove.stop.prevent @touchmove.stop.prevent
> >

View File

@@ -162,8 +162,13 @@
<template #footer> <template #footer>
<view class="footer"> <view class="footer">
<view class="btn-wq button-click" @click="jobApply"> <view v-if="dataType==2" class="btn-wq button-click" :class="{'btn-des' : jobInfo.isApply}" @click="jobApply">
{{ dataType === 2 ? '立即投递' : '立即前往' }} <span v-if="jobInfo.isApply"> 已投递 </span>
<span v-if="!jobInfo.isApply"> 立即投递</span>
</view>
<view v-else class="btn-wq button-click" @click="jobApply">
<span v-if="jobInfo.isApply"> 立即前往</span>
<span v-if="!jobInfo.isApply">立即投递 </span>
</view> </view>
</view> </view>
</template> </template>
@@ -308,19 +313,18 @@ function getCompetivetuveness(jobId) {
// 申请岗位 // 申请岗位
function jobApply() { function jobApply() {
if (dataType.value === 2) { if (dataType.value === 2) {
$api.msg('敬请期待');
return
// 第三方数据申请逻辑 // 第三方数据申请逻辑
const jobId = jobInfo.value.id; const params = {
jobid:jobInfo.value.id,
jobname:jobInfo.value.gwmc
}
if (jobInfo.value.isApply) { if (jobInfo.value.isApply) {
const jobUrl = jobInfo.value.jobUrl; $api.msg('已经投递过该岗位了~');
return window.open(jobUrl); return ;
} else { } else {
$api.createRequest(`/app/job/apply/${jobId}`, {}, 'GET').then((resData) => { $api.createRequest(`/app/internal/sendResume`, params, 'POST').then((resData) => {
getDetail(jobIdRef.value);
$api.msg('投递成功'); $api.msg('投递成功');
const jobUrl = jobInfo.value.jobUrl; getDetail(jobIdRef.value);
return window.open(jobUrl);
}); });
} }
} else { } else {
@@ -651,5 +655,9 @@ for i in 0..100
text-align: center; text-align: center;
line-height: 90rpx line-height: 90rpx
} }
.btn-des{
background: #6697FB;
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11,44,112,0.12);
}
} }
</style> </style>

View File

@@ -259,8 +259,8 @@ function getHoursBetween(startTimeStr, endTimeStr) {
const selectDate = (item) => { const selectDate = (item) => {
if (currentDay.value?.fullDate === item.fullDate) { if (currentDay.value?.fullDate === item.fullDate) {
currentDay.value = {}; // currentDay.value = {};
getFair('refresh'); // getFair('refresh');
return; return;
} }
currentDay.value = item; currentDay.value = item;

View File

@@ -148,7 +148,7 @@
<view <view
class="input_vio" class="input_vio"
@touchstart.prevent="handleTouchStart" @touchstart.prevent="handleTouchStart"
@touchmove="handleTouchMove" @touchmove.passive="handleTouchMove"
@touchend="handleTouchEnd" @touchend="handleTouchEnd"
@touchcancel="handleTouchCancel" @touchcancel="handleTouchCancel"
:catchtouchstart="true" :catchtouchstart="true"

View File

@@ -3,8 +3,21 @@
<view class="app-container"> <view class="app-container">
<!-- 主体内容区域 --> <!-- 主体内容区域 -->
<view class="container-main"> <view class="container-main">
<swiper class="swiper" :current="state.current" @change="changeSwiperType"> <swiper
<swiper-item class="swiper-item" v-for="(_, index) in 2" :key="index"> class="swiper"
:disable-touch="disableTouch"
:current="state.current"
@change="changeSwiperType"
>
<!-- 绑定首页和尾页 -->
<swiper-item
@touchstart.passive="handleTouchStart"
@touchmove.passive="handleTouchMove"
@touchend="disableTouch = false"
class="swiper-item"
v-for="(_, index) in 2"
:key="index"
>
<!-- #ifndef MP-WEIXIN --> <!-- #ifndef MP-WEIXIN -->
<component <component
:is="components[index]" :is="components[index]"
@@ -60,6 +73,11 @@ const { unreadCount } = storeToRefs(useReadMsg());
const showTabbar = ref(true); const showTabbar = ref(true);
const maskFristEntry = ref(false); const maskFristEntry = ref(false);
const disableTouch = ref(false);
const startPointX = ref(0);
const totalPage = 2;
const THRESHOLD = 5;
onLoad(() => { onLoad(() => {
// 判断浏览器是否有 fristEntry 第一次进入 // 判断浏览器是否有 fristEntry 第一次进入
let fristEntry = uni.getStorageSync('fristEntry') === false ? false : true; // 默认未读 let fristEntry = uni.getStorageSync('fristEntry') === false ? false : true; // 默认未读
@@ -87,15 +105,69 @@ const handelComponentsRef = (el, index) => {
} }
}; };
function handleTouchStart(e) {
startPointX.value = e.touches[0].clientX;
disableTouch.value = false;
}
function handleTouchMove(e) {
const currentX = e.touches[0].clientX;
const diffX = currentX - startPointX.value;
if (state.current === 0) {
if (diffX > THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
if (state.current === totalPage - 1) {
if (diffX < -THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
disableTouch.value = false;
}
function changeShowTabbar(val) { function changeShowTabbar(val) {
showTabbar.value = val; showTabbar.value = val;
} }
//1 查看消息类型 //1 查看消息类型
function changeSwiperType(e) { function changeSwiperType(e) {
const newIndex = e.detail.current;
const lastIndex = state.current;
const isSwipingRight = newIndex < lastIndex;
const isSwipingLeft = newIndex > lastIndex;
if (lastIndex === 0 && isSwipingRight) {
disableTouch.value = true;
state.current = 0;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
if (lastIndex === totalPage - 1 && isSwipingLeft) {
disableTouch.value = true;
state.current = lastIndex;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
const index = e.detail.current; const index = e.detail.current;
state.current = index; state.current = index;
handleTabChange(index); handleTabChange(index);
disableTouch.value = false;
} }
function changeType(index) { function changeType(index) {
state.current = index; state.current = index;

View File

@@ -109,7 +109,9 @@
</template> </template>
</tabcontrolVue> </tabcontrolVue>
<SelectJobs ref="selectJobsModel"></SelectJobs> <SelectJobs ref="selectJobsModel"></SelectJobs>
<view class="backdoor" @click="loginbackdoor">后门</view> <view class="backdoor" @click="loginbackdoor">
<uni-icons type="gift-filled" size="30"></uni-icons>
</view>
</AppLayout> </AppLayout>
</template> </template>
@@ -310,8 +312,7 @@ function complete() {
.backdoor{ .backdoor{
position: fixed; position: fixed;
left: 0; left: 0;
top: 500rpx; bottom: 200rpx;
background: red
} }
.input-nx .input-nx
position: relative position: relative
@@ -425,6 +426,7 @@ function complete() {
font-size: 28rpx; font-size: 28rpx;
color: #6A6A6A; color: #6A6A6A;
.input-con .input-con
pointer-events: none;
font-weight: 400; font-weight: 400;
font-size: 32rpx; font-size: 32rpx;
color: #333333; color: #333333;

View File

@@ -49,7 +49,7 @@
</view> </view>
<view class="card-main"> <view class="card-main">
<view class="main-title">服务专区</view> <view class="main-title">服务专区</view>
<view class="main-row btn-feel"> <view class="main-row btn-feel" @click="selectFile">
<view class="row-left"> <view class="row-left">
<image class="left-img" src="@/static/icon/server1.png"></image> <image class="left-img" src="@/static/icon/server1.png"></image>
<text class="left-text">实名认证</text> <text class="left-text">实名认证</text>
@@ -106,6 +106,7 @@ import { reactive, inject, watch, ref, onMounted } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import Tabbar from '@/components/tabbar/midell-box.vue'; import Tabbar from '@/components/tabbar/midell-box.vue';
import { onLoad, onShow } from '@dcloudio/uni-app'; import { onLoad, onShow } from '@dcloudio/uni-app';
import FileUploader from '@/utils/FileUploader.js';
const { $api, navTo } = inject('globalFunction'); const { $api, navTo } = inject('globalFunction');
import useUserStore from '@/stores/useUserStore'; import useUserStore from '@/stores/useUserStore';
const popup = ref(null); const popup = ref(null);
@@ -133,6 +134,15 @@ function getUserstatistics() {
counts.value = resData.data; counts.value = resData.data;
}); });
} }
function selectFile() {
// FileUploader.showMenuAndUpload({
// success: function (res) {
// alert('上传成功: ' + JSON.stringify(res));
// },
// });
}
function chooseFileUploadTest(pam) {}
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>

View File

@@ -15,8 +15,20 @@
<!-- 主体内容区域 --> <!-- 主体内容区域 -->
<view class="container-main"> <view class="container-main">
<swiper class="swiper" :current="state.current" @change="changeSwiperType"> <swiper
<swiper-item class="swiper-item" v-for="(_, index) in 2" :key="index"> class="swiper"
:disable-touch="disableTouch"
:current="state.current"
@change="changeSwiperType"
>
<swiper-item
class="swiper-item"
@touchstart.passive="handleTouchStart"
@touchmove.passive="handleTouchMove"
@touchend="disableTouch = false"
v-for="(_, index) in 2"
:key="index"
>
<!-- #ifndef MP-WEIXIN --> <!-- #ifndef MP-WEIXIN -->
<component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" /> <component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" />
<!-- #endif --> <!-- #endif -->
@@ -46,6 +58,11 @@ import { storeToRefs } from 'pinia';
import { useReadMsg } from '@/stores/useReadMsg'; import { useReadMsg } from '@/stores/useReadMsg';
const { unreadCount } = storeToRefs(useReadMsg()); const { unreadCount } = storeToRefs(useReadMsg());
const disableTouch = ref(false);
const startPointX = ref(0);
const totalPage = 2;
const THRESHOLD = 5;
onShow(() => { onShow(() => {
// 获取消息列表 // 获取消息列表
useReadMsg().fetchMessages(); useReadMsg().fetchMessages();
@@ -59,6 +76,40 @@ onMounted(() => {
handleTabChange(state.current); handleTabChange(state.current);
}); });
function handleTouchStart(e) {
// 确保有触摸点
if (e.touches.length > 0) {
startPointX.value = e.touches[0].clientX;
disableTouch.value = false;
}
}
function handleTouchMove(e) {
if (e.touches.length === 0) return;
const currentX = e.touches[0].clientX;
const diffX = currentX - startPointX.value;
if (state.current === 0) {
if (diffX > THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
if (state.current === totalPage - 1) {
if (diffX < -THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
disableTouch.value = false;
}
const handelComponentsRef = (el, index) => { const handelComponentsRef = (el, index) => {
if (el) { if (el) {
swiperRefs[index].value = el; swiperRefs[index].value = el;
@@ -66,9 +117,35 @@ const handelComponentsRef = (el, index) => {
}; };
// 查看消息类型 // 查看消息类型
function changeSwiperType(e) { function changeSwiperType(e) {
const newIndex = e.detail.current;
const lastIndex = state.current;
const isSwipingRight = newIndex < lastIndex;
const isSwipingLeft = newIndex > lastIndex;
if (lastIndex === 0 && isSwipingRight) {
disableTouch.value = true;
state.current = 0;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
if (lastIndex === totalPage - 1 && isSwipingLeft) {
disableTouch.value = true;
state.current = lastIndex;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
const index = e.detail.current; const index = e.detail.current;
state.current = index; state.current = index;
handleTabChange(index); handleTabChange(index);
disableTouch.value = false;
} }
function changeType(index) { function changeType(index) {
state.current = index; state.current = index;

View File

@@ -220,7 +220,7 @@ function handleControl(e) {
} }
onMounted(() => { onMounted(() => {
$api.msg('使用模拟定位'); // $api.msg('使用模拟定位');
getInit(); getInit();
}); });

View File

@@ -13,8 +13,20 @@
<view class="head-item" :class="{ actived: state.current === 3 }" @click="changeType(3)">商圈附近</view> <view class="head-item" :class="{ actived: state.current === 3 }" @click="changeType(3)">商圈附近</view>
</view> </view>
<view class="nearby-content"> <view class="nearby-content">
<swiper class="swiper" :current="state.current" @change="changeSwiperType"> <swiper
<swiper-item class="swiper-item" v-for="(_, index) in 4" :key="index"> class="swiper"
:disable-touch="disableTouch"
:current="state.current"
@change="changeSwiperType"
>
<swiper-item
@touchstart.passive="handleTouchStart"
@touchmove.passive="handleTouchMove"
@touchend="disableTouch = false"
class="swiper-item"
v-for="(_, index) in 4"
:key="index"
>
<!-- #ifndef MP-WEIXIN --> <!-- #ifndef MP-WEIXIN -->
<component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" /> <component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" />
<!-- #endif --> <!-- #endif -->
@@ -49,6 +61,11 @@ const showFilter1 = ref(false);
const showFilter2 = ref(false); const showFilter2 = ref(false);
const showFilter3 = ref(false); const showFilter3 = ref(false);
const disableTouch = ref(false);
const startPointX = ref(0);
const totalPage = 4;
const THRESHOLD = 5;
const state = reactive({ const state = reactive({
current: 0, current: 0,
all: [{}], all: [{}],
@@ -63,11 +80,72 @@ const handelComponentsRef = (el, index) => {
swiperRefs[index].value = el; swiperRefs[index].value = el;
} }
}; };
function handleTouchStart(e) {
// 确保有触摸点
if (e.touches.length > 0) {
startPointX.value = e.touches[0].clientX;
disableTouch.value = false;
}
}
function handleTouchMove(e) {
if (e.touches.length === 0) return;
const currentX = e.touches[0].clientX;
const diffX = currentX - startPointX.value;
if (state.current === 0) {
if (diffX > THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
if (state.current === totalPage - 1) {
if (diffX < -THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
disableTouch.value = false;
}
// 查看消息类型 // 查看消息类型
function changeSwiperType(e) { function changeSwiperType(e) {
const newIndex = e.detail.current;
const lastIndex = state.current;
const isSwipingRight = newIndex < lastIndex;
const isSwipingLeft = newIndex > lastIndex;
if (lastIndex === 0 && isSwipingRight) {
disableTouch.value = true;
state.current = 0;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
if (lastIndex === totalPage - 1 && isSwipingLeft) {
disableTouch.value = true;
state.current = lastIndex;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
const index = e.detail.current; const index = e.detail.current;
state.current = index; state.current = index;
handleTabChange(index); handleTabChange(index);
disableTouch.value = false;
} }
function changeType(index) { function changeType(index) {
state.current = index; state.current = index;

View File

@@ -16,46 +16,34 @@ const useLocationStore = defineStore("location", () => {
function getLocation() { function getLocation() {
return new Promise((resole, reject) => { return new Promise((resole, reject) => {
uni.getLocation({ try {
type: 'wgs84', lightAppJssdk.map.getLocation({
altitude: true, success: function(data) {
isHighAccuracy: true, longitudeVal.value = Number(data.longitude)
enableHighAccuracy: true, // 关键参数:启用传感器辅助 latitudeVal.value = Number(data.latitude)
timeout: 10000, resole(data)
success: function(res) { },
const resd = { fail: function(data) {
longitudeVal.value = 120.382665
latitudeVal.value = 36.066938
resole({
longitude: 120.382665, longitude: 120.382665,
latitude: 36.066938 latitude: 36.066938
} })
if (config.UsingSimulatedPositioning) { // 使用模拟定位 msg('用户位置获取失败')
longitudeVal.value = resd.longitude console.log('失败', data)
latitudeVal.value = resd.latitude
msg('用户位置获取成功')
resole(resd)
} else {
longitudeVal.value = res.longitude
latitudeVal.value = res.latitude
msg('用户位置获取成功')
resole(res)
}
},
fail: function(err) {
// longitudeVal.value = ''
// latitudeVal.value = ''
// reject(err)
const resd = {
longitude: 120.382665,
latitude: 36.066938
}
longitudeVal.value = resd.longitude
latitudeVal.value = resd.latitude
msg('用户位置获取失败,使用模拟定位')
resole(resd)
},
complete: function(e) {
console.warn('getUserLocation' + JSON.stringify(e))
} }
}) })
} catch (e) {
longitudeVal.value = 120.382665
latitudeVal.value = 36.066938
resole({
longitude: 120.382665,
latitude: 36.066938
})
msg('测试环境,使用模拟定位')
console.log('失败', data)
}
}) })
} }

150
utils/FileUploader.js Normal file
View File

@@ -0,0 +1,150 @@
/**
* LightApp 文件上传工具类封装
* * 使用方法:
* 1. 列表选择上传:
* FileUploader.showMenuAndUpload({ baseUrl: 'http://...' }).then(res => ...);
* * 2. 直接调用某种类型上传:
* FileUploader.directUpload({
* baseUrl: 'http://...',
* chooseType: 'chooseImageUpload'
* }).then(res => ...);
*/
import config from "@/config.js"
export default {
/**
* 默认配置
*/
defaults: {
baseUrl: config.baseUrl, // 必填API的基础路径
uploadPath: '/app/oss/upload', // 上传接口路径
fileKey: 'file',
maxSize: 10,
maxSelectNum: 1,
minTime: 3,
maxTime: 15,
transmissionType: 0, // 0-图片地址, 1-base64
},
/**
* 映射菜单索引到上传类型
*/
typeMapping: {
0: 'chooseImageUpload', // 相册
1: 'takingPicturesUpload', // 相机
2: 'takingVideoUpload', // 视频
3: 'chooseFileUpload' // 文件
},
/**
* 核心方法:调用 SDK 的 chooseFileUpload
* @param {Object} options - 配置项
* @returns {Promise}
*/
_executeUpload: function(options) {
return new Promise((resolve, reject) => {
// 合并配置
const config = {
...this.defaults,
...options
};
// 构造 SDK 需要的参数结构
const pam = {
url: config.baseUrl + config.uploadPath,
fileKey: config.fileKey,
params: config.params || {},
header: config.header || {},
chooseType: config.chooseType || 'chooseFileUpload',
transmissionType: config.transmissionType,
maxSize: config.maxSize,
maxSelectNum: config.maxSelectNum,
minTime: config.minTime,
maxTime: config.maxTime
};
// 针对特定类型的特殊处理 (参考原代码逻辑)
if (config.chooseType === 'takingPicturesUpload') {
// 原代码注释中提到: // pam1.fileKey = 'picfile';
// 如果需要特殊 fileKey 可以在这里处理
}
console.log('开始调用SDK上传, 参数:', pam);
if (typeof lightAppJssdk === 'undefined') {
const msg = 'lightAppJssdk 未定义,请在 爱山东 环境中运行';
alert(msg);
return reject(msg);
}
lightAppJssdk.uploadFile.chooseFileUpload({
arg0: pam,
success: function(data) {
// 支持传入 success 回调,也支持 Promise resolve
if (options.success) options.success(data);
console.log(data)
resolve(data);
},
fail: function(err) {
// 支持传入 fail 回调,也支持 Promise reject
if (options.fail) options.fail(err);
// 默认弹窗提示错误,可以通过 silent: true 关闭
if (!options.silent) alert(typeof err === 'object' ? JSON.stringify(
err) : err);
reject(err);
}
});
});
},
/**
* 场景1: 弹出菜单选择,然后上传 (封装了原 selectFile)
* @param {Object} options - 配置项 (需包含 baseUrl)
*/
showMenuAndUpload: function(options = {}) {
return new Promise((resolve, reject) => {
if (typeof lightAppJssdk === 'undefined') {
alert('lightAppJssdk 未定义');
return reject('lightAppJssdk undefined');
}
const menuList = options.menuList || ['相册', '相机', '视频', '文件'];
lightAppJssdk.notification.showMediaAlert({
arg0: menuList,
success: (data) => {
// data.index 对应 menuList 的索引
const selectedType = this.typeMapping[data.index];
if (!selectedType) {
const err = '未知的选择类型';
if (options.fail) options.fail(err);
return reject(err);
}
// 选中后,调用核心上传方法
this._executeUpload({
...options,
chooseType: selectedType
}).then(resolve).catch(reject);
},
fail: (err) => {
if (options.fail) options.fail(err);
if (!options.silent) alert(err);
reject(err);
}
});
});
},
/**
* 场景2: 直接上传 (不弹窗,直接调起特定类型的上传)
* @param {Object} options - 需包含 baseUrl 和 chooseType
*/
directUpload: function(options = {}) {
if (!options.chooseType) {
// 如果没传类型,默认当做普通文件上传
options.chooseType = 'chooseFileUpload';
}
return this._executeUpload(options);
}
};