前端-胡立永 3 days ago
parent
commit
f54fe343f5
9 changed files with 443 additions and 102 deletions
  1. +280
    -0
      components/AddressPicker.vue
  2. +27
    -1
      components/screen/screenWork.vue
  3. +11
    -1
      pages/index/index.vue
  4. +1
    -1
      pages_order/mine/InvitationCredit.vue
  5. +61
    -15
      pages_order/work/addResume.vue
  6. +30
    -10
      pages_order/work/jobPosting.vue
  7. +33
    -1
      store/store.js
  8. +0
    -10
      utils/oss-upload/oss/index.js
  9. +0
    -63
      utils/oss-upload/oss/web.js

+ 280
- 0
components/AddressPicker.vue View File

@ -0,0 +1,280 @@
<template>
<uv-popup ref="popup" mode="bottom" :round="30"
:safeAreaInsetBottom="false" @close="handleClose">
<view class="address-picker">
<view class="header">
<view class="title">选择地址</view>
<view class="close-btn" @click="close">
<uv-icon name="close" size="40rpx"></uv-icon>
</view>
</view>
<view class="content">
<!-- 左侧一级地址列表 -->
<view class="left-panel">
<scroll-view scroll-y class="scroll-view">
<view
class="address-item"
:class="{ active: selectedProvince && selectedProvince.id === item.id }"
v-for="item in addressList"
:key="item.id"
@click="selectProvince(item)">
{{ item.adress }}
</view>
</scroll-view>
</view>
<!-- 右侧二三级地址列表 -->
<view class="right-panel">
<scroll-view scroll-y class="scroll-view">
<!-- 二级地址 -->
<template v-if="selectedProvince && !selectedCity">
<view
class="address-item"
v-for="item in cityList"
:key="item.id"
@click="selectCity(item)">
{{ item.adress }}
</view>
</template>
<!-- 三级地址 -->
<template v-if="selectedCity">
<view
class="address-item back-item"
@click="backToCity">
<uv-icon name="arrow-left" size="30rpx"></uv-icon>
返回{{ selectedProvince.adress }}
</view>
<view
class="address-item"
v-for="item in districtList"
:key="item.id"
@click="selectDistrict(item)">
{{ item.adress }}
</view>
</template>
</scroll-view>
</view>
</view>
</view>
</uv-popup>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'AddressPicker',
props: {
//
onlyCity: {
type: Boolean,
default: false
}
},
data() {
return {
selectedProvince: null, //
selectedCity: null, //
selectedDistrict: null, //
cityList: [], //
districtList: [], //
}
},
computed: {
...mapState(['addressList'])
},
methods: {
//
open() {
this.$refs.popup.open()
},
//
close() {
this.$refs.popup.close()
},
//
handleClose() {
this.selectedProvince = null
this.selectedCity = null
this.selectedDistrict = null
this.cityList = []
this.districtList = []
},
//
async selectProvince(province) {
this.selectedProvince = province
this.selectedCity = null
this.selectedDistrict = null
this.districtList = []
//
try {
this.cityList = await this.$store.dispatch('getChildAddressList', province.id)
//
if (this.cityList.length === 0) {
this.confirm()
}
} catch (error) {
console.error('获取城市列表失败:', error)
this.cityList = []
//
this.confirm()
}
},
//
async selectCity(city) {
this.selectedCity = city
this.selectedDistrict = null
//
if (this.onlyCity) {
this.confirm()
return
}
//
try {
this.districtList = await this.$store.dispatch('getChildAddressList', city.id)
//
if (this.districtList.length === 0) {
this.confirm()
}
} catch (error) {
console.error('获取区县列表失败:', error)
this.districtList = []
//
this.confirm()
}
},
//
selectDistrict(district) {
this.selectedDistrict = district
this.confirm()
},
//
backToCity() {
this.selectedCity = null
this.selectedDistrict = null
this.districtList = []
},
//
confirm() {
const result = {
province: this.selectedProvince,
city: this.selectedCity,
district: this.selectedDistrict
}
//
let fullAddress = ''
if (this.selectedProvince) {
fullAddress += this.selectedProvince.adress
}
if (this.selectedCity) {
fullAddress += this.selectedCity.adress
}
if (this.selectedDistrict) {
fullAddress += this.selectedDistrict.adress
}
result.fullAddress = fullAddress
result.selectedAddress = this.selectedDistrict || this.selectedCity || this.selectedProvince
this.$emit('confirm', result)
this.close()
}
}
}
</script>
<style scoped lang="scss">
.address-picker {
height: 70vh;
background: #fff;
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1px solid #eee;
.title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.close-btn {
padding: 10rpx;
}
}
.content {
display: flex;
height: calc(70vh - 160rpx);
.left-panel {
width: 240rpx;
border-right: 1px solid #eee;
background: #f8f8f8;
}
.right-panel {
flex: 1;
}
.scroll-view {
height: 100%;
}
.address-item {
padding: 30rpx 20rpx;
font-size: 28rpx;
color: #333;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
&.active {
background: #fff;
color: $uni-color;
font-weight: bold;
position: relative;
&::after {
content: '';
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 6rpx;
background: $uni-color;
}
}
&.back-item {
display: flex;
align-items: center;
color: $uni-color;
background: #f8f8f8;
uv-icon {
margin-right: 10rpx;
}
}
}
}
}
</style>

