ソースを参照

Merge branch 'recruit-enterprise' of https://git.citupro.com/zhengnaiwen_citu/menduner-uniapp into recruit-enterprise

lifanagju_citu 1 ヶ月 前
コミット
83e3a6354a

+ 13 - 0
api/enterprise.js

@@ -113,4 +113,17 @@ export const getEnterpriseRegisterApply = (email) => {
       auth: false
     }
   })
+}
+
+// 重置密码
+export const entUpdatePassword = (data) => {
+  return request({
+    url: '/app-api/menduner/system/recruit/user/update-password',
+    method: 'PUT',
+    data,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
 }

+ 58 - 5
api/interview.js

@@ -1,5 +1,18 @@
 import request from "@/utils/request"
 
+// 面试信息分页
+export const getInterviewInvitePage = async (params) => {
+	return request({
+		url: '/app-api/menduner/system/recruit/interview-invite/page',
+		params,
+		method: 'GET',
+		custom: {
+			showLoading: false,
+			auth: true
+		}
+	})
+}
+
 // 完成面试
 export const completedInterviewInvite = async (id) => {
 	return request({
@@ -13,12 +26,52 @@ export const completedInterviewInvite = async (id) => {
 	})
 }
 
-// 面试信息分页
-export const getInterviewInvitePage = async (params) => {
+// 保存、重新邀约
+export const saveInterviewInvite = async (data) => {
 	return request({
-		url: '/app-api/menduner/system/recruit/interview-invite/page',
-		params,
-		method: 'GET',
+		url: '/app-api/menduner/system/recruit/interview-invite/save',
+		method: 'POST',
+		data,
+		custom: {
+			showLoading: false,
+			openEncryption: true,
+			auth: true
+		}
+	})
+}
+
+// 取消面试
+export const cancelInterviewInvite = async (data) => {
+	return request({
+		url: '/app-api/menduner/system/recruit/interview-invite/cancellation',
+		method: 'POST',
+		data,
+		custom: {
+			showLoading: false,
+			auth: true
+		}
+	})
+}
+
+// 未能爽约面试
+export const noAttendInterviewInvite = async (data) => {
+	return request({
+		url: '/app-api/menduner/system/recruit/interview-invite/not/attended',
+		method: 'POST',
+		data,
+		custom: {
+			showLoading: false,
+			auth: true
+		}
+	})
+}
+
+// 面试反馈
+export const feedbackInterviewInvite = async (data) => {
+	return request({
+		url: '/app-api/menduner/system/recruit/interview-invite/feedback',
+		method: 'POST',
+		data,
 		custom: {
 			showLoading: false,
 			auth: true

+ 0 - 15
api/new/interview.js

@@ -1,15 +0,0 @@
-import request from "@/utils/request"
-
-// 面试-保存、重新邀约
-export const saveInterviewInvite = (data) => {
-	return request({
-		url: '/app-api/menduner/system/recruit/interview-invite/save',
-		method: "POST",
-		data,
-		custom: {
-			openEncryption: true,
-			auth: true,
-			showLoading: false
-		}
-	})
-}

+ 24 - 0
pages.json

@@ -71,6 +71,24 @@
 						"navigationBarTitleText": "面试管理"
 					}
 				},
+				{
+					"path": "interview/feedback",
+					"style": {
+						"navigationBarTitleText": "面试反馈"
+					}
+				},
+				{
+					"path": "interview/cancel",
+					"style": {
+						"navigationBarTitleText": "取消面试"
+					}
+				},
+				{
+					"path": "interview/attended",
+					"style": {
+						"navigationBarTitleText": "面试爽约"
+					}
+				},
 				{
 					"path": "chart/index",
 					"style": {
@@ -82,6 +100,12 @@
 					"style": {
 						"navigationBarTitleText": "简历管理"
 					}
+				},
+				{
+					"path": "editPassword/index",
+					"style": {
+						"navigationBarTitleText": "修改登录密码"
+					}
 				}
 			]
 		},

+ 3 - 2
pages/index/my.vue

@@ -79,8 +79,9 @@ const vip = computed(() => new Date().getTime() < useUserStore?.userInfo?.vipExp
 const popup = ref()
 
 const defaultList = [
-	{ title: '简历', path: '/pagesA/resume/index' },
-	{ title: '面试', path: '/pagesA/interview/index' },
+	{ title: '简历管理', path: '/pagesA/resume/index' },
+	{ title: '面试管理', path: '/pagesA/interview/index' },
+	{ title: '修改密码', path: '/pagesA/editPassword/index' },
 	{ title: '联系我们', path: '/pagesB/contactUs/index' },
 	{ title: '协议中心', path: '/pagesB/agreement/index', open: true },
 	{ title: '我要求职', appId: 'wx5dd538ccc752b03a' },

+ 2 - 2
pages/register/contact.vue

@@ -19,10 +19,10 @@
 					<uni-easyinput v-model="val.email" placeholder="请输入企业邮箱(用于日后“登录邮箱”)"></uni-easyinput>
 				</uni-forms-item>
 				<uni-forms-item name="password" label="账户登录密码" required>
-					<uni-easyinput v-model="val.password" placeholder="请输入"></uni-easyinput>
+					<uni-easyinput v-model="val.password" placeholder="请输入" type="password"></uni-easyinput>
 				</uni-forms-item>
 				<uni-forms-item name="passwordConfirm" label="密码二次确认" required>
-					<uni-easyinput v-model="val.passwordConfirm" placeholder="请输入"></uni-easyinput>
+					<uni-easyinput v-model="val.passwordConfirm" placeholder="请输入" type="password"></uni-easyinput>
 				</uni-forms-item>
 			</uni-forms>
 		</view>

+ 68 - 0
pagesA/editPassword/index.vue

@@ -0,0 +1,68 @@
+<template>
+	<view style="padding: 30rpx;">
+		<uni-forms ref="formRef" :modelValue="formData" :rules="formRules" validateTrigger="bind" label-width="80px" label-align="right" label-position="left">
+			<uni-forms-item name="password" label="新密码" required>
+				<uni-easyinput v-model="formData.password" type="password" placeholder="请输入新密码"></uni-easyinput>
+			</uni-forms-item>
+			<uni-forms-item name="passwordConfirm" label="二次确认" required>
+				<uni-easyinput v-model="formData.passwordConfirm" type="password" placeholder="请再次输入新密码"></uni-easyinput>
+			</uni-forms-item>
+		</uni-forms>
+
+		<button class="send-button" @tap="handleSubmit">提 交</button>
+	</view>
+</template>
+
+<script setup>
+import { ref, unref } from 'vue'
+import { password } from '@/utils/validate'
+import { userStore } from '@/store/user'
+import { entUpdatePassword } from '@/api/enterprise'
+
+const user = userStore()
+const formRef = ref(null)
+const formData = ref({
+	id: user?.userInfo?.id,
+	password: null,
+	passwordConfirm: null
+})
+const formRules = {
+	password,
+	passwordConfirm: {
+		rules: [
+			{ required: true, errorMessage: '请再次输入密码' },
+			{ 
+				validateFunction: function(rule, value, data, callback) {
+					if (value !== data.password) callback('两次输入的密码不一致')
+					return true
+				}
+			}
+		]
+	}
+}
+
+// 提交
+const handleSubmit = async () => {
+	const valid = await unref(formRef).validate()
+	if (!valid) return
+
+	uni.showLoading({ title: '提交中' })
+	try {
+		await entUpdatePassword(formData.value)
+		uni.hideLoading()
+		uni.showToast({
+			title: '修改成功',
+			icon: 'success'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+	} catch {
+		uni.hideLoading()
+	}
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 68 - 0
pagesA/interview/attended.vue

@@ -0,0 +1,68 @@
+<template>
+	<view style="padding: 30rpx;">
+		<uni-forms ref="formRef" :modelValue="formData" :rules="formRules" validateTrigger="bind" label-width="80px" label-align="right" label-position="left">
+			<uni-forms-item name="reason" label="爽约原因" required>
+				<uni-easyinput v-model="formData.reason" type="textarea" placeholder="请输入爽约原因"></uni-easyinput>
+			</uni-forms-item>
+		</uni-forms>
+		<button class="send-button" @tap="handleSubmit">提 交</button>
+	</view>
+</template>
+
+<script setup>
+import { ref, unref } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import { noAttendInterviewInvite } from '@/api/interview'
+
+const formRef = ref(null)
+const formData = ref({
+	id: null,
+	reason: null
+})
+const formRules = {
+	reason: {
+		rules: [{ required: true, errorMessage: '请输入爽约原因' }]
+	}
+}
+
+onLoad(async (options) => {
+	const { id } = options
+	if (!id) {
+		uni.showToast({
+			title: 'ID缺失',
+			icon: 'none'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+		return
+	}
+
+	formData.value.id = id
+})
+
+// 提交
+const handleSubmit = async () => {
+	const valid = await unref(formRef).validate()
+	if (!valid) return
+
+	uni.showLoading({ title: '提交中' })
+	try {
+		await noAttendInterviewInvite(formData.value)
+		uni.hideLoading()
+		uni.showToast({
+			title: '提交成功',
+			icon: 'success'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+	} catch {
+		uni.hideLoading()
+	}
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 68 - 0
pagesA/interview/cancel.vue

@@ -0,0 +1,68 @@
+<template>
+	<view style="padding: 30rpx;">
+		<uni-forms ref="formRef" :modelValue="formData" :rules="formRules" validateTrigger="bind" label-width="80px" label-align="right" label-position="left">
+			<uni-forms-item name="reason" label="取消原因" required>
+				<uni-easyinput v-model="formData.reason" type="textarea" placeholder="请输入取消原因"></uni-easyinput>
+			</uni-forms-item>
+		</uni-forms>
+		<button class="send-button" @tap="handleSubmit">提 交</button>
+	</view>
+</template>
+
+<script setup>
+import { ref, unref } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import { cancelInterviewInvite } from '@/api/interview'
+
+const formRef = ref(null)
+const formData = ref({
+	id: null,
+	reason: null
+})
+const formRules = {
+	reason: {
+		rules: [{ required: true, errorMessage: '请输入取消原因' }]
+	}
+}
+
+onLoad(async (options) => {
+	const { id } = options
+	if (!id) {
+		uni.showToast({
+			title: 'ID缺失',
+			icon: 'none'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+		return
+	}
+
+	formData.value.id = id
+})
+
+// 提交
+const handleSubmit = async () => {
+	const valid = await unref(formRef).validate()
+	if (!valid) return
+
+	uni.showLoading({ title: '提交中' })
+	try {
+		await cancelInterviewInvite(formData.value)
+		uni.hideLoading()
+		uni.showToast({
+			title: '提交成功',
+			icon: 'success'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+	} catch {
+		uni.hideLoading()
+	}
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 31 - 25
pagesA/interview/item.vue → pagesA/interview/components/item.vue

@@ -1,6 +1,6 @@
 <template>
 	<view>
-		<uni-card v-for="(val, index) in items" :key="index" :is-shadow="true" @tap.stop="handleDetail(val)" :border='false' shadow="0px 0px 3px 1px rgba(0,0,0,0.1)">
+		<uni-card v-for="(val, index) in items" :key="index" :is-shadow="true" :border='false' shadow="0px 0px 3px 1px rgba(0,0,0,0.1)">
 			<!-- 基本信息 -->
 			<view class="d-flex align-center">
 				<view class="user-avatar">
@@ -37,7 +37,7 @@
 				<view 
 					class="sub-li-bottom-item d-flex align-center justify-center" 
 					@tap.stop="handleLoadMore(val)" 
-					:style="{'color': !actionItems(val)?.length ? '#ccc' : '#00B760'}"
+					:style="{'color': val?.job?.status === '1' || !actionItems(val)?.length ? '#ccc' : '#00B760'}"
 				>
 					<view>更多操作</view>
 					<uni-icons type="list" class="ss-m-l-10" size="20" :color="!actionItems(val)?.length ? '#ccc' : '#00B760'"></uni-icons>
@@ -53,7 +53,7 @@
 					class="action-item"
 					v-for="(val, index) in actionItems(itemData)" 
 					:key="index"
-					@tap.stop="handleActionClick(val.type, itemData)"
+					@tap.stop="handleActionClick(val.value, itemData)"
 				>{{ val.title }}</view>
 			</view>
       <button class="big-cancel-button" @tap.stop="handleClosePopup">取消</button>
@@ -61,16 +61,16 @@
 
     <!-- 完成面试 -->
     <uni-popup ref="finishPopup" type="dialog">
-				<uni-popup-dialog 
-          type="warn" 
-          cancelText="取消"
-          confirmText="确定" 
-          title="系统提示" 
-          content="是否确认已完成面试?"
-          @confirm="handleFinishConfirm"
-          @close="handleFinishClose"
-        ></uni-popup-dialog>
-			</uni-popup>
+			<uni-popup-dialog 
+        type="warn" 
+        cancelText="取消"
+        confirmText="确定" 
+        title="系统提示" 
+        content="是否确认已完成面试?"
+        @confirm="handleFinishConfirm"
+        @close="handleFinishClose"
+      ></uni-popup-dialog>
+		</uni-popup>
 	</view>
 </template>
 
@@ -103,6 +103,11 @@ const itemData = ref({})
 
 // 更多操作
 const handleLoadMore = (val) => {
+	if (val?.job?.status === '1') {
+		itemData.value = {}
+		uni.showToast({ title: '职位已关闭,暂无更多操作', icon: 'none' })
+		return
+	}
 	if (!actionItems(val).length) {
 		itemData.value = {}
 		uni.showToast({ title: '暂无更多操作', icon: 'none' })
@@ -136,18 +141,6 @@ const handleFinishConfirm = async () => {
   }
 }
 
-// 邀请面试
-// const handleInterviewInvite = (item) => {
-// 	if (item?.job?.status === '1') {
-// 		uni.showToast({ title: '职位已关闭', icon: 'none' })
-// 		return
-// 	}
-// 	uni.navigateTo({
-// 	  url: `/pagesB/InviteInterview/index?id=${item.userId}&jobId=${item.job.id}`
-// 	})
-// 	handleClosePopup()
-// }
-
 const handleActionClick = (type, val) => {
   if (val.job?.status === '1' && (type !== 'completed')) {
     uni.showToast({ title: '职位已关闭', icon: 'none' })
@@ -158,6 +151,19 @@ const handleActionClick = (type, val) => {
   if (type === 'completed') {
     finishPopup.value.open()
   }
+	// 修改面试、重新邀约
+	if (type === 'edit') {
+		uni.navigateTo({
+			url: '/pagesB/InviteInterview/index?editData=' + encodeURIComponent(JSON.stringify(val))
+		})
+	}
+	// 取消面试、爽约、面试反馈
+	if (['cancel', 'attended', 'feedback'].includes(type)) {
+		uni.navigateTo({
+			url: `/pagesA/interview/${type}?id=${val.id}`
+		})
+	}
+	popup.value.close()
 }
 
 const obj = {

+ 68 - 0
pagesA/interview/feedback.vue

@@ -0,0 +1,68 @@
+<template>
+	<view style="padding: 30rpx;">
+		<uni-forms ref="formRef" :modelValue="formData" :rules="formRules" validateTrigger="bind" label-width="80px" label-align="right" label-position="left">
+			<uni-forms-item name="evaluate" label="反馈内容" required>
+				<uni-easyinput v-model="formData.evaluate" type="textarea" placeholder="请输入反馈内容"></uni-easyinput>
+			</uni-forms-item>
+		</uni-forms>
+		<button class="send-button" @tap="handleSubmit">提 交</button>
+	</view>
+</template>
+
+<script setup>
+import { ref, unref } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import { feedbackInterviewInvite } from '@/api/interview'
+
+const formRef = ref(null)
+const formData = ref({
+	id: null,
+	evaluate: null
+})
+const formRules = {
+	evaluate: {
+		rules: [{ required: true, errorMessage: '请输入反馈内容' }]
+	}
+}
+
+onLoad(async (options) => {
+	const { id } = options
+	if (!id) {
+		uni.showToast({
+			title: 'ID缺失',
+			icon: 'none'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+		return
+	}
+
+	formData.value.id = id
+})
+
+// 提交
+const handleSubmit = async () => {
+	const valid = await unref(formRef).validate()
+	if (!valid) return
+
+	uni.showLoading({ title: '提交中' })
+	try {
+		await feedbackInterviewInvite(formData.value)
+		uni.hideLoading()
+		uni.showToast({
+			title: '提交成功',
+			icon: 'success'
+		})
+		setTimeout(() => {
+			uni.navigateBack({ delta: 1 })
+		}, 1000)
+	} catch {
+		uni.hideLoading()
+	}
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 9 - 7
pagesA/interview/index.vue

@@ -13,10 +13,10 @@
       <view style="margin: 20rpx;">
         <uni-data-select 
           v-model="query.jobId" 
-          :clear="false" 
+          :clear="true" 
           :localdata="jobList" 
           @change="handleChangeJob" 
-          placeholder="招聘职位"
+          placeholder="招聘职位"
 			></uni-data-select>
       </view>
     </view>
@@ -30,7 +30,7 @@
 
 <script setup>
 import { ref } from 'vue'
-import CardItem from './item.vue'
+import CardItem from './components/item.vue'
 import { getInterviewInvitePage } from '@/api/interview'
 import { getJobAdvertised } from '@/api/search'
 import { onShow, onLoad } from '@dcloudio/uni-app'
@@ -52,10 +52,10 @@ const query = ref({
 // 职位列表
 const jobList = ref([])
 const getJobList = async () => {
-  const { data } = await getJobAdvertised({ status: 0 })
+  const { data } = await getJobAdvertised()
   if (data.length) {
     jobList.value = data.map(e => {
-      return { text: `${formatName(e.name)}`, value: e.id }
+      return { text: `${formatName(e.name)}_${e.status === '1' ? '已关闭' : '招聘中'}`, value: e.id }
     })
   }
 }
@@ -100,15 +100,17 @@ const getList = async () => {
 
 onShow(() => {
   if (!tabList.value.length) return
+  items.value = []
+  query.value.pageNo = 1
   getList()
 })
 
 // 选择招聘中职位
-const handleChangeJob = (e) => {
+const handleChangeJob = () => {
 	query.value.pageNo = 1
 	items.value = []
 	total.value = 0
-	if (e) getList()
+	getList()
 }
 
 const handleRefresh = () => {

+ 18 - 1
pagesB/InviteInterview/index.vue

@@ -29,7 +29,7 @@ import { mobile } from '@/utils/validate'
 import { getJobAdvertised } from '@/api/new/position'
 import { formatName } from '@/utils/getText'
 import { getInterviewInviteDefaultTime } from '@/utils/date'
-import { saveInterviewInvite } from '@/api/new/interview'
+import { saveInterviewInvite } from '@/api/interview'
 
 const formRef = ref(null)
 const useUserStore = userStore()
@@ -78,6 +78,23 @@ const handleChangeJob = (e) =>{
 }
 
 onLoad(async (options) => {
+	// 编辑面试、重新邀约
+	if (options?.editData) {
+		const obj = JSON.parse(decodeURIComponent(options.editData))
+		for (let key in formData.value) {
+			formData.value[key] = obj[key]
+		}
+		formData.value.id = obj.id
+		if (obj.jobFairId) formData.value.jobFairId = obj.jobFairId
+		// 有实习时间的则为学生,需传递实习时间
+		if (obj?.practiceStartTime && obj?.practiceEndTime) {
+			formData.value.practiceStartTime = obj.practiceStartTime
+			formData.value.practiceEndTime = obj.practiceEndTime
+		}
+		await getJobList()
+		return
+	}
+
 	const { id, jobId } = options
 	if (!id) {
 		uni.showToast({