瀏覽代碼

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

Xiao_123 1 月之前
父節點
當前提交
833d0479b2

+ 54 - 27
components/RichEditor/index.vue

@@ -31,19 +31,23 @@
 				</view>
  
 				<view class="editor-wrapper">
-					<editor id="editor" class="ql-container" placeholder="开始输入..."
-					show-img-size show-img-toolbar show-img-resize
-					@statuschange="onStatusChange" @ready="onEditorReady"
-					@input="onInputChange"
-					@blur="handleBlur">
-					</editor>
+					<editor
+						id="editor"
+						class="ql-container"
+						placeholder="开始输入..."
+						show-img-size show-img-toolbar show-img-resize
+						@statuschange="onStatusChange"
+						@ready="onEditorReady"
+						@input="onInputChange"
+						@blur="handleBlur"
+					></editor>
 				</view>
 			</view>
 		</view>
-		<view v-if="maxLength > 0" class="word-count">
+		<view v-if="max && max-0" class="word-count" :class="currentWordCount > max-0 ? 'warn' : 'normal'">
 			<text>{{ currentWordCount }}</text>
 			<text> / </text>
-			<text>{{ maxLength }}</text>
+			<text>{{ max }}</text>
 		</view>
 	</view>
 </template>
@@ -55,9 +59,10 @@
 	*/
 	export default {
 		props:{
-			maxLength: {
+			max: {
 				type: Number,
-				default: 0
+				default: 0,
+				validator: value => value >= 0
 			},
 			richValue: {
 				type: String,
@@ -91,44 +96,64 @@
           zitixiabiao: false,
           zitishangbiao: false,
           shanchu: true,
-          direction: false,
+          direction: false
         },
-				prevHtml: null,
+				inputTimer: null,
 				currentWordCount: 0,
 				readOnly: false,
 				formats: {}
 			}
 		},
+		watch: {
+			richValue: {
+				handler(newVal) {
+					this.setEditorContent(newVal || '')
+				},
+				immediate: true,
+				deep: true
+			}
+		},
 		methods: {
+			isExceedValidate(alert = false, isReturn = false, title = '字数超出限制') {
+				const bool = Boolean(this.max-0 && (this.currentWordCount-0 > this.max-0)) 
+				if (alert && bool) uni.showToast({ title, icon: 'none', duration: 2000 })
+				if (isReturn && bool) return true
+			},
 			handleBlur() {
 				this.editorCtx.getContents({
 					success: (res) => {
-						this.$emit('blur',res.html)
+						this.$emit('blur', res.html === '<p><br></p>' ? '' : res.html)
 					}
 				})
 			},
 			onInputChange(e) {
-				const text = e?.detail?.text || null
-				const html = e?.detail?.html || null
-				if (!text || !html) return
-
-				if (this.maxLength && (text.length >= this.maxLength)) {
-					uni.showToast({ icon: 'none', title: `最多可输入${this.maxLength}个字符` })
-					setEditorContent(this.prevHtml)
-					return
-				}
-
-				this.currentWordCount = text.length || 0
-				this.prevHtml = html
+				clearTimeout(this.inputTimer)
+				this.inputTimer = setTimeout(() => {
+					const text = e?.detail?.text ? e.detail.text : null
+					const html = e?.detail?.html ? e.detail.html : null
+					if (!text || !html) return
+					this.currentWordCount = text.length || 0
+					if (this.max-0 && (text.length >= this.max-0)) {
+						uni.showToast({ icon: 'none', title: `最多可输入${this.max}个字符` })
+					}
+					// this.$emit('change', html)
+				}, 500)
 			},
 			setEditorContent(content) {
 				this.editorCtx.setContents({
 					html: content
 				});
+				this.editorCtx.getContents({
+					success: (res) => {
+						this.currentWordCount = res?.text?.length || 0
+					}
+				})
 			},
 			onEditorReady() {
+				// #ifdef APP-PLUS || MP-WEIXIN || H5
 				this.createSelectorQuery().select('#editor').context((res) => {
 					this.editorCtx = res.context
+					
 					this.setEditorContent(this.richValue)
 				}).exec()
 				// #endif	
@@ -181,7 +206,7 @@
 				})
 			},
 			insertImage() {
-                // 上传图片方法 这里需要调用上传图片接口,拿到图片url并插入
+				// 上传图片方法 这里需要调用上传图片接口,拿到图片url并插入
 				this.$utils.uploadImage(1, (res) => {
 					this.editorCtx.insertImage({
 						src: res,
@@ -246,10 +271,12 @@
   color: #06c;
 }
 
+.warn { color: #fe574a; }
+.normal { color: #999; }
+
 .word-count {
 	margin-top: 10px;
   font-size: 12px;
-  color: #999;
 	text-align: right;
 	margin: 4px;
 }

+ 15 - 14
components/positionItem/components/baseInfo.vue

@@ -19,11 +19,10 @@
         </view>
 			</uni-forms-item>
       <uni-forms-item label="岗位职责" name="content" required>
-        <uni-easyinput type="textarea" v-model="formData.content" autoHeight  placeholder="请输入内容"></uni-easyinput>
-        <!-- <RichEditor @blur="richEditorBlur" :richValue="formData.content" /> -->
+        <RichEditor ref="contentRef" :richValue="formData.content" @blur="val => editorBlur('content', val)" :max="1500" />
 			</uni-forms-item>
       <uni-forms-item label="岗位要求 " name="requirement" required>
-        <uni-easyinput type="textarea" v-model="formData.requirement" autoHeight  placeholder="请输入内容"></uni-easyinput>
+        <RichEditor ref="requirementRef" :richValue="formData.requirement" @blur="val => editorBlur('requirement', val)" :max="1500" />
 			</uni-forms-item>
 		</uni-forms>
     <!-- 确认框 -->
@@ -31,7 +30,7 @@
       <uni-popup-dialog
         type="warn"
         cancelText="取消"
-        confirmText="确认" 
+        confirmText="确认"
         title="系统提示"
         content="您确定要放弃目前岗位描述的内容吗?"
         @confirm="handleConfirm"
@@ -46,7 +45,7 @@ import { dictObj } from '@/utils/position.js'
 import { getNextDate } from '@/utils/date'
 import { getRecruitPositionDetails } from '@/api/new/position'
 import { dateToTimestamp } from '@/utils/date.js'
-// import RichEditor from '@/components/RichEditor'
+import RichEditor from '@/components/RichEditor'
 const props = defineProps({
   data: {
     type: Object,
@@ -56,8 +55,7 @@ const props = defineProps({
 
 const formData = ref({
   positionId: props.data?.positionId || '',
-  // name: props.data?.name || '',
-  name: props.data?.name + new Date().getTime().toString() || '',
+  name: props.data?.name || '' + new Date().getTime().toString(), // + new Date().getTime().toString()
   expireTime: props.data?.expireTime || getNextDate(15, 'YYYY-MM-DD', 'day'),
   content: props.data?.content || '',
   requirement: props.data?.requirement || ''
@@ -92,6 +90,10 @@ const rules = {
 	},
 }
 
+const editorBlur = (key, val) => {
+  formData.value[key] = val || ''
+}
+
 const pushTemplate = () => {
   formData.value.content = jobTemplateRes.value.content
   formData.value.requirement = jobTemplateRes.value.requirement
@@ -124,7 +126,6 @@ const useJobTemplate = async () => {
     return
   }
   jobTemplateRes.value = res.data
-  console.log('res.data:', res.data)
   if (formData.value?.content || formData.value?.requirement) {
     // 弹窗提示
     confirm.value.open()
@@ -134,25 +135,25 @@ const useJobTemplate = async () => {
   }
 }
 
-// const richEditorBlur = (content) => {
-//   formData.value.content = content
-// }
-
 const form = ref()
+const contentRef = ref()
+const requirementRef = ref()
 const soFar = ref(props.data?.expireTime === null ? [1] : [])
 const getQuery = async () => {
   const valid = await unref(form).validate()
   if (!valid) return
+  contentRef.value?.isExceedValidate(true, true, '岗位职责字数超出限制')
+  requirementValid.value?.isExceedValidate(true, true, '岗位要求字数超出限制')
+
   const obj = {
     hirePrice: 0,
     soFar: Boolean(soFar.value?.length),
     hire: false,
     ...formData.value
   }
+
   obj.expireTime = obj.soFar ? null : dateToTimestamp(obj.expireTime)
   obj && Object.keys(obj).length && Object.keys(obj).forEach(key => { if (['areaId', 'eduType', 'expType'].includes(key) && obj[key] === -1)  obj[key] = null })
-
-  console.log('基本信息:', obj)
   return obj
 }
 

+ 35 - 25
components/positionItem/components/requirement.vue

@@ -1,30 +1,30 @@
 <!--  -->
 <template>
 	<view class="f-straight wrapper">
-		<uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="90px" label-align="right">
+		<uni-forms ref="form" :modelValue="formData" :rules="salaryDisabled ? rules : {...rules, ...salaryRules}" validateTrigger="bind" label-width="90px" label-align="right">
 			<uni-forms-item label="招聘类型" name="type" required>
 				<uni-data-picker popup-title="请选择招聘类型" v-model="formData.type" :localdata="jobType" :clear-icon="false" :map="{ text: 'key', value: 'value'}" @change="typeChange"></uni-data-picker>
 			</uni-forms-item>
 			<uni-forms-item label="学历要求" name="eduType" required>
-				<uni-data-picker popup-title="请选择学历要求" v-model="formData.eduType" :localdata="dictObj?.edu || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
+				<uni-data-picker popup-title="请选择学历要求" v-model="formData.eduType" :localdata="dictObj?.edu_extend || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
 			</uni-forms-item>
 			<uni-forms-item label="工作经验" name="expType" required>
-				<uni-data-picker popup-title="请选择工作经验" v-model="formData.expType" :localdata="dictObj?.exp || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
+				<uni-data-picker popup-title="请选择工作经验" v-model="formData.expType" :localdata="dictObj?.exp_extend || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
 			</uni-forms-item>
-      <uni-forms-item label="最低薪资" name="payFrom" :required="Boolean(!salary?.length)" label-width="90px">
+      <uni-forms-item label="最低薪资" name="payFrom" :required="!salaryDisabled" label-width="90px">
 				<view class="d-flex">
-          <uni-number-box v-model="formData.payFrom" :disabled="Boolean(salary?.length)" :min="1" :max="999999999" :step="salaryStep" :width="100" @change="payChange"></uni-number-box>
-          <uni-data-checkbox v-model="salary" multiple :localdata="[{ text: '薪资面议', value: 1 }]" selectedColor="#00B760" class="ss-m-l-20" ></uni-data-checkbox>
+          <uni-number-box v-model="formData.payFrom" :disabled="salaryDisabled" :min="1" :max="999999999" :step="salaryStep" :width="100" @change="payChange"></uni-number-box>
+          <uni-data-checkbox v-model="salary" multiple :localdata="[{ text: '薪资面议', value: 1 }]" selectedColor="#00B760" class="ss-m-l-20" @change="salaryCheckboxChange"></uni-data-checkbox>
         </view>
 			</uni-forms-item>
-      <uni-forms-item label="最高薪资" name="payTo" :required="Boolean(!salary?.length)" label-width="90px">
-        <uni-number-box v-model="formData.payTo" :disabled="Boolean(salary?.length)" :min="payToMin" :max="999999999" :step="salaryStep" :width="100"></uni-number-box>
+      <uni-forms-item label="最高薪资" name="payTo" :required="!salaryDisabled" label-width="90px">
+        <uni-number-box v-model="formData.payTo" :disabled="salaryDisabled" :min="payToMin" :max="999999999" :step="salaryStep" :width="100"></uni-number-box>
 			</uni-forms-item>
-			<uni-forms-item label="计薪时段" name="payUnit" :required="Boolean(!salary?.length)">
-				<uni-data-picker popup-title="请选择计薪时段" :placeholder="Boolean(salary?.length) ? '薪资面议' : '请选择'" v-model="formData.payUnit" :readonly="Boolean(salary?.length)" :localdata="dictObj?.payUnit || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
+			<uni-forms-item label="计薪时段" name="payUnit" :required="!salaryDisabled">
+				<uni-data-picker popup-title="请选择计薪时段" :placeholder="salaryDisabled ? '薪资面议' : '请选择'" v-model="formData.payUnit" :readonly="Boolean(salary?.length)" :localdata="dictObj?.payUnit || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
 			</uni-forms-item>
       <uni-forms-item label="工作城市" name="areaId" required label-width="90px">
-				<uni-data-picker popup-title="请选择工作城市" v-model="formData.areaId" :localdata="dictObj?.areaTreeData || []" :clear-icon="false" :map="{ text: 'name', value: 'id'}"></uni-data-picker>
+				<uni-data-picker popup-title="请选择工作城市" v-model="formData.areaId" :localdata="dictObj?.areaTreeData_extend || []" :clear-icon="false" :map="{ text: 'name', value: 'id'}"></uni-data-picker>
 			</uni-forms-item>
 			<uni-forms-item required label="详情地址" name="address">
         <uni-easyinput v-model="formData.address" placeholder="请填写详细地址"></uni-easyinput>
@@ -54,7 +54,7 @@
 	</view>
 </template>
 <script setup>
-import { ref, unref } from 'vue'
+import { ref, unref, computed } from 'vue'
 import { dictObj } from '@/utils/position.js'
 import { getEnterprisePubJobTypePermission } from '@/api/new/position'
 import portrait from './portrait.vue'
@@ -68,16 +68,24 @@ const props = defineProps({
 
 const formData = ref({
   type: props.data?.type || '',
-  eduType: props.data?.eduType || '',
-  expType: props.data?.expType || '',
+  eduType: props.data?.eduType ? props.data?.eduType : props.data ? -1 : '',
+  expType: props.data?.expType ? props.data?.expType : props.data ? -1 : '',
   payFrom: props.data?.payFrom || '',
   payTo: props.data?.payTo || '',
   payUnit: props.data?.payUnit || '',
-  areaId: props.data?.areaId || '',
+  areaId: props.data?.areaId ? props.data?.areaId : props.data ? -1 : '',
   address: props.data?.address || '',
 })
 const tagList = ref(props.data?.tagList?.length ? props.data.tagList : [])
 
+const salaryDisabled = computed(() => {
+  return Boolean(salary?.value.length)
+})
+
+const salaryCheckboxChange = (e) => {
+  // const bool = e.detail.value.length ? e.detail.value[0] : ''
+}
+
 const rules = {
 	type:{
 		rules: [{required: true, errorMessage: '请选择招聘类型' }]
@@ -88,7 +96,16 @@ const rules = {
 	expType:{
 		rules: [{required: true, errorMessage: '请选择工作经验' }]
 	},
-	payFrom:{
+	areaId:{
+		rules: [{required: true, errorMessage: '请选择工作城市' }]
+	},
+	address:{
+		rules: [{required: true, errorMessage: '请填写详细地址' }]
+	},
+}
+
+const salaryRules = {
+	payFrom: {
 		rules: [
       {
         required: true,
@@ -113,7 +130,7 @@ const rules = {
       }
     ]
 	},
-	payTo:{
+	payTo: {
 		rules: [
       {
         required: true,
@@ -140,13 +157,7 @@ const rules = {
 	},
 	payUnit: {
 		rules: [{required: true, errorMessage: '请选择计薪时段' }]
-	},
-	areaId:{
-		rules: [{required: true, errorMessage: '请选择工作城市' }]
-	},
-	address:{
-		rules: [{required: true, errorMessage: '请填写详细地址' }]
-	},
+	}
 }
 
 const jobType = ref([])
@@ -195,7 +206,6 @@ const getQuery = async () => {
     if (obj.salary && ['payFrom', 'payTo', 'payUnit'].includes(key)) obj[key] = null 
   })
 
-  console.log('岗位要求:', obj)
   return obj
 }
 

+ 1 - 3
components/positionItem/index.vue

@@ -54,7 +54,7 @@ let fairId = ''
 onLoad((options) => {
   jobId = options?.jobId || props.jobId || ''
   fairId = options?.fairId || ''
-  console.log('jobId:', jobId); console.log('fairId:', fairId)
+  // console.log('jobId:', jobId); console.log('fairId:', fairId)
   if (jobId) getPositionDetail(jobId)
   else {
     show.value = showExtend.value = true
@@ -69,7 +69,6 @@ const getPositionDetail = async (id) => {
   if (!res?.data && !Object.keys(res.data).length) return
   itemData.value = {...res.data, ...dealDictObjData({}, res.data)}
   show.value = true
-  console.log('itemData:', itemData.value)
   if (itemData.value?.type === '3') {
     isStudent.value = true
     getPositionExtendDetail(id)
@@ -84,7 +83,6 @@ const getPositionExtendDetail = async (jobId) => {
   const res = await getJobAdvertisedExtend(jobId)
   extendData.value = res?.data || {}
   showExtend.value = true
-  console.log('extendData:', extendData.value)
 }
 
 const baseInfoRef = ref(null)

+ 1 - 1
layout/components/authModal/login/index.vue

@@ -125,7 +125,7 @@ const state = ref({
     code: ''
   },
   account: {
-    phone: '1687284007@qq.com',
+    phone: '1687284007@qq.com', // 1687284007 18406571584 
     password: 'Citu123456'
   },
   rules: {

+ 12 - 3
utils/position.js

@@ -7,13 +7,16 @@ export const dictObj = reactive({
   scale: [], // 规模
   industry: [], // 行业
   edu: [], // 学历
+  edu_extend: [], // 扩展
   exp: [], // 工作经验
+  exp_extend: [], // 扩展
   area: [], // 地区
   jobStatus: [], // 求职状态
   marital: [], // 婚姻状态
   sex: [],
   jobType: [],
   areaTreeData: [],
+  areaTreeData_extend: [], // 扩展
   areaTreeDataExtend: [],
   positionSecondData: [],
   eduSystemType: []
@@ -42,11 +45,17 @@ const dictList = ref([
 const getDictList = async () => {
   dictList.value.forEach(async (val) => {
     const { data } = await getDict(val.type, val.params, val.apiType)
-    // if (val.type === 'menduner_pay_unit') {
-    //   debugger
-    // }
     dictObj[val.value] = data.data
+
+    // 字典扩展
+    let obj = null
+    if (['edu', 'exp'].indexOf(val.value) !== -1) obj = { label: '不限', value: -1 }
+    else if (['areaTreeData'].indexOf(val.value) !== -1) obj = { name: '全国', id: -1 }
+    else obj = null
+    // 
+    if (obj) dictObj[val.value + '_extend'] = [obj, ...data.data]
   })
+  // console.log('dictObj:', dictObj)
 }
 export const getDictListData = async () => {
   await getDictList()