+ 27
- 1
components/screen/screenWork.vue View File

@ -9,7 +9,7 @@
:custom-style="{padding: '0 30rpx'}" :custom-style="{padding: '0 30rpx'}"
@click="selectMenu"> @click="selectMenu">
<uv-drop-down-item name="areaId" type="2"
<uv-drop-down-item name="areaId" type="1"
:label="dropItem('areaId').label" :label="dropItem('areaId').label"
:value="dropItem('areaId').value"> :value="dropItem('areaId').value">
</uv-drop-down-item> </uv-drop-down-item>
@ -41,6 +41,9 @@
@clickItem="clickItem" @clickItem="clickItem"
@popupChange="change"></uv-drop-down-popup> @popupChange="change"></uv-drop-down-popup>
<!-- 地址选择组件 -->
<AddressPicker ref="addressPicker" @confirm="onAddressConfirm" />
<uv-popup ref="popup" :round="30" <uv-popup ref="popup" :round="30"
:safeAreaInsetBottom="false"> :safeAreaInsetBottom="false">
<view class="popup"> <view class="popup">
@ -76,7 +79,11 @@
import { import {
mapState, mapState,
} from 'vuex' } from 'vuex'
import AddressPicker from '@/components/AddressPicker.vue'
export default { export default {
components: {
AddressPicker
},
props : { props : {
sign : { sign : {
default : 'dropDown_1' default : 'dropDown_1'
@ -244,6 +251,13 @@
this.activeName = name; this.activeName = name;
// 使AddressPicker
if(name === 'areaId'){
this.$refs.addressPicker.open()
return
}
//
if(type == 1){ if(type == 1){
this.$refs.popup.open() this.$refs.popup.open()
return return
@ -313,6 +327,18 @@
this.$refs.popup.close() this.$refs.popup.close()
}, },
//
onAddressConfirm(addressResult) {
// areaId
this.areaId.label = addressResult.fullAddress
this.areaId.value = addressResult.selectedAddress.selectedAddress
// clickItemresult
this.clickItem({
label: addressResult.fullAddress,
value: addressResult.selectedAddress.selectedAddress
})
},
} }
} }
</script> </script>


+ 11
- 1
pages/index/index.vue View File

@ -39,8 +39,12 @@
v-if="jobTypeList.length > 4" v-if="jobTypeList.length > 4"
@click="$utils.navigateTo(`/pages_order/work/workTypeList`)" @click="$utils.navigateTo(`/pages_order/work/workTypeList`)"
> >
<image class="grid-icon" src="/static/image/home/5.png" mode="aspectFill"></image>
<image class="grid-icon" :src="configList.config_other_job
|| config_other_job " mode="aspectFill"></image>
<text class="grid-text">其他招工</text> <text class="grid-text">其他招工</text>
<!--
|| `/static/image/home/5.png` -->
</uv-grid-item> </uv-grid-item>
</uv-grid> </uv-grid>
</view> </view>
@ -125,12 +129,18 @@
productList: [], productList: [],
keyword : '', keyword : '',
screenWorkList : [], screenWorkList : [],
config_other_job : '',
} }
}, },
onPullDownRefresh(){ onPullDownRefresh(){
this.$refs.workList.getData(this.screenWorkList) this.$refs.workList.getData(this.screenWorkList)
this.$store.commit('getBanner') this.$store.commit('getBanner')
}, },
onLoad(){
uni.on('initConfig', (e) => {
this.config_other_job = e.config_other_job
})
},
// //
onShow() { onShow() {
this.$refs.workList.getData(this.screenWorkList) this.$refs.workList.getData(this.screenWorkList)


+ 1
- 1
pages_order/mine/InvitationCredit.vue View File

@ -81,7 +81,7 @@
</view> --> </view> -->
<view class="" <view class=""
style="padding: 20rpx;">
style="padding: 20rpx;background-color: #fff;">
<uv-parse :content="configList.config_score_rule"></uv-parse> <uv-parse :content="configList.config_score_rule"></uv-parse>
</view> </view>


+ 61
- 15
pages_order/work/addResume.vue View File

@ -14,13 +14,20 @@
<view class="title"> <view class="title">
{{ item.title }} {{ item.title }}
</view> </view>
<view class="tagList">
<view class="tagList" v-if="!item.useAddressPicker">
<view :class="{act : i == item.index}" <view :class="{act : i == item.index}"
@click="clickTag(item, i)" v-for="(t, i) in item.tag" @click="clickTag(item, i)" v-for="(t, i) in item.tag"
:key="t.id"> :key="t.id">
{{ t.name || t.adress }} {{ t.name || t.adress }}
</view> </view>
</view> </view>
<!-- 地址选择器模式 -->
<view class="address-selector" v-else @click="openAddressPicker">
<view class="selected-address">
{{ selectedAddress || '请选择工作地区' }}
</view>
<uv-icon name="arrow-right" size="30rpx"></uv-icon>
</view>
</view> </view>
</view> </view>
@ -118,13 +125,19 @@
<uv-picker ref="picker" <uv-picker ref="picker"
:columns="columns" :columns="columns"
@confirm="pickerConfirm"></uv-picker> @confirm="pickerConfirm"></uv-picker>
<!-- 地址选择组件 -->
<AddressPicker ref="addressPicker" @confirm="onAddressConfirm" />
</view> </view>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import index from '../../uni_modules/uv-ui-tools'
import AddressPicker from '@/components/AddressPicker.vue'
export default { export default {
components: {
AddressPicker
},
data() { data() {
return { return {
list: [ list: [
@ -140,6 +153,7 @@ import index from '../../uni_modules/uv-ui-tools'
tag: [], tag: [],
index: 0, index: 0,
type : 'expectAddress', type : 'expectAddress',
useAddressPicker: true, // 使
}, },
{ {
title: '您希望从事工作的性质', title: '您希望从事工作的性质',
@ -181,6 +195,7 @@ import index from '../../uni_modules/uv-ui-tools'
], ],
}, },
pickerKey : 'workAge', pickerKey : 'workAge',
selectedAddress: '', //
} }
}, },
computed : { computed : {
@ -229,7 +244,10 @@ import index from '../../uni_modules/uv-ui-tools'
// } // }
this.list.forEach(n => { this.list.forEach(n => {
this.form[n.type] = n.tag[n.index].id
// 使tag
if(!n.useAddressPicker) {
this.form[n.type] = n.tag[n.index].id
}
}) })
if (this.$utils.verificationAll(this.form, { if (this.$utils.verificationAll(this.form, {
@ -283,19 +301,31 @@ import index from '../../uni_modules/uv-ui-tools'
this.form = res.result.records[0] this.form = res.result.records[0]
this.list.forEach((n, i) => { this.list.forEach((n, i) => {
n.tag.forEach((e, index) => {
if(this.form[n.type] == e.id){
n.index = index
}
})
//
if(n.useAddressPicker && this.form[n.type]) {
this.selectedAddress = this.form[n.type]
} else {
n.tag.forEach((e, index) => {
if(this.form[n.type] == e.id){
n.index = index
}
})
}
}) })
} }
}) })
}, },
//
openAddressPicker() {
this.$refs.addressPicker.open()
},
//
onAddressConfirm(addressResult) {
this.selectedAddress = addressResult.fullAddress
// ID
this.form.expectAddress = addressResult.fullAddress
},
}, },
} }
</script> </script>
@ -328,12 +358,28 @@ import index from '../../uni_modules/uv-ui-tools'
font-size: 26rpx; font-size: 26rpx;
} }
.act {
color: #fff;
background: $uni-color;
}
.act {
color: #fff;
background: $uni-color;
} }
} }
.address-selector {
display: flex;
justify-content: space-between;
align-items: center;
background: rgba($uni-color, 0.1);
padding: 20rpx;
margin: 10rpx;
border-radius: 10rpx;
font-size: 26rpx;
.selected-address {
flex: 1;
color: #333;
}
}
}
} }
.form-sheet-cell{ .form-sheet-cell{


+ 30
- 10
pages_order/work/jobPosting.vue View File

@ -17,7 +17,7 @@
title="所在城市" title="所在城市"
rightIconStyle="fontSize: 30rpx;" rightIconStyle="fontSize: 30rpx;"
:value="form.areaId_dictText || '请选择所在城市'" :value="form.areaId_dictText || '请选择所在城市'"
@click="openPicker('areaId',$refs.addressListPicker)"
@click="openAddressPicker"
isLink isLink
></uv-cell> ></uv-cell>
@ -189,10 +189,7 @@
keyName="name" keyName="name"
@confirm="pickerConfirm"></uv-picker> @confirm="pickerConfirm"></uv-picker>
<uv-picker ref="addressListPicker"
:columns="[addressList]"
keyName="adress"
@confirm="pickerConfirm"></uv-picker>
<uv-datetime-picker <uv-datetime-picker
ref="datetimePicker" ref="datetimePicker"
@ -202,6 +199,9 @@
@confirm="datePickerConfirm"> @confirm="datePickerConfirm">
</uv-datetime-picker> </uv-datetime-picker>
<!-- 地址选择组件 -->
<AddressPicker ref="addressPicker" onlyCity @confirm="onAddressConfirm" />
<view class="uni-color-btn" <view class="uni-color-btn"
@click="submit"> @click="submit">
发布 发布
@ -212,7 +212,11 @@
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import AddressPicker from '@/components/AddressPicker.vue'
export default { export default {
components: {
AddressPicker
},
data() { data() {
return { return {
form : { form : {
@ -288,11 +292,14 @@
if (res.code == 200) { if (res.code == 200) {
let detail = res.result.jobInfo let detail = res.result.jobInfo
this.addressList.forEach(address => {
if(address.id == detail.areaId){
detail.areaId_dictText = address.adress
}
})
// areaId
if(detail.areaId && !detail.areaId_dictText) {
this.addressList.forEach(address => {
if(address.id == detail.areaId){
detail.areaId_dictText = address.adress
}
})
}
this.jobTypeList.forEach(type => { this.jobTypeList.forEach(type => {
if(type.id == detail.typeId){ if(type.id == detail.typeId){
@ -306,6 +313,7 @@
delete detail.hanHaiMember delete detail.hanHaiMember
delete detail.updateTime delete detail.updateTime
delete detail.updateBy delete detail.updateBy
delete detail.areaId // areaId
this.form = detail this.form = detail
@ -350,6 +358,7 @@
if (this.$utils.verificationAll(this.form, { if (this.$utils.verificationAll(this.form, {
title: '请输入招工标题', title: '请输入招工标题',
areaId_dictText: '请选择所在城市',
workAddress : '请选择工作地点', workAddress : '请选择工作地点',
workAge : '请选择工龄要求', workAge : '请选择工龄要求',
// company : '', // company : '',
@ -426,6 +435,17 @@
this.form.latitude = '' this.form.latitude = ''
this.form.longitude = '' this.form.longitude = ''
}, },
//
openAddressPicker() {
this.$refs.addressPicker.open()
},
//
onAddressConfirm(addressResult) {
// ID
this.form.areaId_dictText = addressResult.fullAddress
},
} }
} }
</script> </script>


+ 33
- 1
store/store.js View File

@ -16,6 +16,7 @@ const store = new Vuex.Store({
jobTypeList : [],//工种 jobTypeList : [],//工种
natureList : [],//工作性质 natureList : [],//工作性质
addressList : [],//开放地址 addressList : [],//开放地址
addressTreeMap : {},//多级地址映射,key为父级id,value为子级数组
UserExtensionInfo : {},//用户扩展信息,包含认证信息、统计信息 UserExtensionInfo : {},//用户扩展信息,包含认证信息、统计信息
}, },
getters: { getters: {
@ -31,6 +32,8 @@ const store = new Vuex.Store({
n.paramValueImage n.paramValueImage
// state.configList[n.keyName + '_keyValue'] = n.keyValue // state.configList[n.keyName + '_keyValue'] = n.keyValue
}) })
uni.emit('initConfig', state.configList)
} }
}) })
@ -109,6 +112,7 @@ const store = new Vuex.Store({
api('commonQueryAddressList', { api('commonQueryAddressList', {
pageNo : 1, pageNo : 1,
pageSize : 99999, pageSize : 99999,
pid : 0,
}, res => { }, res => {
if(res.code != 200){ if(res.code != 200){
return return
@ -229,8 +233,36 @@ const store = new Vuex.Store({
} }
}) })
}, },
// 设置子级地址列表到状态中
setChildAddressList(state, { pid, list }){
state.addressTreeMap[pid] = list
},
},
actions: {
// 获取子级地址列表
async getChildAddressList({ state, commit }, pid){
// 如果已经缓存了,直接返回
if(state.addressTreeMap[pid]){
return Promise.resolve(state.addressTreeMap[pid])
}
return new Promise((resolve, reject) => {
api('commonQueryAddressList', {
pageNo : 1,
pageSize : 99999,
pid : pid,
}, res => {
if(res.code == 200){
// 存储到映射中
commit('setChildAddressList', { pid, list: res.result.records })
resolve(res.result.records)
} else {
reject(res)
}
})
})
},
}, },
actions: {},
}) })
export default store export default store

+ 0
- 10
utils/oss-upload/oss/index.js View File

@ -2,10 +2,6 @@
* 阿里云OSS工具类 * 阿里云OSS工具类
*/ */
import OSSConfig from "@/utils/oss-upload/oss/OSSConfig.js" import OSSConfig from "@/utils/oss-upload/oss/OSSConfig.js"
//支持web端
import {
uploadFileToOSS
} from '@/utils/oss-upload/oss/web.js'
import ossConfig from '@/config.js' import ossConfig from '@/config.js'
/** /**
@ -98,9 +94,6 @@ export function ossUploadImage({
count: 1, count: 1,
sizeType, sizeType,
success(res) { success(res) {
// #ifdef H5
return uploadFileToOSS(res.tempFiles[0]).then(success).catch(fail)
// #endif
ossUpload(res.tempFilePaths[0], key, folder).then(success).catch(fail) ossUpload(res.tempFilePaths[0], key, folder).then(success).catch(fail)
}, },
fail fail
@ -128,9 +121,6 @@ export function ossUploadVideo({
maxDuration, maxDuration,
camera, camera,
success(res) { success(res) {
// #ifdef H5
return uploadFileToOSS(res.tempFile).then(success).catch(fail)
// #endif
ossUpload(res.tempFilePath, key, folder).then(success).catch(fail) ossUpload(res.tempFilePath, key, folder).then(success).catch(fail)
}, },
fail fail


+ 0
- 63
utils/oss-upload/oss/web.js View File

@ -1,63 +0,0 @@
// 此方法适用于web
import OSS from "ali-oss"
import config from '@/config.js'
/**
* 生成一个随机的Key
*/
function storeKey() {
let s = [];
let hexDigits = "0123456789abcdef";
for (let i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4";
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = "-";
return s.join("");
}
/**
* 根据当天日期在OSS端生成文件夹
*/
function storeFolder() {
const date = new Date();
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
return [date.getFullYear(), date.getMonth() + 1, date.getDate()].map(formatNumber).join('-')
}
export function uploadFileToOSS(file) {
uni.showLoading({
title: '上传中...'
});
return new Promise((resolve,reject) => {
// 创建OSS实例
const client = new OSS(config.aliOss.config);
// 设置文件名和文件目录
const suffix = '.' + file.name.split('.').pop();
let key = storeFolder()
if(key[key.length - 1] != '/') key += '/'
const fileName = key + storeKey() + suffix; // 注意:文件名需要是唯一的
// 使用put接口上传文件
client.multipartUpload(fileName, file, {
headers: {
'Content-Disposition': 'inline',
'Content-Type': file.type
}
}).then(res => {
uni.hideLoading();
resolve(config.aliOss.url + res.name);
}).catch(err => {
uni.hideLoading();
reject(err)
})
})
}

Loading…
Cancel
Save