Commit 8713ee22 authored by 李明环(东信)'s avatar 李明环(东信)

页面补全

parent ef8e094b
# 小程序平台模板 vue3 api: lygsh-api.wjzpgz.com
admin 前端: lygsh-admin.wjzpgz.com
admin 后端: lygsh-admin-parent.wjzpgz.com
七牛图片: lygsh-image.wjzpgz.com
## 安装依赖 七牛后台 bucket:lygsh-admin
``` 七牛云图片 bucket:lygsh-images
yarn install
```
### 本地服务 后台登陆默认账号密码:admin/admin123321
```
yarn start
```
### 小程序平台打包
```
yarn build
```
## 默认安装的 UI 库
[wot-design-uni](https://wot-design-uni.netlify.app/component/button.html)
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"@dcloudio/uni-quickapp-webview": "3.0.0-4000720240327002", "@dcloudio/uni-quickapp-webview": "3.0.0-4000720240327002",
"axios": "^1.7.2", "axios": "^1.7.2",
"dayjs": "^1.11.12", "dayjs": "^1.11.12",
"lodash": "^4.17.21",
"pinia": "2.0.36", "pinia": "2.0.36",
"vue": "^3.3.11", "vue": "^3.3.11",
"vue-i18n": "^9.1.9", "vue-i18n": "^9.1.9",
......
...@@ -53,6 +53,12 @@ importers: ...@@ -53,6 +53,12 @@ importers:
axios: axios:
specifier: ^1.7.2 specifier: ^1.7.2
version: 1.7.2 version: 1.7.2
dayjs:
specifier: ^1.11.12
version: 1.11.12
lodash:
specifier: ^4.17.21
version: 4.17.21
pinia: pinia:
specifier: 2.0.36 specifier: 2.0.36
version: 2.0.36(typescript@4.9.5)(vue@3.4.34(typescript@4.9.5)) version: 2.0.36(typescript@4.9.5)(vue@3.4.34(typescript@4.9.5))
...@@ -1913,6 +1919,9 @@ packages: ...@@ -1913,6 +1919,9 @@ packages:
resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
dayjs@1.11.12:
resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==}
de-indent@1.0.2: de-indent@1.0.2:
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
...@@ -6707,6 +6716,8 @@ snapshots: ...@@ -6707,6 +6716,8 @@ snapshots:
whatwg-mimetype: 2.3.0 whatwg-mimetype: 2.3.0
whatwg-url: 8.7.0 whatwg-url: 8.7.0
dayjs@1.11.12: {}
de-indent@1.0.2: {} de-indent@1.0.2: {}
debug@2.6.9: debug@2.6.9:
......
...@@ -5,6 +5,25 @@ onLaunch(() => { ...@@ -5,6 +5,25 @@ onLaunch(() => {
onShow(() => { onShow(() => {
console.log("App Show"); console.log("App Show");
console.log("============");
/* uni.chooseLocation({
success: function (res) {
console.log("位置名称:" + res.name);
console.log("详细地址:" + res.address);
console.log("纬度:" + res.latitude);
console.log("经度:" + res.longitude);
}
}); */
// uni.getLocation({
// type: "wgs84",
// success: function (res) {
// console.log("当前位置的经度:" + res.longitude);
// console.log("当前位置的纬度:" + res.latitude);
// },
// fail(err) {
// console.log("errerrerr", err);
// }
// });
}); });
onHide(() => { onHide(() => {
......
import instance from "@/utils/request";
//文章分页
export const getArticleListApi = params => instance.post("/article/getPageList", params);
//获取文章i详情
export const getArticleDetailApi = id => instance.post(`/article/detail/${id}`);
//获取文章i详情
export const getArticleTypesApi = type => instance.post(`/article/category/list/${type}`);
...@@ -7,3 +7,5 @@ export const getDictDataApi = params => instance.post("/common/dict/getDictData" ...@@ -7,3 +7,5 @@ export const getDictDataApi = params => instance.post("/common/dict/getDictData"
export const getTreeListApi = params => instance.post("/dict/dictProvinceCityDistrict/getTreeList", params); export const getTreeListApi = params => instance.post("/dict/dictProvinceCityDistrict/getTreeList", params);
// 获取岗位列表 // 获取岗位列表
export const dictJobTypeApi = params => instance.post("/dict/dictJobType/getTree", params); export const dictJobTypeApi = params => instance.post("/dict/dictJobType/getTree", params);
// 获取岗位列表类型(1职位,2政策,3动态)
export const getBannerListApi = type => instance.post(`/banner/list/${type}`);
import instance from "@/utils/request";
// 获取职位列表
export const getjobListApi = params => instance.post("/job/getPageList", params);
// 获取职位详情
export const getJobDetailApi = id => instance.post(`/job/detail/${id}`);
// 投递简历
export const submitResumeApi = id => instance.post(`/job/application/${id}`);
// 获取投递
export const getSubmitResumeApi = id => instance.post(`/job/getApplication/${id}`);
// 获取职位详情
export const getCompanyDetailApi = id => instance.post(`/company/detail/${id}`);
// 需求信息分页
export const getNeedListApi = data => instance.post("/need/getPageList", data);
// 需求登记
export const needRegisterApi = id => instance.post(`/need/register/${id}`);
// 获取平台分页 1零工,2其它
export const getPlatformPageList = params => instance.post(`/platform/getPageList`, params);
import instance from "@/utils/request";
// 获取用户简历
export const getUserResumeApi = () => instance.post("/personal/user/resume/get");
// 获取等用户信息
export const getLoginUserApi = () => instance.post("/personal/user/getLoginUser");
// 保存个人优势
export const saveAdvantageApi = params => instance.post("/personal/user/resume/saveAdvantage", params);
// 保存用户求职状态
export const saveJobStatusApi = params => instance.post("/personal/user/resume/saveJobStatus", params);
// 保存用户基本信息
export const saveUserInfoApi = params => instance.post("/personal/user/save", params);
// 保存身份证信息
export const saveIdCardApi = params => instance.post("/personal/user/saveIdCard", params);
// 保存求职意向
export const saveJobIntentionApi = params => instance.post("/personal/user/resume/saveJobIntention", params);
// 保存工作经历
export const saveWorkExperienceApi = params => instance.post("/personal/user/resume/saveWorkExperience", params);
// 保存教育经历
export const saveEducationExperienceApi = params => instance.post("/personal/user/resume/saveEducationExperience", params);
// 获取投递列表
export const getApplicationListApi = params => instance.post("/job/getApplicationList", params);
// 获取面试列表
export const getInterviewListApi = params => instance.post("/job/getInterviewList", params);
<template>
<view class="list">
<view
v-for="(v, i) in list"
:key="i"
@click="navigateTo(`/pages/articleDetails/index?id=${v.id}`)"
class="item flex-between"
:class="[v.infoType == 1 ? 'layout1' : 'layout2']"
>
<img :src="evn.APP_IMAGE_BASE_API + v.thumbnailPath" v-if="v.infoType == 2" />
<view>
<view class="title">{{ v.title }}</view>
<view class="flex-align-center">
<view class="poster">{{ v.author }}</view>
<view class="date">{{ dayjs(v.publishDate).format("YYYY/MM/DD") }}</view>
</view>
</view>
<img :src="evn.APP_IMAGE_BASE_API + v.thumbnailPath" v-if="v.infoType == 1" />
</view>
</view>
</template>
<script setup>
// infoType 1文图 2视频
import { defineProps } from "vue";
import { navigateTo } from "@/utils/utils";
import evn from "@/utils/config";
import dayjs from "dayjs";
const props = defineProps({
list: {
type: Array,
default: () => [
{
type: 2,
title: "2023年贵阳市第四季度供求情况分2023年贵阳市第四季度供求情况分析报告析报告",
poster: "社会保障局",
date: "01-12 12:30"
},
{
type: 1,
title: "2023年贵阳市第四季度供求情况分析报告",
poster: "社会保障局",
date: "01-12 12:30"
}
]
}
});
</script>
<style lang="scss" scoped>
.list {
.item {
padding: 32rpx 0;
margin: 0 32rpx;
border-bottom: 2rpx solid #f3f4f8;
& > view {
flex: 1;
}
img {
width: 202rpx;
height: 114rpx;
margin-left: 24rpx;
}
.title {
margin-bottom: 16rpx;
font-size: 28rpx;
font-weight: 500;
line-height: 36rpx;
color: #000000;
}
.poster,
.date {
margin-right: 16rpx;
font-size: 24rpx;
font-weight: 500;
line-height: 28rpx;
color: #77818f;
letter-spacing: 0rpx;
}
}
.layout2 {
flex-direction: column;
align-items: flex-start;
img {
width: 100%;
height: 294rpx;
margin: 0;
}
.title {
margin-top: 32rpx;
}
}
}
</style>
<template>
<view class="postion-card1" @tap="jump(data.id)">
<view class="flex-between">
<view class="postion-name">{{ data.jobName }}</view>
<view class="salary">{{ data.minSalary / 1000 }}k-{{ data.maxSalary / 1000 }}k<text>/月</text></view>
</view>
<view class="benefits">
<text v-for="(v, i) in data.benefits?.split(',')" :key="i">{{ v }}</text>
</view>
<view class="flex-between">
<text class="company-name">{{ data.companyName }}</text>
<text class="address">贵阳-观山湖区</text>
</view>
</view>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
data: {
type: Object,
default: () => ({})
},
jump: {
type: Boolean,
default: true
}
});
const jump = id => {
if (props.jump) {
uni.navigateTo({
url: `/pages/postionList/positionDetails/index?id=${id}`
});
}
};
</script>
<style lang="scss" scoped>
.postion-card1 {
.flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
.postion-name {
font-size: 16px;
font-weight: 600;
line-height: 18px;
color: #1b2026;
}
.salary {
font-size: 18px;
font-weight: 500;
line-height: 12px;
color: #1f86ff;
text-align: center;
letter-spacing: 0;
text {
font-size: 14px;
}
}
.benefits {
display: flex;
gap: 4px;
align-items: center;
margin: 12px 0;
text {
padding: 2px 4px;
font-size: 10px;
line-height: 14px;
color: #4e5969;
background: #f2f3f5;
}
}
.company-name {
font-size: 12px;
font-weight: normal;
line-height: 18px;
color: #1b2026;
letter-spacing: 0;
}
.address {
font-size: 12px;
font-weight: normal;
line-height: 12px;
color: #1b2026;
text-align: center;
letter-spacing: 0;
}
}
</style>
<template>
<view class="steps flex-between">
<view class="item" v-for="(item, index) in stepViewData" :key="index">
<!-- 0 灰色, 1 蓝色 2 红色 -->
<image v-if="item.state == 0" src="@/static/image/postion/step/hookDisabled.png" />
<image v-if="item.state == 1" src="@/static/image/postion/step/hook.png" />
<image v-if="item.state == 2" src="@/static/image/postion/step/fork.png" />
<view
class="title"
:class="{
grey: item.state == 0,
blue: item.state == 1,
red: item.state == 2
}"
>{{ item.title }}</view
>
<view class="date">{{ item.date }}</view>
</view>
<view class="line-wrap">
<view></view>
<view></view>
</view>
</view>
</template>
<script setup>
import { watch, ref } from "vue";
import dayjs from "dayjs";
const props = defineProps({
data: {
type: Object,
default: () => ({})
}
});
const stepViewData = ref([]);
/* 设置步骤条显示数据 */
const setStepViewData = data => {
if (!data) return;
let list = [];
const format = date => dayjs(date).format("MM-DD hh:mm");
list.push({
state: 1,
title: "已投递",
date: format(data.createTime)
});
if (data.status == 1 || data.status == 2 || data.status == 3 || data.status == 4) {
list.push({
state: 1,
title: "已查看",
date: format(data.reviewTime)
});
} else {
list.push({
state: 0,
title: "待查看",
date: ""
});
}
switch (data.status) {
case 2:
list.push({
state: 1,
title: "待面试",
date: format(data.interviewTime)
});
break;
case 3:
list.push({
state: 1,
title: "已面试",
date: format(data.interviewTime)
});
break;
case 4:
list.push({
state: 2,
title: "已拒绝",
date: format(data.interviewTime)
});
break;
default:
list.push({
state: 0,
title: "待反馈",
date: ""
});
break;
}
stepViewData.value = list;
};
watch(
() => props.data,
value => {
if (value) {
setStepViewData(value);
}
},
{
immediate: true
}
);
</script>
<style lang="scss" scoped>
.steps {
position: relative;
box-sizing: border-box;
display: flex;
justify-content: space-between;
width: 750rpx;
padding: 18rpx 60rpx;
.item {
position: relative;
text-align: center;
image {
width: 76rpx;
height: 76rpx;
}
.title {
font-size: 28rpx;
font-weight: 500;
line-height: 36rpx;
}
.blue {
color: #1f86ff;
}
.red {
color: #f63717;
}
.grey {
color: #a3a7b3;
}
.date {
position: absolute;
right: 50%;
font-size: 24rpx;
font-weight: 500;
line-height: 36rpx;
color: #a3a7b3;
letter-spacing: 0rpx;
white-space: nowrap;
transform: translate(50%, 0);
}
}
.line-wrap {
position: absolute;
top: 76rpx;
left: 0;
display: flex;
justify-content: space-evenly;
width: 100%;
view {
width: 80rpx;
height: 2rpx;
background-color: #1f86ff;
}
}
}
</style>
@import "wot-design-uni/components/common/abstracts/variable";
@import "wot-design-uni/components/common/abstracts/mixin";
.wot-theme-dark {
@include b(col-picker) {
@include when(border) {
.wd-col-picker__cell {
@include halfPixelBorder("top", $-cell-padding, $-dark-border-color);
}
}
@include e(label) {
color: $-dark-color;
}
@include e(cell) {
color: $-dark-color;
background-color: $-dark-background2;
@include when(disabled) {
.wd-col-picker__value {
color: $-dark-color3;
}
}
}
@include e(list-item) {
@include when(disabled) {
color: $-dark-color3;
}
}
@include e(list-item-tip) {
color: $-dark-color-gray;
}
@include e(value) {
color: $-dark-color;
@include m(placeholder) {
color: $-dark-color-gray;
}
}
:deep(.wd-col-picker__arrow) {
color: $-dark-color;
}
@include e(list) {
color: $-dark-color;
}
@include e(selected) {
color: $-dark-color;
}
}
}
@include b(col-picker) {
@include when(border) {
.wd-col-picker__cell {
@include halfPixelBorder("top", $-cell-padding);
}
}
@include e(cell) {
position: relative;
display: flex;
align-items: flex-start;
padding: $-cell-wrapper-padding $-cell-padding;
overflow: hidden;
font-size: $-cell-title-fs;
line-height: $-cell-line-height;
color: $-cell-title-color;
text-decoration: none;
background-color: $-color-white;
}
@include e(cell) {
@include when(disabled) {
.wd-col-picker__value {
color: $-input-disabled-color;
}
}
@include when(align-right) {
.wd-col-picker__value {
text-align: right;
}
}
@include when(error) {
.wd-col-picker__value {
color: $-input-error-color;
}
:deep(.wd-col-picker__arrow) {
color: $-input-error-color;
}
}
@include when(large) {
font-size: $-cell-title-fs-large;
:deep(.wd-col-picker__arrow) {
font-size: $-cell-icon-size-large;
}
}
}
@include e(error-message) {
font-size: $-form-item-error-message-font-size;
line-height: $-form-item-error-message-line-height;
color: $-form-item-error-message-color;
text-align: left;
vertical-align: middle;
}
@include e(label) {
position: relative;
box-sizing: border-box;
width: $-input-cell-label-width;
margin-right: $-cell-padding;
color: $-cell-title-color;
@include when(required) {
padding-left: 12px;
&::after {
position: absolute;
top: 2px;
left: 0;
font-size: $-cell-required-size;
line-height: 1.1;
color: $-cell-required-color;
content: "*";
}
}
}
@include e(value-wraper) {
display: flex;
}
@include e(value) {
flex: 1;
margin-right: 10px;
color: $-cell-value-color;
@include when(ellipsis) {
@include lineEllipsis;
}
@include m(placeholder) {
color: $-input-placeholder-color;
}
}
@include e(body) {
flex: 1;
}
@include edeep(arrow) {
display: block;
font-size: $-cell-icon-size;
line-height: $-cell-line-height;
color: $-cell-arrow-color;
}
@include e(selected) {
height: $-col-picker-selected-height;
overflow: hidden;
font-size: $-col-picker-selected-fs;
color: $-col-picker-selected-color;
}
@include e(selected-container) {
position: relative;
display: flex;
user-select: none;
}
@include e(selected-item) {
flex: 0 0 auto;
height: $-col-picker-selected-height;
padding: $-col-picker-selected-padding;
line-height: $-col-picker-selected-height;
@include when(selected) {
font-weight: $-col-picker-selected-fw;
}
}
@include e(selected-line) {
position: absolute;
bottom: 5px;
left: 0;
z-index: 1;
width: $-col-picker-line-width;
height: $-col-picker-line-height;
background: $-col-picker-line-color;
border-radius: calc($-col-picker-line-height / 2);
box-shadow: $-col-picker-line-box-shadow;
}
@include e(list-container) {
position: relative;
}
@include e(list) {
box-sizing: border-box;
height: $-col-picker-list-height;
padding-bottom: $-col-picker-list-padding-bottom;
overflow: auto;
font-size: $-col-picker-list-fs;
color: $-col-picker-list-color;
-webkit-overflow-scrolling: touch;
}
@include e(list-item) {
display: flex;
align-items: flex-start;
padding: $-col-picker-list-item-padding;
@include when(selected) {
color: $-col-picker-list-color-checked;
:deep(.wd-col-picker__checked) {
opacity: 1;
}
}
@include when(disabled) {
color: $-col-picker-list-color-disabled;
}
}
@include e(list-item-label) {
line-height: 1.285;
}
@include e(list-item-tip) {
margin-top: 2px;
font-size: $-col-picker-list-fs-tip;
color: $-col-picker-list-color-tip;
}
@include edeep(checked) {
display: block;
margin-left: 4px;
font-size: $-col-picker-list-checked-icon-size;
color: $-col-picker-list-color-checked;
opacity: 0;
}
@include e(loading) {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
}
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from "vue";
import {
baseProps,
makeArrayProp,
makeBooleanProp,
makeNumberProp,
makeRequiredProp,
makeStringProp
} from "wot-design-uni/components/common/props";
import type { FormItemRule } from "wot-design-uni/components/wd-form/types";
export const colPickerProps = {
...baseProps,
/**
* 选中项
*/
modelValue: makeRequiredProp(Array as PropType<Array<string | number>>),
/**
* 选择器数据,二维数组
*/
columns: makeArrayProp<Record<string, any>[]>(),
/**
* 选择器左侧文案
*/
label: String,
/**
* 设置左侧标题宽度
*/
labelWidth: makeStringProp("33%"),
/**
* 使用 label 插槽时设置该选项
*/
useLabelSlot: makeBooleanProp(false),
/**
* 使用默认插槽时设置该选项
*/
useDefaultSlot: makeBooleanProp(false),
/**
* 禁用
*/
disabled: makeBooleanProp(false),
/**
* 只读
*/
readonly: makeBooleanProp(false),
/**
* 选择器占位符
*/
placeholder: String,
/**
* 弹出层标题
*/
title: String,
/**
* 接收当前列的选中项 item、当前列下标、当前列选中项下标下一列数据处理函数 resolve、结束选择 finish
*/
columnChange: Function as PropType<ColPickerColumnChange>,
/**
* 自定义展示文案的格式化函数,返回一个字符串
*/
displayFormat: Function as PropType<ColPickerDisplayFormat>,
/**
* 确定前校验函数,接收 (value, resolve) 参数,通过 resolve 继续执行 picker,resolve 接收 1 个 boolean 参数
*/
beforeConfirm: Function as PropType<ColPickerBeforeConfirm>,
/**
* 选择器的值靠右展示
*/
alignRight: makeBooleanProp(false),
/**
* 是否为错误状态,错误状态时右侧内容为红色
*/
error: makeBooleanProp(false),
/**
* 是否必填
*/
required: makeBooleanProp(false),
/**
* 设置选择器大小,可选值:large
*/
size: String,
/**
* 选项对象中,value 对应的 key
*/
valueKey: makeStringProp("value"),
/**
* 选项对象中,展示的文本对应的 key
*/
labelKey: makeStringProp("label"),
/**
* 选项对象中,提示文案对应的 key
*/
tipKey: makeStringProp("tip"),
/**
* loading 图标的颜色
*/
loadingColor: makeStringProp("#4D80F0"),
/**
* 点击遮罩是否关闭
*/
closeOnClickModal: makeBooleanProp(true),
/**
* 自动触发 column-change 事件来补全数据,当 columns 为空数组或者 columns 数组长度小于 value 数组长度时,会自动触发 column-change
*/
autoComplete: makeBooleanProp(false),
/**
* 弹窗层级
*/
zIndex: makeNumberProp(15),
/**
* 弹出面板是否设置底部安全距离(iphone X 类型的机型)
*/
safeAreaInsetBottom: makeBooleanProp(true),
/**
* 是否超出隐藏
*/
ellipsis: makeBooleanProp(false),
/**
* 表单域 model 字段名,在使用表单校验功能的情况下,该属性是必填的
*/
prop: String,
/**
* 表单验证规则,结合wd-form组件使用
*/
rules: makeArrayProp<FormItemRule>(),
/**
* label 外部自定义样式
*/
customViewClass: makeStringProp(""),
/**
* value 外部自定义样式
*/
customLabelClass: makeStringProp(""),
customValueClass: makeStringProp("")
};
export type ColPickerProps = ExtractPropTypes<typeof colPickerProps>;
export type ColPickerColumnChangeOption = {
selectedItem: Record<string, any>;
index: number;
rowIndex: number;
resolve: (nextColumn: Record<string, any>[]) => void;
finish: (isOk?: boolean) => void;
};
export type ColPickerColumnChange = (option: ColPickerColumnChangeOption) => void;
export type ColPickerDisplayFormat = (selectedItems: Record<string, any>[]) => string;
export type ColPickerBeforeConfirm = (
value: (string | number)[],
selectedItems: Record<string, any>[],
resolve: (isPass: boolean) => void
) => void;
export type ColPickerExpose = {
// 关闭picker弹框
close: () => void;
// 打开picker弹框
open: () => void;
};
export type ColPickerInstance = ComponentPublicInstance<ColPickerExpose, ColPickerProps>;
<template>
<view :class="`wd-col-picker ${cell.border.value ? 'is-border' : ''} ${customClass}`" :style="customStyle">
<view class="wd-col-picker__field" @click="showPicker">
<slot v-if="useDefaultSlot"></slot>
<view
v-else
:class="`wd-col-picker__cell ${disabled && 'is-disabled'} ${readonly && 'is-readonly'} ${
alignRight && 'is-align-right'
} ${error && 'is-error'} ${size && 'is-' + size}`"
>
<view
v-if="label || useLabelSlot"
:class="`wd-col-picker__label ${isRequired && 'is-required'} ${customLabelClass}`"
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
>
<block v-if="label">{{ label }}</block>
<slot v-else name="label"></slot>
</view>
<view class="wd-col-picker__body">
<view class="wd-col-picker__value-wraper">
<view
:class="`wd-col-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${
showValue ? '' : 'wd-col-picker__value--placeholder'
}`"
>
{{ showValue || placeholder || translate("placeholder") }}
</view>
<wd-icon v-if="!disabled && !readonly" custom-class="wd-col-picker__arrow" name="arrow-right" />
</view>
<view v-if="errorMessage" class="wd-col-picker__error-message">{{ errorMessage }}</view>
</view>
</view>
</view>
<wd-action-sheet
v-model="pickerShow"
:duration="250"
:title="title || translate('title')"
:close-on-click-modal="closeOnClickModal"
:z-index="zIndex"
:safe-area-inset-bottom="safeAreaInsetBottom"
@open="handlePickerOpend"
@close="handlePickerClose"
>
<view class="wd-col-picker__selected">
<scroll-view :scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
<view class="wd-col-picker__selected-container">
<view
v-for="(select, colIndex) in selectList"
:key="colIndex"
:class="`wd-col-picker__selected-item ${colIndex === currentCol && 'is-selected'}`"
@click="handleColClick(colIndex)"
>
{{ selectShowList[colIndex] || translate("select") }}
</view>
<view class="wd-col-picker__selected-line" :style="lineStyle"></view>
</view>
</scroll-view>
</view>
<view class="wd-col-picker__list-container">
<view
v-for="(col, colIndex) in selectList"
:key="colIndex"
class="wd-col-picker__list"
:style="colIndex === currentCol ? 'display: block;' : 'display: none;'"
>
<view
v-for="(item, index) in col"
:key="index"
:class="`wd-col-picker__list-item ${
pickerColSelected[colIndex] && item[valueKey] === pickerColSelected[colIndex] && 'is-selected'
} ${item.disabled && 'is-disabled'}`"
@click="chooseItem(colIndex, index)"
>
<view>
<view class="wd-col-picker__list-item-label">{{ item[labelKey] }}</view>
<view v-if="item[tipKey]" class="wd-col-picker__list-item-tip">{{ item[tipKey] }}</view>
</view>
<wd-icon custom-class="wd-col-picker__checked" name="check"></wd-icon>
</view>
<view v-if="loading" class="wd-col-picker__loading">
<wd-loading :color="loadingColor" />
</view>
</view>
</view>
</wd-action-sheet>
</view>
</template>
<script lang="ts">
export default {
name: "wd-col-picker",
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: "shared"
}
};
</script>
<script lang="ts" setup>
import { computed, getCurrentInstance, onMounted, ref, watch } from "vue";
import { debounce, getRect, isArray, isBoolean, isFunction } from "wot-design-uni/components/common/util";
import { useCell } from "wot-design-uni/components/composables/useCell";
import { FORM_KEY, type FormItemRule } from "wot-design-uni/components/wd-form/types";
import { useParent } from "wot-design-uni/components/composables/useParent";
import { useTranslate } from "wot-design-uni/components/composables/useTranslate";
import { colPickerProps, type ColPickerExpose } from "./types";
const { translate } = useTranslate("col-picker");
const $container = ".wd-col-picker__selected-container";
const $item = ".wd-col-picker__selected-item";
const props = defineProps(colPickerProps);
const emit = defineEmits(["close", "update:modelValue", "confirm"]);
const pickerShow = ref<boolean>(false);
const currentCol = ref<number>(0);
const selectList = ref<Record<string, any>[][]>([]);
const pickerColSelected = ref<(string | number)[]>([]);
const selectShowList = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const isChange = ref<boolean>(false);
const lastSelectList = ref<Record<string, any>[][]>([]);
const lastPickerColSelected = ref<(string | number)[]>([]);
const lineStyle = ref<string>("");
const scrollLeft = ref<number>(0);
const inited = ref<boolean>(false);
const isCompleting = ref<boolean>(false);
const { proxy } = getCurrentInstance() as any;
const cell = useCell();
const updateLineAndScroll = debounce(function (animation = true) {
setLineStyle(animation);
lineScrollIntoView();
}, 50);
const showValue = computed(() => {
const selectedItems = (props.modelValue || []).map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
});
if (props.displayFormat) {
return props.displayFormat(selectedItems);
} else {
return selectedItems
.map(item => {
return item[props.labelKey];
})
.join("");
}
});
watch(
() => props.modelValue,
newValue => {
if (newValue === pickerColSelected.value) return;
pickerColSelected.value = newValue;
newValue.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
handleAutoComplete();
},
{
deep: true,
immediate: true
}
);
watch(
() => props.columns,
(newValue, oldValue) => {
if (newValue.length && !isArray(newValue[0])) {
console.error(
"[wot design] error(wd-col-picker): the columns props of wd-col-picker should be a two-dimensional array"
);
return;
}
if (newValue.length === 0 && !oldValue) return;
const newSelectedList = newValue.slice(0);
selectList.value = newSelectedList;
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, newSelectedList)[props.labelKey];
});
lastSelectList.value = newSelectedList;
if (newSelectedList.length > 0) {
currentCol.value = newSelectedList.length - 1;
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.columnChange,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of columnChange must be Function");
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.displayFormat,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of displayFormat must be Function");
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.beforeConfirm,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of beforeConfirm must be Function");
}
},
{
deep: true,
immediate: true
}
);
const { parent: form } = useParent(FORM_KEY);
// 表单校验错误信息
const errorMessage = computed(() => {
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
return form.errorMessages[props.prop];
} else {
return "";
}
});
// 是否展示必填
const isRequired = computed(() => {
let formRequired = false;
if (form && form.props.rules) {
const rules = form.props.rules;
for (const key in rules) {
if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
formRequired = rules[key].some((rule: FormItemRule) => rule.required);
}
}
}
return props.required || props.rules.some(rule => rule.required) || formRequired;
});
onMounted(() => {
inited.value = true;
});
// 打开弹框
function open() {
showPicker();
}
// 关闭弹框
function close() {
handlePickerClose();
}
function handlePickerOpend() {
updateLineAndScroll(false);
}
function handlePickerClose() {
pickerShow.value = false;
// 如果目前用户正在选择,需要在popup关闭时将数据重置回上次数据,popup 关闭时间 250
if (isChange.value) {
setTimeout(() => {
selectList.value = lastSelectList.value.slice(0);
pickerColSelected.value = lastPickerColSelected.value.slice(0);
selectShowList.value = lastPickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, lastSelectList.value)[props.labelKey];
});
currentCol.value = lastSelectList.value.length - 1;
isChange.value = false;
}, 250);
}
emit("close");
}
function showPicker() {
const { disabled, readonly } = props;
if (disabled || readonly) return;
pickerShow.value = true;
lastPickerColSelected.value = pickerColSelected.value.slice(0);
lastSelectList.value = selectList.value.slice(0);
}
function getSelectedItem(value: string | number, colIndex: number, selectList: Record<string, any>[][]) {
const { valueKey, labelKey } = props;
if (selectList[colIndex]) {
const selecteds = selectList[colIndex].filter(item => {
return item[valueKey] === value;
});
if (selecteds.length > 0) {
return selecteds[0];
}
}
return {
[valueKey]: value,
[labelKey]: ""
};
}
function chooseItem(colIndex: number, index: number) {
const item = selectList.value[colIndex][index];
if (item.disabled) return;
const newPickerColSelected = pickerColSelected.value.slice(0, colIndex);
newPickerColSelected.push(item[props.valueKey]);
isChange.value = true;
pickerColSelected.value = newPickerColSelected;
selectList.value = selectList.value.slice(0, colIndex + 1);
selectShowList.value = newPickerColSelected.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
handleColChange(colIndex, item, index);
}
function handleColChange(colIndex: number, item: Record<string, any>, index: number, callback?: () => void) {
loading.value = true;
const { columnChange, beforeConfirm } = props;
columnChange &&
columnChange({
selectedItem: item,
index: colIndex,
rowIndex: index,
resolve: (nextColumn: Record<string, any>[]) => {
if (!isArray(nextColumn)) {
console.error(
"[wot design] error(wd-col-picker): the data of each column of wd-col-picker should be an array"
);
return;
}
const newSelectList = selectList.value.slice(0);
newSelectList[colIndex + 1] = nextColumn;
selectList.value = newSelectList;
loading.value = false;
currentCol.value = colIndex + 1;
updateLineAndScroll(true);
if (typeof callback === "function") {
isCompleting.value = false;
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
callback();
}
},
finish: (isOk?: boolean) => {
// 每设置展示数据回显
if (typeof callback === "function") {
loading.value = false;
isCompleting.value = false;
return;
}
if (isBoolean(isOk) && !isOk) {
loading.value = false;
return;
}
if (beforeConfirm) {
beforeConfirm(
pickerColSelected.value,
pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
}),
(isPass: boolean) => {
if (isPass) {
onConfirm();
} else {
loading.value = false;
}
}
);
} else {
onConfirm();
}
}
});
}
function onConfirm() {
isChange.value = false;
loading.value = false;
pickerShow.value = false;
emit("update:modelValue", pickerColSelected.value);
emit("confirm", {
value: pickerColSelected.value,
selectedItems: pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
})
});
}
function handleColClick(index: number) {
isChange.value = true;
currentCol.value = index;
updateLineAndScroll(true);
}
/**
* @description 更新navBar underline的偏移量
* @param {Boolean} animation 是否伴随动画
*/
function setLineStyle(animation = true) {
if (!inited.value) return;
getRect($item, true, proxy).then(rects => {
const rect = rects[currentCol.value];
// const width = lineWidth || (slidableNum < items.length ? rect.width : (rect.width - 14))
const width = 16;
let left = rects.slice(0, currentCol.value).reduce((prev: any, curr: any) => prev + curr.width, 0);
left += (Number(rect.width) - width) / 2;
const transition = animation ? "transition: width 300ms ease, transform 300ms ease;" : "";
const lineStyleTemp = `
transform: translateX(${left}px);
${transition}
`;
// 防止重复绘制
if (lineStyle.value !== lineStyleTemp) {
lineStyle.value = lineStyleTemp;
}
});
}
/**
* @description scroll-view滑动到active的tab_nav
*/
function lineScrollIntoView() {
if (!inited.value) return;
Promise.all([getRect($item, true, proxy), getRect($container, false, proxy)]).then(([navItemsRects, navRect]) => {
if (!isArray(navItemsRects) || navItemsRects.length === 0) return;
// 选中元素
const selectItem = navItemsRects[currentCol.value];
// 选中元素之前的节点的宽度总和
const offsetLeft = navItemsRects.slice(0, currentCol.value).reduce((prev, curr) => prev + Number(curr.width), 0);
// scroll-view滑动到selectItem的偏移量
scrollLeft.value = offsetLeft - ((navRect as any).width - Number(selectItem.width)) / 2;
});
}
// 递归列数据补齐
function diffColumns(colIndex: number) {
// colIndex 为 -1 时,item 为空对象,>=0 时则具有 value 属性
const item = colIndex === -1 ? {} : { [props.valueKey]: props.modelValue[colIndex] };
handleColChange(colIndex, item, -1, () => {
// 如果 columns 长度还小于 value 长度,colIndex + 1,继续递归补齐
if (selectList.value.length < props.modelValue.length) {
diffColumns(colIndex + 1);
}
});
}
function handleAutoComplete() {
if (props.autoComplete) {
// 如果 columns 数组长度为空,或者长度小于 value 的长度,自动触发 columnChange 来补齐数据
if (selectList.value.length < props.modelValue.length || selectList.value.length === 0) {
// isCompleting 是否在自动补全,锁操作
if (!isCompleting.value) {
// 如果 columns 长度为空,则传入的 colIndex 为 -1
const colIndex = selectList.value.length === 0 ? -1 : selectList.value.length - 1;
diffColumns(colIndex);
}
isCompleting.value = true;
}
}
}
defineExpose<ColPickerExpose>({
close,
open
});
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>
@import "wot-design-uni/components/common/abstracts/variable";
@import "wot-design-uni/components/common/abstracts/mixin";
.wot-theme-dark {
@include b(col-picker) {
@include when(border) {
.wd-col-picker__cell {
@include halfPixelBorder("top", $-cell-padding, $-dark-border-color);
}
}
@include e(label) {
color: $-dark-color;
}
@include e(cell) {
color: $-dark-color;
background-color: $-dark-background2;
@include when(disabled) {
.wd-col-picker__value {
color: $-dark-color3;
}
}
}
@include e(list-item) {
@include when(disabled) {
color: $-dark-color3;
}
}
@include e(list-item-tip) {
color: $-dark-color-gray;
}
@include e(value) {
color: $-dark-color;
@include m(placeholder) {
color: $-dark-color-gray;
}
}
:deep(.wd-col-picker__arrow) {
color: $-dark-color;
}
@include e(list) {
color: $-dark-color;
}
@include e(selected) {
color: $-dark-color;
}
}
}
.tags {
gap: 32rpx;
padding: 0 32rpx;
div {
padding: 8rpx 16rpx;
font-size: 24rpx;
color: #4d80f0;
background-color: #4d80f01f;
}
}
@include b(col-picker) {
@include when(border) {
.wd-col-picker__cell {
@include halfPixelBorder("top", $-cell-padding);
}
}
@include e(cell) {
position: relative;
display: flex;
align-items: flex-start;
padding: $-cell-wrapper-padding $-cell-padding;
overflow: hidden;
font-size: $-cell-title-fs;
line-height: $-cell-line-height;
color: $-cell-title-color;
text-decoration: none;
background-color: $-color-white;
}
@include e(cell) {
@include when(disabled) {
.wd-col-picker__value {
color: $-input-disabled-color;
}
}
@include when(align-right) {
.wd-col-picker__value {
text-align: right;
}
}
@include when(error) {
.wd-col-picker__value {
color: $-input-error-color;
}
:deep(.wd-col-picker__arrow) {
color: $-input-error-color;
}
}
@include when(large) {
font-size: $-cell-title-fs-large;
:deep(.wd-col-picker__arrow) {
font-size: $-cell-icon-size-large;
}
}
}
@include e(error-message) {
font-size: $-form-item-error-message-font-size;
line-height: $-form-item-error-message-line-height;
color: $-form-item-error-message-color;
text-align: left;
vertical-align: middle;
}
@include e(label) {
position: relative;
box-sizing: border-box;
width: $-input-cell-label-width;
margin-right: $-cell-padding;
color: $-cell-title-color;
@include when(required) {
padding-left: 12px;
&::after {
position: absolute;
top: 2px;
left: 0;
font-size: $-cell-required-size;
line-height: 1.1;
color: $-cell-required-color;
content: "*";
}
}
}
@include e(value-wraper) {
display: flex;
}
@include e(value) {
flex: 1;
margin-right: 10px;
color: $-cell-value-color;
@include when(ellipsis) {
@include lineEllipsis;
}
@include m(placeholder) {
color: $-input-placeholder-color;
}
}
@include e(body) {
flex: 1;
}
@include edeep(arrow) {
display: block;
font-size: $-cell-icon-size;
line-height: $-cell-line-height;
color: $-cell-arrow-color;
}
@include e(selected) {
height: $-col-picker-selected-height;
overflow: hidden;
font-size: $-col-picker-selected-fs;
color: $-col-picker-selected-color;
}
@include e(selected-container) {
position: relative;
display: flex;
user-select: none;
}
@include e(selected-item) {
flex: 0 0 auto;
height: $-col-picker-selected-height;
padding: $-col-picker-selected-padding;
line-height: $-col-picker-selected-height;
@include when(selected) {
font-weight: $-col-picker-selected-fw;
}
}
@include e(selected-line) {
position: absolute;
bottom: 5px;
left: 0;
z-index: 1;
width: $-col-picker-line-width;
height: $-col-picker-line-height;
background: $-col-picker-line-color;
border-radius: calc($-col-picker-line-height / 2);
box-shadow: $-col-picker-line-box-shadow;
}
@include e(list-container) {
position: relative;
}
@include e(list) {
box-sizing: border-box;
height: $-col-picker-list-height;
padding-bottom: $-col-picker-list-padding-bottom;
overflow: auto;
font-size: $-col-picker-list-fs;
color: $-col-picker-list-color;
-webkit-overflow-scrolling: touch;
}
@include e(list-item) {
display: flex;
align-items: flex-start;
padding: $-col-picker-list-item-padding;
@include when(selected) {
color: $-col-picker-list-color-checked;
:deep(.wd-col-picker__checked) {
opacity: 1;
}
}
@include when(disabled) {
color: $-col-picker-list-color-disabled;
}
}
@include e(list-item-label) {
line-height: 1.285;
}
@include e(list-item-tip) {
margin-top: 2px;
font-size: $-col-picker-list-fs-tip;
color: $-col-picker-list-color-tip;
}
@include edeep(checked) {
display: block;
margin-left: 4px;
font-size: $-col-picker-list-checked-icon-size;
color: $-col-picker-list-color-checked;
opacity: 0;
}
@include e(loading) {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
}
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from "vue";
import {
baseProps,
makeArrayProp,
makeBooleanProp,
makeNumberProp,
makeRequiredProp,
makeStringProp
} from "wot-design-uni/components/common/props";
import type { FormItemRule } from "wot-design-uni/components/wd-form/types";
export const colPickerProps = {
...baseProps,
/**
* 选中项
*/
modelValue: makeRequiredProp(Array as PropType<Array<string | number>>),
/* 多选数据 */
mValue: {
type: Array,
default: () => []
},
mMax: {
type: Number,
default: 1
},
/**
* 选择器数据,二维数组
*/
columns: makeArrayProp<Record<string, any>[]>(),
/**
* 选择器左侧文案
*/
label: String,
/**
* 设置左侧标题宽度
*/
labelWidth: makeStringProp("33%"),
/**
* 使用 label 插槽时设置该选项
*/
useLabelSlot: makeBooleanProp(false),
/**
* 使用默认插槽时设置该选项
*/
useDefaultSlot: makeBooleanProp(false),
/**
* 禁用
*/
disabled: makeBooleanProp(false),
/**
* 只读
*/
readonly: makeBooleanProp(false),
/**
* 选择器占位符
*/
placeholder: String,
/**
* 弹出层标题
*/
title: String,
/**
* 接收当前列的选中项 item、当前列下标、当前列选中项下标下一列数据处理函数 resolve、结束选择 finish
*/
columnChange: Function as PropType<ColPickerColumnChange>,
/**
* 自定义展示文案的格式化函数,返回一个字符串
*/
displayFormat: Function as PropType<ColPickerDisplayFormat>,
/**
* 确定前校验函数,接收 (value, resolve) 参数,通过 resolve 继续执行 picker,resolve 接收 1 个 boolean 参数
*/
beforeConfirm: Function as PropType<ColPickerBeforeConfirm>,
/**
* 选择器的值靠右展示
*/
alignRight: makeBooleanProp(false),
/**
* 是否为错误状态,错误状态时右侧内容为红色
*/
error: makeBooleanProp(false),
/**
* 是否必填
*/
required: makeBooleanProp(false),
/**
* 设置选择器大小,可选值:large
*/
size: String,
/**
* 选项对象中,value 对应的 key
*/
valueKey: makeStringProp("value"),
/**
* 选项对象中,展示的文本对应的 key
*/
labelKey: makeStringProp("label"),
/**
* 选项对象中,提示文案对应的 key
*/
tipKey: makeStringProp("tip"),
/**
* loading 图标的颜色
*/
loadingColor: makeStringProp("#4D80F0"),
/**
* 点击遮罩是否关闭
*/
closeOnClickModal: makeBooleanProp(true),
/**
* 自动触发 column-change 事件来补全数据,当 columns 为空数组或者 columns 数组长度小于 value 数组长度时,会自动触发 column-change
*/
autoComplete: makeBooleanProp(false),
/**
* 弹窗层级
*/
zIndex: makeNumberProp(15),
/**
* 弹出面板是否设置底部安全距离(iphone X 类型的机型)
*/
safeAreaInsetBottom: makeBooleanProp(true),
/**
* 是否超出隐藏
*/
ellipsis: makeBooleanProp(false),
/**
* 表单域 model 字段名,在使用表单校验功能的情况下,该属性是必填的
*/
prop: String,
/**
* 表单验证规则,结合wd-form组件使用
*/
rules: makeArrayProp<FormItemRule>(),
/**
* label 外部自定义样式
*/
customViewClass: makeStringProp(""),
/**
* value 外部自定义样式
*/
customLabelClass: makeStringProp(""),
customValueClass: makeStringProp("")
};
export type ColPickerProps = ExtractPropTypes<typeof colPickerProps>;
export type ColPickerColumnChangeOption = {
selectedItem: Record<string, any>;
index: number;
rowIndex: number;
addMValue: Function;
resolve: (nextColumn: Record<string, any>[]) => void;
finish: (isOk?: boolean) => void;
};
export type ColPickerColumnChange = (option: ColPickerColumnChangeOption) => void;
export type ColPickerDisplayFormat = (selectedItems: Record<string, any>[]) => string;
export type ColPickerBeforeConfirm = (
value: (string | number)[],
selectedItems: Record<string, any>[],
resolve: (isPass: boolean) => void
) => void;
export type ColPickerExpose = {
// 关闭picker弹框
close: () => void;
// 打开picker弹框
open: () => void;
};
export type ColPickerInstance = ComponentPublicInstance<ColPickerExpose, ColPickerProps>;
<template>
<view :class="`wd-col-picker ${cell.border.value ? 'is-border' : ''} ${customClass}`" :style="customStyle">
<view class="wd-col-picker__field" @click="showPicker">
<slot v-if="useDefaultSlot"></slot>
<view
v-else
:class="`wd-col-picker__cell ${disabled && 'is-disabled'} ${readonly && 'is-readonly'} ${
alignRight && 'is-align-right'
} ${error && 'is-error'} ${size && 'is-' + size}`"
>
<view
v-if="label || useLabelSlot"
:class="`wd-col-picker__label ${isRequired && 'is-required'} ${customLabelClass}`"
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
>
<block v-if="label">{{ label }}</block>
<slot v-else name="label"></slot>
</view>
<view class="wd-col-picker__body">
<view class="wd-col-picker__value-wraper">
<view
:class="`wd-col-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${
showValue ? '' : 'wd-col-picker__value--placeholder'
}`"
>
{{ showValue || placeholder || translate("placeholder") }}
</view>
<wd-icon v-if="!disabled && !readonly" custom-class="wd-col-picker__arrow" name="arrow-right" />
</view>
<view v-if="errorMessage" class="wd-col-picker__error-message">{{ errorMessage }}</view>
</view>
</view>
</view>
<wd-action-sheet
v-model="pickerShow"
:duration="250"
:title="title || translate('title')"
:close-on-click-modal="closeOnClickModal"
:z-index="zIndex"
:safe-area-inset-bottom="safeAreaInsetBottom"
@open="handlePickerOpend"
@close="handlePickerClose"
>
<view class="flex-align-center tags">
<div v-for="(item, index) in mValue" :key="index" type="primary">{{ item.name }}</div>
</view>
<view class="wd-col-picker__selected">
<scroll-view :scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
<view class="wd-col-picker__selected-container">
<view
v-for="(select, colIndex) in selectList"
:key="colIndex"
:class="`wd-col-picker__selected-item ${colIndex === currentCol && 'is-selected'}`"
@click="handleColClick(colIndex)"
>
{{ selectShowList[colIndex] || translate("select") }}
</view>
<view class="wd-col-picker__selected-line" :style="lineStyle"></view>
</view>
</scroll-view>
</view>
<view class="wd-col-picker__list-container">
<view
v-for="(col, colIndex) in selectList"
:key="colIndex"
class="wd-col-picker__list"
:style="colIndex === currentCol ? 'display: block;' : 'display: none;'"
>
<view
v-for="(item, index) in col"
:key="index"
:class="`wd-col-picker__list-item ${item.disabled && 'is-disabled'} ${
mValue.some(v => v[valueKey] == item[valueKey]) && 'is-selected'
}`"
@click="chooseItem(colIndex, index)"
>
<!-- ${pickerColSelected[colIndex] && item[valueKey] === pickerColSelected[colIndex] && 'is-selected'} -->
<view>
<view class="wd-col-picker__list-item-label"> {{ item[labelKey] }}</view>
<view v-if="item[tipKey]" class="wd-col-picker__list-item-tip">{{ item[tipKey] }}</view>
</view>
<wd-icon custom-class="wd-col-picker__checked" name="check"></wd-icon>
</view>
<view v-if="loading" class="wd-col-picker__loading">
<wd-loading :color="loadingColor" />
</view>
</view>
</view>
</wd-action-sheet>
</view>
</template>
<script lang="ts">
export default {
name: "col-picker",
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: "shared"
}
};
</script>
<script lang="ts" setup>
import { computed, getCurrentInstance, onMounted, ref, watch } from "vue";
import { debounce, getRect, isArray, isBoolean, isFunction } from "wot-design-uni/components/common/util";
import { useCell } from "wot-design-uni/components/composables/useCell";
import { FORM_KEY, type FormItemRule } from "wot-design-uni/components/wd-form/types";
import { useParent } from "wot-design-uni/components/composables/useParent";
import { useTranslate } from "wot-design-uni/components/composables/useTranslate";
import { colPickerProps, type ColPickerExpose } from "./types";
const { translate } = useTranslate("col-picker");
const $container = ".wd-col-picker__selected-container";
const $item = ".wd-col-picker__selected-item";
const props = defineProps(colPickerProps);
console.log(props.mMax);
console.log(props.mValue);
const emit = defineEmits(["close", "update:modelValue", "update:mValue", "confirm"]);
const pickerShow = ref<boolean>(false);
const currentCol = ref<number>(0);
const selectList = ref<Record<string, any>[][]>([]);
const pickerColSelected = ref<(string | number)[]>([]);
const selectShowList = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const isChange = ref<boolean>(false);
const lastSelectList = ref<Record<string, any>[][]>([]);
const lastPickerColSelected = ref<(string | number)[]>([]);
const lineStyle = ref<string>("");
const scrollLeft = ref<number>(0);
const inited = ref<boolean>(false);
const isCompleting = ref<boolean>(false);
const { proxy } = getCurrentInstance() as any;
const cell = useCell();
const updateLineAndScroll = debounce(function (animation = true) {
setLineStyle(animation);
lineScrollIntoView();
}, 50);
const showValue = computed(() => {
const selectedItems = (props.modelValue || []).map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
});
if (props.displayFormat) {
return props.displayFormat(selectedItems);
} else {
return selectedItems
.map(item => {
return item[props.labelKey];
})
.join("");
}
});
watch(
() => props.modelValue,
newValue => {
if (newValue === pickerColSelected.value) return;
pickerColSelected.value = newValue;
newValue.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
handleAutoComplete();
},
{
deep: true,
immediate: true
}
);
watch(
() => props.columns,
(newValue, oldValue) => {
if (newValue.length && !isArray(newValue[0])) {
console.error(
"[wot design] error(wd-col-picker): the columns props of wd-col-picker should be a two-dimensional array"
);
return;
}
if (newValue.length === 0 && !oldValue) return;
const newSelectedList = newValue.slice(0);
selectList.value = newSelectedList;
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, newSelectedList)[props.labelKey];
});
lastSelectList.value = newSelectedList;
if (newSelectedList.length > 0) {
currentCol.value = newSelectedList.length - 1;
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.columnChange,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of columnChange must be Function");
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.displayFormat,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of displayFormat must be Function");
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.beforeConfirm,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of beforeConfirm must be Function");
}
},
{
deep: true,
immediate: true
}
);
const { parent: form } = useParent(FORM_KEY);
// 表单校验错误信息
const errorMessage = computed(() => {
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
return form.errorMessages[props.prop];
} else {
return "";
}
});
// 是否展示必填
const isRequired = computed(() => {
let formRequired = false;
if (form && form.props.rules) {
const rules = form.props.rules;
for (const key in rules) {
if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
formRequired = rules[key].some((rule: FormItemRule) => rule.required);
}
}
}
return props.required || props.rules.some(rule => rule.required) || formRequired;
});
onMounted(() => {
inited.value = true;
});
// 打开弹框
function open() {
showPicker();
}
// 关闭弹框
function close() {
handlePickerClose();
}
function handlePickerOpend() {
updateLineAndScroll(false);
}
function handlePickerClose() {
pickerShow.value = false;
// 如果目前用户正在选择,需要在popup关闭时将数据重置回上次数据,popup 关闭时间 250
if (isChange.value) {
setTimeout(() => {
selectList.value = lastSelectList.value.slice(0);
pickerColSelected.value = lastPickerColSelected.value.slice(0);
selectShowList.value = lastPickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, lastSelectList.value)[props.labelKey];
});
currentCol.value = lastSelectList.value.length - 1;
isChange.value = false;
}, 250);
}
emit("close");
}
function showPicker() {
const { disabled, readonly } = props;
if (disabled || readonly) return;
pickerShow.value = true;
lastPickerColSelected.value = pickerColSelected.value.slice(0);
lastSelectList.value = selectList.value.slice(0);
}
function getSelectedItem(value: string | number, colIndex: number, selectList: Record<string, any>[][]) {
const { valueKey, labelKey } = props;
if (selectList[colIndex]) {
const selecteds = selectList[colIndex].filter(item => {
return item[valueKey] === value;
});
if (selecteds.length > 0) {
return selecteds[0];
}
}
return {
[valueKey]: value,
[labelKey]: ""
};
}
function chooseItem(colIndex: number, index: number) {
const item = selectList.value[colIndex][index];
if (item.disabled) return;
const newPickerColSelected = pickerColSelected.value.slice(0, colIndex);
newPickerColSelected.push(item[props.valueKey]);
isChange.value = true;
pickerColSelected.value = newPickerColSelected;
selectList.value = selectList.value.slice(0, colIndex + 1);
selectShowList.value = newPickerColSelected.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
handleColChange(colIndex, item, index);
}
function handleColChange(colIndex: number, item: Record<string, any>, index: number, callback?: () => void) {
loading.value = true;
const { columnChange, beforeConfirm } = props;
columnChange &&
columnChange({
selectedItem: item,
index: colIndex,
rowIndex: index,
resolve: (nextColumn: Record<string, any>[]) => {
if (!isArray(nextColumn)) {
console.error(
"[wot design] error(wd-col-picker): the data of each column of wd-col-picker should be an array"
);
return;
}
const newSelectList = selectList.value.slice(0);
newSelectList[colIndex + 1] = nextColumn;
selectList.value = newSelectList;
loading.value = false;
currentCol.value = colIndex + 1;
updateLineAndScroll(true);
if (typeof callback === "function") {
isCompleting.value = false;
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
callback();
}
},
addMValue: value => {
emit("update:mValue", [...props.mValue, value]);
},
finish: (isOk?: boolean) => {
// 每设置展示数据回显
if (typeof callback === "function") {
loading.value = false;
isCompleting.value = false;
return;
}
if (isBoolean(isOk) && !isOk) {
loading.value = false;
return;
}
if (beforeConfirm) {
beforeConfirm(
pickerColSelected.value,
pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
}),
(isPass: boolean) => {
if (isPass) {
onConfirm();
} else {
loading.value = false;
}
}
);
} else {
onConfirm();
}
}
});
}
function onConfirm() {
isChange.value = false;
loading.value = false;
pickerShow.value = false;
emit("update:modelValue", pickerColSelected.value);
emit("confirm", {
value: pickerColSelected.value,
selectedItems: pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
})
});
}
function handleColClick(index: number) {
isChange.value = true;
currentCol.value = index;
updateLineAndScroll(true);
}
/**
* @description 更新navBar underline的偏移量
* @param {Boolean} animation 是否伴随动画
*/
function setLineStyle(animation = true) {
if (!inited.value) return;
getRect($item, true, proxy).then(rects => {
const rect = rects[currentCol.value];
// const width = lineWidth || (slidableNum < items.length ? rect.width : (rect.width - 14))
const width = 16;
let left = rects.slice(0, currentCol.value).reduce((prev: any, curr: any) => prev + curr.width, 0);
left += (Number(rect.width) - width) / 2;
const transition = animation ? "transition: width 300ms ease, transform 300ms ease;" : "";
const lineStyleTemp = `
transform: translateX(${left}px);
${transition}
`;
// 防止重复绘制
if (lineStyle.value !== lineStyleTemp) {
lineStyle.value = lineStyleTemp;
}
});
}
/**
* @description scroll-view滑动到active的tab_nav
*/
function lineScrollIntoView() {
if (!inited.value) return;
Promise.all([getRect($item, true, proxy), getRect($container, false, proxy)]).then(([navItemsRects, navRect]) => {
if (!isArray(navItemsRects) || navItemsRects.length === 0) return;
// 选中元素
const selectItem = navItemsRects[currentCol.value];
// 选中元素之前的节点的宽度总和
const offsetLeft = navItemsRects.slice(0, currentCol.value).reduce((prev, curr) => prev + Number(curr.width), 0);
// scroll-view滑动到selectItem的偏移量
scrollLeft.value = offsetLeft - ((navRect as any).width - Number(selectItem.width)) / 2;
});
}
// 递归列数据补齐
function diffColumns(colIndex: number) {
// colIndex 为 -1 时,item 为空对象,>=0 时则具有 value 属性
const item = colIndex === -1 ? {} : { [props.valueKey]: props.modelValue[colIndex] };
handleColChange(colIndex, item, -1, () => {
// 如果 columns 长度还小于 value 长度,colIndex + 1,继续递归补齐
if (selectList.value.length < props.modelValue.length) {
diffColumns(colIndex + 1);
}
});
}
function handleAutoComplete() {
if (props.autoComplete) {
// 如果 columns 数组长度为空,或者长度小于 value 的长度,自动触发 columnChange 来补齐数据
if (selectList.value.length < props.modelValue.length || selectList.value.length === 0) {
// isCompleting 是否在自动补全,锁操作
if (!isCompleting.value) {
// 如果 columns 长度为空,则传入的 colIndex 为 -1
const colIndex = selectList.value.length === 0 ? -1 : selectList.value.length - 1;
diffColumns(colIndex);
}
isCompleting.value = true;
}
}
}
defineExpose<ColPickerExpose>({
close,
open
});
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>
...@@ -43,7 +43,9 @@ ...@@ -43,7 +43,9 @@
/* ios打包配置 */ /* ios打包配置 */
"ios" : {}, "ios" : {},
/* SDK配置 */ /* SDK配置 */
"sdkConfigs" : {} "sdkConfigs" : {
"maps" : {}
}
} }
}, },
/* 快应用特有相关 */ /* 快应用特有相关 */
...@@ -65,8 +67,8 @@ ...@@ -65,8 +67,8 @@
"mp-toutiao" : { "mp-toutiao" : {
"usingComponents" : true "usingComponents" : true
}, },
"uniStatistics": { "uniStatistics" : {
"enable": false "enable" : false
}, },
"vueVersion" : "3", "vueVersion" : "3",
"h5" : { "h5" : {
...@@ -78,6 +80,18 @@ ...@@ -78,6 +80,18 @@
"treeShaking" : { "treeShaking" : {
"enable" : true "enable" : true
} }
},
"sdkConfigs" : {
"maps" : {
"amap" : {
"key" : "06dbd82eab0908a62324622a319a80bb",
"securityJsCode" : "674986097d062e86d7aabc3fe75541e3",
"serviceHost" : ""
}
}
},
"unipush" : {
"enable" : false
} }
} }
} }
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
{ {
"path": "pages/postionList/index", "path": "pages/postionList/index",
"style": { "style": {
"navigationBarTitleText": "职位" "navigationBarTitleText": "职位",
"navigationStyle": "custom"
} }
}, },
{ {
...@@ -36,6 +37,98 @@ ...@@ -36,6 +37,98 @@
"style": { "style": {
"navigationBarTitleText": "政策" "navigationBarTitleText": "政策"
} }
},
{
"path": "pages/articleDetails/index",
"style": {
"navigationBarTitleText": "文章详情"
}
},
{
"path": "pages/user/resume/index",
"style": {
"navigationBarTitleText": "我的简历"
}
},
{
"path": "pages/user/resume/essentialInformation/index",
"style": {
"navigationBarTitleText": "基本信息"
}
},
{
"path": "pages/user/resume/realNameAuthentication/index",
"style": {
"navigationBarTitleText": "实名认证"
}
},
{
"path": "pages/user/resume/introduce/index",
"style": {
"navigationBarTitleText": "个人优势"
}
},
{
"path": "pages/user/resume/jobIntention/index",
"style": {
"navigationBarTitleText": "求职意向"
}
},
{
"path": "pages/user/resume/workExperience/index",
"style": {
"navigationBarTitleText": "工作经历"
}
},
{
"path": "pages/user/resume/educationExperience/index",
"style": {
"navigationBarTitleText": "教育经历"
}
},
{
"path": "pages/postionList/demandRegistration/index",
"style": {
"navigationBarTitleText": "需求登记"
}
},
{
"path": "pages/postionList/platformList/index",
"style": {
"navigationBarTitleText": "第三方平台列表"
}
},
{
"path": "pages/postionList/companyDetails/index",
"style": {
"navigationBarTitleText": "公司简介",
"navigationBarBackgroundColor": "#1D2C3E",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/user/deliveryFeedback/index",
"style": {
"navigationBarTitleText": "投递反馈"
}
},
{
"path": "pages/user/myDelivery/index",
"style": {
"navigationBarTitleText": "我的投递"
}
},
{
"path": "pages/postionList/trap/index",
"style": {
"navigationBarTitleText": "求职陷阱"
}
},
{
"path": "pages/postionList/positionDetails/index",
"style": {
"navigationBarTitleText": "职位详情"
}
} }
], ],
"tabBar": { "tabBar": {
......
<template>
<div class="page">
<div class="top">
<video :src="evn.APP_IMAGE_BASE_API + data.videoPath" v-if="data.infoType === 2"></video>
<div class="title">{{ data.title }}</div>
<div class="flex-between">
<div class="publisher">{{ data.publisher }}</div>
<div class="date">{{ dayjs(data.publishDate).format("YYYY/MM/DD hh:mm") }}</div>
</div>
<div class="watch flex-align-center">
<img src="@/static/image/icon/eye.png" alt="" />
{{ data.views }}
</div>
</div>
<div class="content" v-html="data.content"></div>
</div>
</template>
<script setup>
import { getArticleDetailApi } from "@/api/article.js";
import evn from "@/utils/config.js";
import { ref } from "vue";
import dayjs from "dayjs";
const data = ref({});
onLoad(({ id }) => {
getArticleDetailApi(id).then(res => {
console.log(res);
data.value = res.data;
});
});
</script>
<style lang="scss" scoped>
.page {
padding: 32rpx;
.top {
padding-bottom: 32rpx;
margin-bottom: 32rpx;
border-bottom: 2rpx solid #f3f4f8;
video {
width: 100%;
}
.title {
font-size: 32rpx;
font-weight: 600;
line-height: 48rpx;
color: #1b2026;
}
.flex-between {
margin: 16rpx 0;
font-size: 24rpx;
font-weight: 500;
line-height: 28rpx;
color: #77818f;
letter-spacing: 0rpx;
}
.watch {
font-size: 24rpx;
font-weight: 500;
line-height: 28rpx;
color: #77818f;
img {
width: 25.34rpx;
height: 16rpx;
margin-right: 8rpx;
}
}
}
}
</style>
<template> <template>
<div> <div class="policy">
123 <div class="tab-name" :enable-flex="true" :scroll-x="true">
<view :class="{ item: 1, active: active == v.id }" v-for="v in typeList" :key="v.id" @click="changeType(v)">{{
v.name
}}</view>
</div>
<scroll-view :scroll-y="true" class="content" @scrolltolower="getData()">
<article-list :list="list"></article-list>
</scroll-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import articleList from "@/components/articleList/index.vue";
import { getArticleListApi, getArticleTypesApi } from "@/api/article.js";
import { reactive, ref } from "vue";
const active = ref("");
const typeList = ref([{ id: "", name: "全部" }]);
getArticleTypesApi(2).then(res => {
typeList.value.push(...res.data);
});
const changeType = type => {
active.value = type.id;
pageNo = 1;
list.splice(0, list.length);
flag = false;
getData();
};
/* 文章 */
// 判断是否还有数据
let pageNo = 1;
let flag = false;
const list = reactive([]);
const getData = () => {
if (flag) {
return;
}
getArticleListApi({
type: 2,
categoryId: active.value,
pageNo: pageNo++,
pageSize: 10
}).then(res => {
if (res.data.length < 10) {
flag = true;
}
list.push(...res.data);
});
};
changeType({ id: "" });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.policy {
display: flex;
flex-direction: column;
height: 100%;
}
.tab-name {
display: flex;
width: 100%;
height: 80rpx;
overflow-x: auto;
white-space: nowrap;
.item {
padding: 22rpx 24rpx;
font-size: 28rpx;
&.active {
background-image: url("https://lygsh-image.wjzpgz.com/icon/arc.png");
background-repeat: no-repeat;
background-position: 50% 100%;
background-size: 35.64rpx 11.24rpx;
}
}
}
.content {
flex-grow: 1;
height: 200rpx;
}
</style> </style>
<template> <template>
<div> <div class="message-list">
123 <scroll-view scroll-y="{{true}}">
<view class="system">
<view class="item flex-between" v-for="(v, i) in 8" :key="i">
<img src="@/static/image/user/default-avatar.png" alt="" />
<view class="content">
<view class="name-date flex-between">
<text class="name">预约提醒</text>
<text class="date">2024-06-21 12:30</text>
</view>
<view class="message flex-between">
<text>预约活动还有24小时开始</text>
<view class="flex-align-center">
<text class="link">立即前往</text>
<view class="arrow"></view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</div> </div>
</template> </template>
<script setup> <script setup>
uni.getSystemInfo({ import { ref } from "vue";
const ossImgPrefix = "";
const res = ref({});
const getAddress = () => {
console.log("123");
uni.getLocation({
type: "wgs84",
success: function (res) { success: function (res) {
console.log(res) res.value = res;
}, },
fail: function (err) { fail(err) {
console.log(err) console.log("errerrerr", err);
} }
}) });
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
div{ .message-list {
border: 1rpx solid red; display: flex;
flex-direction: column;
height: 100%;
}
.tabs {
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 14rpx;
background-color: #ffffff;
text {
width: 280rpx;
height: 80rpx;
font-size: 36rpx;
line-height: 80rpx;
color: #1b2026;
text-align: center;
&.active {
position: relative;
font-size: 36rpx;
font-weight: 600;
background-image: url("https://lygsh-image.wjzpgz.com/community/communityActiveTab.png");
background-repeat: no-repeat;
background-position: 50% 100%;
background-size: 20% 20%;
}
}
}
.container {
flex-grow: 1;
height: 1rpx;
background-color: #aa0f00;
}
scroll-view {
flex-grow: 1;
height: 200rpx;
background-color: #ffffff;
.feedback {
.item {
position: relative;
padding: 32rpx;
padding-left: 80rpx;
&:not(:first-child) {
border-top: 16rpx solid #f3f4f8;
}
&.new::after {
position: absolute;
top: 50%;
left: 32rpx;
display: block;
width: 24rpx;
height: 24rpx;
content: "";
background-color: #f05a25;
border-radius: 50%;
transform: translate(0, -50%);
}
.job-name {
.name {
font-size: 32rpx;
font-weight: 600;
line-height: 36rpx;
color: #1b2026;
}
.salary {
font-size: 36rpx;
font-weight: 500;
line-height: 24rpx;
color: #1f86ff;
text {
font-size: 28rpx;
font-weight: normal;
line-height: 24rpx;
color: #1f86ff;
}
}
}
.com-name {
margin-top: 16rpx;
font-size: 24rpx;
font-weight: normal;
line-height: 36rpx;
color: #77818f;
letter-spacing: 0rpx;
}
.hr {
margin-top: 18rpx;
font-size: 24rpx;
line-height: 36rpx;
color: #77818f;
.hr-name {
margin-right: 34rpx;
img {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
}
}
}
.state {
position: absolute;
right: 28rpx;
bottom: 32rpx;
padding: 16rpx 32rpx;
font-size: 24rpx;
font-weight: 600;
line-height: 28rpx;
color: #f53f3f;
background: #ffece8;
}
}
}
.system {
.item {
padding: 32rpx;
border-bottom: 16rpx solid #f3f4f8;
img {
width: 86rpx;
height: 86rpx;
border-radius: 50%;
}
.content {
flex: 1;
margin-left: 24rpx;
.name-date {
.name {
font-size: 28rpx;
font-weight: 600;
line-height: 42rpx;
color: #1b2026;
text-align: center;
}
.date {
font-size: 24rpx;
font-weight: 500;
line-height: 36rpx;
color: #77818f;
}
}
.message {
margin-top: 14rpx;
font-size: 24rpx;
font-weight: normal;
line-height: 36rpx;
color: #1b2026;
.link {
font-size: 24rpx;
font-weight: 500;
line-height: 36rpx;
color: #1f86ff;
}
.arrow {
border-color: #1f86ff;
}
}
}
}
}
} }
</style> </style>
<template> <template>
<div> <div class="policy">
123 <div class="tab-name" :enable-flex="true" :scroll-x="true">
<view :class="{ item: 1, active: active == v.id }" v-for="v in typeList" :key="v.id" @click="changeType(v)">{{
v.name
}}</view>
</div>
<scroll-view :scroll-y="true" class="content" @scrolltolower="getData()">
<article-list :list="list"></article-list>
</scroll-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import articleList from "@/components/articleList/index.vue";
import { getArticleListApi, getArticleTypesApi } from "@/api/article.js";
import { reactive, ref } from "vue";
const active = ref("");
const typeList = ref([{ id: "", name: "全部" }]);
getArticleTypesApi(1).then(res => {
typeList.value.push(...res.data);
});
const changeType = type => {
active.value = type.id;
pageNo = 1;
list.splice(0, list.length);
flag = false;
getData();
};
/* 文章 */
// 判断是否还有数据
let pageNo = 1;
let flag = false;
const list = reactive([]);
const getData = () => {
if (flag) {
return;
}
getArticleListApi({
type: 1,
categoryId: active.value,
pageNo: pageNo++,
pageSize: 10
}).then(res => {
if (res.data.length < 10) {
flag = true;
}
list.push(...res.data);
});
};
changeType({ id: "" });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.policy {
display: flex;
flex-direction: column;
height: 100%;
}
.tab-name {
display: flex;
width: 100%;
height: 80rpx;
overflow-x: auto;
white-space: nowrap;
.item {
padding: 22rpx 24rpx;
font-size: 28rpx;
&.active {
background-image: url("https://lygsh-image.wjzpgz.com/icon/arc.png");
background-repeat: no-repeat;
background-position: 50% 100%;
background-size: 35.64rpx 11.24rpx;
}
}
}
.content {
flex-grow: 1;
height: 200rpx;
}
</style> </style>
<template>
<div class="page">
<!-- 公司详情 -->
<view class="pos-details">
<view class="pos-title">
<view class="pos-logo">
<!-- <image mode="widthFix" wx:if="{{partTimeJobData.logoPath}}" src="{{videosrc}}{{partTimeJobData.logoPath}}"></image> -->
<image v-if="partTimeJobData.logoPath" src="@/static/image/temp/test.jpg"></image>
<image v-else src="@/static/image/temp/test.jpg"></image>
</view>
<view>
<view class="pos-name">{{ partTimeJobData.name }}</view>
<view class="cos-position">
<!-- <text>{{partTimeJobData.placeCityName}}</text> -->
<text>贵州</text>
<text class="margin-8">|</text>
<text>{{ partTimeJobData.jobList?.length }}个在招职位</text>
</view>
</view>
</view>
</view>
<!-- 公司地址 -->
<view class="pos-address">
<text class="title">公司地址</text>
<view class="address flex-between">
<text>{{ partTimeJobData.address }}</text>
<view>
<image src="@/static/image/icon/navigation.png" mode="" />
导航
</view>
</view>
</view>
<!-- 公司介绍 -->
<view class="pos-introduce pos-padding-top0" v-if="partTimeJobData.companyIntro">
<view class="title">
<text class="text">公司介绍</text>
</view>
<view class="pos-duty activeClass">
<text>{{ partTimeJobData.companyIntro }}</text>
</view>
</view>
<!-- 公司基本信息 -->
<view class="pos-introduce pos-padding-top0">
<view class="title">
<text class="text">企业基本信息</text>
</view>
<view class="pos-int" v-if="partTimeJobData.companyType">
<text class="pos-label">企业类型:</text>
<text class="pos-label-text">{{ partTimeJobData.companyType }}</text>
</view>
<view class="pos-int" v-if="partTimeJobData.operatingStatus">
<text class="pos-label">经营状态:</text>
<text class="pos-label-text">{{ partTimeJobData.operatingStatus }}</text>
</view>
<view class="pos-int" v-if="partTimeJobData.registeredCapital">
<text class="pos-label">注册资本:</text>
<text class="pos-label-text">{{ partTimeJobData.registeredCapital }}</text>
</view>
<view class="pos-int" v-if="partTimeJobData.companyType">
<text class="pos-label">行业类型:</text>
<text class="pos-label-text">{{ partTimeJobData.industryCategory }}</text>
</view>
</view>
<!-- 职位推荐 -->
<view
class="pos-recommend"
:style="`top:${activeRecommend ? top : recommendTop}px`"
v-if="partTimeJobData.jobList?.length"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
<view class="title">
<text class="text"
>公司在招职位<text class="num">{{ partTimeJobData.jobList.length }}</text></text
>
</view>
<scroll-view scroll-x="{{true}}" class="pos-select">
<view class="flex-align-center">
<text :class="activeJobListType === '' ? 'active' : ''" @:tap="filterOpstionList('')">全部</text>
<text
:class="activeJobListType === item ? 'active' : ''"
v-for="(item, index) in partTimeJobData.jobTypeTextList"
:key="item"
@:tap="filterOpstionList(item)"
>{{ item }}</text
>
</view>
</scroll-view>
<!-- 职位列表 -->
<scroll-view scroll-y="{{true}}" class="recommend-list-wrap">
<block v-for="(item, index) in partTimeJobData.jobList" :key="index">
<view class="card-wrap" v-if="item.isShow">
<postion-card1 :data="item"></postion-card1>
</view>
</block>
</scroll-view>
</view>
</div>
</template>
<script setup>
import { getCompanyDetailApi } from "@/api/postion.js";
import { ref } from "vue";
import postionCard1 from "@/components/postionCard1/index.vue";
import SwipeHandler from "@/utils/swipeHandler";
const partTimeJobData = ref({});
onLoad(({ id }) => {
console.log(id);
getCompanyDetailApi(id).then(res => {
console.log(res);
partTimeJobData.value = res.data;
partTimeJobData.value.jobList.forEach(v => {
v.isShow = true;
});
});
});
/* 推荐列表 */
const swipeHandler = new SwipeHandler();
const activeRecommend = ref(false);
const recommendTop = ref(0);
const top = ref(0);
const activeJobListType = ref("");
const onTouchStart = e => {
swipeHandler.onTouchStart(e);
};
const onTouchMove = e => {
swipeHandler.onTouchMove(e);
};
const onTouchEnd = e => {
let direction = swipeHandler.onTouchEnd(e);
console.log(direction);
if (direction === "up") {
activeRecommend.value = true;
}
if (direction === "down") {
activeRecommend.value = false;
}
};
const setRecommendTop = () => {
const { windowHeight, windowTop } = uni.getWindowInfo();
top.value = windowTop;
recommendTop.value = windowHeight - 178;
};
onLoad(() => {
setRecommendTop();
});
// 筛选推荐列表
const filterOpstionList = type => {
partTimeJobData.jobList.forEach(v => {
v.isShow = !type ? true : v.jobTypeText == type;
});
};
</script>
<style lang="scss" scoped>
/* stylelint-disable no-duplicate-selectors */
/* 公司详情 */
.pos-details {
padding: 28rpx 32rpx;
background: #ffffff;
}
.pos-details .pos-title {
display: flex;
margin-bottom: 16rpx;
}
.pos-details .pos-title .pos-logo {
display: inline-block;
width: 88rpx;
height: 88rpx;
margin-right: 16rpx;
overflow: hidden;
vertical-align: middle;
border-radius: 8rpx;
}
.pos-details .pos-title .pos-name {
display: inline-block;
flex: 1;
font-size: 36rpx;
font-weight: 500;
line-height: 40rpx;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.pos-details .pos-title .pos-logo image {
width: 100%;
height: 100%;
}
.pos-details .cos-position {
font-size: 24rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
}
.pos-details .pos-title .label {
width: auto;
height: 36rpx;
padding: 0 8rpx;
margin-right: 16rpx;
font-size: 24rpx;
font-weight: 400;
line-height: 36rpx;
color: rgb(250 122 96 / 100%);
text-align: center;
vertical-align: middle;
background: rgb(252 229 229 / 100%);
border-radius: 4rpx;
}
.pos-details .pos-title .text {
font-size: 36rpx;
font-weight: 500;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.pos-details .pos-type {
margin-bottom: 16rpx;
overflow: hidden;
}
.pos-details .pos-type .salary {
float: left;
}
.pos-details .pos-type .salary .number {
font-size: 40rpx;
color: #ff5937;
}
.pos-details .pos-type .salary .unit {
font-size: 24rpx;
color: #ff5937;
}
.pos-details .pos-type .type {
float: right;
font-size: 24rpx;
line-height: 52rpx;
color: #808080;
}
.pos-details .time {
margin-bottom: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(58 58 60 / 100%);
}
.pos-details .time text {
margin-right: 12rpx;
margin-bottom: 8rpx;
}
.pos-details .pos-label {
margin-bottom: 24rpx;
}
.pos-details .pos-label .label-list {
display: inline-block;
width: auto;
height: 40rpx;
padding: 0 16rpx;
font-size: 24rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
border: 2rpx solid rgb(186 186 186 / 100%);
border-radius: 2rpx;
}
.pos-details .pos-address {
padding: 24rpx 0;
padding-top: 14rpx;
border-top: 2rpx solid rgb(238 239 238 / 100%);
}
.pos-details .pos-address image {
display: inline-block;
width: 28rpx;
height: 32rpx;
margin-right: 12rpx;
vertical-align: middle;
}
.pos-details .pos-address text {
font-size: 24rpx;
font-weight: 400;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.pos-details .cos-welfare {
width: 100%;
max-height: 50rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pos-details .cos-welfare .welfare-list {
float: left;
width: auto;
height: 40rpx;
padding: 0 10rpx;
margin: 0 12rpx 10rpx 0;
font-size: 24rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
border: 2rpx solid rgb(186 186 186 / 100%);
border-radius: 4rpx;
}
/* // 公司信息 */
.cos-info {
position: relative;
padding: 28rpx 32rpx;
background: #ffffff;
}
.cos-info .cos-title {
margin-bottom: 16rpx;
}
.cos-info .cos-title .cos-name {
margin-right: 12rpx;
font-size: 28rpx;
font-weight: 600;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.cos-info .cos-title .label-icon {
width: 28rpx;
height: 30rpx;
margin-right: 4rpx;
vertical-align: middle;
}
.cos-info .cos-title .label-name {
padding: 2rpx 6rpx;
font-size: 20rpx;
font-weight: 400;
color: rgb(155 1 1 / 100%);
vertical-align: middle;
background: rgb(255 233 237 / 100%);
border-radius: 4rpx;
}
.cos-info .modu-icon {
position: absolute;
top: 50%;
right: 32rpx;
width: 12rpx;
height: 20rpx;
transform: translateY(-50%);
}
/* // 职位介绍 */
.pos-introduce {
position: relative;
padding: 28rpx 32rpx;
background: #ffffff;
}
.pos-padding-bott0 {
padding-bottom: 0;
}
.pos-padding-top0 {
padding-top: 0;
}
.pos-introduce .title {
margin-bottom: 20rpx;
}
.pos-introduce .title .sign {
display: inline-block;
width: 12rpx;
height: 12rpx;
margin-right: 16rpx;
vertical-align: middle;
background: rgb(26 138 250 / 100%);
border-radius: 50%;
}
.pos-introduce .title .text {
font-size: 32rpx;
font-weight: 500;
color: rgb(51 51 51 / 100%);
vertical-align: middle;
}
.pos-introduce .pos-int {
margin-bottom: 16rpx;
}
.pos-introduce .pos-int .pos-label {
display: inline-block;
font-size: 24rpx;
font-weight: 400;
line-height: 34rpx;
color: rgb(128 128 128 / 100%);
}
.pos-introduce .pos-int .pos-label-text {
display: inline-block;
font-size: 24rpx;
font-weight: 400;
line-height: 34rpx;
color: #3a3a3c;
}
.pos-introduce .pos-duty {
display: -webkit-box;
margin-bottom: 36rpx;
overflow: hidden;
font-size: 24rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
word-break: break-all;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
}
.pos-introduce .activeClass {
margin-bottom: 0;
-webkit-line-clamp: inherit;
}
.pos-introduce .duty-more {
position: absolute;
right: 0;
bottom: 28rpx;
left: 0;
padding-top: 22rpx;
text-align: center;
background: linear-gradient(to top, rgb(255 255 255 / 100%), rgb(255 255 255 / 80%), rgb(255 255 255 / 70%));
}
.pos-introduce .duty-more text {
margin-right: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(24 146 255 / 100%);
vertical-align: middle;
}
.pos-introduce .duty-more image {
display: inline-block;
width: 20rpx;
height: 12rpx;
vertical-align: middle;
}
.pos-introduce .Tips {
position: relative;
width: 100%;
height: 50rpx;
margin-top: 60rpx;
font-size: 24rpx;
font-weight: 400;
line-height: 34rpx;
color: rgb(128 128 128 / 100%);
border-top: 1px solid #e9e9e9;
}
.pos-introduce .Tips view {
position: absolute;
left: 50%;
padding: 0 28rpx;
margin-top: -18rpx;
background: #ffffff;
transform: translateX(-50%);
}
.pos-introduce .Tips view text {
color: #3a3a3a;
}
/* // 职位推荐 */
.pos-recommend {
padding: 28rpx 32rpx;
padding-bottom: 138rpx;
background: #ffffff;
}
/* // .pos-recommend .title{} */
.pos-recommend .title .sign {
display: inline-block;
width: 12rpx;
height: 12rpx;
margin-right: 16rpx;
vertical-align: middle;
background: rgb(26 138 250 / 100%);
border-radius: 50%;
}
.pos-recommend .title .text {
font-size: 32rpx;
font-weight: 500;
color: rgb(51 51 51 / 100%);
vertical-align: middle;
}
.pos-recommend .recommend-list {
padding-top: 28rpx;
border-bottom: 2rpx solid rgb(238 239 238 / 100%);
}
.pos-recommend .recommend-list .recommend-title {
margin-bottom: 16rpx;
overflow: hidden;
}
.recommend-list .recommend-title .sign {
width: auto;
height: 28rpx;
padding: 0 10rpx;
margin-right: 12rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 25rpx;
color: rgb(250 122 96 / 100%);
text-align: center;
vertical-align: middle;
background: rgb(252 229 229 / 100%);
border-radius: 4rpx;
}
.recommend-list .recommend-title .title {
font-size: 32rpx;
font-weight: 500;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.recommend-list .recommend-title .salary {
float: right;
margin-top: 12rpx;
font-size: 28rpx;
font-weight: 600;
color: rgb(255 89 55 / 100%);
}
.recommend-list .cos-details {
display: flex;
}
.recommend-list .cos-details .cos-requirement {
flex: 1;
}
.recommend-list .cos-details .cos-requirement .cos-title {
margin-bottom: 16rpx;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-name {
display: inline-block;
max-width: 260rpx;
height: 32rpx;
margin-right: 8rpx;
overflow: hidden;
font-size: 24rpx;
font-weight: 400;
color: rgb(58 58 60 / 100%);
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-recommend {
display: inline-block;
height: 36rpx;
padding: 0 4rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 36rpx;
color: rgb(155 1 1 / 100%);
vertical-align: middle;
background: rgb(255 233 237 / 100%);
border-radius: 4rpx;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.recommend-list .cos-details .cos-requirement .cos-title image {
display: inline-block;
width: 36rpx;
height: 36rpx;
vertical-align: middle;
background-color: rgb(255 233 237 / 100%);
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
}
.recommend-list .cos-details .cos-ask {
margin-bottom: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
}
.recommend-list .cos-details .cos-welfare {
overflow: hidden;
}
.recommend-list .cos-details .cos-welfare .welfare-list {
float: left;
width: auto;
height: 40rpx;
padding: 0 10rpx;
margin: 0 12rpx 12rpx 0;
font-size: 24rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
border: 2rpx solid rgb(186 186 186 / 100%);
border-radius: 4rpx;
}
.recommend-list .cos-details .cos-video {
position: relative;
width: 160rpx;
height: 120rpx;
overflow: hidden;
}
.recommend-list .cos-details .recommend-video {
width: 100%;
height: 100%;
}
.recommend-list .salary-info {
padding-bottom: 28rpx;
overflow: hidden;
}
.recommend-list .salary-info .salary {
font-size: 28rpx;
font-weight: 600;
color: rgb(255 89 55 / 100%);
vertical-align: middle;
}
.recommend-list .salary-info .deliveryBtn {
float: right;
}
.cos-play-icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 64rpx;
height: 64rpx;
transform: translate(-50%, -50%);
}
/* // 底部按钮 */
.btn {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
display: flex;
height: 88rpx;
line-height: 88rpx;
background-color: #ffffff;
border: 2rpx solid rgb(233 233 233 / 100%);
}
.btn .btn-list {
flex: 1;
font-size: 32rpx;
font-weight: 400;
color: #ffffff;
text-align: center;
background-color: #bababa;
}
.btn .back-color {
color: #ffffff;
background-color: #1892ff;
}
.btn .btn-share {
width: 220rpx;
text-align: center;
}
.btn .btn-share image {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.btn .share-btn {
display: inline-block;
width: 100%;
padding: 0;
margin: 0;
font-size: 32rpx;
font-weight: 400;
color: rgb(24 146 255 / 100%);
vertical-align: middle;
background: rgb(0 0 0 / 0%);
border: none;
}
.btn .share-btn::after {
border: none;
}
.margin-top24 {
margin-top: 24rpx;
}
.margin-8 {
margin: 0 8rpx;
}
/* 分享 */
.pull-vote {
position: fixed;
right: 32rpx;
bottom: 80rpx;
z-index: 9;
width: 96rpx;
height: 96rpx;
}
.desc {
font-size: 24rpx;
font-weight: 400;
color: #9b9b9b;
}
.canvas-wrapper {
position: fixed;
left: -2400rpx;
z-index: 10;
}
.page {
padding-bottom: 350px;
background-color: #1d2c3e;
}
.pos-details {
padding: 28rpx 32rpx;
background: transparent;
.pos-title {
.pos-logo {
width: 96rpx;
height: 96rpx;
image {
width: 96rpx;
height: 96rpx;
}
}
.pos-name {
margin-bottom: 8rpx;
font-size: 36rpx;
font-weight: 600;
color: #ffffff;
}
.cos-position {
color: #bec3cb;
}
}
}
.pos-address {
padding: 32rpx;
margin: 32rpx;
color: #ffffff;
background-color: #0f1a27;
border-radius: 8rpx;
.title {
font-size: 28rpx;
font-weight: 600;
}
.address {
margin-top: 24rpx;
font-size: 24rpx;
view {
flex-shrink: 0;
width: 132rpx;
height: 52rpx;
line-height: 52rpx;
text-align: center;
background-color: rgb(255 255 255 / 10%);
border-radius: 26rpx;
image {
width: 24rpx;
height: 24rpx;
vertical-align: middle;
}
}
}
}
.pos-introduce {
background-color: transparent;
.title {
.text {
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
}
}
.pos-duty {
padding-bottom: 30rpx;
font-size: 24rpx;
line-height: 48rpx;
color: #ffffff;
border-bottom: 2rpx solid #f3f4f833;
}
.pos-int {
margin-bottom: 16rpx;
.pos-label,
.pos-label-text {
font-size: 24rpx;
line-height: 26rpx;
color: #ffffff;
}
}
}
.pos-recommend {
position: fixed;
box-sizing: border-box;
display: flex;
flex-direction: column;
width: 750rpx;
height: 100%;
padding: 0;
padding-bottom: 30rpx;
border-top-left-radius: 24rpx;
border-top-right-radius: 24rpx;
// top: 550px;
transition: all 0.5s;
.title {
padding-bottom: 30rpx;
margin: 32rpx;
border-bottom: 2rpx solid #f3f4f8;
.text {
font-size: 36rpx;
font-weight: 600;
color: #1b2026;
.num {
font-size: 24rpx;
font-weight: 500;
color: #4e5969;
}
}
}
.pos-select {
width: 750rpx;
padding-bottom: 32rpx;
border-bottom: 16rpx solid #f3f4f8;
.flex-align-center {
flex-wrap: nowrap;
width: auto;
margin: 0 32rpx;
text {
padding: 10rpx 24rpx;
margin-left: 24rpx;
font-size: 28rpx;
line-height: 44rpx;
color: #4e5969;
white-space: nowrap;
/* 自动布局 */
background: rgb(255 255 255 / 10%);
border: 2rpx solid #e1e2e6;
border-radius: 12rpx;
}
.active {
color: #1f86ff;
background: rgb(31 134 255 / 10%);
border-color: #1f86ff;
}
}
}
.recommend-list {
position: relative;
padding: 32rpx 32rpx 0;
margin: 0 32rpx;
margin-bottom: 20rpx;
background-color: #ffffff;
.recommend-title {
margin-bottom: 24rpx;
.title {
padding: 0;
margin: 0;
font-size: 32rpx;
font-weight: 600;
color: #1b2026;
border: 0;
}
}
.cos-welfare {
.welfare-list {
color: #4e5969;
background: #f2f3f5;
border: 0;
}
}
.cos-title {
display: flex;
align-items: center;
justify-content: space-between;
.cos-name {
font-size: 24rpx;
color: #1b2026;
}
.address {
font-size: 12px;
color: #1b2026;
}
}
.salary-info {
position: absolute;
top: 40rpx;
right: 32rpx;
.salary {
font-family: DIN;
font-size: 36rpx;
font-weight: 500;
color: #1f86ff;
}
}
}
.recommend-list-wrap {
flex-grow: 1;
height: 1000rpx;
.card-wrap {
padding: 32rpx;
border-bottom: 1px solid #f3f4f8;
}
}
}
</style>
<template>
<div class="page">
<scroll-view scroll-y="{{true}}" @scrolltolower="getData">
<view class="item" v-for="(item, index) in list" :key="item.id">
<view class="flex-between">
<text class="name">{{ item.needName }}</text>
<view v-if="item.userId" class="state disable">已提交</view>
<view v-else class="state" @tap="showPopup(item)">我需要</view>
</view>
<view class="content">
{{ item.needDesc }}
</view>
</view>
</scroll-view>
</div>
<wd-overlay :show="show" @click="show = false">
<view class="popout-wrap" @click.stop>
<view class="popout">
<image src="@/static/image/postion/demandRegistrationPopout.png" />
<view class="text1">需求登记</view>
<view class="text2">平台将自动获取您个人信息</view>
<view class="text2">用于后续平台联系您提供服务</view>
<view class="btn flex-between">
<view class="cancel" @tap="show = false">取消</view>
<view class="confirm" @tap="submit">立即提交</view>
</view>
</view>
</view>
</wd-overlay>
</template>
<script setup>
import { reactive, ref } from "vue";
import { getNeedListApi, needRegisterApi } from "@/api/postion";
const list = reactive([]);
let page = 1;
const getData = () => {
getNeedListApi({
pageSize: 10,
pageNo: page++
}).then(res => {
if (res.code == 200) {
// console.log(list);
list.push(...res.data);
}
});
};
const show = ref(false);
let tempItem = null;
const showPopup = item => {
tempItem = item;
show.value = true;
};
const submit = () => {
needRegisterApi(tempItem.needId).then(res => {
if (res.code == 200) {
tempItem.userId = true;
uni.showToast({
title: "申请成功",
icon: "success"
});
}
show.value = false;
});
};
getData();
</script>
<style lang="scss" scoped>
.page {
height: 100%;
scroll-view {
height: 100%;
}
}
.item {
padding: 16px;
color: #1b2026;
border-bottom: 8px solid #f3f4f8;
.name {
font-size: 16px;
font-weight: 600;
line-height: 21px;
}
.state {
padding: 4px 10px;
color: #ffffff;
background: #1f86ff;
border-radius: 6px;
}
.disable {
background: #d6ddeb;
}
.content {
margin-top: 7px;
font-size: 12px;
font-weight: normal;
line-height: 18px;
letter-spacing: 0;
}
}
.popout-wrap {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.popout {
display: flex;
flex-direction: column;
align-items: center;
width: 300px;
height: 248px;
background-color: #ffffff;
border-radius: 8px;
image {
width: 126px;
height: 96px;
margin-top: 16px;
}
view {
font-size: 14px;
font-weight: normal;
line-height: 20px;
color: #000000;
text-align: center;
letter-spacing: 0;
}
.text1 {
margin-bottom: 7px;
color: #1b2026;
}
.btn {
box-sizing: border-box;
width: 100%;
padding-right: 6px;
padding-left: 29px;
margin-top: 17px;
.cancel {
padding: 7px 16px;
font-size: 14px;
font-weight: 500;
line-height: 22px;
color: #1f86ff;
background: rgb(31 134 255 / 10%);
border-radius: 6px;
}
.confirm {
padding: 7px 53px;
line-height: 22px;
color: #ffffff;
text-align: center;
letter-spacing: 0;
background: #1f86ff;
border-radius: 6px;
}
}
}
</style>
<template> <template>
<div class="b" :style="{ height: height + 'px' }"> <!--pages/wanted/wanted.wxml-->
{{ height }} <!-- 自定义顶部 -->
<!-- <nav-bar class="nav-bar" bgColor="#fff" bind:getData="getData">
<view class="search-form">
<image class="search-icon" src="{{ossImgPrefix}}/icon/search.png"></image>
<input placeholder="搜索职位,公司" placeholder-class="log-input-p" type="text"></input>
</view>
</nav-bar> -->
<!-- 轮播区 -->
<div class="c" :style="{ height: height2 + 'px' }"> <wd-swiper
{{ height2 }} class="banner"
</div> :list="swiperList"
</div> autoplay
v-model:current="current"
:indicator="{ type: 'dots-bar' }"
@click="handleClickSwiper"
></wd-swiper>
<!-- 零工培训 -->
<view class="router-link flex-between">
<view v-for="(v, i) in routerLinkList" :key="i" tap="navigateTo" @click="clickNav(v.url)">
<img :src="v.icon" />
<view>{{ v.text }}</view>
</view>
</view>
<!-- 筛选导航 -->
<view class="select-nav" :style="{ top: '0px' }" catchtouchmove="{{true}}">
<view class="recommend">推荐</view>
<view class="select-item">
<text :class="{ active: maskType == 'address' }" @tap="openMask('address')">贵州省</text>
<text :class="{ active: maskType == 'position' }" @tap="openMask('position')">职位类型</text>
<text :class="{ active: maskType == 'other' }" @tap="openMask('other')">更多筛选</text>
</view>
</view>
<!-- 蒙版弹框 -->
<view class="pop-mask" :style="{ paddingTop: '70rpx' }" v-if="maskType" @click="maskType = null">
<!-- 区域弹窗 -->
<view
@click.stop=""
catchtap="preventD"
class="screen-pop address screen-pop-padding {{regionPop? 'screen-pop-tion':''}} "
v-if="maskType === 'address'"
>
<view class="region-pop-content">
<view class="region-pop-left">
<scroll-view scroll-y style="height: 652rpx">
<view
class="region-list"
:class="{ 'region-list-color': cityId == item.code }"
v-for="(item, index) in cityData"
:key="item.code"
@tap="bindCityList(item.code, item.name)"
>{{ item.name }}</view
>
</scroll-view>
</view>
<view class="region-pop-right">
<scroll-view scroll-y style="height: 652rpx">
<view
class="region-list"
:class="{ 'region-list-color': regionId == v.code }"
v-for="(v, i) in regionData"
:key="v.code"
@tap="bindRegionList(v.code, v.name)"
>{{ v.name }}</view
>
</scroll-view>
</view>
</view>
</view>
<!-- 职位类型弹窗 -->
<view
@click.stop=""
catchtap="preventD"
class="screen-pop position screen-pop-padding {{sortPop? 'screen-pop-tion':''}}"
v-if="maskType === 'position'"
>
<view class="screen-pop-box">
<view class="screen-pop-content screen-pop-padding">
<scroll-view scroll-y class="screen-pop-padding40" style="height: 652rpx">
<view>
<view class="screen-pop-title">全部</view>
<view class="pop-title-label">
<view
class="label-list"
:class="{ 'label-list-color': sortNav == '职位类型' }"
@tap="bindSortList('全部', '')"
>全部</view
>
</view>
</view>
<view v-for="(item, index) in positionType" :key="index">
<view class="screen-pop-title">{{ item.name }}</view>
<view class="pop-title-label">
<view
v-for="(v, i) in item.children"
:class="['label-list', sortNav == v.name ? 'label-list-color' : '']"
:key="i"
@tap="bindSortList(v.name, v.id)"
>{{ v.name }}</view
>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
<!-- 筛选弹窗 -->
<view
@click.stop=""
catchtap="preventD"
class="screen-pop other screen-pop-padding {{screenPop? 'screen-pop-tion':''}}"
v-if="maskType === 'other'"
>
<view class="screen-pop-box">
<view class="screen-pop-content screen-pop-padding" style="bottom: 130rpx">
<scroll-view scroll-y class="screen-pop-padding40" style="height: 522rpx">
<view class="screen-pop-title">性别要求</view>
<view class="pop-title-label">
<view
v-for="item in screenSexData"
:class="['label-list', screenSex == item.text ? 'label-list-color' : '']"
:key="item.code"
@tap="bindScreenSexList(item.text, item.code)"
>{{ item.text }}</view
>
</view>
<view class="screen-pop-title">身份要求</view>
<view class="pop-title-label">
<view
v-for="item in identityData"
:class="['label-list', screenEducation == item.text ? 'label-list-color' : '']"
:key="item.code"
@tap="bindScreenEducationList(item.text, item.code)"
>{{ item.text }}</view
>
</view>
</scroll-view>
</view>
<view class="pop-bottom">
<view class="pop-btn" @tap="maskType = ''">完成</view>
<view class="pop-btn" bindtap="bindScreenReset">重置</view>
</view>
</view>
</view>
</view>
<!-- 全职职位列表 -->
<view class="content">
<view class="position-content">
<view class="item" v-for="(v, i) in positionListData" :key="v">
<postion-card1 :data="v"></postion-card1>
</view>
</view>
<!-- 暂无职位推荐-->
<view class="nothing" v-if="!positionListData.length">
<view class="nothing-text">暂无职位推荐</view>
</view>
</view>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, reactive } from "vue";
let a = uni.getWindowInfo(); import { getjobListApi } from "@/api/postion.js";
console.log(a); import { getTreeListApi, dictJobTypeApi, getBannerListApi } from "@/api/common.js";
const height = ref(0); import postionCard1 from "@/components/postionCard1/index.vue";
const height2 = ref(0); import { getEumData } from "@/utils/utils.js";
const pixelRatio = ref(a.pixelRatio); import evn from "@/utils/config.js";
height.value = a.screenTop; /* 轮播 */
height2.value = a.statusBarHeight; const swiperList = ref([]);
// 获取数据
getBannerListApi(1).then(res => {
console.log(res);
swiperList.value = res.data.map(item => evn.APP_IMAGE_BASE_API + item.imgPath);
});
const current = ref(0);
const handleClickSwiper = e => {
console.log(e);
};
const routerLinkList = [
{
icon: new URL("@/static/image/postion/qiuzhidengji.png", import.meta.url).href,
text: "求职登记",
url: "/pages/user/resume/index"
},
{
icon: new URL("@/static/image/postion/xuqiudengji.png", import.meta.url).href,
text: "需求登记",
url: "/pages/postionList/demandRegistration/index"
},
{
icon: new URL("@/static/image/postion/qiuzhixianjing.png", import.meta.url).href,
text: "求职陷阱",
url: "/pages/postionList/trap/index"
},
{
icon: new URL("@/static/image/postion/linggongzhuanqu.png", import.meta.url).href,
text: "零工专区",
url: "/pages/postionList/platformList/index?type=零工专区"
},
{
icon: new URL("@/static/image/postion/qitapingtai.png", import.meta.url).href,
text: "其他平台",
url: "/pages/postionList/platformList/index?type=其他平台"
}
];
const clickNav = url => {
if (url) {
uni.navigateTo({
url
});
}
};
const nothingFlag = false;
const maskType = ref("");
/* 筛选 */
const openMask = type => {
maskType.value = type;
// 页面滚动到合适位子
uni.pageScrollTo({
scrollTop: 280,
duration: 0
});
};
// 省市区
let regionPop = false; //区域
let regionNav = "贵州省"; //选中区域
let cityId = ref(null); //选中市id
const cityData = ref([]); //市
const regionId = ref(null); //选中区域id
const regionData = ref([]); //区
const getTreeData = () => {
getTreeListApi({
isCityNeedUnlimited: true,
isDistrictNeedUnlimited: true
}).then(res => {
if (res.code === 200) {
let _data = res.data;
for (let i = 0; i < _data.length; i++) {
if (_data[i].code == 520000) {
let _children = _data[i].children;
cityData.value = _children;
for (let j = 0; j < _children.length; j++) {
if (_children[j].code == 520100) {
regionData.value = _data[i].children[j].children;
}
}
}
}
}
});
};
getTreeData();
// 选择市
const bindCityList = (code, name) => {
for (let i = 0; i < cityData.value.length; i++) {
if (cityData.value[i].code == code) {
let _children = cityData.value[i].children;
regionData.value = _children;
cityId.value = code;
}
}
};
// 选择区
const bindRegionList = (code, name) => {
let _regionNav;
if (name == "全部") {
for (let i = 0; i < cityData.length; i++) {
if (cityId.value == cityData[i].code) {
_regionNav = cityData[i].name;
}
}
} else {
pageNo = 1;
regionNav = name;
regionId.value = code;
}
};
// 职业类型筛选
const positionType = ref([]);
const sortNav = ref("职位类型");
const sortId = ref("");
const dictJobType = () => {
dictJobTypeApi({ jobDateType: 1 }).then(({ code, data }) => {
if (code == 200) {
positionType.value = data;
}
});
};
const bindSortList = (name, id) => {
if (name == "全部") {
sortNav.value = "职位类型";
sortId.value = id;
pageNo = 1;
} else {
sortNav.value = name;
sortId.value = id;
pageNo = 1;
}
};
dictJobType();
// 其他筛选
const identityData = ref([]);
const screenSexData = ref([]);
const screenSex = ref("");
const screenSexCode = ref("");
const screenEducation = ref("");
const screenEducationCode = ref("");
const initOtherData = async () => {
screenSexData.value = await getEumData("EnumGenderRequirement");
identityData.value = await getEumData("EnumIdentityRequirement");
};
const bindScreenSexList = (text, code) => {
screenSex.value = text;
screenSexCode.value = code;
};
const bindScreenEducationList = (text, code) => {
screenEducation.value = text;
screenEducationCode.value = code;
};
initOtherData();
/* 获取职位列表 */
let pageNo = 1,
pageSize = 10,
isPartTimeJob = null,
cityCode = null,
districtCode = null,
jobType = null,
genderType = null,
jobIdentityType = null,
orderBy = null;
const positionListData = reactive([]);
const getListData = () => {
let data = {
pageNo: pageNo,
pageSize: pageSize,
isPartTimeJob: isPartTimeJob,
provinceCode: "",
cityCode: cityCode || null,
districtCode: districtCode || null,
jobType: jobType || null,
genderType: genderType || null,
jobIdentityType: jobIdentityType || null,
orderBy: orderBy || 1
};
getjobListApi(data).then(res => {
if (res.code == 200) {
positionListData.push(...res.data);
}
});
};
getListData();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.b { /* page {
border: 1px solid red; background: #ffffff;
.c { } */
border: 1px solid #00ff00;
// 顶部导航
.nav-bar {
position: relative;
.search-form {
// background: rgba(245, 245, 245, 1);
position: relative;
box-sizing: content-box;
width: 452rpx;
height: 60rpx;
margin-left: 32rpx;
overflow: hidden;
background-color: #f7f7f7;
border-radius: 30rpx;
.search-icon {
position: absolute;
top: 50%;
left: 42rpx;
z-index: 10;
width: 28rpx;
height: 28rpx;
transform: translateY(-50%);
}
input {
// background-color: #F7F7F7;
position: absolute;
right: 0rpx;
left: 0rpx;
z-index: 9999;
box-sizing: border-box;
width: 100%;
width: auto;
height: 100%;
padding: 0 88rpx;
}
} }
} }
// 轮播
.banner {
padding: 0 32rpx;
margin-top: 30rpx;
swiper-item {
overflow: hidden;
background-color: #0c81ee;
border-radius: 10rpx;
}
}
// 链接跳转
.router-link {
padding: 40rpx 60rpx;
text-align: center;
border-bottom: 16rpx solid #f3f4f8;
img {
width: 83.66rpx;
height: 80rpx;
}
view {
font-size: 24rpx;
font-weight: normal;
color: #1b2026;
}
}
// 筛选条
.select-nav {
position: sticky;
z-index: 30;
display: flex;
align-items: center;
justify-content: space-between;
height: 80rpx;
padding: 0 32rpx;
background-color: #ffffff;
.recommend {
position: relative;
font-size: 36rpx;
font-weight: bold;
color: #1b2026;
letter-spacing: 0;
&::after {
position: absolute;
right: -8rpx;
bottom: 4rpx;
z-index: -1;
display: block;
width: 36px;
height: 16rpx;
content: "";
background: linear-gradient(90deg, rgb(241 246 251 / 0%) 0%, #76a5ff 100%);
}
}
.select-item {
margin-right: 8rpx;
text {
position: relative;
padding: 2rpx 20rpx 2rpx 12rpx;
margin-left: 24rpx;
font-size: 24rpx;
line-height: 24rpx;
color: #1b2026;
background-color: #ffffff;
&::after {
position: absolute;
right: 12rpx;
bottom: 6rpx;
display: block;
width: 0;
height: 0;
content: "";
border: 4rpx solid #1b2026;
border-top-color: transparent;
border-left-color: transparent;
}
&.active {
color: #ffffff;
background: linear-gradient(180deg, #3570ff -3%, #29a5ff 100%);
border-radius: 8rpx;
&::after {
border: 4rpx solid #ffffff;
border-top-color: transparent;
border-left-color: transparent;
}
}
}
}
}
// 筛选弹框
.pop-mask {
position: fixed;
inset: 0;
z-index: 20;
background-color: #00000066;
.address {
.region-pop-content {
text-align: center;
background-color: #ffffff;
.region-pop-left {
width: 375rpx;
padding: 0;
.region-list {
width: 375rpx;
padding: 0;
border: 0;
}
.region-list-color {
background-color: #f3f4f8;
}
}
.region-pop-right {
width: 375rpx;
padding: 0;
.region-list {
background-color: #f3f4f8;
border: 0;
}
}
}
}
.position,
.other {
.screen-pop-box {
background-color: #ffffff;
.screen-pop-title {
font-size: 28rpx;
font-weight: 600;
color: #1b2026;
}
.label-list-color {
font-weight: 600;
color: #1f86ff;
background-color: rgb(31 134 255 / 10%);
border-color: transparent;
}
}
}
}
// 工作列表
.content {
min-height: 100vh;
.position-content {
padding: 0;
background: #f6f7f8;
.recommend-list {
position: relative;
padding: 32rpx 32rpx 0;
margin-bottom: 20rpx;
background-color: #ffffff;
border: 0;
}
.item {
padding: 32rpx;
background-color: #ffffff;
border-bottom: 16rpx solid #f3f4f8;
}
}
}
/* nav全职兼职推荐 */
.nav {
/* height: 100rpx; */
box-sizing: border-box;
width: 100%;
padding: 28rpx 40rpx;
padding-bottom: 0;
background: #ffffff;
}
.nav .nav-list {
display: inline-block;
margin-right: 40rpx;
}
.nav .nav-list .nav-list-title {
font-size: 32rpx;
font-weight: 400;
line-height: 44rpx;
color: rgb(128 128 128 / 100%);
transition: 0.3s ease all;
}
.nav .nav-list .nav-active {
font-size: 36rpx;
font-weight: 600;
color: rgb(58 58 60 / 100%);
}
.nav .nav-list .nav-list-before {
width: 60rpx;
height: 8rpx;
margin: 0 auto;
margin-top: 4rpx;
background: rgb(24 146 255 / 100%);
border-radius: 4rpx;
opacity: 0;
transition: 0.3s ease all;
}
.nav .nav-list .before-active {
opacity: 1;
}
/* 筛选导航 */
.nav-screen {
background: #ffffff;
border-bottom: 1px solid rgb(238 239 238 / 100%);
}
/* 职位筛选弹窗 */
.nav-screen .screen-pop-mask {
position: fixed;
inset: 0;
z-index: 10;
background: rgb(0 0 0 / 40%);
transition: 0.3s ease all;
}
.nav-screen .screen-pop {
position: absolute;
/* top: 326rpx; */
top: 230rpx;
left: -1000rpx;
z-index: 20;
width: 100%;
max-height: 652rpx;
padding-left: 40rpx;
overflow-y: auto;
background: #ffffff;
transition: 0.3s ease all;
}
.nav-screen .screen-pop-tion {
left: 0;
}
.nav-screen .screen-pop-list {
font-size: 28rpx;
line-height: 80rpx;
color: #3a3a3c;
background: #ffffff;
border-top: 1px solid #e9e9e9;
}
.nav-screen .screen-pop-list:nth-child(1) {
border: none;
}
/* nav */
.nav-screen-position .nav-screen-child text {
font-size: 32rpx;
font-weight: 500;
line-height: 44rpx;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.nav-screen-position .nav-screen-child .icon {
width: 18rpx;
height: 10rpx;
margin-left: 16rpx;
vertical-align: middle;
transition: 0.3s ease all;
}
.nav-screen-position .nav-screen-child .icon-tion {
transform: rotate(180deg);
}
.nav-screen-list {
display: flex;
/* position: absolute; */
/* top: 94rpx; */
padding: 28rpx 40rpx;
overflow: hidden;
background: #ffffff;
/* z-index: 20; */
}
.nav-screen-list .nav-screen-child {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
width: 200rpx;
height: 56rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
background: rgb(245 245 245 / 100%);
border: 2rpx solid rgb(0 0 0 / 0%);
border-radius: 4rpx;
}
.nav-screen-list .nav-screen-color {
color: #1892ff;
background: rgb(245 245 245 / 0%);
border: 2rpx solid #1892ff;
}
.nav-screen-list .nav-screen-child:nth-child(2) {
margin: 0 34rpx;
}
.nav-screen-list .nav-screen-child text {
overflow: hidden;
font-size: 24rpx;
font-weight: 400;
line-height: 34rpx;
text-overflow: ellipsis;
white-space: nowrap;
}
.nav-screen-list .nav-screen-child .icon {
width: 18rpx;
height: 10rpx;
margin-left: 6rpx;
vertical-align: middle;
transition: 0.3s ease all;
}
.nav-screen-list .nav-screen-child .icon-tion {
transform: rotate(180deg);
}
/* 职位列表 */
.position-content {
padding: 28rpx 32rpx;
padding-bottom: 0rpx;
background: #ffffff;
}
.position-content .recommend-list {
margin-bottom: 28rpx;
border-bottom: 2rpx solid rgb(238 239 238 / 100%);
}
.position-content .recommend-list .recommend-title {
margin-bottom: 14rpx;
overflow: hidden;
}
.recommend-list .recommend-title .sign {
width: auto;
height: 28rpx;
padding: 0 10rpx;
margin-right: 12rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 25rpx;
color: rgb(250 122 96 / 100%);
text-align: center;
vertical-align: middle;
background: rgb(252 229 229 / 100%);
border-radius: 4rpx;
}
.recommend-list .recommend-title .title {
font-size: 32rpx;
font-weight: 500;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.recommend-list .salary-info {
margin-bottom: 28rpx;
overflow: hidden;
}
.recommend-list .salary-info .salary {
font-size: 28rpx;
font-weight: 600;
color: rgb(255 89 55 / 100%);
vertical-align: middle;
}
.recommend-list .salary-info .deliveryBtn {
float: right;
}
.recommend-list .cos-details {
display: flex;
margin-bottom: 18rpx;
}
.recommend-list .cos-details .cos-requirement {
flex: 1;
}
.recommend-list .cos-details .cos-requirement .cos-title {
margin-bottom: 20rpx;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-name {
display: inline-block;
max-width: 260rpx;
height: 32rpx;
overflow: hidden;
font-weight: 400;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-name-width {
max-width: 500rpx;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-recommend {
display: inline-block;
height: 36rpx;
padding: 0 4rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 36rpx;
color: rgb(155 1 1 / 100%);
vertical-align: middle;
background: rgb(255 233 237 / 100%);
border-radius: 4rpx;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.recommend-list .cos-details .cos-requirement .cos-title image {
display: inline-block;
width: 36rpx;
height: 36rpx;
vertical-align: middle;
background-color: rgb(255 233 237 / 100%);
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
}
.recommend-list .cos-details .cos-ask {
margin-bottom: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
}
.recommend-list .cos-details .margin-none {
margin-bottom: 0;
}
.recommend-list .cos-details .cos-welfare {
width: 100%;
max-height: 50rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.recommend-list .cos-details .cos-welfare .welfare-list {
float: left;
width: auto;
height: 40rpx;
padding: 0 10rpx;
margin: 0 12rpx 10rpx 0;
font-size: 24rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
border: 2rpx solid rgb(186 186 186 / 100%);
border-radius: 4rpx;
}
.recommend-list .cos-details .cos-video {
position: relative;
width: 160rpx;
height: 120rpx;
overflow: hidden;
}
.recommend-list .cos-details .recommend-video {
width: 100%;
height: 100%;
}
.cos-play-icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 64rpx;
height: 64rpx;
transform: translate(-50%, -50%);
}
/* 筛选弹窗 */
.nav-screen .screen-pop-padding {
padding-left: 0;
}
.screen-pop-box {
position: relative;
width: 100%;
height: 652rpx;
}
.screen-pop-content {
position: absolute;
inset: 0 0 0rpx;
padding: 0 40rpx;
overflow: hidden;
}
.screen-pop-padding {
padding: 0;
}
.screen-pop-padding40 {
box-sizing: border-box;
padding-left: 40rpx;
}
::-webkit-scrollbar {
width: 0;
height: 0;
color: rgb(0 0 0 / 0%);
}
.screen-pop-content .screen-pop-title {
margin-top: 28rpx;
margin-bottom: 16rpx;
font-size: 28rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(58 58 60 / 100%);
}
.screen-pop-content .screen-pop-title text {
color: #1892ff;
}
.screen-pop-content .pop-title-label {
overflow: hidden;
}
.screen-pop-content .pop-padding {
padding: 0 12rpx;
}
.screen-pop-content .label-list {
float: left;
padding: 12rpx 32rpx;
margin: 12rpx 0;
margin-right: 20rpx;
font-size: 28rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
border: 1px solid rgb(186 186 186 / 100%);
border-radius: 8rpx;
}
.screen-pop-content .label-list-color {
color: #1892ff;
border-color: #1892ff;
}
.pop-bottom {
position: absolute;
right: 0;
bottom: 0;
left: 0;
padding: 28rpx 32rpx;
overflow: hidden;
background: #ffffff;
border-top: 1px solid rgb(238 239 238 / 100%);
}
.pop-bottom .pop-btn {
float: right;
width: 132rpx;
height: 64rpx;
margin-left: 28rpx;
font-size: 28rpx;
font-weight: 400;
line-height: 64rpx;
color: rgb(58 58 60 / 100%);
text-align: center;
border: 1px solid rgb(186 186 186 / 100%);
border-radius: 8rpx;
}
.pop-bottom .pop-btn:nth-child(2) {
color: #ffffff;
background: rgb(24 146 255 / 100%);
border-color: rgb(24 146 255 / 100%);
}
/* 区域弹窗 */
.region-pop-content {
position: relative;
width: 100%;
height: 652rpx;
}
.region-pop-content .region-pop-left {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 40%;
overflow: hidden;
background: #ffffff;
}
.region-pop-content .region-pop-right {
position: absolute;
top: 0;
right: 0;
bottom: 0;
box-sizing: border-box;
width: 60%;
padding-left: 32rpx;
overflow: hidden;
background: #f7f7f7;
}
.region-pop-content .region-list {
font-size: 28rpx;
line-height: 80rpx;
color: #3a3a3c;
background: #f7f7f7;
border-top: 1px solid #e9e9e9;
}
.region-pop-content .region-pop-left .region-list {
padding-left: 32rpx;
background: #ffffff;
}
.screen-pop .region-list-color {
color: #1892ff;
}
.region-pop-content .region-list:nth-child(1) {
border: none;
}
.range-slider-block {
position: relative;
width: 50rpx;
height: 50rpx;
text-align: center;
background-color: white;
border-radius: 50%;
box-shadow: 0 0 5px #888888;
}
.range-slider-block .range-slider-icon {
position: absolute;
top: 50%;
left: 50%;
display: inline-block;
width: 16rpx;
height: 16rpx;
line-height: 50rpx;
background: #1892ff;
border-radius: 50%;
transform: translate(-50%, -50%);
}
.range-slider-value {
width: 54rpx;
font-size: 24rpx;
font-weight: 400;
line-height: 34rpx;
color: rgb(128 128 128 / 100%);
}
/* 暂无职位推荐 */
.nothing {
/* position: absolute; */
/* top: 60%; */
width: 100%;
margin-top: 150rpx;
/* z-index: 3; */
/* transform: translateY(-50%); */
background: #ffffff;
}
.nothing .nothing-back {
display: block;
width: 406rpx;
height: 256rpx;
margin: 0 auto;
margin-bottom: 28rpx;
/* margin-top: 428rpx; */
}
.nothing .nothing-text {
margin-bottom: 80rpx;
font-size: 28rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
}
.nothing .nothing-btn {
box-sizing: border-box;
display: flex;
width: 220rpx;
height: 68rpx;
margin: 0 auto;
border: 1px solid rgb(24 146 255 / 100%);
border-radius: 8rpx;
}
.nothing .nothing-btn image {
width: 40rpx;
height: 40rpx;
margin: 14rpx 10rpx 14rpx 26rpx;
}
.nothing .nothing-btn text {
display: inline-block;
flex: 1;
font-size: 28rpx;
font-weight: 400;
line-height: 68rpx;
color: rgb(24 146 255 / 100%);
vertical-align: middle;
}
.margin-8 {
margin: 0 8rpx;
}
</style> </style>
<template>
<div class="page">
<view class="search-form">
<image class="search-icon" src="@/static/image/icon/search.png"></image>
<input placeholder="请输入要查询的内容" placeholder-class="log-input-p" type="text" />
</view>
<view class="list">
<view class="item flex-between" v-for="v in platformList" :key="v.id">
<view class="com flex-align-center">
<image :src="evn.APP_IMAGE_BASE_API + v.logo" />
<view class="text">
<view class="title">{{ v.name }}</view>
<view class="describe">点击跳转平台</view>
</view>
</view>
<view class="arrow"></view>
</view>
</view>
</div>
</template>
<script setup>
import { getPlatformPageList } from "@/api/postion.js";
import { reactive } from "vue";
import evn from "@/utils/config.js";
let type = 1;
let pageNo = 1;
const platformList = reactive([]);
const getData = () => {
getPlatformPageList({
type,
pageSize: 10,
pageNo: pageNo++
}).then(res => {
console.log(res);
platformList.push(...res.data);
});
};
onLoad(opstion => {
console.log(opstion);
if (opstion.type == "零工专区") {
type = 1;
} else {
type = 2;
}
uni.setNavigationBarTitle({
title: opstion.type
});
getData();
});
</script>
<style lang="scss" scoped>
.page {
background-color: #ffffff;
}
.search-form {
position: relative;
box-sizing: content-box;
width: 686rpx;
height: 72rpx;
padding-top: 27rpx;
margin: 0 32rpx;
overflow: hidden;
border-top: 1px solid #f3f4f8;
// background: rgba(245, 245, 245, 1);
border-radius: 2px;
.search-icon {
position: absolute;
top: 46rpx;
left: 42rpx;
z-index: 10;
width: 28rpx;
height: 28rpx;
}
input {
// background-color: #F7F7F7;
position: absolute;
right: 0rpx;
left: 0rpx;
z-index: 9;
box-sizing: border-box;
width: 100%;
width: auto;
height: 72rpx;
padding: 0 88rpx;
background-color: #f2f3f5;
}
}
.list {
padding: 0 32rpx;
margin-top: 6rpx;
.item {
padding: 30rpx 0;
border-bottom: 2rpx solid #f3f4f8;
}
.com {
color: #1b2026;
image {
width: 80rpx;
height: 80rpx;
margin-right: 24rpx;
border-radius: 50%;
}
.title {
font-size: 28rpx;
font-weight: 600;
}
.describe {
font-size: 24rpx;
}
}
}
</style>
<template>
<div class="postion-details">
<!--pages/position-details/position-details.wxml-->
<view class="steps-wrap">
<steps v-if="partTimeJobData.jobApplication" :data="partTimeJobData.jobApplication"></steps>
</view>
<!-- 职位详情 -->
<view class="pos-details">
<view class="pos-title">
<text class="text">{{ partTimeJobData.jobName }}</text>
</view>
<view class="salary-wrap">
<view v-if="partTimeJobData">
<view class="salary" v-if="partTimeJobData.isPartTimeJob == 1">
<text class="number">{{ partTimeJobData.maxSalary }}</text>
<text class="unit">元/{{ partTimeJobData.paymentType }}</text>
</view>
<view class="salary" v-else>
<text class="number"
>{{ partTimeJobData.minSalary / 1000 }}k-{{ partTimeJobData.maxSalary / 1000 }}k</text
>
<text class="unit">/月</text>
</view>
</view>
<view v-if="partTimeJobData.isSalaryNego == 1">
<view class="salary">
<text class="number">面议</text>
</view>
</view>
</view>
<!-- 经验 -->
<view class="experience-and-education flex-align-center">
<view class="flex-align-center">
<img src="@/static/image/postion/experience.png" alt="" />
<text>1-3年</text>
</view>
<view class="flex-align-center">
<img src="@/static/image/postion/education.png" alt="" />
<text>学历不限</text>
</view>
</view>
<view class="pos-type flex-between">
<view class="flex-align-center position">
<img src="@/static/image/postion/position.png" alt="" />
<text>{{ partTimeJobData.cityName }}·{{ partTimeJobData.districtName }}</text>
</view>
<view class="type">
<text v-if="partTimeJobData.isPartTimeJob == 1">兼职</text>
<text v-else>全职</text>
<text class="margin-8">|</text>
<text>{{ partTimeJobData.jobTypeText }}</text>
</view>
</view>
<view class="cos-welfare" v-if="partTimeJobData.welfareTags">
<view class="welfare-list" v-for="(wel, i) in partTimeJobData.welfareTags" :key="i">{{ wel }}</view>
</view>
</view>
<!-- 职位介绍 -->
<view class="pos-introduce margin-top24">
<view class="title">
<text class="gradient-title">职位详情</text>
</view>
<view class="pos-int">
<!-- <text class="pos-label pos-age">
<block wx:if="{{partTimeJobData.minAge}}">{{partTimeJobData.minAge}}-{{partTimeJobData.maxAge}}</block>
<block wx:else>年龄不限</block>
</text> -->
<text class="pos-label" v-for="(item, index) in partTimeJobData.benefitsList" :key="index">{{ item }}</text>
</view>
<view class="pos-duty {{dutyFlag ? 'activeClass' : ''}}">{{ partTimeJobData.jobDesc }}</view>
<view
class="duty-more"
bindtap="moreClick"
:style="{ display: dutyFlag ? 'none' : '' }"
v-if="partTimeJobData.content?.length > 150"
>
<text>查看全部</text>
</view>
</view>
<!-- 公司信息 -->
<view class="cos-info margin-top24">
<view
class="flex-align-center"
@click="navigateTo(`/pages/postionList/companyDetails/index?id=${partTimeJobData.company.id}`)"
data-id="{{partTimeJobData.company.id}}"
bindtap="bindNavCompany"
>
<view class="cosimage">
<img src="@/static/image/temp/test.jpg" />
</view>
<view>
<view class="cos-title">
<text class="cos-name" v-if="partTimeJobData.company?.name != undefined">{{
partTimeJobData.company?.name
}}</text>
<!-- <image
wx:if="{{partTimeJobData.permRecommendType}}"
class="label-icon"
src="../../imgs/icon/sign.png"
></image> -->
<text v-if="partTimeJobData.permRecommendType" class="label-name"
><text v-if="EnumRecommendType">{{ EnumRecommendType[1].text }}</text></text
>
</view>
<view class="cos-position">
<text>{{ partTimeJobData.company?.placeCityName }}</text>
<text>{{ partTimeJobData.countRecruiting | 0 }} <text class="margin-8">|</text>个在招职位</text>
</view>
<!-- <img class="modu-icon" src="@/static/image/temp/test.jpg" /> -->
<view class="arrow modu-icon"></view>
</view>
</view>
<view class="map">
<map id="mapId" class="map" :latitude="mapCenter.latitude" :longitude="mapCenter.longitude" :markers="markers">
</map>
</view>
</view>
<!-- 职位推荐 -->
<view class="pos-recommend margin-top24">
<view class="title">
<text class="gradient-title">优选职位</text>
</view>
<!-- 职位列表 -->
<view
class="recommend-list"
v-for="(item, index) in recommendList"
:key="index"
data-id="{{item.id}}"
bindtap="bindNavigateTo"
>
<view class="cos-details">
<view class="cos-requirement">
<view class="recommend-title">
<text class="sign" v-if="item.permEmergencyType">急聘</text>
<text class="title">{{ item.title }}</text>
</view>
<view class="cos-welfare">
<view class="welfare-list" v-if="item.eduDegreeType != null">
<block v-if="item.eduDegreeType == '不限'">学历{{ item.eduDegreeType }}</block>
<block v-else>{{ item.eduDegreeType }}</block>
</view>
<view class="welfare-list" v-if="item.workAge != null">{{ item.workAge }}</view>
<view class="welfare-list" v-if="item.welfareTags" v-for="(wel, i) in item.welfareTags" :key="i">{{
wel
}}</view>
</view>
<view class="cos-title">
<text class="cos-name cos-name-width" v-if="item.company.name != undefined">{{
item.company.name
}}</text>
<text class="address"> {{ item.cityName }}-{{ item.districtName }} </text>
</view>
</view>
</view>
<view class="salary-info">
<text class="salary" v-if="item.isSalaryNego == 0"
>{{ item.minSalary }}-{{ item.maxSalary }}/<text style="font-weight: normal"></text>
</text>
<text class="salary" v-if="item.isSalaryNego == 1" style="font-weight: normal">面议</text>
</view>
</view>
</view>
<!-- 聊工作/投简历Btn -->
<view class="btn" v-if="!partTimeJobData.jobApplication">
<view class="btn-list back-color" v-if="!partTimeJobData.isRegister" @tap="bindDelivery">投简历</view>
</view>
<!-- 提示 -->
<view class="warn-wrap">
<view class="warn">
<view class="title flex-align-center">
<!-- <image src="{{ossImgPrefix}}/warn.png" /> -->
乐业安全提示
</view>
<view class="content">
未标明收费的职位不会收取任何费用,若商家要求缴纳费用或押金,<text>请一定提高警惕并第一时间向我们举报!</text>
</view>
</view>
</view>
</div>
</template>
<script setup>
import steps from "@/components/steps/index.vue";
import { ref, reactive } from "vue";
import dayjs from "dayjs";
import { getJobDetailApi, submitResumeApi } from "@/api/postion";
const partTimeJobData = ref({});
const recommendList = ref([]);
const stepViewData = ref(null);
const mapCenter = reactive({
latitude: 26.63,
longitude: 106.67
});
let id = null;
const markers = reactive([
{
id: 1,
latitude: 26.63,
longitude: 106.67,
width: 16,
height: 20,
iconPath: new URL("@/static/image/icon/markers.png", import.meta.url).href,
callout: {
content: "观山湖区高新区产业技术发展研究院",
borderRadius: 2,
padding: 7,
display: "ALWAYS",
textAlign: "center",
bgColor: "#fff",
color: "#000"
}
}
]);
const getJobDetail = id => {
getJobDetailApi(id).then(({ data }) => {
data.id = id;
partTimeJobData.value = data;
// 设置地图点
markers[0].latitude = data.locationLatitude;
markers[0].longitude = data.locationLongitude;
markers[0].callout.content = data.address;
mapCenter.latitude = data.locationLatitude;
mapCenter.longitude = data.locationLongitude;
});
};
/* 投递简历 */
const bindDelivery = () => {
submitResumeApi(partTimeJobData.value.id).then(res => {
if (res.code === 200) {
uni.showToast({
title: "投递成功",
icon: "none"
});
partTimeJobData.value.jobApplication = res.data;
}
});
};
const navigateTo = url => {
uni.navigateTo({
url
});
};
onLoad(({ id }) => {
getJobDetail(id);
});
</script>
<style lang="scss" scoped>
/* pages/position-details/position-details.wxss */
/* // 视频 */
.video-box {
position: relative;
width: 100%;
height: 430rpx;
}
.video-box .recommend-video {
width: 100%;
height: 100%;
}
.video-box .cos-play-icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 92rpx;
height: 92rpx;
transform: translate(-50%, -50%);
}
/* // 职位详情 */
.pos-details .pos-title .label {
width: auto;
height: 36rpx;
padding: 0 8rpx;
margin-right: 16rpx;
font-size: 24rpx;
font-weight: 400;
line-height: 36rpx;
color: rgb(250 122 96 / 100%);
text-align: center;
vertical-align: middle;
background: rgb(252 229 229 / 100%);
border-radius: 4rpx;
}
.pos-details .time {
margin-bottom: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(58 58 60 / 100%);
}
.pos-details .time text {
margin-right: 12rpx;
margin-bottom: 8rpx;
}
.pos-details .pos-label {
margin-bottom: 24rpx;
}
.pos-details .pos-label .label-list {
display: inline-block;
width: auto;
height: 40rpx;
padding: 0 16rpx;
font-size: 24rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
text-align: center;
border: 2rpx solid rgb(186 186 186 / 100%);
border-radius: 2rpx;
}
.pos-details .pos-address {
position: relative;
padding: 24rpx 0;
padding-top: 14rpx;
border-top: 2rpx solid rgb(238 239 238 / 100%);
}
.pos-details .pos-address .sid {
display: inline-block;
width: 28rpx;
height: 32rpx;
margin-right: 12rpx;
vertical-align: middle;
}
.pos-details .pos-address text {
font-size: 24rpx;
font-weight: 400;
color: rgb(58 58 60 / 100%);
vertical-align: middle;
}
.pos-details .pos-address .modu-icon {
position: absolute;
top: 50%;
right: 0;
width: 12rpx;
height: 20rpx;
}
.pos-details .cos-welfare {
width: 100%;
max-height: 50rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// .pos-details .cos-welfare .welfare-list {
// float: left;
// width: auto;
// height: 40rpx;
// line-height: 40rpx;
// border-radius: 4rpx;
// text-align: center;
// padding: 0 10rpx;
// font-size: 24rpx;
// font-weight: 400;
// color: rgba(128, 128, 128, 1);
// margin: 0 12rpx 10rpx 0;
// }
/* // 公司信息 */
.cos-info .cos-title {
margin-bottom: 16rpx;
}
.cos-info .cos-title .cos-name {
display: inline-block;
max-width: 400rpx;
margin-right: 12rpx;
overflow: hidden;
font-size: 28rpx;
font-weight: 600;
color: rgb(58 58 60 / 100%);
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.cos-info .cos-title .label-icon {
width: 36rpx;
height: 36rpx;
vertical-align: middle;
background-color: rgb(255 233 237 / 100%);
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
}
.cos-info .cos-title .label-name {
display: inline-block;
height: 36rpx;
padding: 0 4rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 36rpx;
color: rgb(155 1 1 / 100%);
vertical-align: middle;
background: rgb(255 233 237 / 100%);
border-radius: 4rpx;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.cos-info .cos-position {
font-size: 24rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
}
.cos-info .modu-icon {
position: absolute;
top: 35%;
right: 32rpx;
}
/* // 职位介绍 */
.pos-introduce .title .sign {
display: inline-block;
width: 12rpx;
height: 12rpx;
margin-right: 16rpx;
vertical-align: middle;
background: rgb(26 138 250 / 100%);
border-radius: 50%;
}
.pos-introduce .activeClass {
margin-bottom: 0;
-webkit-line-clamp: inherit;
}
.pos-introduce .duty-more {
position: absolute;
right: 0;
bottom: 28rpx;
left: 0;
padding-top: 22rpx;
text-align: center;
background: linear-gradient(to top, rgb(255 255 255 / 100%), rgb(255 255 255 / 80%), rgb(255 255 255 / 70%));
}
.pos-introduce .duty-more text {
margin-right: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(24 146 255 / 100%);
vertical-align: middle;
}
.pos-introduce .duty-more img {
display: inline-block;
width: 20rpx;
height: 12rpx;
vertical-align: middle;
}
/* // 提示 */
/* .warn {
padding: 28rpx 32rpx;
background: #fff;
display: flex;
}
.warn image {
display: inline-block;
width: 60rpx;
height: 56rpx;
margin-right: 16rpx;
margin-top: 4rpx;
}
.warn text {
flex: 1;
font-size: 24rpx;
font-weight: 400;
color: rgba(245, 166, 35, 1);
} */
/* // 职位推荐 */
.pos-recommend {
padding: 28rpx 32rpx;
background: #ffffff;
}
/* // .pos-recommend .title{} */
.pos-recommend .title .sign {
display: inline-block;
width: 12rpx;
height: 12rpx;
margin-right: 16rpx;
vertical-align: middle;
background: rgb(26 138 250 / 100%);
border-radius: 50%;
}
.pos-recommend .title .text {
font-size: 32rpx;
font-weight: 500;
color: rgb(51 51 51 / 100%);
vertical-align: middle;
}
.pos-recommend .recommend-list {
padding-top: 28rpx;
border-bottom: 2rpx solid rgb(238 239 238 / 100%);
}
.pos-recommend .recommend-list .recommend-title {
margin-bottom: 16rpx;
overflow: hidden;
}
.recommend-list .recommend-title .sign {
width: auto;
height: 28rpx;
padding: 0 10rpx;
margin-right: 12rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 25rpx;
color: rgb(250 122 96 / 100%);
text-align: center;
vertical-align: middle;
background: rgb(252 229 229 / 100%);
border-radius: 4rpx;
}
.recommend-list .recommend-title .salary {
float: right;
margin-top: 12rpx;
font-size: 28rpx;
font-weight: 600;
color: rgb(255 89 55 / 100%);
}
.recommend-list .cos-details {
display: flex;
}
.recommend-list .cos-details .cos-requirement {
flex: 1;
}
.recommend-list .cos-details .cos-requirement .cos-title {
margin-bottom: 16rpx;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-name {
display: inline-block;
max-width: 260rpx;
height: 32rpx;
margin-right: 8rpx;
overflow: hidden;
font-size: 24rpx;
font-weight: 400;
color: rgb(58 58 60 / 100%);
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-name-width {
max-width: 500rpx;
}
.recommend-list .cos-details .cos-requirement .cos-title .cos-recommend {
display: inline-block;
height: 36rpx;
padding: 0 4rpx;
font-size: 20rpx;
font-weight: 400;
line-height: 36rpx;
color: rgb(155 1 1 / 100%);
vertical-align: middle;
background: rgb(255 233 237 / 100%);
border-radius: 4rpx;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.recommend-list .cos-details .cos-requirement .cos-title img {
display: inline-block;
width: 36rpx;
height: 36rpx;
vertical-align: middle;
background-color: rgb(255 233 237 / 100%);
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
}
.recommend-list .cos-details .cos-ask {
margin-bottom: 16rpx;
font-size: 24rpx;
font-weight: 400;
color: rgb(128 128 128 / 100%);
}
.recommend-list .cos-details .cos-welfare {
overflow: hidden;
}
.recommend-list .cos-details .cos-welfare .welfare-list {
float: left;
width: auto;
height: 40rpx;
padding: 0 10rpx;
// color: rgba(128, 128, 128, 1);
margin: 0 12rpx 12rpx 0;
font-size: 24rpx;
font-weight: 400;
line-height: 40rpx;
text-align: center;
border-radius: 4rpx;
}
.recommend-list .cos-details .cos-video {
position: relative;
width: 160rpx;
height: 120rpx;
overflow: hidden;
}
.recommend-list .cos-details .recommend-video {
width: 100%;
height: 100%;
}
.recommend-list .salary-info .deliveryBtn {
float: right;
}
.cos-play-icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 64rpx;
height: 64rpx;
transform: translate(-50%, -50%);
}
.postion-details {
padding-top: 1rpx;
background-color: #f3f4f8;
}
.steps-wrap {
display: flex;
align-items: center;
justify-content: center;
padding: 16px 0;
background: #ffffff;
.steps {
width: 686rpx;
height: 204rpx;
// padding: 0 32rpx;
box-shadow: 0 10rpx 29.2rpx rgb(181 208 240 / 32%);
}
}
/* // 底部按钮 */
.btn .btn-share {
width: 220rpx;
text-align: center;
}
.btn .btn-chat {
flex: 1;
font-size: 32rpx;
font-weight: 400;
color: rgb(24 146 255 / 100%);
text-align: center;
}
.btn .btn-share img {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.btn .share-btn {
display: inline-block;
width: 100%;
padding: 0;
margin: 0;
font-size: 32rpx;
font-weight: 400;
color: rgb(24 146 255 / 100%);
vertical-align: middle;
background: rgb(0 0 0 / 0%);
border: none;
}
.btn .share-btn::after {
border: none;
}
.margin-top24 {
margin-top: 24rpx;
}
.margin-8 {
margin: 0 8rpx;
}
.pos-details {
position: relative;
padding: 32rpx;
padding-top: 0;
background: #ffffff;
img {
width: 32rpx;
height: 32rpx;
}
.pos-title {
padding-top: 32rpx;
margin-bottom: 16rpx;
border-top: 2rpx solid #f3f4f8;
.text {
font-size: 32rpx;
font-weight: 600;
color: #1b2026;
}
}
.experience-and-education {
view {
margin-right: 28rpx;
}
text {
font-size: 24rpx;
color: #4e5969;
}
}
.pos-type {
margin-top: 22rpx;
.position {
text {
font-size: 12px;
line-height: 12px;
color: #1b2026;
}
}
.type {
font-size: 24rpx;
color: #1b2026;
}
}
.salary-wrap {
position: absolute;
top: 32rpx;
right: 32rpx;
.salary {
font-family: DIN;
font-size: 36rpx;
font-weight: 600;
color: #1f86ff;
}
.unit {
font-size: 28rpx;
}
}
}
.pos-introduce {
position: relative;
padding: 28rpx 32rpx;
background: #ffffff;
.title {
margin-bottom: 20rpx;
.text {
font-family: "PingFang SC";
font-size: 32rpx;
font-weight: 600;
line-height: 36rpx;
color: rgb(51 51 51 / 100%);
color: #1b2026;
letter-spacing: 0rpx;
vertical-align: middle;
}
}
.pos-int {
margin-bottom: 16rpx;
.pos-label {
display: inline-block;
width: auto;
height: 40rpx;
padding: 0 10rpx;
margin-right: 12rpx;
font-family: "PingFang SC";
font-size: 20rpx;
font-weight: 400;
line-height: 40rpx;
color: rgb(128 128 128 / 100%);
color: #4e5969;
background: #f2f3f5;
border: 2rpx solid rgb(186 186 186 / 100%);
border: 0;
border-radius: 4rpx;
}
}
.pos-duty {
display: -webkit-box;
margin-bottom: 36rpx;
overflow: hidden;
font-size: 28rpx;
font-weight: 400;
font-weight: normal;
line-height: 36rpx;
color: rgb(128 128 128 / 100%);
color: #1b2026;
letter-spacing: 0;
word-break: break-all;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
}
}
.cos-info {
position: relative;
padding: 28rpx 32rpx;
background: #ffffff;
.flex-align-center {
position: relative;
.cosimage {
img {
width: 88rpx;
height: 88rpx;
margin-right: 26rpx;
border-radius: 50%;
}
}
.cos-title {
margin: 0;
}
}
.map {
margin-top: 32rpx;
map {
width: 686rpx;
height: 330rpx;
}
}
}
.recommend-list {
position: relative;
background-color: #ffffff;
border: 0;
.recommend-title {
margin-bottom: 24rpx;
.title {
font-size: 32rpx;
font-weight: 600;
color: rgb(58 58 60 / 100%);
color: #1b2026;
vertical-align: middle;
}
}
.cos-welfare {
.welfare-list {
color: #4e5969;
background: #f2f3f5;
border: 0;
}
}
.cos-title {
display: flex;
align-items: center;
justify-content: space-between;
.cos-name {
font-size: 24rpx;
color: #1b2026;
}
.address {
font-size: 12px;
color: #1b2026;
}
}
.salary-info {
position: absolute;
top: 26rpx;
right: 32rpx;
padding-bottom: 28rpx;
overflow: hidden;
.salary {
font-family: DIN;
font-size: 36rpx;
font-weight: 500;
color: rgb(255 89 55 / 100%);
color: #1f86ff;
vertical-align: middle;
}
}
}
.btn {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
height: 88rpx;
padding: 16rpx 0;
line-height: 88rpx;
background-color: #ffffff;
border: 2rpx solid rgb(233 233 233 / 100%);
.btn-list {
flex: 1;
flex: none;
font-size: 32rpx;
font-weight: 400;
color: #ffffff;
text-align: center;
background-color: #bababa;
}
.back-color {
width: 622rpx;
height: 80rpx;
font-size: 30rpx;
font-weight: 600;
color: #ffffff;
text-align: center;
background: #1f86ff;
border-radius: 6rpx;
}
}
.warn-wrap {
padding: 0 32rpx;
padding-bottom: 130rpx;
background-color: #ffffff;
.warn {
padding: 34rpx;
background: #fff2ed;
img {
width: 25rpx;
height: 28rpx;
margin-right: 14rpx;
}
.title {
font-size: 28rpx;
font-weight: 600;
color: #73331c;
}
.content {
margin-top: 16rpx;
font-size: 22rpx;
font-weight: 600;
line-height: 36rpx;
color: #65301e;
text {
color: #ff662f;
}
}
}
}
</style>
<template>
<div class="trap">
<scroll-view :scroll-y="true" class="content" @scrolltolower="getData()">
<article-list :list="list"></article-list>
</scroll-view>
</div>
</template>
<script setup>
import articleList from "@/components/articleList/index.vue";
import { getArticleListApi, getArticleTypesApi } from "@/api/article.js";
import { reactive, ref } from "vue";
/* const active = ref("");
const typeList = ref([{ id: "", name: "全部" }]);
getArticleTypesApi(2).then(res => {
typeList.value.push(...res.data);
});
const changeType = type => {
active.value = type.id;
pageNo = 1;
list.splice(0, list.length);
flag = false;
getData();
}; */
/* 文章 */
// 判断是否还有数据
let pageNo = 1;
let flag = false;
const list = reactive([]);
const getData = () => {
if (flag) {
return;
}
getArticleListApi({
type: 4,
categoryId: "",
pageNo: pageNo++,
pageSize: 10
}).then(res => {
if (res.data.length < 10) {
flag = true;
}
list.push(...res.data);
});
};
getData();
// changeType({ id: "" });
</script>
<style lang="scss" scoped>
.trap {
display: flex;
flex-direction: column;
height: 100%;
}
.tab-name {
display: flex;
width: 100%;
height: 80rpx;
overflow-x: auto;
white-space: nowrap;
.item {
padding: 22rpx 24rpx;
font-size: 28rpx;
&.active {
background-image: url("https://lygsh-image.wjzpgz.com/icon/arc.png");
background-repeat: no-repeat;
background-position: 50% 100%;
background-size: 35.64rpx 11.24rpx;
}
}
}
.content {
flex-grow: 1;
height: 200rpx;
}
</style>
<template>
<div class="page">
<!-- <view v-if="v.status == 2" class="state success"> 待面试 </view>
<view v-if="v.status == 4" class="state warning"> 已拒绝 </view> -->
<view class="card" v-if="postionData.jobApplication.status == 4">
<view class="t1">不合适</view>
<view class="t2">抱歉!经公司慎重考虑,很遗憾你不适合该职位感谢你的投递!</view>
<view class="shadow"></view>
</view>
<view class="card success" v-if="postionData.jobApplication.status == 2">
<view class="t1">面试邀约</view>
<view class="t2">你好,陈春瑞!通过对你的简历了解,希望能和你面谈,特此发送面试邀约</view>
<view class="shadow"></view>
</view>
<view class="pos-card">
<view class="pos-name flex-between">
<text class="name">{{ postionData.jobName }}</text>
<view>{{ postionData.minSalary / 1000 }}k-{{ postionData.maxSalary / 1000 }}k/<text>/月</text></view>
</view>
<view class="com-name">{{ postionData.companyName }}</view>
<view class="tags">
<text class="item" v-for="v in postionData.benefits.split(',')" :key="v">{{ v }}</text>
</view>
</view>
<view class="pos-detail">
{{ jobDesc }}
</view>
<view class="steps-wrap">
<steps :data="postionData.jobApplication"></steps>
</view>
</div>
</template>
<script setup>
import steps from "@/components/steps/index.vue";
import { reactive, ref } from "vue";
import { getJobDetailApi } from "@/api/postion";
const postionData = ref({});
onLoad(({ id }) => {
console.log(id);
getJobDetailApi(id).then(res => {
console.log(res);
postionData.value = res.data;
});
});
</script>
<style lang="scss" scoped>
.page {
box-sizing: border-box;
padding-top: 48rpx;
background-color: #ffffff;
}
.card {
position: relative;
box-sizing: border-box;
width: 686rpx;
height: 236rpx;
padding-top: 32rpx;
margin: 0 auto;
text-align: center;
background: linear-gradient(180deg, #f05a25 0%, #ff0000 100%), linear-gradient(180deg, #f05a25 0%, #ff0000 100%),
linear-gradient(180deg, #f05a25 0%, #ff0000 100%);
border-radius: 12rpx;
.t1 {
font-size: 36rpx;
font-weight: 600;
line-height: 48rpx;
color: #ffffff;
}
.t2 {
margin-top: 20rpx;
font-size: 28rpx;
font-weight: 600;
line-height: 52rpx;
color: #ffffff;
}
.shadow {
position: absolute;
top: 40rpx;
left: 38rpx;
z-index: -1;
width: 592rpx;
height: 200rpx;
background: rgb(200 0 0 / 78%);
filter: blur(36rpx);
border-radius: 12rpx;
opacity: 1;
}
}
.success {
background: linear-gradient(180deg, #1fc9ff 0%, #1f86ff 100%), linear-gradient(180deg, #f05a25 0%, #ff0000 100%),
linear-gradient(180deg, #f05a25 0%, #ff0000 100%);
}
.pos-card {
padding: 0 32rpx;
margin-top: 60rpx;
.pos-name {
.name {
font-size: 32rpx;
font-weight: 600;
line-height: 36rpx;
color: #1b2026;
}
view {
font-family: DIN;
font-size: 36rpx;
font-weight: 500;
line-height: 24rpx;
color: #1f86ff;
text {
font-size: 28rpx;
font-weight: normal;
line-height: 24rpx;
color: #1f86ff;
text-align: center;
}
}
}
.com-name {
margin: 16rpx 0;
font-size: 24rpx;
font-weight: normal;
line-height: 36rpx;
color: #1b2026;
}
.tags {
display: flex;
gap: 20rpx;
align-items: center;
.item {
padding: 4rpx 8rpx;
font-size: 20rpx;
font-weight: normal;
line-height: 28rpx;
color: #4e5969;
background: #f2f3f5;
}
}
}
.pos-detail {
padding: 0 32rpx;
margin-top: 64rpx;
font-size: 24rpx;
font-weight: normal;
line-height: 36rpx;
letter-spacing: 0rpx;
}
.steps-wrap {
position: fixed;
bottom: 40rpx;
border-top: 2rpx solid rgb(31 35 41 / 15%);
}
</style>
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
<view class="avatar"> <view class="avatar">
<!-- <image wx:if="{{avatarPath}}" src="{{imgPrefix}}/{{avatarPath}}" mode="" /> <!-- <image wx:if="{{avatarPath}}" src="{{imgPrefix}}/{{avatarPath}}" mode="" />
<image wx:else="" class="userinfo-avatar" src="{{ossImgPrefix}}/user/default-avatar.png"></image> --> <image wx:else="" class="userinfo-avatar" src="{{ossImgPrefix}}/user/default-avatar.png"></image> -->
<img src="@/static/image/user/default-avatar.png" alt="" /> <img v-if="avatarPath" :src="evn.APP_IMAGE_BASE_API + avatarPath" />
<img v-else src="@/static/image/user/default-avatar.png" alt="" />
</view> </view>
<view class="name">{{ realName || "未实名" }}</view> <view class="name">{{ realName || "未实名" }}</view>
<view class="education">{{ schoolName }} | {{ educationLevelText || "无" }}</view> <view class="education">{{ schoolName }} | {{ educationLevelText || "无" }}</view>
...@@ -20,7 +21,7 @@ ...@@ -20,7 +21,7 @@
<view> <view>
<view class="flex-between"> <view class="flex-between">
<text>我的简历</text> <text>我的简历</text>
<button>去完善</button> <button @click="navigateTo('/pages/user/resume/index')">去完善</button>
</view> </view>
<view class="t1">完善简历可获得更多机会哦~</view> <view class="t1">完善简历可获得更多机会哦~</view>
</view> </view>
...@@ -40,30 +41,19 @@ ...@@ -40,30 +41,19 @@
<script setup> <script setup>
import navBar from "@/components/navBar/index.vue"; import navBar from "@/components/navBar/index.vue";
import instance from "@/utils/request.js"; import { getUserResumeApi, getLoginUserApi } from "@/api/user";
import axios from "axios"; import { ref } from "vue";
import { navigateTo, getEnumText } from "@/utils/utils.js";
instance.post("/job/getPageList").then(res => { import evn from "@/utils/config.js";
console.log(res);
});
axios
.post("https://gdlxy-api-test.wjzpgz.com/screen/lab/getLabDeviceState", {
labNum: 250
})
.then(res => {
console.log(res);
});
/* 路由 */
const navList = [ const navList = [
{ {
icon: new URL("@/static/image/user/history.png", import.meta.url).href, icon: new URL("@/static/image/user/history.png", import.meta.url).href,
url: "/subPackages/app/pages/myDelivery/myDelivery?type=我的投递", url: "/pages/user/myDelivery/index?type=我的投递",
text: "我的投递" text: "我的投递"
}, },
{ {
icon: new URL("@/static/image/user/feedback.png", import.meta.url).href, icon: new URL("@/static/image/user/feedback.png", import.meta.url).href,
url: "/subPackages/app/pages/myDelivery/myDelivery?type=我的面试", url: "/pages/user/myDelivery/index?type=我的面试",
text: "我的面试" text: "我的面试"
}, },
{ {
...@@ -77,15 +67,29 @@ const navList = [ ...@@ -77,15 +67,29 @@ const navList = [
text: "退出登录" text: "退出登录"
} }
]; ];
const navigateTo = url => { /* 个人信息 */
uni.navigateTo({ const realName = ref("");
url const avatarPath = ref("");
const schoolName = ref("");
const educationLevelText = ref("");
/* 获取用户信息 */
const getUserInfo = () => {
getLoginUserApi().then(async res => {
const { avatarPath: _avatarPath, realName: _realName, educationLevel } = res.data;
realName.value = _realName;
avatarPath.value = _avatarPath;
/* this.setData({
avatarPath,
realName,
}); */
educationLevelText.value = await getEnumText("EnumEducation", educationLevel);
});
getUserResumeApi().then(res => {
const { educationExperience } = res.data;
schoolName.value = JSON.parse(educationExperience)[0].schoolName;
}); });
}; };
/* 个人信息 */ getUserInfo();
const realName = "";
const schoolName = "";
const educationLevelText = "";
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
<template>
<div class="page">
<view class="item" v-for="v in list" :key="v.id" @click="jumpToDetail(v)">
<view class="name-salary flex-between">
<text class="name">{{ v.jobName }}</text>
<!-- <text class="salary">6k-12k<text>/月</text></text> -->
<text class="salary">{{ v.salary }}</text>
</view>
<view class="com-name">{{ v.companyName }}</view>
<view class="flex-align-center tags">
<text v-for="(benefit, index) in v.benefits.split(',')" :key="index">{{ benefit }}</text>
</view>
<view v-if="v.status == 0" class="state success"> 已投递 </view>
<view v-if="v.status == 1" class="state success"> 已查看 </view>
<view v-if="v.status == 2" class="state success"> 待面试 </view>
<view v-if="v.status == 3" class="state success"> 已面试 </view>
<view v-if="v.status == 4" class="state warning"> 已拒绝 </view>
</view>
</div>
</template>
<script setup>
import { getApplicationListApi, getInterviewListApi } from "@/api/user";
import { reactive } from "vue";
import { getEnumText } from "@/utils/utils.js";
let pageNo = 1;
let type = 1;
const list = reactive([]);
onLoad(e => {
type = e.type;
getList();
});
const jumpToDetail = e => {
uni.navigateTo({
url: "/pages/user/deliveryFeedback/index?id=" + e.jobId
});
};
// "code": "0",
// "text": "已投递",
// "code": "1",
// "text": "已查看",
// "code": "2",
// "text": "待面试",
// "code": "3",
// "text": "已面试",
// "code": "4",
// "text": "已拒绝",
const getList = () => {
let api = type == "我的投递" ? getApplicationListApi : getInterviewListApi;
api({
pageNo: pageNo++,
pageSize: 10
}).then(res => {
list.push(...res.data);
});
};
</script>
<style lang="scss" scoped>
.page {
background-color: #ffffff;
}
.item {
position: relative;
padding: 16px;
border-bottom: 8px solid #f3f4f8;
.name-salary {
.name {
font-size: 16px;
font-weight: 600;
line-height: 18px;
color: #1b2026;
}
.salary {
font-size: 18px;
font-weight: 500;
line-height: 12px;
color: #1f86ff;
text {
font-size: 14px;
font-weight: normal;
line-height: 12px;
}
}
}
.com-name {
margin-top: 8px;
font-size: 12px;
font-weight: normal;
line-height: 18px;
color: #77818f;
}
.tags {
gap: 7px;
margin-top: 10px;
text {
padding: 2px 4px;
font-size: 10px;
color: #4e5969;
background: #f2f3f5;
}
}
.state {
position: absolute;
right: 16px;
bottom: 24px;
padding: 8px 16px;
font-size: 12px;
font-weight: 600;
line-height: 14px;
&.warning {
color: #f53f3f;
background: #ffece8;
}
&.success {
color: #31cbae;
background: rgb(49 203 174 / 10%);
}
}
}
</style>
<template>
<view class="item">
<view class="label">学校名称</view>
<input v-model="params.schoolName" placeholder="请输入用户名" border="{{ false }}" />
</view>
<view class="item">
<view class="label">专业名称</view>
<input v-model="params.major" placeholder="请输入用户名" border="{{ false }}" />
</view>
<view class="item">
<view class="label">开始时间</view>
<wd-datetime-picker
:default-value="new Date().getTime()"
:maxDate="new Date().getTime()"
:minDate="new Date('1960/01/01').getTime()"
type="year-month"
v-model="params.startDate"
use-default-slot
class="my-datetime-picker"
>
<view :class="`inner ${params.startDate ? '' : 'placeholder'}`">
{{ format(params.startDate) || "选择开始时间" }}
</view>
</wd-datetime-picker>
</view>
<view class="item">
<view class="label">结束时间</view>
<wd-datetime-picker
:default-value="new Date().getTime()"
:minDate="params.startDate"
:maxDate="new Date().getTime()"
type="year-month"
v-model="params.endDate"
use-default-slot
class="my-datetime-picker"
>
<view :class="`inner ${params.endDate ? '' : 'placeholder'}`">
{{ format(params.endDate) || "结束时间" }}
</view>
</wd-datetime-picker>
</view>
<view class="btn-wrap">
<button @click="submit">保存</button>
</view>
</template>
<script setup>
import { saveEducationExperienceApi } from "@/api/user";
import dayjs from "dayjs";
import { reactive } from "vue";
const params = reactive({ schoolName: "", startDate: 0, endDate: 0, major: "" });
const format = date => date && dayjs(date).format("YYYY-MM-DD");
const submit = () => {
saveEducationExperienceApi(JSON.stringify([params])).then(res => {
if (res.code === 200) {
uni.showToast({
title: "保存成功",
icon: "none"
});
setTimeout(() => {
uni.navigateBack();
}, 1000);
}
});
};
</script>
<style lang="scss" scoped>
.item {
display: flex;
align-items: center;
margin: 0 32rpx;
border-bottom: 2rpx solid #f3f4f8;
.label {
flex: 0 0 160rpx;
padding: 32rpx 0;
font-size: 24rpx;
font-weight: 500;
line-height: 24rpx;
color: #77818f;
}
.placeholder {
color: #77818f;
}
.inner {
height: 88rpx;
padding: 0 32rpx;
font-size: 28rpx;
line-height: 88rpx;
}
textarea {
box-sizing: border-box;
width: 100%;
height: 272rpx;
padding: 32rpx;
margin: 10rpx auto 32rpx;
background: #f2f5fb;
border-radius: 8rpx;
}
}
.btn-wrap {
position: fixed;
bottom: 0;
box-sizing: border-box;
width: 100%;
padding: 16rpx 64rpx;
border-top: 2rpx solid rgb(31 35 41 / 15%);
button {
font-size: 30rpx;
font-weight: 600;
color: #ffffff;
background: #1f86ff;
border-radius: 12rpx;
}
}
</style>
<template>
<div class="essential-information">
<view
class="real-name-authentication flex-between"
v-if="verified == 0"
@tap="navigateTo('/pages/user/resume/realNameAuthentication/index')"
data-url="/subPackages/resume/pages/real-name-authentication/real-name-authentication"
>
<view class="flex-align-center">
<img src="@/static/image/user/realNameAuthentication.png" mode="" />
<view>
<view class="text1">实名认证</view>
<view class="text2">完成实名认证找工作更容易~</view>
</view>
</view>
<view class="btn">去认证</view>
</view>
<!-- 个人资料 -->
<view class="my-info" v-if="!cropperFlag">
<view class="my-info-list flex-row-b-c pd-b-38 upload-avatar" @tap="bindUploadImg">
<view class="my-info-title avatar-label">
<text>头像</text>
</view>
<img class="avatar" v-if="userInfo.avatarPath" :src="evn.APP_IMAGE_BASE_API + userInfo.avatarPath" />
<img class="avatar" v-else src="@/static/image/user/default-avatar.png" />
</view>
<!-- 性别 -->
<view class="my-info-list pd-b-38">
<view class="my-info-title label">
<text>性别</text>
</view>
<view class="gender radios">
<wd-radio-group v-model="userInfo.gender" shape="dot" inline>
<wd-radio :value="1"></wd-radio>
<wd-radio :value="2"></wd-radio>
</wd-radio-group>
</view>
</view>
<!-- 出生年月 -->
<view class="my-info-list flex-between">
<view class="my-info-title label">
<text>出生年月</text>
</view>
<wd-datetime-picker
v-model="userInfo.birthDate"
:maxDate="new Date().getTime()"
:minDate="new Date('1950/01/01').getTime()"
type="date"
@confirm="confirmBirthdayData"
use-default-slot
style="flex: 1"
>
<div style="flex: 1" class="flex-between">
<view :class="['my-info-form', !userInfo.birthDate ? 'placeholder-style' : '']">
{{ userInfo.birthDate ? dateformat(userInfo.birthDate) : "选择出生年月" }}</view
>
<view class="arrow"></view>
</div>
</wd-datetime-picker>
</view>
<!-- 身份 -->
<view class="my-info-list pd-b-38">
<view class="my-info-title label">
<text>身份</text>
</view>
<wd-radio-group v-model="userInfo.identityType" shape="dot" inline>
<wd-radio :value="v.code" :key="v.code" v-for="v in identityTypeOpstion">{{ v.text }}</wd-radio>
</wd-radio-group>
</view>
<!-- 工作年限 -->
<view class="my-info-list flex-column" v-if="userInfo.identityCode != 0">
<view class="my-info-title label">
<!-- <text>{{identityCode == 0 ? '参加实习时间' : '参加工作时间'}}</text> -->
<text>工作年限</text>
</view>
<input
class="my-info-form"
v-model="userInfo.workExperience"
placeholder="请输入工作年限"
placeholder-class="placeholder-style"
type="number"
/>
</view>
<!-- 学历 -->
<view class="my-info-list flex-column">
<view class="my-info-title label">
<text>学历</text>
</view>
<wd-picker
:columns="educationOpstion"
label-key="text"
value-key="code"
v-model="userInfo.educationLevel"
use-default-slot
@confirm="changeEducationLevel"
style="flex: 1"
>
<view class="picker">
<view :class="['my-info-form', educationText ? '' : 'placeholder-style']">{{
educationText || "请选择"
}}</view>
</view>
</wd-picker>
<!-- <image class="my-info-icon" src="{{ossImgPrefix}}/my/right.png"></image> -->
<view class="arrow"></view>
</view>
<!-- 手机 -->
<view class="my-info-list flex-column">
<view class="my-info-title label">
<text>手机</text>
</view>
<input
class="my-info-form"
v-model="userInfo.phone"
maxlength="11"
type="number"
placeholder="请填写手机号"
placeholder-class="placeholder-style"
/>
</view>
<!-- 邮箱 -->
<view class="my-info-list flex-column">
<view class="my-info-title label">
<text>邮箱</text>
</view>
<input
class="my-info-form"
v-model="userInfo.email"
placeholder="请填写邮箱"
placeholder-class="placeholder-style"
/>
</view>
</view>
<view class="my-form-submit" v-if="!cropperFlag">
<button class="my-form-button" @tap="submit">保 存</button>
</view>
</div>
</template>
<script setup>
import { reactive, ref } from "vue";
import { getLoginUserApi, saveUserInfoApi } from "@/api/user.js";
import { getEumData, navigateTo } from "@/utils/utils.js";
import { uploadFiles } from "@/utils/fileUpload.js";
import evn from "@/utils/config.js";
import dayjs from "dayjs";
const verified = 0;
const cropperFlag = 0;
const identityCode = 0;
const userInfo = ref({
userId: "575447396285247488",
username: "15585110655",
avatarPath: "v2MpPublishMedia/2024-07-16/1721120465826.jpg",
realName: "陈家驹",
gender: 2,
phone: "13368604081",
email: "15165156@qq.com",
birthDate: 1633017600000,
identityType: 2,
educationLevel: 6,
workExperience: 11,
personalTags: null,
verified: 1,
loginTime: 1721804335908,
jobStatus: 1,
completeResume: false,
user: null
});
/* 头像 */
const bindUploadImg = () => {
uni.chooseFile({
count: 1,
type: "image",
crop: {
width: 200,
height: 200,
resize: false
},
success(res) {
uploadFiles(res.tempFiles).then(imgs => {
userInfo.value.avatarPath = imgs[0].key;
});
/* const files = res.tempFilePaths.map(v => ({
fileType: "image",
filePath: v
}));
uploaderMediaFile(files).then(img => {
userInfo.value.avatarPath = img[0].key;
}); */
}
});
};
/* 选中时间 */
const dateformat = date => dayjs(date).format("YYYY-MM-DD");
const confirmBirthdayData = e => {
console.log(e);
};
/* 身份 */
const identityTypeOpstion = ref([]);
getEumData("EnumIdentityType").then(res => {
res.forEach(v => {
v.code = v.code * 1;
});
identityTypeOpstion.value = res;
});
/* 学历 */
const educationText = ref("");
const educationOpstion = ref([]);
getEumData("EnumEducation").then(res => {
res.forEach(v => {
v.code = v.code * 1;
});
educationOpstion.value = res;
});
const changeEducationLevel = e => {
educationText.value = e.selectedItems.text;
};
const getData = async () => {
const { data, code } = await getLoginUserApi();
console.log(data);
if (code == 200) {
userInfo.value = data;
}
};
getData();
/* 提交 */
const submit = () => {
console.log(userInfo);
const { avatarPath, realName, gender, phone, email, birthDate, identityType, educationLevel, workExperience, personalTags } =
userInfo.value;
saveUserInfoApi({
avatarPath,
realName,
gender,
phone,
email,
birthDate,
identityType,
educationLevel,
workExperience,
personalTags
}).then(res => {
console.log(res);
});
};
</script>
<style lang="scss" scoped>
/* pages/my-resume/my-resume.wxss */
.essential-information {
box-sizing: border-box;
height: 100%;
background: #ffffff;
}
.real-name-authentication {
padding: 12rpx 20rpx;
margin: 0 32rpx;
background: rgb(31 134 255 / 10%);
border-radius: 12rpx;
img {
width: 94rpx;
height: 96rpx;
margin-right: 30rpx;
}
.text1 {
font-size: 28rpx;
font-weight: 600;
line-height: 36rpx;
color: #1f86ff;
}
.text2 {
font-size: 22rpx;
font-weight: normal;
line-height: 36rpx;
color: #1f86ff;
}
.btn {
width: 130rpx;
height: 48rpx;
font-size: 24rpx;
line-height: 48rpx;
color: #ffffff;
text-align: center;
background: #1f86ff;
border-radius: 8rpx;
}
}
/* 个人资料 */
.my-info .info-title {
float: left;
overflow: hidden;
font-size: 36rpx;
font-weight: 500;
color: rgb(51 51 51 / 100%);
background: #ffffff;
}
.my-info .info-title text {
display: inline-block;
color: #3a3a3c;
}
/* .my-info .info-title text::after {
content: "";
width: 100%;
display: inline-block;
} */
.my-info .info-title view {
float: right;
color: #ed877b;
}
.my-info .my-info-bottom {
border: none;
border-bottom: 24rpx solid #f5f5f5;
}
.my-info .border-none {
border: none;
}
.my-info .my-info-title {
margin-right: 60rpx;
}
.my-info .my-info-title view {
float: right;
color: #ed877b;
}
.my-info .my-info-img {
float: left;
width: 80rpx;
height: 80rpx;
margin-right: 24rpx;
border-radius: 50%;
}
.my-info .my-info-form {
width: 66%;
padding: 20rpx 0 38rpx;
font-size: 28rpx;
font-weight: 600;
color: #213452;
}
.my-info .post-detail-data {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.log-input-p {
color: #808080;
}
.my-info .my-info-icon {
position: absolute;
top: 50%;
right: 9rpx;
width: 48rpx;
height: 48rpx;
transform: translate(0, -50%);
}
.my-info .my-info-len {
float: right;
margin-right: 32rpx;
font-size: 28rpx;
color: #808080;
}
.my-form-submit .my-form-button {
width: 600rpx;
height: 72rpx;
padding: 0;
margin: 12rpx auto 14rpx;
margin-top: 60rpx;
font-size: 32rpx;
font-weight: 400;
color: #ffffff;
background: #1892ff;
border-radius: 8px;
}
.my-info .my-infoImg {
color: #808080;
}
/* 图片裁剪 */
.body {
display: flex;
flex-direction: column;
height: 100%;
}
.body .stage {
flex-grow: 1;
}
.body .bar {
display: flex;
flex-direction: row;
height: 80rpx;
padding: 36rpx;
background-color: black;
}
.body .btn {
position: relative;
flex-grow: 1;
font-size: 32rpx;
line-height: 80rpx;
color: white;
text-align: center;
}
.body .btn-cancel {
border-top-left-radius: 40rpx;
border-bottom-left-radius: 40rpx;
}
.body .btn-submit {
border-top-right-radius: 40rpx;
border-bottom-right-radius: 40rpx;
}
.appExtension {
padding: 28rpx 32rpx;
font-size: 26rpx;
font-weight: 400;
color: rgb(245 166 35 / 100%);
text-align: center;
}
.appExtension .appBtn {
margin-bottom: 12rpx;
}
.appExtension .appBtn .btn {
display: inline-block;
width: 140rpx;
height: 52rpx;
margin-right: 16rpx;
line-height: 52rpx;
vertical-align: middle;
border: 2rpx solid rgb(245 166 35 / 100%);
border-radius: 8rpx;
}
/** 新样式 **/
.label {
font-size: 24rpx;
color: #616c7a;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
}
.avatar-label {
font-size: 28rpx;
font-weight: 600;
color: #213452;
}
.warning {
display: flex;
align-items: center;
width: 100%;
margin-top: 20rpx;
}
.warning .icon {
width: 28rpx;
height: 28rpx;
margin-right: 6rpx;
}
.warning .text {
font-size: 24rpx;
color: #fa4a00;
}
.flex-row-b-c {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: space-between !important;
}
.flex-column {
display: flex;
flex-direction: column;
}
.pd-b-38 {
padding-bottom: 38rpx;
}
.mr-32 {
margin-right: 32rpx;
}
/* radios */
.radios {
display: flex;
align-items: center;
}
.radios .icon {
width: 108rpx;
height: 48rpx;
}
.placeholder-style {
font-size: 28rpx !important;
color: #a0afc3 !important;
}
.footer-warning {
margin: 0;
margin-bottom: 48rpx;
}
.footer-warning .text {
color: #8693a3;
}
.my-info {
padding: 0 32rpx;
.my-info-list {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
padding: 32rpx 0;
padding-top: 48rpx;
padding-right: 5rpx;
/* height: 96rpx;
line-height: 96rpx; */
overflow: hidden;
background: #ffffff;
border-bottom: 1rpx solid #e9e9e9;
/* picker {
flex: 1;
} */
.label {
flex: 0 0 200rpx;
margin: 0;
font-size: 24rpx;
font-weight: 500;
line-height: 36rpx;
color: #77818f;
}
.placeholder-style {
font-size: 28rpx;
font-weight: normal;
line-height: 36rpx;
color: #77818f;
}
.my-info-form {
flex: 1;
padding: 0;
}
.radios {
font-size: 28rpx;
line-height: 36rpx;
color: #1b2026;
.radios-item {
display: flex;
align-items: center;
margin-right: 48rpx;
.inner {
box-sizing: border-box;
width: 32rpx;
height: 32rpx;
margin-right: 16rpx;
border: 2rpx solid #77818f;
border-radius: 50%;
}
&.active {
.inner {
display: flex;
align-items: center;
justify-content: center;
border-color: #1f86ff;
&::after {
display: block;
width: 16rpx;
height: 16rpx;
content: "";
background-color: #1f86ff;
border-radius: 50%;
}
}
}
}
}
}
.upload-avatar {
.avatar {
width: 56rpx;
height: 56rpx;
}
}
.identity {
flex-wrap: wrap;
.radios-item:not(:last-child) {
margin-bottom: 16rpx;
}
}
}
.my-form-submit {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
border-top: 1rpx solid #ebebeb;
}
</style>
<template>
<div class="resume-page">
<!-- 个人信息 -->
<view class="user-info flex-between" @click="navigateTo('/pages/user/resume/essentialInformation/index')">
<view>
<view class="name"
>{{ resumeData.realName || "未实名" }}
<img src="@/static/image/icon/edit.png" />
</view>
<view class="other"
>{{ resumeData.workExperienceYear }}年经验·{{ resumeData.age }}岁·{{ resumeData.educationLevel }}</view
>
</view>
<image v-if="resumeData.avatarPath" class="avatar" :src="evn.APP_IMAGE_BASE_API + resumeData.avatarPath" mode="" />
<image v-else class="avatar" src="@/static/image/user/default-avatar.png" mode="" />
</view>
<!-- 求职状态 -->
<view class="state">
<text class="gradient-title">求职状态</text>
<wd-picker
:columns="jobStatusColumns"
label-key="text"
value-key="code"
@confirm="changeJobStatus"
v-model="value"
use-default-slot
>
<view class="flex-between">
<text>{{ resumeData.jobStatusText }}</text>
<view class="arrow" bind:tap="onOpenStateSelect"></view>
</view>
</wd-picker>
</view>
<!-- 个人优势 -->
<view class="advantage" @click="navigateTo('/pages/user/resume/introduce/index')">
<view class="flex-between">
<text class="gradient-title">个人优势</text>
<view class="arrow" bind:tap="navigateTo"></view>
</view>
<view class="content">
{{ resumeData.personalAdvantage }}
</view>
</view>
<!-- 求职意向 -->
<view class="intention" @click="navigateTo('/pages/user/resume/jobIntention/index')">
<view class="flex-between">
<text class="gradient-title">求职意向</text>
<view class="arrow"></view>
</view>
<view class="postion">{{ resumeData.preferredPosition }}</view>
<view class="salary">{{ resumeData.minSalary }}-{{ resumeData.maxSalary }}| {{ resumeData.preferredCityName }}</view>
</view>
<!-- 工作经历 -->
<view class="experience" @click="navigateTo('/pages/user/resume/workExperience/index')">
<view class="flex-between">
<text class="gradient-title">工作经历</text>
<view class="arrow"></view>
</view>
<view class="list">
<view class="item" v-for="(item, index) in resumeData.workExperience" :key="index">
<view class="name-date flex-between">
<text class="name">·{{ item.companyName }}</text>
<text class="date">{{ item.startDate }} ~ {{ item.endDate }}</text>
</view>
<view class="postion">·{{ item.position }}</view>
<view class="content"> ·{{ item.content }} </view>
</view>
</view>
</view>
<!-- 教育经历 -->
<view class="experience" @click="navigateTo('/pages/user/resume/educationExperience/index')">
<view class="flex-between">
<text class="gradient-title">教育经历</text>
<view class="arrow"></view>
</view>
<view class="list">
<view class="item" v-for="(item, index) in resumeData.educationExperience" :key="index">
<view class="name-date flex-between">
<text class="name">·{{ item.schoolName }}</text>
<text class="date">{{ item.startDate }}~{{ item.endDate }}</text>
</view>
<view class="postion">·{{ item.major }}</view>
<!-- <view class="content">
·内容:预计,建筑工程将在今年底竣工。宿舍会在明年8月启用,让多达600名学生入住。
国大学生事务处处长何汉杰说,国大的宿舍都各有特色,并解释为何要兴建以体育为主题的宿舍。
</view> -->
</view>
</view>
</view>
<wd-toast />
</div>
</template>
<script setup>
import { reactive } from "vue";
import { getUserResumeApi, getLoginUserApi, saveJobStatusApi } from "@/api/user";
import { getEnumText, getEumData } from "@/utils/utils.js";
import { useToast } from "wot-design-uni";
import { navigateTo } from "@/utils/utils.js";
import evn from "@/utils/config.js";
const toast = useToast();
const resumeData = reactive({
preferredCityName: "",
personalAdvantage: "",
preferredPosition: "",
maxSalary: "",
minSalary: "",
workExperience: [],
educationExperience: [],
workExperience: "",
workExperienceYear: "",
jobStatusText: "",
educationLevel: "",
realName: "",
username: "",
avatarPath: "",
birthDate: "",
jobStatus: "",
age: ""
});
function calculateAge(birthday) {
var birthdayDate = new Date(birthday); // 将时间戳转换为日期对象
var today = new Date(); // 获取当前日期
var age = today.getFullYear() - birthdayDate.getFullYear(); // 计算年份差
// 检查生日是否已经过去
var m = today.getMonth() - birthdayDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthdayDate.getDate())) {
age--;
}
return age;
}
// 数据回显
const getUserResume = () => {
getUserResumeApi().then(res => {
// console.log(res);
const {
personalAdvantage,
preferredPosition,
maxSalary,
minSalary,
preferredCityName,
workExperience,
educationExperience
} = res.data;
resumeData.preferredCityName = preferredCityName;
resumeData.personalAdvantage = personalAdvantage; // 求职状态回
resumeData.preferredPosition = preferredPosition.split(",").join("|");
resumeData.maxSalary = maxSalary && maxSalary / 1000 + "k";
resumeData.minSalary = minSalary && minSalary / 1000 + "k";
resumeData.workExperience = JSON.parse(workExperience || "[]");
resumeData.educationExperience = JSON.parse(educationExperience || "[]");
});
// 获取用户基本信息
getLoginUserApi().then(async res => {
if (res.code === 200) {
const { workExperience, educationLevel, realName, username, avatarPath, birthDate, jobStatus } = res.data;
/* this.setData({
realName,
workExperienceYear: workExperience,
educationLevel: getEnumText("EnumEducation", educationLevel),
jobStatusText: getEnumText("EnumUserJobStatus", jobStatus), // 求职状态回显
username,
avatarPath,
age: calculateAge(birthDate)
}); */
resumeData.realName = realName;
resumeData.workExperienceYear = workExperience;
resumeData.educationLevel = await getEnumText("EnumEducation", educationLevel);
resumeData.jobStatusText = await getEnumText("EnumUserJobStatus", jobStatus);
resumeData.username = username;
resumeData.avatarPath = avatarPath;
resumeData.age = calculateAge(birthDate);
}
});
};
getUserResume();
// 获取求职状态数据
const value = ref();
const jobStatusColumns = ref([]);
const getOpstion = async () => {
jobStatusColumns.value = await getEumData("EnumUserJobStatus");
console.log(jobStatusColumns.value);
};
getOpstion();
const changeJobStatus = async e => {
console.log(e.selectedItems.text);
const { code, message } = await saveJobStatusApi({ jobStatus: e.value });
if (code == 200) {
resumeData.jobStatusText = e.selectedItems.text;
toast.success("保存成功");
} else {
toast.error(message);
}
};
</script>
<style lang="scss" scoped>
.resume-page {
padding-top: 50rpx;
}
.user-info {
padding-bottom: 30rpx;
margin: 0 32rpx;
border-bottom: 2rpx solid #f3f4f8;
.name {
margin-bottom: 16rpx;
font-size: 36rpx;
font-weight: 600;
line-height: 36rpx;
color: #1b2026;
img {
width: 28rpx;
height: 28rpx;
}
}
.other {
font-size: 24rpx;
font-weight: normal;
line-height: 36rpx;
color: #77818f;
}
.avatar {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
}
}
.state {
padding: 0 32rpx 32rpx;
margin-top: 32rpx;
border-bottom: 16rpx solid #f3f4f8;
view {
margin-top: 16rpx;
font-size: 24rpx;
line-height: 36rpx;
color: #1b2026;
}
.arrow {
border-color: #1b2026;
}
}
.advantage {
padding: 32rpx;
border-bottom: 16rpx solid #f3f4f8;
.content {
margin-top: 16rpx;
font-size: 24rpx;
line-height: 36rpx;
color: #1b2026;
}
}
.intention {
padding: 32rpx;
border-bottom: 16rpx solid #f3f4f8;
view {
margin-top: 16rpx;
font-size: 24rpx;
line-height: 36rpx;
color: #1b2026;
}
}
.experience {
padding: 32rpx;
border-bottom: 16rpx solid #f3f4f8;
.list {
.item {
padding: 32rpx 0;
&:not(:last-child) {
border-bottom: 2rpx solid #f3f4f8;
}
.name-date {
line-height: 36rpx;
color: #1b2026;
.name {
font-size: 28rpx;
font-weight: 600;
}
.date {
font-size: 24rpx;
}
}
.postion {
margin-top: 16rpx;
font-size: 24rpx;
line-height: 36rpx;
color: #1b2026;
}
.content {
font-size: 24rpx;
line-height: 36rpx;
color: #77818f;
}
}
}
}
</style>
<template>
<view class="container">
<view class="title">我的优势</view>
<view class="desc text-color">一句话介绍自己,突出自己的核心优势</view>
<view class="content">
<textarea class="input-style" v-model="inputvalue" placeholder="" maxlength="140"></textarea>
<view class="count-wrapper">
<view class="count">{{ inputvalue.length }}/140</view>
</view>
</view>
<view class="btn-wrapper">
<button :disabled="!inputvalue.length" class="save-btn" @tap="save">保存</button>
</view>
</view>
</template>
<script setup>
import { ref } from "vue";
import { saveAdvantageApi } from "@/api/user.js";
const inputvalue = ref("");
const save = () => {
saveAdvantageApi({ personalAdvantage: inputvalue.value }).then(res => {
console.log(res);
});
};
</script>
<style lang="scss" scoped>
.container {
height: 100vh;
padding: 0 32rpx;
background-color: #ffffff;
}
/* 标题 */
.container .title {
padding: 20rpx 0;
font-size: 32rpx;
font-weight: 600;
color: #213452;
}
.desc {
margin-bottom: 32rpx;
font-size: 24rpx;
font-weight: 400;
color: #5c7396;
}
/* 内容 */
.content {
padding-bottom: 38rpx;
border-bottom: 1rpx solid #e9e9e9;
}
.content .input-style {
width: 100%;
height: 216rpx;
}
.content .count-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
}
.content .count-wrapper .look {
display: flex;
align-items: center;
color: #213452;
}
.content .count-wrapper .look .xiaoyanjing {
width: 48rpx;
height: 48rpx;
}
.content .count-wrapper .count {
color: #888888;
}
/* 推荐 */
.recommend {
position: relative;
padding: 53rpx 0 0;
}
.recommend .triangle {
position: absolute;
top: 33rpx;
left: 120rpx;
width: 40rpx;
height: 40rpx;
background-color: #f3f3f3;
transform: rotate(45deg);
}
.recommend .recommend-info {
padding: 34rpx 20rpx;
background-color: #f3f3f3;
}
.recommend-info .header {
display: flex;
align-items: center;
justify-content: space-between;
}
.recommend-info .header .info {
display: flex;
align-items: center;
}
.recommend-info .header .change {
color: #0578ff;
}
/* 保存按钮 */
.btn-wrapper {
position: fixed;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
width: 100%;
padding: 12rpx 0;
border-top: 1rpx solid #ebebeb;
}
.btn-wrapper .save-btn {
width: 600rpx;
height: 72rpx;
font-size: 32rpx;
line-height: 72rpx;
color: #ffffff;
background: #1892ff;
border-radius: 8rpx;
}
/* 公共样式 */
.container view,
.container text {
font-size: 24rpx;
}
.text-color {
color: #213452;
}
.small-avatar {
width: 60rpx;
height: 60rpx;
}
.mr20 {
margin-right: 20rpx;
}
.mt20 {
margin-top: 20rpx;
}
.font-w600 {
font-weight: 600;
}
.mr60 {
margin-right: 60rpx;
}
</style>
<template>
<view class="container">
<view class="header">
<view class="title"> 求职意向 </view>
<view class="desc mt20"> 将根据求职意向,为您推荐最合适的工作 </view>
</view>
<view class="form">
<!-- 期望职位 -->
<colPicker
label="期望职位"
v-model="value"
:columns="columns"
v-model:mValue="mValue"
value-key="id"
label-key="name"
:column-change="columnChange"
:before-confirm="beforeConfirm"
@confirm="handleConfirm"
use-default-slot
>
<view class="form-item">
<view class="form-info">
<view class="label">选择岗位</view>
</view>
<div>{{ mValue.map(v => v.name).join("|") }}</div>
<view class="arrow"></view>
</view>
</colPicker>
<!-- 工作城市 -->
<wd-col-picker
label="期望职位"
v-model="cityValue"
:columns="cityOpstion"
value-key="code"
label-key="name"
:column-change="columnChangeCity"
@confirm="handleConfirmCity"
use-default-slot
>
<view class="form-item">
<view class="form-info">
<view class="label">工作城市</view>
</view>
<div>{{ cityText }}</div>
<view class="arrow"></view>
</view>
</wd-col-picker>
<!-- 薪资要求 -->
<wd-col-picker
label="期望职位"
v-model="salaryValue"
:columns="salaryOpstion"
:column-change="columnChangeSalary"
@confirm="handleConfirmSalary"
use-default-slot
>
<view class="form-item">
<view class="form-info">
<view class="label">薪资要求</view>
</view>
<div>{{ salaryText }}</div>
<view class="arrow"></view>
</view>
</wd-col-picker>
</view>
<view class="btn-wrapper">
<button class="save-btn" @tap="submit">保存</button>
</view>
</view>
</template>
<script setup>
import { dictJobTypeApi, getTreeListApi } from "@/api/common";
import { saveJobIntentionApi } from "@/api/user";
import { ref } from "vue";
import colPicker from "@/components/wd-col-picker22/wd-col-picker.vue";
import _ from "lodash";
/* 岗位 */
const value = ref([]);
const mValue = ref([]);
const columns = ref([]);
dictJobTypeApi({}).then(res => {
columns.value.push(res.data);
console.log(columns);
});
const columnChange = ({ selectedItem, resolve, finish }) => {
if (selectedItem.children) {
resolve(selectedItem.children);
} else {
finish();
}
};
const beforeConfirm = (value2, selectedItems, resolve) => {
/* 判断是否点到重复的 */
const tagter = _.last(selectedItems);
const index = mValue.value.indexOf(tagter);
if (index != -1) {
mValue.value.splice(index, 1);
} else {
mValue.value.push(tagter);
if (mValue.value.length >= 3) {
// _.pullAt(mValue.value, 0);
resolve(true);
}
}
resolve(false);
};
const handleConfirm = ({ selectedItems }) => {};
/* 城市 */
const cityOpstion = ref([]);
const cityValue = ref([]);
const cityText = ref("");
let citySelectedItems = [];
getTreeListApi().then(res => {
cityOpstion.value.push(res.data);
console.log(cityOpstion);
});
const columnChangeCity = ({ selectedItem, resolve, finish }) => {
if (selectedItem.children) {
resolve(selectedItem.children);
} else {
finish();
}
};
const handleConfirmCity = ({ selectedItems }) => {
cityText.value = selectedItems.map(v => v.name).join("-");
citySelectedItems = selectedItems;
};
/* 薪水 */
const salaryOpstion = ref([]);
const salaryValue = ref([]);
const salaryText = ref("");
let salarySelectedItems = [];
const initSalaryOpstion = () => {
let temp = [
{
label: "面议",
value: "",
next: false
}
];
for (let i = 1; i < 50; i++) {
temp.push({
value: i * 1000,
label: i * 1000 + "元",
next: true
});
}
salaryOpstion.value.push(temp);
};
initSalaryOpstion();
const columnChangeSalary = ({ selectedItem, resolve, finish }) => {
let temp = [];
if (selectedItem.next) {
// resolve(selectedItem.children);
console.log(selectedItem);
for (let i = 1; i < 50; i++) {
temp.push({
value: i * 1000 + selectedItem.value,
label: i * 1000 + selectedItem.value + "元",
next: false
});
resolve(temp);
}
} else {
finish();
}
};
const handleConfirmSalary = ({ selectedItems }) => {
console.log(selectedItems);
salaryText.value = selectedItems.map(v => v.label).join("~");
salarySelectedItems = selectedItems;
};
const submit = () => {
let params = {
maxSalary: 24000,
minSalary: 20000,
preferredCityCode: "210400",
preferredCityName: "抚顺市",
preferredDistrictCode: "210404",
preferredDistrictName: "望花区",
preferredPosition: "钟点工,花艺师,宠物医生",
preferredProvinceCode: "210000",
preferredProvinceName: "辽宁省"
};
const [p, c, d] = citySelectedItems;
params.preferredPosition = mValue.value.map(v => v.name).join(",");
params.minSalary = salarySelectedItems[0].value;
params.maxSalary = salarySelectedItems[1].value;
params.preferredProvinceCode = p.code;
params.preferredProvinceName = p.name;
params.preferredCityCode = c.code;
params.preferredCityName = c.name;
params.preferredDistrictCode = d.code;
params.preferredDistrictName = d.name;
saveJobIntentionApi(params).then(res => {
console.log(res);
if (res.code == 200) {
uni.showToast({
title: "操作成功"
});
}
});
};
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
padding: 0 32rpx;
background-color: #ffffff;
}
.container .header {
padding: 30rpx 0;
}
.container .header .title {
font-size: 32rpx;
font-weight: 600;
color: #213452;
}
.container .header .desc {
font-size: 24rpx;
color: #5c7396;
}
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 36rpx 0;
border-bottom: 1rpx solid #e9e9e9;
}
.form-item .form-info .label {
font-size: 24rpx;
color: #616c7a;
}
.form-item .form-info .cont {
font-size: 28rpx;
font-weight: 600;
color: #213452;
}
/* 保存按钮 */
.btn-wrapper {
position: fixed;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
width: 100%;
padding: 12rpx 0;
border-top: 1rpx solid #ebebeb;
}
.btn-wrapper .save-btn {
width: 600rpx;
height: 72rpx;
font-size: 32rpx;
line-height: 72rpx;
color: #ffffff;
background: #1892ff;
border-radius: 8rpx;
}
.mt20 {
margin-top: 20rpx;
}
.right-icon {
width: 48rpx;
height: 48rpx;
}
.color-grey {
font-size: 28rpx;
color: #a0afc3;
}
.placeholder-style {
font-size: 28rpx !important;
color: #a0afc3 !important;
}
</style>
<template>
<div class="page">
<view class="text1">请填写您的真实身份信息</view>
<view class="text2">信息仅用于身份核实</view>
<view class="input-form">
<view class="item">
<view class="label">姓名</view>
<input type="text" v-model="data.realName" placeholder="请输入姓名" />
</view>
<view class="item">
<view class="label">身份证号</view>
<input type="text" v-model="data.citizenId" placeholder="请输入身份证号" />
</view>
</view>
<!-- 身份证 -->
<view class="idcard flex-between">
<img
:src="data.idCardFrontPath ? evn.APP_IMAGE_BASE_API + data.idCardFrontPath : idCardFrontPathDefle"
@tap="uploadeImage(1)"
/>
<img
:src="data.idCardBackPath ? evn.APP_IMAGE_BASE_API + data.idCardBackPath : idCardBackPathDefle"
@tap="uploadeImage(2)"
/>
</view>
<view class="btn-wrap">
<button @tap="submit">保存</button>
</view>
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
import { uploadFiles } from "@/utils/fileUpload.js";
import evn from "@/utils/config.js";
import { saveIdCardApi } from "@/api/user.js";
const data = reactive({
citizenId: "",
idCardFrontPath: "",
idCardBackPath: "",
realName: ""
});
const idCardFrontPathDefle = new URL("@/static/image/user/idcardFront.png", import.meta.url);
const idCardBackPathDefle = new URL("@/static/image/user/idcardBack.png", import.meta.url);
const uploadeImage = type => {
// 正面
uni.chooseImage({
count: 1,
success: async e => {
console.log(e);
const fList = await uploadFiles(e.tempFiles);
console.log(fList);
if (type == 1) {
data.idCardFrontPath = fList[0].key;
} else {
data.idCardBackPath = fList[0].key;
}
}
});
};
const submit = () => {
saveIdCardApi(data).then(res => {
console.log(res);
});
};
</script>
<style lang="scss" scoped>
.page {
box-sizing: border-box;
padding: 32rpx;
}
.text1 {
margin-bottom: 16rpx;
font-size: 32rpx;
font-weight: 500;
line-height: 36rpx;
color: #1b2026;
}
.text2 {
margin-bottom: 80rpx;
font-size: 24rpx;
font-weight: normal;
line-height: 36rpx;
color: #1b2026;
}
.label {
font-size: 24rpx;
font-weight: 500;
color: #77818f;
}
.input-form {
border-bottom: 2rpx solid #f3f4f8;
.item {
display: flex;
align-items: center;
.label {
flex: 0 0 200rpx;
}
input {
padding: 24rpx 0;
}
}
}
.idcard {
padding-top: 32rpx;
img {
width: 328rpx;
height: 184rpx;
}
}
.btn-wrap {
position: fixed;
bottom: 0;
box-sizing: border-box;
width: 100%;
padding: 16rpx 64rpx;
border-top: 2rpx solid rgb(31 35 41 / 15%);
button {
font-size: 30rpx;
font-weight: 600;
color: #ffffff;
background: #1f86ff;
border-radius: 12rpx;
}
}
</style>
<template>
<view class="container">
<view class="header">
<view class="title"> 工作/实习经历 </view>
<view class="desc mt20"> 从最近的一份工作/实习经历填写哦 </view>
</view>
<view class="form">
<!-- 公司名称 -->
<view class="form-item">
<view class="form-info">
<view class="label">公司名称</view>
<input type="text" v-model="params.companyName" placeholder="请输入" />
</view>
</view>
<!-- 在职时间 -->
<view class="form-item" bindtap="goToSelectJobType">
<view class="form-info">
<view class="label">在职时间</view>
<view class="time-wrapper flex-r-c mt20">
<wd-datetime-picker
:default-value="new Date().getTime()"
:maxDate="new Date().getTime()"
:minDate="new Date('1960/01/01').getTime()"
type="year-month"
v-model="params.startDate"
class="my-datetime-picker"
/>
<view class="line"></view>
<wd-datetime-picker
:default-value="new Date().getTime()"
:minDate="params.startDate"
:maxDate="new Date().getTime()"
type="year-month"
v-model="params.endDate"
/>
</view>
</view>
</view>
<!-- 职位类型 -->
<wd-col-picker
label="期望职位"
v-model="postionValue"
:columns="postionOpstion"
value-key="name"
label-key="name"
:column-change="columnChangePostion"
@confirm="handleConfirmPostion"
use-default-slot
>
<view class="form-item">
<view class="form-info">
<view class="label">职位类型</view>
<view :class="['cont', 'mt20', !jobTypeText ? 'placeholder-style' : '']">{{
jobTypeText || "请选择"
}}</view>
</view>
<view class="arrow"></view>
</view>
</wd-col-picker>
<!-- 工作内容 -->
<view class="form-item">
<view class="form-info">
<view class="label">工作内容</view>
<textarea v-model="params.content" placeholder="请输入" />
</view>
</view>
</view>
<!-- <view class="btn-wrapper" wx:if="{{isEdit && leng > 1}}">
<button class="del-btn ml32" bindtap="delWorkExperience">删除</button>
<button class="save-btn save-btn-samll" bindtap="save">保存</button>
</view> -->
<view class="btn-wrapper">
<button class="save-btn" @tap="save">保存</button>
</view>
</view>
</template>
<script setup>
import { ref } from "vue";
import { dictJobTypeApi } from "@/api/common";
import { saveWorkExperienceApi } from "@/api/user";
import _ from "lodash";
const jobTypeText = ref("");
const params = reactive({
companyName: "",
startDate: 0,
endDate: 0,
position: "",
content: ""
});
const postionValue = ref([]);
const postionOpstion = ref([]);
dictJobTypeApi({}).then(res => {
postionOpstion.value.push(res.data);
});
const columnChangePostion = ({ selectedItem, resolve, finish }) => {
if (selectedItem.children) {
resolve(selectedItem.children);
} else {
finish();
}
};
const handleConfirmPostion = ({ selectedItems }) => {
console.log(selectedItems);
jobTypeText.value = _.last(selectedItems).name;
};
const save = () => {
params.position = jobTypeText.value;
console.log(params);
saveWorkExperienceApi(JSON.stringify([params])).then(res => {
console.log(res);
if (res.code == 200) {
uni.showToast({
title: "保存成功",
icon: "success"
});
}
});
};
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
padding: 0 32rpx;
background-color: #ffffff;
}
.container .header {
padding: 30rpx 0;
}
.container .header .title {
font-size: 32rpx;
font-weight: 600;
color: #213452;
}
.container .header .desc {
font-size: 24rpx;
color: #5c7396;
}
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 36rpx 0;
border-bottom: 1rpx solid #e9e9e9;
}
.form-item .form-info {
width: 92%;
}
.form-item .form-info .label {
font-size: 24rpx;
color: #616c7a;
}
.form-item .form-info .cont {
font-size: 28rpx;
font-weight: 600;
color: #213452;
}
/* 保存按钮 */
.btn-wrapper {
position: fixed;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
width: 100%;
padding: 12rpx 0;
border-top: 1rpx solid #ebebeb;
}
.btn-wrapper .save-btn {
width: 600rpx;
height: 72rpx;
font-size: 32rpx;
line-height: 72rpx;
color: #ffffff;
background: #1892ff;
border-radius: 8rpx;
}
.mt20 {
margin-top: 20rpx;
}
.ml32 {
margin-left: 32rpx;
}
.right-icon {
width: 48rpx;
height: 48rpx;
}
.color-grey {
font-size: 28rpx;
color: #a0afc3;
}
.placeholder-style {
font-size: 28rpx !important;
color: #a0afc3 !important;
}
.flex-r-c {
display: flex;
align-items: center;
justify-content: space-between;
}
.line {
width: 40rpx;
height: 2rpx;
margin: 0 80rpx;
background-color: #8693a3;
}
.overflow-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.btn-wrapper .del-btn {
width: 276rpx;
height: 72rpx;
font-size: 32rpx;
line-height: 72rpx;
color: #1892ff;
background: #ffffff;
border: 2rpx solid #1892ff;
border-radius: 8rpx;
}
.btn-wrapper .save-btn-samll {
width: 380rpx;
height: 72rpx;
}
:deep(.my-datetime-picker) {
.wd-icon-arrow-right {
display: none;
}
}
</style>
...@@ -44,3 +44,6 @@ ...@@ -44,3 +44,6 @@
content: ""; content: "";
background: linear-gradient(90deg, rgb(241 246 251 / 0%) 0%, #76a5ff 100%); background: linear-gradient(90deg, rgb(241 246 251 / 0%) 0%, #76a5ff 100%);
} }
uni-page-body {
height: 100%;
}
import axios from "axios"; import axios from "axios";
const baseURL = "https://lygsh-api.wjzpgz.com/";
// 创建一个 axios 实例 // 创建一个 axios 实例
const instance = axios.create({ const instance = axios.create({
baseURL: "https://lygsh-api.wjzpgz.com/api", // 设置基础 URL baseURL, // 设置基础 URL
// baseURL: "http://192.168.11.63:8080/api", // 设置基础 URL // baseURL: "http://192.168.11.63:8080/", // 设置基础 URL
timeout: 5000, // 设置请求超时时间 timeout: 5000, // 设置请求超时时间
headers: { headers: {
"Content-Type": "application/json" // 设置默认请求头 "Content-Type": "application/json" // 设置默认请求头
...@@ -17,7 +17,10 @@ instance.interceptors.request.use( ...@@ -17,7 +17,10 @@ instance.interceptors.request.use(
// const token = localStorage.getItem('token'); // const token = localStorage.getItem('token');
// if (token) { // if (token) {
// config.headers.Authorization = `Bearer ${token}`; // config.headers.Authorization = `Bearer ${token}`;
// } // }·
const token =
"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNTU4NTExMDY1NSIsInVzZXJ0eXBlIjoiY29uc3VtZXIiLCJleHAiOjE3MjMxMDAzMzUsImNyZWF0ZWQiOjE3MjE4MDQzMzU5MjAsImF1dGhvcml0aWVzIjpbeyJhdXRob3JpdHkiOiJDT05TVU1FUiJ9XX0.5ONGQaDC6G5yChBuUC4Q9P-HucdArrBBy_rLSGKCu43XxmMgE4dONYoqJ86GwuqPqtV5RayLA5YKTCe8atgVCQ";
config.headers.Authorization = `Bearer ` + token;
return config; return config;
}, },
error => { error => {
......
class SwipeHandler {
constructor() {
this.startY = 0;
this.endY = 0;
this.startTime = 0;
this.endTime = 0;
}
onTouchStart(e) {
this.startY = e.touches[0].clientY;
this.startTime = Date.now();
}
onTouchMove(e) {
// 在这里可以更新Y坐标,但通常只需要开始和结束时的坐标
}
onTouchEnd(e) {
this.endY = e.changedTouches[0].clientY;
this.endTime = Date.now();
const distanceThreshold = 150; // 设置滑动距离阈值,单位:像素
const timeThreshold = 200; // 设置时间阈值,单位:毫秒
const distance = this.startY - this.endY;
const duration = this.endTime - this.startTime;
if (Math.abs(distance) > distanceThreshold && duration < timeThreshold) {
if (distance > 0) {
// 向上滑动
console.log('向上滑动');
return 'up'
} else {
// 向下滑动
console.log('向下滑动');
return 'down'
}
}
}
}
export default SwipeHandler
/* const swipeHandler = new SwipeHandler();
Page({
data: {},
onTouchStart: function(e) {
swipeHandler.onTouchStart(e);
},
onTouchMove: function(e) {
swipeHandler.onTouchMove(e);
},
onTouchEnd: function(e) {
swipeHandler.onTouchEnd(e);
}
}); */
\ No newline at end of file
import { getDictDataApi } from "@/api/common";
/**
* 根据类型获取EUM数据。
* 该函数用于根据给定的类型从本地存储或服务器获取EUM数据。如果数据已在本地存储中,则直接返回;
* 否则,从服务器获取数据,并将其存储在本地,然后返回。
*
* @param {string} type - 数据的类型。用于指定要获取的EUM数据的类型。
* @returns {Promise} - 返回一个Promise对象,该对象在数据获取成功后解析为相应的数据。
*/
export const getEumData = type => {
const storage = getStorageSync(type);
return new Promise(resolve => {
if (storage) {
resolve(storage);
} else {
getDictDataApi([type]).then(res => {
const data = res.data[type];
setStorageSync(type, data);
resolve(data);
});
}
});
};
export const getEnumText = async (type, code) => {
const eumData = await getEumData(type);
return eumData.find(item => item.code == code)?.text || "无";
};
/**
* 将数据存储在本地存储空间中。
* @param {string} key 要存储的数据的关键字,用于检索数据。
* @param {*} data 要存储的具体数据,可以是各种数据类型。
*/
export const setStorageSync = (key, data) => {
uni.setStorageSync(key, data);
};
export const getStorageSync = key => uni.getStorageSync(key);
// 路由跳转
export const navigateTo = (url, type = "navigateTo") => {
uni[type]({
url: url
});
};
...@@ -31,15 +31,14 @@ export default defineConfig({ ...@@ -31,15 +31,14 @@ export default defineConfig({
} }
}, },
server: { server: {
open: true,
// 代理配置 // 代理配置
proxy: { /* proxy: {
"^/api": { "^/api": {
target: "https://lygsh-api.wjzpgz.com", // 后端服务实际地址 target: "https://lygsh-api.wjzpgz.com", // 后端服务实际地址
changeOrigin: true, //开启代理 changeOrigin: true, //开启代理
// path是请求方法axios配置的baseUr中去除 协议+域名+端口 剩下的部分。例如http://127.0.0.1:9000/api,这里的path就是/api // path是请求方法axios配置的baseUr中去除 协议+域名+端口 剩下的部分。例如http://127.0.0.1:9000/api,这里的path就是/api
rewrite: path => path.replace(/^\/api/, "") // 路径重写 rewrite: path => path.replace(/^\/api/, "") // 路径重写
} }
} } */
} }
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment