@ -0,0 +1,23 @@ |
|||
.DS_Store |
|||
node_modules/ |
|||
unpackage/ |
|||
dist/ |
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
# Editor directories and files |
|||
.project |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw* |
|||
@ -0,0 +1,23 @@ |
|||
<script> |
|||
export default { |
|||
onLaunch: function() { |
|||
console.log('App Launch') |
|||
}, |
|||
onShow: function() { |
|||
console.log('App Show') |
|||
console.log(uni.getStorageSync('loginRes')) |
|||
if(!uni.getStorageSync('loginRes') || !uni.getStorageSync('loginRes').accessToken){ |
|||
uni.navigateTo({ |
|||
url:'/pages/login/login' |
|||
}) |
|||
} |
|||
}, |
|||
onHide: function() { |
|||
console.log('App Hide') |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
/*每个页面公共css */ |
|||
</style> |
|||
@ -0,0 +1,91 @@ |
|||
// api.js
|
|||
|
|||
// 基础URL,可以根据环境来设置
|
|||
// uEnvDev
|
|||
const accountInfo = wx.getAccountInfoSync(); |
|||
// env类型 develop:开发版、trial:体验版、release:正式版
|
|||
export const env = accountInfo.miniProgram.envVersion; |
|||
if (!env) { |
|||
console.error("获取运行环境失败!"); |
|||
} |
|||
const baseApi = { |
|||
// 开发版
|
|||
develop: "http://110.40.156.216:30005/api", |
|||
// 体验版
|
|||
trial: "http://110.40.156.216:30005/api", |
|||
// 正式版
|
|||
release: "http://110.40.156.216:30005/api" |
|||
}; |
|||
console.log(env, 'env') |
|||
// request请求baseURL
|
|||
const BASE_URL = baseApi[env] || 'http://110.40.156.216:30005/api'; |
|||
|
|||
|
|||
function request(url, method, data = {}) { |
|||
const userInfo = uni.getStorageSync('loginInfo') || {}; |
|||
const UTCOffset = new Date().getTimezoneOffset(); |
|||
return new Promise((resolve, reject) => { |
|||
uni.request({ |
|||
url: BASE_URL + url, // 完整的URL
|
|||
method: method, |
|||
data: data, |
|||
header: { |
|||
'AccessToken': userInfo.accessToken || '-1', // 请求头,可根据需要调整
|
|||
'UserId': userInfo.userId || '1', // 请求头,可根据需要调整
|
|||
'LanguageType': 0, |
|||
'LoginName': userInfo.loginName || '', |
|||
'CompanyId': userInfo.companyId || '', |
|||
'UTCOffset': UTCOffset, |
|||
}, |
|||
success: (res) => { |
|||
if (res.statusCode === 200) { |
|||
console.log(res) |
|||
if (res.data.code === 200 | res.data.code === 0) { |
|||
resolve(res.data) |
|||
} else { |
|||
reject(res.data) |
|||
} |
|||
/* if (res.data.code === 500) { |
|||
uni.showToast({ |
|||
title: '系统错误', // 提示的文本内容
|
|||
icon: 'none', // 提示的图标,可选值:'success' | 'loading' | 'none'
|
|||
duration: 2000 // 提示框的显示时间,单位为毫秒,默认1500ms
|
|||
}); |
|||
} |
|||
if (res.data.code === 401) { |
|||
uni.showToast({ |
|||
title: '登录过期,重新登录中', // 提示的文本内容
|
|||
icon: 'none', // 提示的图标,可选值:'success' | 'loading' | 'none'
|
|||
duration: 2000 // 提示框的显示时间,单位为毫秒,默认1500ms
|
|||
}); |
|||
} |
|||
if (res.data.code === 20001) { |
|||
reject(res.data); |
|||
} |
|||
resolve(res.data) */ |
|||
} else { |
|||
reject(res); |
|||
} |
|||
|
|||
}, |
|||
fail: (err) => { |
|||
uni.showToast({ |
|||
title: '请求错误', // 提示的文本内容
|
|||
icon: 'none', // 提示的图标,可选值:'success' | 'loading' | 'none'
|
|||
duration: 2000 // 提示框的显示时间,单位为毫秒,默认1500ms
|
|||
}); |
|||
reject(err); // 请求失败
|
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
// GET 请求
|
|||
export function get(url, params = {}) { |
|||
return request(url, 'GET', params); |
|||
} |
|||
|
|||
// POST 请求
|
|||
export function post(url, data = {}) { |
|||
return request(url, 'POST', data); |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
import { get, post } from "./httpSetting"; |
|||
|
|||
/** |
|||
* 登录 |
|||
*/ |
|||
export const userLogin = (params ={}) => post('/app/auth/login', params); |
|||
|
|||
export const getAppJobVO = (params ={}) => get('/app/job/getAppJobVO', params); |
|||
@ -0,0 +1,246 @@ |
|||
<template> |
|||
<view class="recruitment-card"> |
|||
<!-- 卡片头部信息 --> |
|||
<view class="card-head"> |
|||
<div class="factory-info"> |
|||
<h3 class="factory-name">{{dataSource.factoryName || '默认工厂'}}</h3> |
|||
<span class="factory-type">{{dataSource.factoryType || '电子厂'}}</span> |
|||
</div> |
|||
<div class="card-actions"> |
|||
<!-- <view class="favorite-btn" @click="toggleFavorite"> |
|||
<text class="heart-icon">{{isFavorite ? '♥' : '♡'}}</text> |
|||
</view> --> |
|||
<button class="call-btn" @click="makeCall">拨打电话</button> |
|||
<button class="review-btn" @click.stop="handleGoToDetail">查看详情</button> |
|||
<view class="more-btn" @click.stop> |
|||
<text>···</text> |
|||
</view> |
|||
</div> |
|||
</view> |
|||
|
|||
<!-- 工作时间和内容 --> |
|||
<view class="work-info"> |
|||
<text class="work-time">{{dataSource.workTime || '8:00-20:00'}}</text> |
|||
<text class="work-type">{{dataSource.workType || '两班倒'}}</text> |
|||
<text class="work-content">{{dataSource.workContent || '主营汽车线束'}}</text> |
|||
<span class="distance">{{dataSource.distance || '距你2.5km'}}</span> |
|||
</view> |
|||
|
|||
<view class="card-bm"> |
|||
<template v-for="(item, index) in processedCompanyData" :key="item.label"> |
|||
<view class="item-info-swiper"> |
|||
<view class="label">{{item.label}}</view> |
|||
<view class="value"> |
|||
{{item.value}}<text class="label-two">{{item.unit}}</text> |
|||
</view> |
|||
<view class="label-two"> |
|||
{{item.exLabel}} |
|||
</view> |
|||
</view> |
|||
<view v-if="index < processedCompanyData.length - 1" class="divider"></view> |
|||
</template> |
|||
|
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: "recruitment", |
|||
props: { |
|||
dataSource: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
isFavorite: false, |
|||
companyData: [{ |
|||
label: '薪资', |
|||
value: '20', |
|||
unit: '', |
|||
exLabel: '元/小时' |
|||
}, |
|||
{ |
|||
label: '年龄', |
|||
value: '20-42', |
|||
unit: '', |
|||
exLabel: '元/小时' |
|||
}, |
|||
{ |
|||
label: '吃饭', |
|||
value: '2', |
|||
unit: '餐', |
|||
exLabel: '白-夜' |
|||
}, |
|||
{ |
|||
label: '住宿', |
|||
value: '20', |
|||
unit: '', |
|||
exLabel: '人间' |
|||
}, |
|||
], |
|||
|
|||
}; |
|||
}, |
|||
computed: { |
|||
processedCompanyData() { |
|||
return this.dataSource.companyData || this.companyData; |
|||
} |
|||
}, |
|||
methods: { |
|||
// 拨打电话 |
|||
makeCall(e) { |
|||
e.stopPropagation(); |
|||
uni.makePhoneCall({ |
|||
phoneNumber: '400-123-4567' |
|||
}); |
|||
}, |
|||
// 切换收藏状态 |
|||
toggleFavorite(e) { |
|||
e.stopPropagation(); |
|||
this.isFavorite = !this.isFavorite; |
|||
}, |
|||
handleGoToDetail(e) { |
|||
uni.navigateTo({ |
|||
url: '/pages/positionDetail/positionDetail' |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.recruitment-card { |
|||
background-color: #fff; |
|||
padding: 8px 16px; |
|||
z-index: 10; |
|||
|
|||
.card-head { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 8px; |
|||
flex-wrap: wrap; |
|||
.factory-info { |
|||
width: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 8px; |
|||
margin-bottom: 8px; |
|||
.factory-name { |
|||
font-size: 18px; |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin: 0; |
|||
} |
|||
|
|||
.factory-type { |
|||
background-color: #f0f0f0; |
|||
color: #666; |
|||
padding: 2px 8px; |
|||
border-radius: 4px; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.distance { |
|||
color: #999; |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
|
|||
.card-actions { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 8px; |
|||
|
|||
.favorite-btn { |
|||
font-size: 20px; |
|||
color: #ff4757; |
|||
padding: 4px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.call-btn { |
|||
background-color: #ff4757; |
|||
color: white; |
|||
border: none; |
|||
padding: 6px 12px; |
|||
border-radius: 4px; |
|||
font-size: 14px; |
|||
line-height: 1.4; |
|||
} |
|||
|
|||
.review-btn { |
|||
background-color: transparent; |
|||
color: #666; |
|||
border: 1px solid #ddd; |
|||
padding: 6px 12px; |
|||
border-radius: 4px; |
|||
font-size: 14px; |
|||
line-height: 1.4; |
|||
} |
|||
|
|||
.more-btn { |
|||
color: #999; |
|||
font-size: 18px; |
|||
cursor: pointer; |
|||
padding: 4px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.work-info { |
|||
display: flex; |
|||
gap: 12px; |
|||
font-size: 12px; |
|||
color: #666; |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.card-bm { |
|||
display: flex; |
|||
padding: 0; |
|||
justify-content: space-around; |
|||
|
|||
.item-wrapper { |
|||
display: flex; |
|||
align-items: center; |
|||
flex: 1; |
|||
} |
|||
|
|||
.item-info-swiper { |
|||
padding: 0; |
|||
display: inline-block; |
|||
text-align: center; |
|||
flex: 1; |
|||
|
|||
.label { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
color: #333; |
|||
} |
|||
|
|||
.value { |
|||
font-size: 24px; |
|||
margin-top: 4px; |
|||
margin-bottom: 4px; |
|||
color: $uni-color-primary; |
|||
} |
|||
|
|||
.label-two { |
|||
font-size: 12px; |
|||
color: #666; |
|||
} |
|||
} |
|||
|
|||
.divider { |
|||
width: 1px; |
|||
height: 60px; |
|||
background-color: #e5e5e5; |
|||
margin: 0; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,20 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="zh-CN"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<script> |
|||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || |
|||
CSS.supports('top: constant(a)')) |
|||
document.write( |
|||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + |
|||
(coverSupport ? ', viewport-fit=cover' : '') + '" />') |
|||
</script> |
|||
<title></title> |
|||
<!--preload-links--> |
|||
<!--app-context--> |
|||
</head> |
|||
<body> |
|||
<div id="app"><!--app-html--></div> |
|||
<script type="module" src="/main.js"></script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,25 @@ |
|||
import App from './App' |
|||
import * as Pinia from 'pinia'; |
|||
|
|||
// #ifndef VUE3
|
|||
import Vue from 'vue' |
|||
import './uni.promisify.adaptor' |
|||
Vue.config.productionTip = false |
|||
App.mpType = 'app' |
|||
const app = new Vue({ |
|||
...App |
|||
}) |
|||
app.$mount() |
|||
// #endif
|
|||
|
|||
// #ifdef VUE3
|
|||
import { createSSRApp } from 'vue' |
|||
export function createApp() { |
|||
const app = createSSRApp(App) |
|||
app.use(Pinia.createPinia()); |
|||
return { |
|||
app, |
|||
Pinia |
|||
} |
|||
} |
|||
// #endif
|
|||
@ -0,0 +1,78 @@ |
|||
{ |
|||
"name" : "laowumap", |
|||
"appid" : "__UNI__3F7EFE0", |
|||
"description" : "", |
|||
"versionName" : "1.0.0", |
|||
"versionCode" : "100", |
|||
"transformPx" : false, |
|||
/* 5+App特有相关 */ |
|||
"app-plus" : { |
|||
"usingComponents" : true, |
|||
"nvueStyleCompiler" : "uni-app", |
|||
"compilerVersion" : 3, |
|||
"splashscreen" : { |
|||
"alwaysShowBeforeRender" : true, |
|||
"waiting" : true, |
|||
"autoclose" : true, |
|||
"delay" : 0 |
|||
}, |
|||
/* 模块配置 */ |
|||
"modules" : {}, |
|||
/* 应用发布信息 */ |
|||
"distribute" : { |
|||
/* android打包配置 */ |
|||
"android" : { |
|||
"permissions" : [ |
|||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", |
|||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", |
|||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
|||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
|||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
|||
"<uses-feature android:name=\"android.hardware.camera\"/>", |
|||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
|||
] |
|||
}, |
|||
/* ios打包配置 */ |
|||
"ios" : {}, |
|||
/* SDK配置 */ |
|||
"sdkConfigs" : {} |
|||
} |
|||
}, |
|||
/* 快应用特有相关 */ |
|||
"quickapp" : {}, |
|||
/* 小程序特有相关 */ |
|||
"mp-weixin" : { |
|||
"appid" : "wx6b37987f8de3af0f", |
|||
"setting" : { |
|||
"urlCheck" : false |
|||
}, |
|||
"usingComponents" : true, |
|||
"permission" : { |
|||
"scope.userLocation" : { |
|||
"desc" : "您的位置信息将用于地图定位和附近地点展示" |
|||
} |
|||
}, |
|||
"lazyCodeLoading" : "requiredComponents" |
|||
}, |
|||
"mp-alipay" : { |
|||
"usingComponents" : true |
|||
}, |
|||
"mp-baidu" : { |
|||
"usingComponents" : true |
|||
}, |
|||
"mp-toutiao" : { |
|||
"usingComponents" : true |
|||
}, |
|||
"uniStatistics" : { |
|||
"enable" : false |
|||
}, |
|||
"vueVersion" : "3" |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
{ |
|||
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages |
|||
{ |
|||
"path": "pages/index/index", |
|||
"style": { |
|||
"navigationBarTitleText": "挑好厂|找周边工作" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/searchPositions/searchPositions", |
|||
"style": { |
|||
"navigationBarTitleText": "岗位搜索" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/my/my", |
|||
"style": { |
|||
"navigationBarTitleText": "个人中心" |
|||
} |
|||
}, |
|||
{ |
|||
"path" : "pages/map/map", |
|||
"style" : |
|||
{ |
|||
"navigationBarTitleText" : "地图" |
|||
} |
|||
}, |
|||
{ |
|||
"path" : "pages/positionDetail/positionDetail", |
|||
"style" : |
|||
{ |
|||
"navigationBarTitleText" : "岗位详情" |
|||
} |
|||
}, |
|||
{ |
|||
"path" : "pages/login/login", |
|||
"style" : |
|||
{ |
|||
"navigationBarTitleText" : "登录" |
|||
} |
|||
} |
|||
|
|||
], |
|||
"globalStyle": { |
|||
"navigationBarTextStyle": "black", |
|||
"navigationBarTitleText": "uni-app", |
|||
"navigationBarBackgroundColor": "#F8F8F8", |
|||
"backgroundColor": "#F8F8F8" |
|||
}, |
|||
"tabBar": { |
|||
"list": [ |
|||
{ |
|||
"text": "首页", |
|||
"pagePath": "pages/index/index", |
|||
"iconPath": "/static/tabbarIcon/home.png", |
|||
"selectedIconPath": "/static/tabbarIcon/home-select.png" |
|||
}, |
|||
{ |
|||
"text": "搜岗位", |
|||
"pagePath": "pages/searchPositions/searchPositions", |
|||
"iconPath": "/static/tabbarIcon/searchPositions.png", |
|||
"selectedIconPath": "/static/tabbarIcon/searchPositions-select.png" |
|||
}, |
|||
{ |
|||
"text": "我的", |
|||
"pagePath": "pages/my/my", |
|||
"iconPath": "/static/tabbarIcon/my.png", |
|||
"selectedIconPath": "/static/tabbarIcon/my-select.png" |
|||
} |
|||
] |
|||
}, |
|||
"uniIdRouter": {} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
<template> |
|||
<view class="index-page"> |
|||
<map style="height: 100vh; width: 100vw;" id="myMap" :markers="markers" show-location show-compass |
|||
@updated="handleMapLoad"></map> |
|||
<view class="rec-swiper"> |
|||
<recruitment></recruitment> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
companyData: [{ |
|||
label: '薪资', |
|||
value: '20', |
|||
unit: '', |
|||
exLabel: '元/小时' |
|||
}, |
|||
{ |
|||
label: '年龄', |
|||
value: '20-42', |
|||
unit: '', |
|||
exLabel: '元/小时' |
|||
}, |
|||
{ |
|||
label: '吃饭', |
|||
value: '2', |
|||
unit: '餐', |
|||
exLabel: '白-夜' |
|||
}, |
|||
{ |
|||
label: '住宿', |
|||
value: '20', |
|||
unit: '', |
|||
exLabel: '人间' |
|||
}, |
|||
], |
|||
markers: [{ |
|||
id: 1, |
|||
latitude: 39.90923, |
|||
longitude: 116.397428, |
|||
title: '模拟点位1', |
|||
iconPath: '/static/position-icon.png', |
|||
width: 30, |
|||
height: 30, |
|||
label: { |
|||
content: '模拟点位1', |
|||
textAlign: 'center', |
|||
fontSize: 18, |
|||
} |
|||
}, |
|||
{ |
|||
id: 2, |
|||
latitude: 39.8, |
|||
longitude: 116.3, |
|||
title: '模拟点位1', |
|||
iconPath: '/static/position-icon.png', |
|||
width: 30, |
|||
height: 30, |
|||
label: { |
|||
content: '模拟点位1', |
|||
textAlign: 'center', |
|||
fontSize: 18, |
|||
} |
|||
}, |
|||
] |
|||
} |
|||
}, |
|||
onLoad() { |
|||
// 页面加载时的初始化逻辑 |
|||
}, |
|||
methods: { |
|||
handleMapLoad() { |
|||
console.log('地图加载完成'); |
|||
// 获取地图上下文 |
|||
const mapContext = uni.createMapContext('myMap'); |
|||
// 设置地图中心点到第一个标记点 |
|||
mapContext.includePoints({ |
|||
points: this.markers.map(marker => ({ |
|||
latitude: marker.latitude, |
|||
longitude: marker.longitude |
|||
})), |
|||
padding: [50, 50, 200, 50] // 边距设置 |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.index-page { |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
position: relative; |
|||
|
|||
.rec-swiper { |
|||
width: calc(100% - 16px); |
|||
// height: 200px; |
|||
// background-color: red; |
|||
background-color: #FFF; |
|||
margin: 0 8px; |
|||
position: absolute; |
|||
left: 0px; |
|||
bottom: 8px; |
|||
border-radius: 16px; |
|||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,275 @@ |
|||
<template> |
|||
<view class="login-page"> |
|||
<!-- 顶部装饰元素 --> |
|||
<view class="top-decoration"> |
|||
<view class="circle circle-1"></view> |
|||
<view class="circle circle-2"></view> |
|||
<view class="circle circle-3"></view> |
|||
</view> |
|||
|
|||
<!-- Logo区域 --> |
|||
<view class="logo-section"> |
|||
<image class="logo" src="/static/logo.png" mode="aspectFit"></image> |
|||
<text class="app-title">劳务地图</text> |
|||
</view> |
|||
|
|||
<!-- 登录按钮区域 --> |
|||
<view class="login-section"> |
|||
<button class="wechat-login-btn" open-type="getPhoneNumber" @getphonenumber="onWechatLogin"> |
|||
<image class="wechat-icon" src="/static/wechat-icon.png" mode="aspectFit"></image> |
|||
<text class="btn-text">微信一键登录</text> |
|||
</button> |
|||
{{ loginRes }} |
|||
<view class="agreement-section"> |
|||
<label class="checkbox-wrapper"> |
|||
<checkbox :checked="agreeChecked" @tap="toggleAgreement" color="#07c160" /> |
|||
<text class="agreement-text">我已阅读并同意</text> |
|||
</label> |
|||
<text class="agreement-link" @tap="showAgreement">《用户协议》</text> |
|||
<text class="agreement-text">和</text> |
|||
<text class="agreement-link" @tap="showPrivacyPolicy">《隐私政策》</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部装饰 --> |
|||
<view class="bottom-decoration"></view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, ref } from 'vue'; |
|||
import { userLogin } from '../../api'; |
|||
import { useUserStore } from '../../stores/user.js'; |
|||
// 用户协议勾选状态 |
|||
const agreeChecked = ref(false); |
|||
|
|||
// 获取用户 store 实例 |
|||
const userStore = useUserStore(); |
|||
const loginRes = computed(() => userStore.loginRes); |
|||
|
|||
// 微信登录处理 |
|||
const onWechatLogin = (e) => { |
|||
// 检查用户是否同意协议 |
|||
if (!agreeChecked.value) { |
|||
uni.showToast({ |
|||
title: '请先同意用户协议和隐私政策', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
// 显示加载提示 |
|||
uni.showLoading({ |
|||
title: '登录中...' |
|||
}); |
|||
|
|||
// 获取微信登录凭证 |
|||
uni.login({ |
|||
provider: 'weixin', |
|||
success: async (wxLoginRes) => { |
|||
try { |
|||
console.log('微信登录成功', wxLoginRes); |
|||
const code = wxLoginRes.code; |
|||
const loginRes = await userLogin({ code }); |
|||
console.log('登录接口返回:', loginRes); |
|||
|
|||
// 隐藏加载提示 |
|||
uni.hideLoading(); |
|||
|
|||
// 使用 Pinia 存储 loginRes 数据 |
|||
userStore.setLoginRes(loginRes.data); |
|||
console.log('loginRes 已存储到 Pinia:', loginRes.data); |
|||
// 登录成功提示 |
|||
uni.showToast({ |
|||
title: '登录成功', |
|||
icon: 'success' |
|||
}); |
|||
|
|||
// 跳转到首页 |
|||
setTimeout(() => { |
|||
uni.switchTab({ |
|||
url: '/pages/index/index' |
|||
}); |
|||
}, 1000); |
|||
} catch (error) { |
|||
// 隐藏加载提示 |
|||
uni.hideLoading(); |
|||
|
|||
console.error('登录过程出错', error); |
|||
uni.showToast({ |
|||
title: '登录过程出错,请重试', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
}, |
|||
fail: (err) => { |
|||
// 隐藏加载提示 |
|||
uni.hideLoading(); |
|||
|
|||
console.error('微信登录失败', err); |
|||
uni.showToast({ |
|||
title: '微信登录失败,请重试', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
// 切换用户协议勾选状态 |
|||
const toggleAgreement = () => { |
|||
agreeChecked.value = !agreeChecked.value; |
|||
}; |
|||
|
|||
// 显示用户协议 |
|||
const showAgreement = () => { |
|||
uni.showToast({ |
|||
title: '用户协议', |
|||
icon: 'none' |
|||
}); |
|||
}; |
|||
|
|||
// 显示隐私政策 |
|||
const showPrivacyPolicy = () => { |
|||
uni.showToast({ |
|||
title: '隐私政策', |
|||
icon: 'none' |
|||
}); |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.login-page { |
|||
display: flex; |
|||
flex-direction: column; |
|||
min-height: 100vh; |
|||
background: linear-gradient(135deg, #f5f7fa 0%, #e4edf9 100%); |
|||
padding: 20px; |
|||
|
|||
// 顶部装饰 |
|||
.top-decoration { |
|||
position: relative; |
|||
height: 120px; |
|||
margin-bottom: 40px; |
|||
|
|||
.circle { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); |
|||
opacity: 0.1; |
|||
|
|||
&.circle-1 { |
|||
width: 80px; |
|||
height: 80px; |
|||
top: 0; |
|||
right: 10%; |
|||
} |
|||
|
|||
&.circle-2 { |
|||
width: 120px; |
|||
height: 120px; |
|||
top: -20px; |
|||
left: 5%; |
|||
} |
|||
|
|||
&.circle-3 { |
|||
width: 60px; |
|||
height: 60px; |
|||
bottom: 0; |
|||
right: 25%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Logo区域 |
|||
.logo-section { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
margin-bottom: 60px; |
|||
|
|||
.logo { |
|||
width: 100px; |
|||
height: 100px; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.app-title { |
|||
font-size: 24px; |
|||
font-weight: bold; |
|||
color: #333; |
|||
} |
|||
} |
|||
|
|||
// 登录区域 |
|||
.login-section { |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
|
|||
.wechat-login-btn { |
|||
width: 80%; |
|||
height: 50px; |
|||
background: #07c160; |
|||
border-radius: 25px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-bottom: 30px; |
|||
box-shadow: 0 4px 10px rgba(7, 193, 96, 0.3); |
|||
|
|||
.wechat-icon { |
|||
width: 24px; |
|||
height: 24px; |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.btn-text { |
|||
color: white; |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
&::after { |
|||
border: none; |
|||
} |
|||
} |
|||
|
|||
// 协议区域 |
|||
.agreement-section { |
|||
display: flex; |
|||
align-items: center; |
|||
flex-wrap: wrap; |
|||
justify-content: center; |
|||
padding: 0 20px; |
|||
|
|||
.checkbox-wrapper { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-right: 5px; |
|||
|
|||
.agreement-text { |
|||
margin-left: 5px; |
|||
} |
|||
} |
|||
|
|||
.agreement-text { |
|||
font-size: 12px; |
|||
color: #999; |
|||
margin: 0 2px; |
|||
} |
|||
|
|||
.agreement-link { |
|||
font-size: 12px; |
|||
color: #07c160; |
|||
text-decoration: underline; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 底部装饰 |
|||
.bottom-decoration { |
|||
height: 60px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,238 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<!-- 悬浮卡片 --> |
|||
<view v-if="showCard" class="float-card"> |
|||
<view class="card-title">{{ selectedMarker.title }}</view> |
|||
<view class="card-info"> |
|||
<text>纬度:{{ selectedMarker.latitude }}</text> |
|||
<text>经度:{{ selectedMarker.longitude }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 地图中心经纬度信息 --> |
|||
<view class="map-center-info"> |
|||
<text>地图中心:</text> |
|||
<text>纬度:{{ mapCenter.latitude.toFixed(6) }}</text> |
|||
<text>经度:{{ mapCenter.longitude.toFixed(6) }}</text> |
|||
</view> |
|||
|
|||
<!-- 地图组件 --> |
|||
<map style="height: 100vh; width: 100vw;" |
|||
id="myMap" |
|||
name="" |
|||
@updated="handleMapLoad" |
|||
@markertap="handleMarkerTap" |
|||
@regionchange="handleRegionChange" |
|||
show-compass |
|||
:markers="markers" |
|||
show-location></map> |
|||
|
|||
<!-- 添加Marker表单 --> |
|||
<view class="form-container"> |
|||
<view class="form-title">添加新标记</view> |
|||
<view class="form-item"> |
|||
<text>位置名称:</text> |
|||
<input v-model="newMarker.title" type="text" placeholder="请输入位置名称"/> |
|||
</view> |
|||
<view class="form-item"> |
|||
<text>纬度:</text> |
|||
<input v-model.number="newMarker.latitude" type="digit" placeholder="请输入纬度"/> |
|||
</view> |
|||
<view class="form-item"> |
|||
<text>经度:</text> |
|||
<input v-model.number="newMarker.longitude" type="digit" placeholder="请输入经度"/> |
|||
</view> |
|||
<button @click="addMarker" type="primary">添加标记</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
markers: [{ |
|||
id: 1, |
|||
latitude: 39.90923, |
|||
longitude: 116.397428, |
|||
title: '北京天安门', |
|||
iconPath: '/static/logo.png', |
|||
width: 30, |
|||
height: 30 |
|||
}], |
|||
showCard: false, |
|||
selectedMarker: {}, |
|||
newMarker: { |
|||
title: '', |
|||
latitude: 0, |
|||
longitude: 0 |
|||
}, |
|||
mapCenter: { |
|||
latitude: 39.90923, |
|||
longitude: 116.397428 |
|||
}, |
|||
mapContext: null |
|||
} |
|||
}, |
|||
methods: { |
|||
handleMapLoad() { |
|||
console.log("地图加载完成!") |
|||
// 获取地图上下文 |
|||
this.mapContext = uni.createMapContext('myMap'); |
|||
// 获取初始地图中心经纬度 |
|||
this.getMapCenter(); |
|||
}, |
|||
// 处理地图区域变化事件 |
|||
handleRegionChange(e) { |
|||
// 当用户拖动地图结束时获取地图中心经纬度 |
|||
if (e.type === 'end') { |
|||
this.getMapCenter(); |
|||
} |
|||
}, |
|||
// 获取地图中心经纬度 |
|||
getMapCenter() { |
|||
if (this.mapContext) { |
|||
this.mapContext.getCenterLocation({ |
|||
success: (res) => { |
|||
this.mapCenter = { |
|||
latitude: res.latitude, |
|||
longitude: res.longitude |
|||
}; |
|||
console.log('当前地图中心经纬度:', this.mapCenter); |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
// 处理Marker点击事件 |
|||
handleMarkerTap(e) { |
|||
const markerId = e.markerId; |
|||
const marker = this.markers.find(item => item.id === markerId); |
|||
if (marker) { |
|||
this.selectedMarker = { ...marker }; |
|||
this.showCard = true; |
|||
} |
|||
}, |
|||
// 添加新的Marker |
|||
addMarker() { |
|||
if (!this.newMarker.title || !this.newMarker.latitude || !this.newMarker.longitude) { |
|||
uni.showToast({ |
|||
title: '请填写完整信息', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
const newMarker = { |
|||
id: this.markers.length + 1, |
|||
title: this.newMarker.title, |
|||
latitude: this.newMarker.latitude, |
|||
longitude: this.newMarker.longitude, |
|||
iconPath: '/static/logo.png', |
|||
width: 30, |
|||
height: 30 |
|||
}; |
|||
|
|||
this.markers.push(newMarker); |
|||
|
|||
// 重置表单 |
|||
this.newMarker = { |
|||
title: '', |
|||
latitude: 0, |
|||
longitude: 0 |
|||
}; |
|||
|
|||
uni.showToast({ |
|||
title: '添加成功', |
|||
icon: 'success' |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.container { |
|||
position: relative; |
|||
height: 100vh; |
|||
} |
|||
/* 悬浮卡片样式 */ |
|||
.float-card { |
|||
position: absolute; |
|||
top: 20px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 80%; |
|||
max-width: 400px; |
|||
background: rgba(255, 255, 255, 0.9); |
|||
border-radius: 10px; |
|||
padding: 15px; |
|||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
|||
z-index: 999; |
|||
} |
|||
.card-title { |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
margin-bottom: 10px; |
|||
} |
|||
.card-info { |
|||
font-size: 14px; |
|||
color: #666; |
|||
} |
|||
.card-info text { |
|||
display: block; |
|||
margin: 5px 0; |
|||
} |
|||
/* 表单样式 */ |
|||
.form-container { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
background: rgba(255, 255, 255, 0.95); |
|||
padding: 20px; |
|||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); |
|||
} |
|||
.form-title { |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
margin-bottom: 15px; |
|||
text-align: center; |
|||
} |
|||
.form-item { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 15px; |
|||
} |
|||
.form-item text { |
|||
width: 80px; |
|||
} |
|||
.form-item input { |
|||
flex: 1; |
|||
height: 40px; |
|||
border: 1px solid #ddd; |
|||
border-radius: 5px; |
|||
padding: 0 10px; |
|||
} |
|||
button { |
|||
margin-top: 10px; |
|||
} |
|||
/* 地图中心经纬度信息样式 */ |
|||
.map-center-info { |
|||
position: absolute; |
|||
top: 100px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 80%; |
|||
max-width: 400px; |
|||
background: rgba(255, 255, 255, 0.9); |
|||
border-radius: 10px; |
|||
padding: 10px 15px; |
|||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
|||
z-index: 998; |
|||
} |
|||
.map-center-info text { |
|||
display: inline-block; |
|||
font-size: 14px; |
|||
margin-right: 10px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,151 @@ |
|||
<template> |
|||
<view class="my-page"> |
|||
<!-- 登录区域 --> |
|||
<view class="login-section" @click="loginRegister"> |
|||
<view class="avatar"> |
|||
<text class="avatar-icon">😊</text> |
|||
</view> |
|||
<view class="login-text"> |
|||
<text class="login-title">点击登录/注册</text> |
|||
<text class="login-subtitle">登录查看更多消息</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 功能区域 --> |
|||
<view class="features-section"> |
|||
<view class="feature-item" @click="myComments"> |
|||
<view class="feature-icon"> |
|||
<text class="icon-content">📝</text> |
|||
</view> |
|||
<text class="feature-name">我的评价</text> |
|||
</view> |
|||
|
|||
<view class="feature-item" @click="myFavorites"> |
|||
<view class="feature-icon"> |
|||
<text class="icon-content">❤️</text> |
|||
</view> |
|||
<text class="feature-name">收藏岗位</text> |
|||
</view> |
|||
|
|||
<view class="feature-item" @click="contactService"> |
|||
<view class="feature-icon"> |
|||
<text class="icon-content">📞</text> |
|||
</view> |
|||
<text class="feature-name">咨询客服</text> |
|||
</view> |
|||
</view>123 |
|||
{{loginRes}} |
|||
<!-- 底部占位,避免内容被底部导航栏遮挡 --> |
|||
<view class="bottom-space"></view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed } from 'vue'; |
|||
import { useUserStore } from '../../stores/user.js'; |
|||
const userStore = useUserStore(); |
|||
const loginRes = computed(() => userStore.loginRes); |
|||
|
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.my-page { |
|||
background-color: #fff; |
|||
min-height: 100vh; |
|||
padding-top: 12px; // 增加顶部内边距,避免内容紧贴导航栏 |
|||
|
|||
// 登录区域 |
|||
.login-section { |
|||
background-color: #fff; |
|||
padding: 20px; |
|||
display: flex; |
|||
align-items: center; |
|||
tap-highlight-color: transparent; |
|||
|
|||
.avatar { |
|||
width: 60px; |
|||
height: 60px; |
|||
border-radius: 30px; |
|||
background-color: #e6f7ff; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-right: 16px; |
|||
|
|||
.avatar-icon { |
|||
font-size: 30px; |
|||
} |
|||
} |
|||
|
|||
.login-text { |
|||
.login-title { |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.login-subtitle { |
|||
font-size: 14px; |
|||
color: #999; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 功能区域 |
|||
.features-section { |
|||
background-color: #fff; |
|||
padding: 16px 0; |
|||
display: flex; |
|||
justify-content: space-around; |
|||
|
|||
.feature-item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 8px; |
|||
tap-highlight-color: transparent; |
|||
|
|||
.feature-icon { |
|||
width: 50px; |
|||
height: 50px; |
|||
border-radius: 12px; |
|||
background-color: #f0f9ff; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-bottom: 8px; |
|||
|
|||
.icon-content { |
|||
font-size: 24px; |
|||
} |
|||
} |
|||
|
|||
.feature-name { |
|||
font-size: 14px; |
|||
color: #333; |
|||
} |
|||
|
|||
// 为不同的功能图标设置不同的背景色 |
|||
&:nth-child(1) .feature-icon { |
|||
background-color: #e6f7ff; |
|||
} |
|||
|
|||
&:nth-child(2) .feature-icon { |
|||
background-color: #fff1f0; |
|||
} |
|||
|
|||
&:nth-child(3) .feature-icon { |
|||
background-color: #f0f9ff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 底部占位,避免内容被底部导航栏遮挡 |
|||
.bottom-space { |
|||
height: 60px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,419 @@ |
|||
<template> |
|||
<view class="position-detail-page"> |
|||
<!-- 主内容区域 - 可滚动 --> |
|||
<view class="content-wrapper"> |
|||
<!-- 顶部信息区域 --> |
|||
<view class="header-section"> |
|||
<view class="factory-info"> |
|||
<text class="factory-name">安费诺</text> |
|||
<text class="factory-type">电子厂</text> |
|||
<text class="distance">距你2.5km</text> |
|||
</view> |
|||
<button class="call-btn" @click="makeCall">拨打电话</button> |
|||
</view> |
|||
|
|||
<!-- 工作时间区域 --> |
|||
<view class="work-time-section"> |
|||
<text class="time">8:00-20:00 两班倒</text> |
|||
<text class="business">主营汽车线束</text> |
|||
</view> |
|||
|
|||
<!-- 薪资信息区域 --> |
|||
<view class="salary-section"> |
|||
<view class="salary-item"> |
|||
<text class="item-title">小时工</text> |
|||
<text class="salary-content">工资: 20+1元/小时(含1元满勤)+绩效奖金高达500,月薪6500-7500</text> |
|||
</view> |
|||
|
|||
<view class="salary-item"> |
|||
<text class="item-title">正式工</text> |
|||
<text class="salary-content">工资2490元/月+夜班补贴10元/晚+"表现佳有绩效+超产奖金" 平时加班1.5倍,双休日2倍,国假日3倍等,月收入5700-6800/月</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 福利信息区域 --> |
|||
<view class="benefits-section"> |
|||
<text class="benefits-content">转正满2个月体检费196元企业报销(凭发票)</text> |
|||
<text class="benefits-content">有部分为显微镜工作,显微镜工作额外有0-300的岗位补贴(具体以厂区发放为准抱拳)</text> |
|||
</view> |
|||
|
|||
<!-- 分隔线 --> |
|||
<view class="divider"></view> |
|||
|
|||
<!-- 用户评价区域 --> |
|||
<view class="comments-section"> |
|||
<view class="section-title">用户评价</view> |
|||
|
|||
<!-- 动态渲染评价列表 --> |
|||
<view class="comment-item" v-for="(comment, index) in comments" :key="comment.id"> |
|||
<view class="user-info"> |
|||
<view class="avatar"></view> |
|||
<text class="username">{{ comment.username }}</text> |
|||
</view> |
|||
<text class="comment-content">{{ comment.content }}</text> |
|||
<view class="image-container"> |
|||
<view class="comment-image"></view> |
|||
<view class="comment-image"></view> |
|||
<view class="comment-image"></view> |
|||
</view> |
|||
<view class="like-section"> |
|||
<text class="like-count">{{ comment.likes }}</text> |
|||
<text class="like-icon" :class="{ active: comment.isLiked }" @click="toggleLike(index)">👍</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 如果评价数量大于1,显示分隔线 --> |
|||
<view class="comment-divider" v-if="comments.length > 1"></view> |
|||
</view> |
|||
|
|||
<!-- 底部空间,确保内容不被底部按钮遮挡 --> |
|||
<view class="bottom-space"></view> |
|||
</view> |
|||
|
|||
<!-- 底部固定操作按钮 --> |
|||
<view class="bottom-action"> |
|||
<button class="apply-btn" @click="applyJob">立即申请</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
// 职位数据 |
|||
comments: [ |
|||
{ |
|||
id: 1, |
|||
username: '网友120489', |
|||
content: '工作很轻松,基本都是手上的活', |
|||
likes: 6, |
|||
isLiked: false |
|||
}, |
|||
{ |
|||
id: 2, |
|||
username: '网友120489', |
|||
content: '工作很轻松,基本都是手上的活', |
|||
likes: 6, |
|||
isLiked: true |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
methods: { |
|||
// 返回上一页 |
|||
goBack() { |
|||
uni.navigateBack(); |
|||
}, |
|||
// 拨打电话功能 |
|||
makeCall() { |
|||
uni.makePhoneCall({ |
|||
phoneNumber: '400-123-4567' |
|||
}); |
|||
}, |
|||
// 点赞/取消点赞 |
|||
toggleLike(index) { |
|||
if (this.comments[index].isLiked) { |
|||
// 取消点赞 |
|||
this.comments[index].likes--; |
|||
} else { |
|||
// 点赞 |
|||
this.comments[index].likes++; |
|||
} |
|||
// 切换点赞状态 |
|||
this.comments[index].isLiked = !this.comments[index].isLiked; |
|||
}, |
|||
// 申请职位 |
|||
applyJob() { |
|||
uni.showToast({ |
|||
title: '申请成功,请保持电话畅通', |
|||
icon: 'success' |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.position-detail-page { |
|||
// 页面背景色 |
|||
background-color: #f5f5f5; |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
|
|||
// 导航栏 |
|||
.nav-bar { |
|||
height: 44px; |
|||
background-color: #fff; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 0 16px; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 100; |
|||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); |
|||
|
|||
.back-btn { |
|||
width: 40px; |
|||
height: 40px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-size: 20px; |
|||
color: #333; |
|||
} |
|||
|
|||
.nav-title { |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.nav-right { |
|||
width: 40px; |
|||
} |
|||
} |
|||
|
|||
// 内容包装器 |
|||
.content-wrapper { |
|||
overflow-y: auto; |
|||
max-height: calc(100vh); |
|||
padding-bottom: 70px; // 为底部操作按钮留出空间 |
|||
} |
|||
|
|||
// 底部空间,确保内容不被底部按钮遮挡 |
|||
.bottom-space { |
|||
height: 20px; |
|||
} |
|||
|
|||
// 头部信息区域 |
|||
.header-section { |
|||
background-color: #fff; |
|||
padding: 16px; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.factory-info { |
|||
.factory-name { |
|||
font-size: 18px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.factory-type { |
|||
font-size: 14px; |
|||
color: #0099ff; |
|||
background-color: #e6f7ff; |
|||
padding: 2px 6px; |
|||
border-radius: 4px; |
|||
margin-left: 8px; |
|||
} |
|||
|
|||
.distance { |
|||
font-size: 14px; |
|||
color: #999; |
|||
margin-left: 12px; |
|||
} |
|||
} |
|||
|
|||
.call-btn { |
|||
height: 36px; |
|||
padding: 0 16px; |
|||
background-color: #ff4757; |
|||
color: white; |
|||
font-size: 14px; |
|||
border: none; |
|||
border-radius: 18px; |
|||
} |
|||
} |
|||
|
|||
// 工作时间区域 |
|||
.work-time-section { |
|||
background-color: #fff; |
|||
padding: 12px 16px; |
|||
margin-top: 8px; |
|||
|
|||
.time, |
|||
.business { |
|||
font-size: 14px; |
|||
color: #666; |
|||
margin-right: 16px; |
|||
} |
|||
} |
|||
|
|||
// 薪资信息区域 |
|||
.salary-section { |
|||
background-color: #fff; |
|||
padding: 16px; |
|||
margin-top: 8px; |
|||
|
|||
.salary-item { |
|||
margin-bottom: 16px; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.item-title { |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
margin-bottom: 8px; |
|||
display: block; |
|||
} |
|||
|
|||
.salary-content { |
|||
font-size: 14px; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
white-space: pre-wrap; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 福利信息区域 |
|||
.benefits-section { |
|||
background-color: #fff; |
|||
padding: 16px; |
|||
margin-top: 8px; |
|||
|
|||
.benefits-content { |
|||
font-size: 14px; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
margin-bottom: 8px; |
|||
display: block; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 分隔线 |
|||
.divider { |
|||
height: 12px; |
|||
background-color: #f5f5f5; |
|||
margin-top: 8px; |
|||
} |
|||
|
|||
// 用户评价区域 |
|||
.comments-section { |
|||
background-color: #fff; |
|||
padding-top: 12px; |
|||
|
|||
.section-title { |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
padding: 0 16px 12px; |
|||
} |
|||
|
|||
.comment-item { |
|||
padding: 16px; |
|||
|
|||
.user-info { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 12px; |
|||
|
|||
.avatar { |
|||
width: 36px; |
|||
height: 36px; |
|||
border-radius: 50%; |
|||
background-color: #ddd; |
|||
margin-right: 12px; |
|||
} |
|||
|
|||
.username { |
|||
font-size: 14px; |
|||
color: #333; |
|||
} |
|||
} |
|||
|
|||
.comment-content { |
|||
font-size: 15px; |
|||
color: #333; |
|||
line-height: 1.6; |
|||
margin-bottom: 12px; |
|||
display: block; |
|||
} |
|||
|
|||
.image-container { |
|||
display: flex; |
|||
margin-bottom: 12px; |
|||
|
|||
.comment-image { |
|||
width: 80px; |
|||
height: 80px; |
|||
background-color: #eee; |
|||
border-radius: 4px; |
|||
margin-right: 12px; |
|||
|
|||
&:last-child { |
|||
margin-right: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.like-section { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-end; |
|||
|
|||
.like-count { |
|||
font-size: 14px; |
|||
color: #999; |
|||
margin-right: 4px; |
|||
} |
|||
|
|||
.like-icon { |
|||
font-size: 16px; |
|||
cursor: pointer; |
|||
|
|||
&.active { |
|||
color: #ff4757; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.comment-divider { |
|||
height: 1px; |
|||
background-color: #eee; |
|||
margin: 0 16px; |
|||
} |
|||
} |
|||
|
|||
// 底部固定操作按钮 |
|||
.bottom-action { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 50px; |
|||
background-color: #fff; |
|||
padding: 8px 16px; |
|||
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.1); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
z-index: 99; |
|||
|
|||
.apply-btn { |
|||
height: 40px; |
|||
width: 100%; |
|||
background-color: #ff4757; |
|||
color: white; |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
border: none; |
|||
border-radius: 20px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,262 @@ |
|||
<template> |
|||
<view class="search-positions-page"> |
|||
<!-- 搜索区域 --> |
|||
<view class="search-header"> |
|||
<view class="search-input-wrapper"> |
|||
<input type="text" v-model="searchKeyword" placeholder="请输入关键词" class="search-input" /> |
|||
<button class="search-btn" @click="onSearch">搜索</button> |
|||
</view> |
|||
<!-- 搜索标签 --> |
|||
<view class="search-tags"> |
|||
<view class="tag" :class="{ active: activeTag === '长白班' }" @click="onTagClick('长白班')">长白班</view> |
|||
<view class="tag" :class="{ active: activeTag === '高工资' }" @click="onTagClick('高工资')">高工资</view> |
|||
<view class="tag" :class="{ active: activeTag === '包吃住' }" @click="onTagClick('包吃住')">包吃住</view> |
|||
<view class="tag" :class="{ active: activeTag === '日结' }" @click="onTagClick('日结')">日结</view> |
|||
<view class="tag" :class="{ active: activeTag === '大龄工' }" @click="onTagClick('大龄工')">大龄工</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="search-list" :refresher-enabled="true" :refresher-triggered="refreshing" @refresherrefresh="onRefresh" @scrolltolower="onLoadMore"> |
|||
<template v-for="item in list.records" :key="item.jobId"> |
|||
<recruitment :dataSource="item"></recruitment> |
|||
<view class="driver"></view> |
|||
</template> |
|||
<view class="loading-more"> |
|||
<text v-if="loadingMore">加载中...</text> |
|||
<text v-else-if="noMoreData">没有更多数据了</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
onLoad |
|||
} from '@dcloudio/uni-app' |
|||
import { |
|||
getAppJobVO |
|||
} from '../../api'; |
|||
import { |
|||
ref |
|||
} from 'vue'; |
|||
const list = ref([]) |
|||
const searchKeyword = ref('') |
|||
const refreshing = ref(false) |
|||
const loadingMore = ref(false) |
|||
const noMoreData = ref(false) |
|||
const currentPage = ref(1) |
|||
const pageSize = ref(10) |
|||
|
|||
const hanleGetJobList = async (params = {}) => { |
|||
const res = await getAppJobVO({ |
|||
pageNum: currentPage.value, |
|||
pageSize: pageSize.value, |
|||
...params |
|||
}) |
|||
console.log(res) |
|||
|
|||
if (currentPage.value === 1) { |
|||
// 刷新或首次加载 |
|||
list.value = res.data |
|||
} else { |
|||
// 加载更多 |
|||
list.value.records = [...list.value.records, ...res.data.records] |
|||
} |
|||
|
|||
// 检查是否还有更多数据 |
|||
if (res.data.records.length < pageSize.value) { |
|||
noMoreData.value = true |
|||
} else { |
|||
noMoreData.value = false |
|||
} |
|||
} |
|||
|
|||
onLoad(() => { |
|||
currentPage.value = 1 |
|||
hanleGetJobList() |
|||
}) |
|||
|
|||
const onRefresh = async () => { |
|||
refreshing.value = true |
|||
currentPage.value = 1 |
|||
noMoreData.value = false |
|||
try { |
|||
await hanleGetJobList() |
|||
uni.showToast({ |
|||
title: '刷新成功', |
|||
icon: 'success' |
|||
}) |
|||
} catch (error) { |
|||
uni.showToast({ |
|||
title: '刷新失败', |
|||
icon: 'none' |
|||
}) |
|||
} finally { |
|||
refreshing.value = false |
|||
} |
|||
} |
|||
|
|||
const onLoadMore = async () => { |
|||
// 如果已经在加载或没有更多数据,则不执行 |
|||
if (loadingMore.value || noMoreData.value) return |
|||
|
|||
loadingMore.value = true |
|||
currentPage.value++ |
|||
|
|||
try { |
|||
await hanleGetJobList() |
|||
} catch (error) { |
|||
uni.showToast({ |
|||
title: '加载失败', |
|||
icon: 'none' |
|||
}) |
|||
currentPage.value-- |
|||
} finally { |
|||
loadingMore.value = false |
|||
} |
|||
} |
|||
|
|||
const onSearch = () => { |
|||
console.log(searchKeyword.value) |
|||
const params = { |
|||
jobName: searchKeyword.value |
|||
} |
|||
// 搜索时重置到第一页 |
|||
currentPage.value = 1 |
|||
noMoreData.value = false |
|||
hanleGetJobList(params) |
|||
} |
|||
/* // 导入recruitment组件 |
|||
import recruitment from '@/components/recruitment/recruitment.vue'; |
|||
export default { |
|||
// 注册组件 |
|||
components: { |
|||
recruitment |
|||
}, |
|||
data() { |
|||
return { |
|||
searchKeyword: '', |
|||
activeTag: '' |
|||
} |
|||
}, |
|||
methods: { |
|||
// 搜索方法 |
|||
onSearch() { |
|||
// 实现搜索逻辑 |
|||
console.log('搜索关键词:', this.searchKeyword); |
|||
}, |
|||
// 标签点击方法 |
|||
onTagClick(tag) { |
|||
this.activeTag = this.activeTag === tag ? '' : tag; |
|||
console.log('点击标签:', tag); |
|||
} |
|||
} |
|||
} */ |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.search-positions-page { |
|||
// 页面容器设置 |
|||
height: 100vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
background-color: #f8f8f8; |
|||
|
|||
// 搜索头部样式 - 固定在顶部 |
|||
.search-header { |
|||
padding: 12px 16px; |
|||
background-color: #fff; |
|||
z-index: 10; |
|||
|
|||
// 搜索框包装器 |
|||
.search-input-wrapper { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 12px; |
|||
|
|||
// 搜索输入框 |
|||
.search-input { |
|||
flex: 1; |
|||
height: 32px; |
|||
background-color: #f5f5f5; |
|||
border-radius: 20px 0 0 20px; |
|||
padding: 0 16px; |
|||
border: none; |
|||
font-size: 14px; |
|||
color: #333; |
|||
outline: none; |
|||
|
|||
&::placeholder { |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
// 搜索按钮 |
|||
.search-btn { |
|||
height: 32px; |
|||
width: 80px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
background-color: #ff4757; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 0 20px 20px 0; |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
} |
|||
} |
|||
|
|||
// 搜索标签区域 |
|||
.search-tags { |
|||
display: flex; |
|||
gap: 12px; |
|||
flex-wrap: wrap; |
|||
|
|||
// 标签样式 |
|||
.tag { |
|||
padding: 4px 8px; |
|||
border: 1px solid #ddd; |
|||
border-radius: 8px; |
|||
font-size: 12px; |
|||
color: #666; |
|||
background-color: white; |
|||
|
|||
// 选中状态 |
|||
&.active { |
|||
color: #ff4757; |
|||
border-color: #ff4757; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 列表样式 - 可滚动区域 |
|||
.search-list { |
|||
padding: 4px; |
|||
flex: 1; |
|||
overflow-y: auto; |
|||
|
|||
// 隐藏滚动条但保留滚动功能 |
|||
::-webkit-scrollbar { |
|||
display: none; |
|||
} |
|||
|
|||
-ms-overflow-style: none; |
|||
scrollbar-width: none; |
|||
} |
|||
|
|||
.driver { |
|||
width: 100%; |
|||
height: 1px; |
|||
background-color: #eee; |
|||
} |
|||
|
|||
.loading-more { |
|||
text-align: center; |
|||
padding: 16px 0; |
|||
font-size: 14px; |
|||
color: #999; |
|||
} |
|||
} |
|||
</style> |
|||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 894 B |
|
After Width: | Height: | Size: 845 B |
|
After Width: | Height: | Size: 516 B |
|
After Width: | Height: | Size: 505 B |
|
After Width: | Height: | Size: 629 B |
|
After Width: | Height: | Size: 610 B |
|
After Width: | Height: | Size: 873 B |
@ -0,0 +1,64 @@ |
|||
import { defineStore } from 'pinia'; |
|||
|
|||
export const useUserStore = defineStore('user', { |
|||
state: () => ({ |
|||
loginRes: uni.getStorageSync('loginRes') || null, // 存储登录响应数据
|
|||
userInfo: uni.getStorageSync('userInfo') || null, // 用户信息
|
|||
token: uni.getStorageSync('token') || null // 认证令牌
|
|||
}), |
|||
|
|||
getters: { |
|||
isLoggedIn: (state) => !!state.token, |
|||
userId: (state) => state.userInfo?.userId || null |
|||
}, |
|||
|
|||
actions: { |
|||
/** |
|||
* 设置登录响应数据 |
|||
* @param {Object} data - 登录响应数据 |
|||
*/ |
|||
setLoginRes(data) { |
|||
this.loginRes = data; |
|||
uni.setStorageSync('loginRes', data); |
|||
}, |
|||
|
|||
/** |
|||
* 设置用户信息 |
|||
* @param {Object} userInfo - 用户信息 |
|||
*/ |
|||
setUserInfo(userInfo) { |
|||
this.userInfo = userInfo; |
|||
uni.setStorageSync('userInfo', userInfo); |
|||
}, |
|||
|
|||
/** |
|||
* 设置认证令牌 |
|||
* @param {String} token - 认证令牌 |
|||
*/ |
|||
setToken(token) { |
|||
this.token = token; |
|||
uni.setStorageSync('token', token); |
|||
}, |
|||
|
|||
/** |
|||
* 清除所有用户数据 |
|||
*/ |
|||
clearUserData() { |
|||
this.loginRes = null; |
|||
this.userInfo = null; |
|||
this.token = null; |
|||
uni.removeStorageSync('loginRes'); |
|||
uni.removeStorageSync('userInfo'); |
|||
uni.removeStorageSync('token'); |
|||
}, |
|||
|
|||
/** |
|||
* 更新用户信息 |
|||
* @param {Object} updates - 要更新的用户信息字段 |
|||
*/ |
|||
updateUserInfo(updates) { |
|||
this.userInfo = { ...this.userInfo, ...updates }; |
|||
uni.setStorageSync('userInfo', this.userInfo); |
|||
} |
|||
} |
|||
}); |
|||
@ -0,0 +1,13 @@ |
|||
uni.addInterceptor({ |
|||
returnValue (res) { |
|||
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { |
|||
return res; |
|||
} |
|||
return new Promise((resolve, reject) => { |
|||
res.then((res) => { |
|||
if (!res) return resolve(res) |
|||
return res[0] ? reject(res[0]) : resolve(res[1]) |
|||
}); |
|||
}); |
|||
}, |
|||
}); |
|||
@ -0,0 +1,76 @@ |
|||
/** |
|||
* 这里是uni-app内置的常用样式变量 |
|||
* |
|||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 |
|||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App |
|||
* |
|||
*/ |
|||
|
|||
/** |
|||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 |
|||
* |
|||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 |
|||
*/ |
|||
|
|||
/* 颜色变量 */ |
|||
|
|||
/* 行为相关颜色 */ |
|||
$uni-color-primary: #6DC2AA; |
|||
$uni-color-success: #4cd964; |
|||
$uni-color-warning: #f0ad4e; |
|||
$uni-color-error: #dd524d; |
|||
|
|||
/* 文字基本颜色 */ |
|||
$uni-text-color:#333;//基本色 |
|||
$uni-text-color-inverse:#fff;//反色 |
|||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 |
|||
$uni-text-color-placeholder: #808080; |
|||
$uni-text-color-disable:#c0c0c0; |
|||
|
|||
/* 背景颜色 */ |
|||
$uni-bg-color:#ffffff; |
|||
$uni-bg-color-grey:#f8f8f8; |
|||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色 |
|||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 |
|||
|
|||
/* 边框颜色 */ |
|||
$uni-border-color:#c8c7cc; |
|||
|
|||
/* 尺寸变量 */ |
|||
|
|||
/* 文字尺寸 */ |
|||
$uni-font-size-sm:12px; |
|||
$uni-font-size-base:14px; |
|||
$uni-font-size-lg:16px; |
|||
|
|||
/* 图片尺寸 */ |
|||
$uni-img-size-sm:20px; |
|||
$uni-img-size-base:26px; |
|||
$uni-img-size-lg:40px; |
|||
|
|||
/* Border Radius */ |
|||
$uni-border-radius-sm: 2px; |
|||
$uni-border-radius-base: 3px; |
|||
$uni-border-radius-lg: 6px; |
|||
$uni-border-radius-circle: 50%; |
|||
|
|||
/* 水平间距 */ |
|||
$uni-spacing-row-sm: 5px; |
|||
$uni-spacing-row-base: 10px; |
|||
$uni-spacing-row-lg: 15px; |
|||
|
|||
/* 垂直间距 */ |
|||
$uni-spacing-col-sm: 4px; |
|||
$uni-spacing-col-base: 8px; |
|||
$uni-spacing-col-lg: 12px; |
|||
|
|||
/* 透明度 */ |
|||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 |
|||
|
|||
/* 文章场景相关 */ |
|||
$uni-color-title: #2C405A; // 文章标题颜色 |
|||
$uni-font-size-title:20px; |
|||
$uni-color-subtitle: #555555; // 二级标题颜色 |
|||
$uni-font-size-subtitle:26px; |
|||
$uni-color-paragraph: #3F536E; // 文章段落颜色 |
|||
$uni-font-size-paragraph:15px; |
|||